dsh-whale-widget 0.2.7 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/lib/index.js +42 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ DeepSeek Harness(DSH)Web 界面右下角的常驻余额挂件:小鲸鱼气
|
|
|
10
10
|
- 💰 **余额**:60 秒自动刷新 + 点击鲸鱼手动刷新;余额变化时数字**滚动动画**;瞬时网络抖动自动沿用最近余额不报错
|
|
11
11
|
- 📊 **今日已用**:两种模式任选(见下),显示今日消耗金额
|
|
12
12
|
- **小鲸鱼记账(推荐,免令牌)**:不需要任何会话令牌,鲸鱼娘每次观测余额后用余额差值自动记账(`.dshw-usage.json`,跨天自动归零归档)
|
|
13
|
-
-
|
|
13
|
+
- **实时·令牌**:填入平台会话令牌后直接调用平台用量接口,按**峰谷定价**(工作日高峰 9:00–12:00 与 14:00–18:00,其余空闲;2026-08-23 起周末全天按谷价)实时换算今日已用
|
|
14
14
|
- 💬 **每轮对话消耗统计**:监听本机会话事件,每轮对话结束后弹出本轮消耗金额(精确 usage,非估算)
|
|
15
15
|
- 菜单可开关「每轮对话后自动显示消耗金额」;「自动关闭时间」可自定义秒数(填 0 表示不自动关闭)
|
|
16
16
|
- 消耗金额泡泡显示期间,余额变动不弹普通泡泡
|
|
@@ -146,7 +146,7 @@ Remove-Item "$web\DSniang02.png" -ErrorAction SilentlyContinue
|
|
|
146
146
|
|
|
147
147
|
**① 小鲸鱼记账(推荐,默认)—— 完全不需要额外配置**
|
|
148
148
|
|
|
149
|
-
鲸鱼娘自己用**余额差值**记账:每次观测到余额下降就把差值累加到当天用量,跨天自动归零归档(保留 30
|
|
149
|
+
鲸鱼娘自己用**余额差值**记账:每次观测到余额下降就把差值累加到当天用量,跨天自动归零归档(保留 30 天);观测币种发生变化时只重置基准、不记差值(防止多币种账户切换污染账本)。只要配好了 `DEEPSEEK_API_KEY` 就能用,**开箱即用**。
|
|
150
150
|
|
|
151
151
|
- 账本文件:`$DSH_HOME/.dshw-usage.json`(自动生成)
|
|
152
152
|
- 优点:零配置、免令牌
|
package/lib/index.js
CHANGED
|
@@ -63,7 +63,8 @@ const RUA_GIF_CANDIDATES = [
|
|
|
63
63
|
'D:/TestBox/deepseek/rua.gif',
|
|
64
64
|
]
|
|
65
65
|
// DeepSeek CNY prices per million tokens: [空闲时段价, 高峰时段价].
|
|
66
|
-
//
|
|
66
|
+
// 高峰时段:工作日 9:00–12:00 和 14:00–18:00(北京时间);2026-08-23 起周末全天谷价。
|
|
67
|
+
// Adjust here if DeepSeek changes pricing.
|
|
67
68
|
const PEAK_HOURS = [
|
|
68
69
|
[9, 12],
|
|
69
70
|
[14, 18],
|
|
@@ -88,9 +89,18 @@ function priceFor(model) {
|
|
|
88
89
|
return PRICING._default
|
|
89
90
|
}
|
|
90
91
|
// bucket time is an epoch second; derive the Beijing local hour to pick peak vs off-peak price.
|
|
92
|
+
// 2026-08-23 起(北京时间)周末(周六/周日)全天按谷价;生效时刻之前的历史
|
|
93
|
+
// 分桶仍按旧规则计价,所以周末判定带生效分界。
|
|
94
|
+
const WEEKEND_VALLEY_FROM_SEC = Math.floor(Date.UTC(2026, 7, 22, 16, 0, 0) / 1000) // = 北京时间 2026-08-23 00:00
|
|
91
95
|
function isPeakTime(timeSec) {
|
|
92
96
|
if (!isFinite(Number(timeSec))) return false
|
|
93
|
-
const
|
|
97
|
+
const n = Number(timeSec)
|
|
98
|
+
const bj = new Date(n * 1000 + 8 * 3600 * 1000)
|
|
99
|
+
if (n >= WEEKEND_VALLEY_FROM_SEC) {
|
|
100
|
+
const dow = bj.getUTCDay() // 0=周日 6=周六(bj 按 UTC 读即为北京日历日)
|
|
101
|
+
if (dow === 0 || dow === 6) return false
|
|
102
|
+
}
|
|
103
|
+
const hour = bj.getUTCHours()
|
|
94
104
|
for (const [start, end] of PEAK_HOURS) {
|
|
95
105
|
if (hour >= start && hour < end) return true
|
|
96
106
|
}
|
|
@@ -385,10 +395,13 @@ bubbleBox.addEventListener('click', function (e) {
|
|
|
385
395
|
// 再次点击:关闭
|
|
386
396
|
hideBubble()
|
|
387
397
|
} else {
|
|
388
|
-
//
|
|
398
|
+
// 首次点击:切到随机台词段,并重置自动关闭计时——
|
|
399
|
+
// 保证第二段台词有完整停留时间(否则第 4 秒点击只看到 0.5 秒)
|
|
389
400
|
bubbleRandomActive = true
|
|
390
401
|
bubbleRandomLines = pickRandomLines()
|
|
391
402
|
swapBubbleContent(function () { applyBubbleLines(bubbleRandomLines) })
|
|
403
|
+
if (bubbleTimer) { clearTimeout(bubbleTimer); bubbleTimer = null }
|
|
404
|
+
bubbleTimer = setTimeout(hideBubble, BUBBLE_MS)
|
|
392
405
|
}
|
|
393
406
|
})
|
|
394
407
|
|
|
@@ -608,6 +621,10 @@ function showCostBubble(amount) {
|
|
|
608
621
|
if (costBubbleTimer) { clearTimeout(costBubbleTimer); costBubbleTimer = null }
|
|
609
622
|
if (bubbleTimer) { clearTimeout(bubbleTimer); bubbleTimer = null }
|
|
610
623
|
if (gifFadeTimer) { clearTimeout(gifFadeTimer); gifFadeTimer = null }
|
|
624
|
+
// 取消进行中的余额数字滚动与延迟计时器,避免竞态覆盖成本金额
|
|
625
|
+
if (animId) { cancelAnimationFrame(animId); animId = null }
|
|
626
|
+
if (animDelayTimer) { clearTimeout(animDelayTimer); animDelayTimer = null }
|
|
627
|
+
if (settleTimer) { clearTimeout(settleTimer); settleTimer = null }
|
|
611
628
|
costBubbleActive = true
|
|
612
629
|
bubbleRandomActive = false
|
|
613
630
|
bubbleShown = true
|
|
@@ -669,6 +686,11 @@ function animateAmount(from, to, currency, duration) {
|
|
|
669
686
|
}
|
|
670
687
|
var startTime = null
|
|
671
688
|
function step(ts) {
|
|
689
|
+
// 帧级保护:成本泡泡出现后立即停止滚动,避免后续帧把余额写进金额行
|
|
690
|
+
if (costBubbleActive) {
|
|
691
|
+
animId = null
|
|
692
|
+
return
|
|
693
|
+
}
|
|
672
694
|
if (startTime === null) startTime = ts
|
|
673
695
|
var t = Math.min(1, (ts - startTime) / duration)
|
|
674
696
|
var eased = 1 - Math.pow(1 - t, 3)
|
|
@@ -1238,6 +1260,8 @@ function endDrag(e, clickAllowed) {
|
|
|
1238
1260
|
state.left = left
|
|
1239
1261
|
state.top = top
|
|
1240
1262
|
settle()
|
|
1263
|
+
// 拖拽结束立即保存锚点位置(否则刷新/关闭后位置回退到上次改菜单时)
|
|
1264
|
+
saveConfig()
|
|
1241
1265
|
}
|
|
1242
1266
|
// 窗口尺寸变化时:自由位置的鲸鱼按相对边框锚点重算(保持离边距离,窗口恢复原状即回原位);
|
|
1243
1267
|
// 贴边吸附的鲸鱼走 settle()(保持贴边)
|
|
@@ -1635,10 +1659,16 @@ function apply(ctx) {
|
|
|
1635
1659
|
}
|
|
1636
1660
|
return false
|
|
1637
1661
|
}
|
|
1638
|
-
//
|
|
1639
|
-
|
|
1662
|
+
// 记账模式:每次观测到余额后,用余额正差值累计当天用量(跨天自动归零并归档)。
|
|
1663
|
+
// 币种感知:观测币种与上次不同时只重置基准、不记差值——数值跳变来自币种
|
|
1664
|
+
// 切换而非真实消费([0] 选币时代 CNY/USD 随机切换曾记出巨额假账,见 #13)。
|
|
1665
|
+
function recordLedgerUsage(currentBalance, currency) {
|
|
1640
1666
|
const t = todayKey()
|
|
1641
1667
|
let led = readUsageLedger()
|
|
1668
|
+
const cur = String(currency || '')
|
|
1669
|
+
const currencyChanged =
|
|
1670
|
+
typeof led.lastCurrency === 'string' && led.lastCurrency !== '' &&
|
|
1671
|
+
cur !== '' && led.lastCurrency !== cur
|
|
1642
1672
|
if (led.date !== t) {
|
|
1643
1673
|
if (led.date && typeof led.todayUsage === 'number') {
|
|
1644
1674
|
led.history = led.history || {}
|
|
@@ -1646,13 +1676,19 @@ function apply(ctx) {
|
|
|
1646
1676
|
}
|
|
1647
1677
|
led.date = t
|
|
1648
1678
|
led.lastBalance = currentBalance
|
|
1679
|
+
led.lastCurrency = cur
|
|
1649
1680
|
led.todayUsage = 0
|
|
1681
|
+
} else if (currencyChanged) {
|
|
1682
|
+
// 币种切换:只换基准,不把差值记成消费
|
|
1683
|
+
led.lastBalance = currentBalance
|
|
1684
|
+
led.lastCurrency = cur
|
|
1650
1685
|
} else {
|
|
1651
1686
|
const prev = typeof led.lastBalance === 'number' ? led.lastBalance : currentBalance
|
|
1652
1687
|
if (typeof prev === 'number' && typeof currentBalance === 'number' && currentBalance < prev) {
|
|
1653
1688
|
led.todayUsage = (typeof led.todayUsage === 'number' ? led.todayUsage : 0) + (prev - currentBalance)
|
|
1654
1689
|
}
|
|
1655
1690
|
led.lastBalance = currentBalance
|
|
1691
|
+
led.lastCurrency = cur
|
|
1656
1692
|
}
|
|
1657
1693
|
const keys = Object.keys(led.history || {}).sort()
|
|
1658
1694
|
while (keys.length > 30) {
|
|
@@ -1669,7 +1705,7 @@ function apply(ctx) {
|
|
|
1669
1705
|
const payload = await fetchBalance()
|
|
1670
1706
|
if (!payload.ok) return payload
|
|
1671
1707
|
// 无论哪种模式,都先把余额观测记入账本(自动累积「鲸鱼记账」数据)
|
|
1672
|
-
const led = recordLedgerUsage(Number(payload.totalBalance))
|
|
1708
|
+
const led = recordLedgerUsage(Number(payload.totalBalance), payload.currency)
|
|
1673
1709
|
const cfg = readSizeConfig() || {}
|
|
1674
1710
|
const mode = normalizeUsageMode(cfg.usageMode)
|
|
1675
1711
|
const full = { ...payload }
|