@sligqoer/dsh-usage-stats 0.2.2 → 0.2.4
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/CHANGELOG.md +44 -0
- package/README.en.md +11 -9
- package/README.md +11 -9
- package/lib/client.js +133 -30
- package/locale/en.json +1 -1
- package/locale/ja.json +1 -1
- package/locale/zh.json +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,49 @@
|
|
|
1
1
|
# 更新日志 / Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.4 - 2026-10-17
|
|
4
|
+
|
|
5
|
+
<a id="v024-zh"></a>
|
|
6
|
+
**简体中文** · [English](#v024-en)
|
|
7
|
+
|
|
8
|
+
### 🎨 体验优化
|
|
9
|
+
|
|
10
|
+
- 检测页按「选择检测模型 → 确认预算 → 检测结果」显示当前步骤,突出预算与开始操作,增加请求进度、取消入口和空状态。
|
|
11
|
+
- 调整字体、间距和状态颜色,适配深浅主题与窄窗口;预算参数、检测详情和指纹引擎信息默认折叠,更新异常仍直接显示。
|
|
12
|
+
|
|
13
|
+
### 🐛 问题修复
|
|
14
|
+
|
|
15
|
+
- 适配 DSH Desktop 0.2.1-rc.2,并兼容 0.2.1-rc.1、0.2.1-alpha.2、0.2.0-rc.2 和 0.2.0-rc.1,保留已有桌面渲染器标记兼容。
|
|
16
|
+
- 更换模型或参数后重新确认预算,历史结果保留原检测条件;检测运行中不再提前显示无法判定的说明,精简重复提示。
|
|
17
|
+
|
|
18
|
+
<a id="v024-en"></a>
|
|
19
|
+
**English** · [简体中文](#v024-zh)
|
|
20
|
+
|
|
21
|
+
### 🎨 Improvements
|
|
22
|
+
|
|
23
|
+
- Guide detection through model selection, budget confirmation and results, with clearer primary actions, request progress, cancellation and empty states.
|
|
24
|
+
- Refine typography, spacing and status colors for light and dark themes and narrow windows. Collapse budget parameters, technical details and engine information by default while keeping update warnings visible.
|
|
25
|
+
|
|
26
|
+
### 🐛 Bug Fixes
|
|
27
|
+
|
|
28
|
+
- Support DSH Desktop 0.2.1-rc.2 alongside 0.2.1-rc.1, 0.2.1-alpha.2, 0.2.0-rc.2 and 0.2.0-rc.1, retaining both desktop renderer markers.
|
|
29
|
+
- Require a new budget after model or parameter changes and keep saved results tied to their original settings. Avoid premature inconclusive explanations while detection runs and remove repeated notices.
|
|
30
|
+
|
|
31
|
+
## 0.2.3 - 2026-10-16
|
|
32
|
+
|
|
33
|
+
<a id="v023-zh"></a>
|
|
34
|
+
**简体中文** · [English](#v023-en)
|
|
35
|
+
|
|
36
|
+
### 🐛 问题修复
|
|
37
|
+
|
|
38
|
+
- 适配 DSH Desktop 0.2.0-rc.2 的桌面渲染器标记:preload 桥 `dshDesktop` 只暴露 `protocolVersion`,不再提供 `deviceInfo` 函数。「用量统计」设置页此前因此不注册,现在新旧两种标记都接受,纯浏览器访问仍保持不挂载。`0.2.1-alpha.2` 与 `0.2.0-rc.2` 两个宿主版本均受支持。
|
|
39
|
+
|
|
40
|
+
<a id="v023-en"></a>
|
|
41
|
+
**English** · [简体中文](#v023-zh)
|
|
42
|
+
|
|
43
|
+
### 🐛 Bug Fixes
|
|
44
|
+
|
|
45
|
+
- Adapt to the DSH Desktop 0.2.0-rc.2 renderer marker: the `dshDesktop` preload bridge exposes only `protocolVersion` and no longer carries a `deviceInfo` function. The usage statistics settings page failed to register because of this; both markers are now accepted, while plain browser tabs still never mount. Both `0.2.1-alpha.2` and `0.2.0-rc.2` hosts remain supported.
|
|
46
|
+
|
|
3
47
|
## 0.2.2 - 2026-10-16
|
|
4
48
|
|
|
5
49
|
<a id="v022-zh"></a>
|
package/README.en.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
<p align="center">
|
|
13
13
|
<a href="#installation"><img src="https://img.shields.io/badge/DSH-Desktop-2563eb?style=flat-square" alt="DSH Desktop"></a>
|
|
14
|
-
<a href="https://github.com/Jockjrop/dsh-usage-stats/releases/latest"><img src="https://img.shields.io/badge/release-v0.2.
|
|
14
|
+
<a href="https://github.com/Jockjrop/dsh-usage-stats/releases/latest"><img src="https://img.shields.io/badge/release-v0.2.4-64748b?style=flat-square" alt="Plugin version 0.2.4"></a>
|
|
15
15
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-22c55e?style=flat-square" alt="Apache 2.0 license"></a>
|
|
16
16
|
</p>
|
|
17
17
|
|
|
@@ -60,13 +60,13 @@
|
|
|
60
60
|
| --- | --- |
|
|
61
61
|
| **Usage** | View today's and lifetime tokens, active days, hourly calls, daily/weekly heatmaps, trends, model breakdowns and output speed. |
|
|
62
62
|
| **Quotas** | Check provider balances, account credits and quota windows, with manual or scheduled refresh and custom queries. |
|
|
63
|
-
| **Detection** | Select a provider and model independently, confirm a budget, then run LM Fingerprint sampling and review
|
|
63
|
+
| **Detection** | Select a provider and model independently, confirm a budget, then run LM Fingerprint sampling and review request progress, sample status, candidate rankings and saved results. |
|
|
64
64
|
| **Controls** | Adjust display preferences, quota query settings, the advanced model selector and per-model reasoning levels. |
|
|
65
65
|
|
|
66
66
|
- **Follow usage trends:** browse daily/weekly heatmaps, switch between 7/30-day trends and compare providers and models.
|
|
67
67
|
- **Compare output speed:** rank models by TPS and show average time to first token (TTFT); samples without valid timing are excluded from speed rankings.
|
|
68
68
|
- **Refresh quotas on demand:** use DSH credentials for configured providers. Account quotas require the corresponding plugin or host service. Automatic refresh is off by default.
|
|
69
|
-
- **Run independent detection:**
|
|
69
|
+
- **Run independent detection:** follow model selection, budget confirmation and results. Use three samples by default or one for screening, with progress, cancellation, timeouts and usage budgets.
|
|
70
70
|
- **Adjust model settings:** control the advanced model selector and reasoning features independently while retaining model properties, parameter mappings and saved preferences.
|
|
71
71
|
- **Follow the application language:** Chinese, English and Japanese UI text follows DSH's selected language; custom names and quota labels remain unchanged.
|
|
72
72
|
|
|
@@ -74,7 +74,7 @@ Detection compares random-number samples with a reference library. Rankings and
|
|
|
74
74
|
|
|
75
75
|
## Installation
|
|
76
76
|
|
|
77
|
-
Plugin version **0.2.
|
|
77
|
+
Plugin version **0.2.4** supports **DSH Desktop `0.2.1-rc.2`** and retains compatibility with `0.2.1-rc.1`, `0.2.1-alpha.2`, `0.2.0-rc.2` and `0.2.0-rc.1`. The host plugin manager rejects installation or activation on a mismatched runtime.
|
|
78
78
|
|
|
79
79
|
**Recommended: install the [npm package `@sligqoer/dsh-usage-stats`](https://www.npmjs.com/package/@sligqoer/dsh-usage-stats) through DSH Desktop.** It includes prebuilt modules, needs no Git checkout or local build, and supports Check updates when installed by package name.
|
|
80
80
|
|
|
@@ -100,16 +100,16 @@ Click **Enable now**, then open **Settings → Usage Stats**. Fully exit and reo
|
|
|
100
100
|
Enter this in the same installer for this release:
|
|
101
101
|
|
|
102
102
|
```text
|
|
103
|
-
@sligqoer/dsh-usage-stats@0.2.
|
|
103
|
+
@sligqoer/dsh-usage-stats@0.2.4
|
|
104
104
|
```
|
|
105
105
|
|
|
106
106
|
Alternatively, download a `.tgz` and `SHA256SUMS` from the [GitHub release page](https://github.com/Jockjrop/dsh-usage-stats/releases/latest), verify the hash and enter the archive's local absolute path. Do not extract it before installation.
|
|
107
107
|
|
|
108
108
|
```powershell
|
|
109
|
-
Get-FileHash ./sligqoer-dsh-usage-stats-0.2.
|
|
109
|
+
Get-FileHash ./sligqoer-dsh-usage-stats-0.2.4.tgz -Algorithm SHA256
|
|
110
110
|
```
|
|
111
111
|
|
|
112
|
-
Assets include `sligqoer-dsh-usage-stats-0.2.
|
|
112
|
+
Assets include `sligqoer-dsh-usage-stats-0.2.4.tgz`, the equivalent `dsh-usage-stats.tgz`, and `SHA256SUMS`. Both archives contain identical modules.
|
|
113
113
|
|
|
114
114
|
</details>
|
|
115
115
|
|
|
@@ -126,9 +126,11 @@ If you use the old `dsh-usage-stats` package name, uninstall it once and install
|
|
|
126
126
|
|
|
127
127
|
1. Open Usage for the overview, trends, heatmaps and output speed. Use Controls to adjust model breakdown and speed visibility.
|
|
128
128
|
2. Refresh provider or account cards in Quotas. Automatic refresh is off by default; enable it in Controls after confirming the notice.
|
|
129
|
-
3. Select a provider and model in Detection, set sample counts and output limits,
|
|
129
|
+
3. Select a provider and model in Detection, set sample counts and output limits, click **Preview detection budget**, then confirm with **Start detection (uses tokens)**. Reading catalogs or saved results never starts detection.
|
|
130
130
|
4. Use Controls to toggle the advanced model selector, reasoning features and detection independently, or edit custom quota queries.
|
|
131
131
|
|
|
132
|
+
Detection guides you through choosing a model, confirming the budget and reviewing results. Changing the model or parameters requires a new budget preview. While a test runs, you can follow request progress and sample status or cancel it. Saved results retain their original model and parameters; detection details and engine information expand on demand.
|
|
133
|
+
|
|
132
134
|
## Data and compatibility
|
|
133
135
|
|
|
134
136
|
Local data is stored under `DSH_HOME/storages`:
|
|
@@ -184,4 +186,4 @@ npm run release
|
|
|
184
186
|
|
|
185
187
|
Edit `src/` and run `npm run build` to generate `lib/`. `npm run check:release` checks versions, generated files, third-party integrity and private workspace files. `npm run release` builds the package and verifies installation and loading in an isolated temporary project; artifacts go to `release/`.
|
|
186
188
|
|
|
187
|
-
The GitHub workflow requires the tag to match the package version (`v0.2.
|
|
189
|
+
The GitHub workflow requires the tag to match the package version (`v0.2.4` for this release) and publishes the same verified archive to npm and GitHub Releases. The npm trusted publisher workflow file is `.github/workflows/release.yml`. Third-party assets, source revisions and licenses are recorded in `third_party/` and [NOTICE](NOTICE). This project uses the [Apache-2.0 license](LICENSE).
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
<p align="center">
|
|
13
13
|
<a href="#安装"><img src="https://img.shields.io/badge/DSH-Desktop-2563eb?style=flat-square" alt="DSH 桌面端"></a>
|
|
14
|
-
<a href="https://github.com/Jockjrop/dsh-usage-stats/releases/latest"><img src="https://img.shields.io/badge/release-v0.2.
|
|
14
|
+
<a href="https://github.com/Jockjrop/dsh-usage-stats/releases/latest"><img src="https://img.shields.io/badge/release-v0.2.4-64748b?style=flat-square" alt="插件版本 0.2.4"></a>
|
|
15
15
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-22c55e?style=flat-square" alt="Apache 2.0 许可"></a>
|
|
16
16
|
</p>
|
|
17
17
|
|
|
@@ -60,13 +60,13 @@
|
|
|
60
60
|
| --- | --- |
|
|
61
61
|
| **用量** | 查看今日与累计 Token、使用天数、小时调用次数、每日/每周热力图、趋势、模型明细与输出速度。 |
|
|
62
62
|
| **配额** | 集中查看供应商余额、账号积分与周期配额,支持手动或定时刷新及自定义查询。 |
|
|
63
|
-
| **检测** | 独立选择供应商和模型,确认预算后运行 LM Fingerprint
|
|
63
|
+
| **检测** | 独立选择供应商和模型,确认预算后运行 LM Fingerprint 检测,查看请求进度、采样状态、候选排名与历史结果。 |
|
|
64
64
|
| **控制** | 调整展示偏好、配额查询设置、高级模型选择器与逐模型推理强度。 |
|
|
65
65
|
|
|
66
66
|
- **看清使用趋势**:按日/周浏览热力图,切换 7/30 天趋势,按供应商与模型查看用量。
|
|
67
67
|
- **比较输出速度**:按 TPS 排序,显示平均首 Token 耗时(TTFT);缺少有效时间记录的样本不参与速度排名。
|
|
68
68
|
- **按需刷新配额**:通过 DSH 凭据服务查询已配置供应商,账号配额需要对应的账号插件或宿主服务。自动查询默认关闭。
|
|
69
|
-
-
|
|
69
|
+
- **独立运行检测**:按步骤选择模型、确认预算并查看结果;默认采样 3 次,也可选择 1 次初筛,支持进度查看、取消、超时和用量预算控制。
|
|
70
70
|
- **调整模型设置**:分别控制高级模型选择器与模型推理强度,保留已有的模型属性、参数映射和个人设置。
|
|
71
71
|
- **跟随应用语言**:支持中文、英语和日语,随 DSH 所选语言切换;用户自定义名称与配额标签保持原样。
|
|
72
72
|
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
|
|
75
75
|
## 安装
|
|
76
76
|
|
|
77
|
-
当前插件版本为 **0.2.
|
|
77
|
+
当前插件版本为 **0.2.4**,适配 **DSH Desktop `0.2.1-rc.2`**,并保留 `0.2.1-rc.1`、`0.2.1-alpha.2`、`0.2.0-rc.2` 和 `0.2.0-rc.1` 支持。版本不匹配时,宿主插件管理器会拒绝安装或启用。
|
|
78
78
|
|
|
79
79
|
**推荐通过 DSH Desktop 安装 [npm 包 `@sligqoer/dsh-usage-stats`](https://www.npmjs.com/package/@sligqoer/dsh-usage-stats)。** 已包含预构建模块,无需克隆仓库或在本机构建;通过包名安装后可使用插件页的「检查更新」。
|
|
80
80
|
|
|
@@ -100,16 +100,16 @@
|
|
|
100
100
|
安装本次版本时,在同一入口填入:
|
|
101
101
|
|
|
102
102
|
```text
|
|
103
|
-
@sligqoer/dsh-usage-stats@0.2.
|
|
103
|
+
@sligqoer/dsh-usage-stats@0.2.4
|
|
104
104
|
```
|
|
105
105
|
|
|
106
106
|
也可从 [GitHub 发布页](https://github.com/Jockjrop/dsh-usage-stats/releases/latest)下载 `.tgz` 安装包和 `SHA256SUMS`,校验后填入压缩包的本地绝对路径,无需解压。
|
|
107
107
|
|
|
108
108
|
```powershell
|
|
109
|
-
Get-FileHash ./sligqoer-dsh-usage-stats-0.2.
|
|
109
|
+
Get-FileHash ./sligqoer-dsh-usage-stats-0.2.4.tgz -Algorithm SHA256
|
|
110
110
|
```
|
|
111
111
|
|
|
112
|
-
发布附件包含版本安装包 `sligqoer-dsh-usage-stats-0.2.
|
|
112
|
+
发布附件包含版本安装包 `sligqoer-dsh-usage-stats-0.2.4.tgz`、通用安装包 `dsh-usage-stats.tgz` 和校验文件 `SHA256SUMS`;两个安装包内容一致。
|
|
113
113
|
|
|
114
114
|
</details>
|
|
115
115
|
|
|
@@ -126,9 +126,11 @@ Get-FileHash ./sligqoer-dsh-usage-stats-0.2.1.tgz -Algorithm SHA256
|
|
|
126
126
|
|
|
127
127
|
1. 在「用量」查看概览、趋势、热力图和输出速度;在「控制」调整模型明细与速度的显示。
|
|
128
128
|
2. 在「配额」点击供应商或账号卡片的刷新按钮。自动查询默认关闭,可在「控制」确认提示后开启。
|
|
129
|
-
3.
|
|
129
|
+
3. 在「检测」选择供应商与模型,设置采样次数和输出上限,点击「查看检测预算」,确认后点击「开始检测(会消耗 Token)」。读取目录或历史结果不会启动检测。
|
|
130
130
|
4. 在「控制」分别开启或关闭高级模型选择器、模型推理强度和模型检测,编辑自定义配额查询。
|
|
131
131
|
|
|
132
|
+
检测页按「选择检测模型 → 确认预算 → 检测结果」提示当前步骤。更改模型或参数后,需要重新查看预算;检测中可查看请求进度、逐次采样状态并取消。历史结果保留原模型与参数,检测详情和指纹引擎信息可按需展开。
|
|
133
|
+
|
|
132
134
|
## 数据与兼容
|
|
133
135
|
|
|
134
136
|
本地数据位于 `DSH_HOME/storages`:
|
|
@@ -184,4 +186,4 @@ npm run release
|
|
|
184
186
|
|
|
185
187
|
修改 `src/` 后运行 `npm run build` 生成 `lib/`。`npm run check:release` 检查版本、构建一致性、第三方完整性与工作区隐私文件;`npm run release` 构建安装包并在独立临时项目中验证安装与加载,输出位于 `release/`。
|
|
186
188
|
|
|
187
|
-
GitHub 发布流程要求标签与包版本一致(本版为 `v0.2.
|
|
189
|
+
GitHub 发布流程要求标签与包版本一致(本版为 `v0.2.4`),通过检查后使用同一份安装包发布 npm 与 GitHub Release。npm 可信发布对应的工作流文件为 `.github/workflows/release.yml`。第三方资源、来源版本和许可记录于 `third_party/` 与 [NOTICE](NOTICE),本项目使用 [Apache-2.0 许可证](LICENSE)。
|
package/lib/client.js
CHANGED
|
@@ -8,7 +8,7 @@ var SECTION_ID = 'usage-stats'
|
|
|
8
8
|
|
|
9
9
|
var STYLE_ID = 'dsh-usage-stats-styles'
|
|
10
10
|
|
|
11
|
-
var PLUGIN_VERSION = "0.2.
|
|
11
|
+
var PLUGIN_VERSION = "0.2.4"
|
|
12
12
|
|
|
13
13
|
var localeService = null
|
|
14
14
|
|
|
@@ -760,6 +760,22 @@ Object.assign(messages, {
|
|
|
760
760
|
'按渠道配置网关': ['Configure routes by channel', 'チャンネルごとの接続経路'],
|
|
761
761
|
'渠道网关用于登录、模型目录、额度与调用;单个模型可在详情中覆盖调用出口。': ['Channel routes cover login, catalogs, balances and calls. Model details can override the call route.', 'チャンネルの経路はログイン・一覧・残高・呼び出しに適用されます。モデル詳細で呼び出し経路を変更できます。'],
|
|
762
762
|
'代理只改变网络出口,不能保证解除账号地区或模型权限限制。直连仍可能经过系统 TUN。': ['A proxy changes network egress; account regions and model permissions remain provider-controlled. Direct connections may still use the system TUN.', 'プロキシは接続経路を変更します。アカウントの地域とモデル権限は提供元が管理します。直接接続もシステムTUNを通る場合があります。'],
|
|
763
|
+
'确认预算': ['Confirm budget', '予算を確認'],
|
|
764
|
+
'检测步骤': ['Detection steps', '検出の手順'],
|
|
765
|
+
'尚未选择模型': ['No model selected yet', 'モデルが未選択です'],
|
|
766
|
+
'检测会在参考库中排序候选模型;结果为参考排名,不证明模型身份。': ['The detection ranks candidate models in the reference set. Rankings do not prove model identity.', '検出は参照集合内で候補モデルを順位付けします。順位はモデルの身元を証明するものではありません。'],
|
|
767
|
+
'尚未检测本模型': ['This model has not been detected yet', 'このモデルは未検出です'],
|
|
768
|
+
'检测进行中': ['Detection in progress', '検出を実行中です'],
|
|
769
|
+
'{count} 次 · 单次 {tokens} Token': ['{count} calls · {tokens} tokens each', '{count} 回・1回 {tokens} Token'],
|
|
770
|
+
'先查看检测预算,确认后再开始。': ['Preview the detection budget, then confirm to start.', '検出予算を確認してから開始してください。'],
|
|
771
|
+
'等待检测结果': ['Awaiting detection results', '検出結果を待っています'],
|
|
772
|
+
'确认预算并开始后,这里会显示采样进度与候选排名。': ['After you confirm the budget and start, sample progress and candidate rankings appear here.', '予算を確認して開始すると、サンプルの進捗と候補順位がここに表示されます。'],
|
|
773
|
+
'检测进度': ['Detection progress', '検出の進捗'],
|
|
774
|
+
'正在分析指纹…': ['Analyzing fingerprints…', '指紋を分析中…'],
|
|
775
|
+
'本次检测参数': ['Parameters for this test', '今回の検出パラメーター'],
|
|
776
|
+
'已确认预算,可开始检测。': ['Budget confirmed. Ready to start detection.', '予算を確認しました。検出を開始できます。'],
|
|
777
|
+
'更改模型或参数后,需要重新查看检测预算。': ['Preview the budget again after changing the model or parameters.', 'モデルやパラメーターを変更したら、予算を再確認してください。'],
|
|
778
|
+
'检测已结束': ['Detection finished', '検出が終了しました'],
|
|
763
779
|
})
|
|
764
780
|
|
|
765
781
|
function t(text, params) {
|
|
@@ -1092,27 +1108,54 @@ var styles = [
|
|
|
1092
1108
|
'.dshus-speed-value { text-align: right; white-space: nowrap; font-size: 20px; font-weight: 600; }',
|
|
1093
1109
|
'@container (max-width: 420px) { .dshus-speed-head, .dshus-speed-row { grid-template-columns: 18px minmax(0, 1fr) 64px 60px; gap: 8px; } .dshus-speed-value { font-size: 18px; } }',
|
|
1094
1110
|
'@container (max-width: 360px) { .dshus-module.dshus-speed-module { padding: 12px; } .dshus-speed-head, .dshus-speed-row { grid-template-columns: 18px minmax(0, 1fr) 58px 54px; gap: 6px; } }',
|
|
1095
|
-
'.dshus-detection-
|
|
1096
|
-
'.dshus-detection-
|
|
1111
|
+
'.dshus-detection-panel { min-width: 0; scrollbar-color: var(--dsw-alias-border-l2, #d0d5dd) transparent; accent-color: var(--dsw-alias-brand-primary, #3b82f6); caret-color: var(--dsw-alias-label-primary, #1f2430); }',
|
|
1112
|
+
'.dshus-detection-panel ::selection { background: var(--dsw-alias-bg-multi-select, #dbeafe); color: var(--dsw-alias-label-primary, #1f2430); }',
|
|
1113
|
+
'.dshus-detection-panel > .dshus-module { box-shadow: none; padding: 20px; }',
|
|
1114
|
+
'.dshus-detection-panel .dshus-module h3 { color: var(--dsw-alias-label-primary, #1f2430); letter-spacing: normal; }',
|
|
1115
|
+
'.dshus-detection-intro { margin: 0 0 18px; max-width: 72ch; font-size: 13px; line-height: 1.65; color: var(--dsw-alias-label-secondary, #4b5563); }',
|
|
1116
|
+
'.dshus-detection-verdict { margin: 12px 0 8px; font-size: 14px; line-height: 1.6; font-weight: 600; overflow-wrap: anywhere; }',
|
|
1117
|
+
'.dshus-detection-verdict[data-verdict="running"], .dshus-detection-verdict[data-verdict="inconclusive"] { font-size: 22px; line-height: 1.35; letter-spacing: -0.01em; }',
|
|
1118
|
+
'.dshus-detection-verdict[data-verdict="ranking-only"], .dshus-detection-verdict[data-verdict="inconclusive"] { color: var(--dsw-alias-label-secondary, #4b5563); }',
|
|
1119
|
+
'.dshus-detection-verdict[data-verdict="candidate-consistent"] { color: var(--dsw-alias-state-success-primary, #16794a); }',
|
|
1120
|
+
'.dshus-detection-verdict[data-verdict="candidate-different"] { color: var(--dsw-alias-state-warn-label, #946200); }',
|
|
1121
|
+
'.dshus-steps { list-style: none; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin: 0 0 20px; padding: 0 0 18px; border-bottom: 1px solid var(--dsw-alias-border-l2, #e5e7eb); font-variant-numeric: tabular-nums; }',
|
|
1122
|
+
'.dshus-step { display: grid; grid-template-columns: 22px minmax(0, 1fr); align-items: start; gap: 10px; min-width: 0; padding: 10px 12px; border: 1px solid transparent; border-radius: 12px; }',
|
|
1123
|
+
'.dshus-step[data-state="current"] { border-color: var(--dsw-alias-border-l2, #e5e7eb); background: var(--dsw-alias-bg-layer-3, #f3f4f6); }',
|
|
1124
|
+
'.dshus-step-mark { display: flex; align-items: center; justify-content: center; width: 22px; height: 22px; border: 1px solid var(--dsw-alias-border-l2, #d4d4d9); border-radius: 50%; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-secondary, #4b5563); font-size: 11.5px; font-weight: 600; line-height: 1; }',
|
|
1125
|
+
'.dshus-step[data-state="current"] .dshus-step-mark { border-color: var(--dsw-alias-label-primary, #1f2430); background: var(--dsw-alias-label-primary, #1f2430); color: var(--dsw-alias-label-primary-inverted, #fff); }',
|
|
1126
|
+
'.dshus-step[data-state="done"] .dshus-step-mark { color: var(--dsw-alias-label-primary, #1f2430); }',
|
|
1127
|
+
'.dshus-step-body { display: grid; gap: 3px; min-width: 0; }',
|
|
1128
|
+
'.dshus-step-title { color: var(--dsw-alias-label-secondary, #4b5563); font-size: 13px; font-weight: 500; line-height: 1.5; }',
|
|
1129
|
+
'.dshus-step[data-state="current"] .dshus-step-title { color: var(--dsw-alias-label-primary, #1f2430); font-weight: 600; }',
|
|
1130
|
+
'.dshus-step-detail { color: var(--dsw-alias-label-secondary, #4b5563); font-size: 12px; line-height: 1.5; overflow-wrap: anywhere; }',
|
|
1131
|
+
'.dshus-detection-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 18px 0 0; }',
|
|
1132
|
+
'.dshus-detection-panel .dshus-btn { min-height: 36px; height: auto; padding: 8px 12px; line-height: 1.4; white-space: normal; text-align: center; justify-content: center; }',
|
|
1133
|
+
'.dshus-detection-panel .dshus-btn-primary { border-color: var(--dsw-alias-label-primary, #1f2430); background: var(--dsw-alias-label-primary, #1f2430); color: var(--dsw-alias-label-primary-inverted, #fff); font-weight: 500; }',
|
|
1134
|
+
'.dshus-detection-panel .dshus-btn-primary:hover:not(:disabled) { background: var(--dsw-alias-label-secondary, #4b5563); border-color: var(--dsw-alias-label-secondary, #4b5563); }',
|
|
1135
|
+
'.dshus-detection-panel .dshus-btn:focus-visible, .dshus-detection-panel .dshus-field:focus-visible, .dshus-detection-engine > summary:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary, #3b82f6); outline-offset: 3px; }',
|
|
1097
1136
|
'.dshus-detection-fields { display: grid; gap: 8px; margin: 12px 0; }',
|
|
1098
1137
|
'.dshus-detection-fields div { display: flex; gap: 12px; align-items: baseline; min-width: 0; }',
|
|
1099
1138
|
'.dshus-detection-fields dt { flex: 0 0 86px; color: var(--dsw-alias-label-secondary, #6b7280); font-size: 12px; }',
|
|
1100
1139
|
'.dshus-detection-fields dd { margin: 0; overflow-wrap: anywhere; font-size: 13px; }',
|
|
1101
|
-
'.dshus-detection-form { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; margin:
|
|
1140
|
+
'.dshus-detection-form { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; margin: 4px 0 14px; }',
|
|
1102
1141
|
'.dshus-detection-limits { grid-template-columns: repeat(3, minmax(0, 1fr)); }',
|
|
1103
1142
|
'.dshus-detection-field { display: grid; gap: 7px; min-width: 0; }',
|
|
1104
1143
|
'.dshus-detection-field .dshus-field { width: 100%; min-height: 36px; }',
|
|
1105
|
-
'.dshus-detection-reference { padding:
|
|
1144
|
+
'.dshus-detection-reference { padding: 14px 0 0; margin: 16px 0 0; border-top: 1px solid var(--dsw-alias-border-l2, #e5e7eb); font-size: 13px; overflow-wrap: anywhere; font-variant-numeric: tabular-nums; }',
|
|
1106
1145
|
'.dshus-detection-reference p { margin: 6px 0; line-height: 1.6; }',
|
|
1146
|
+
'.dshus-detection-ready { font-weight: 500; }',
|
|
1147
|
+
'.dshus-detection-quote-details { margin-top: 10px; font-size: 13px; }',
|
|
1148
|
+
'.dshus-detection-quote-details > summary { cursor: pointer; color: var(--dsw-alias-label-secondary, #4b5563); line-height: 24px; }',
|
|
1149
|
+
'.dshus-detection-quote-details > summary:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary, #3b82f6); outline-offset: 3px; }',
|
|
1107
1150
|
'.dshus-detection-summary { scroll-margin-top: 90px; }',
|
|
1108
|
-
'.dshus-detection-headline { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 24px; margin:
|
|
1109
|
-
'.dshus-detection-headline h4 { margin: 0; font-size:
|
|
1151
|
+
'.dshus-detection-headline { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 24px; margin: 18px 0 12px; }',
|
|
1152
|
+
'.dshus-detection-headline h4 { margin: 0; font-size: 26px; line-height: 1.3; font-weight: 600; overflow-wrap: anywhere; }',
|
|
1110
1153
|
'.dshus-detection-confidence { display: flex; flex-direction: column; gap: 4px; text-align: right; font-size: 12px; line-height: 1.5; color: var(--dsw-alias-label-secondary, #4b5563); }',
|
|
1111
|
-
'.dshus-detection-confidence strong { font-size:
|
|
1112
|
-
'.dshus-detection-warning { color: var(--dsw-alias-label
|
|
1154
|
+
'.dshus-detection-confidence strong { font-size: 24px; line-height: 1.3; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2430); font-variant-numeric: tabular-nums; }',
|
|
1155
|
+
'.dshus-detection-warning { color: var(--dsw-alias-state-warn-label, #946200); font-weight: 500; }',
|
|
1113
1156
|
'.dshus-detection-list-title { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; margin: 24px 0 8px; font-size: 13px; }',
|
|
1114
1157
|
'.dshus-detection-list-title h4 { margin: 0; font-size: inherit; font-weight: 600; }',
|
|
1115
|
-
'.dshus-detection-list-title > span { font-size: 12px; color: var(--dsw-alias-label-secondary, #4b5563); }',
|
|
1158
|
+
'.dshus-detection-list-title > span { font-size: 12px; color: var(--dsw-alias-label-secondary, #4b5563); text-align: right; }',
|
|
1116
1159
|
'.dshus-detection-rankings { list-style: none; padding: 0; margin: 0; font-variant-numeric: tabular-nums; }',
|
|
1117
1160
|
'.dshus-detection-rank { display: grid; grid-template-columns: 20px minmax(0, 1fr) minmax(64px, 24%) 64px; gap: 12px; align-items: center; padding: 12px 0; border-top: 1px solid var(--dsw-alias-border-l2, #e5e7eb); font-size: 13px; }',
|
|
1118
1161
|
'.dshus-detection-rank[data-unscored] { grid-template-columns: 20px minmax(0, 1fr) 80px; }',
|
|
@@ -1123,18 +1166,34 @@ var styles = [
|
|
|
1123
1166
|
'.dshus-detection-bar { height: 6px; border-radius: 3px; overflow: hidden; background: var(--dsw-alias-bg-layer-3, #e5e7eb); }',
|
|
1124
1167
|
'.dshus-detection-bar > span { display: block; height: 100%; border-radius: inherit; background: var(--dsw-alias-brand-primary, #3b82f6); }',
|
|
1125
1168
|
'.dshus-detection-samples { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; padding: 16px 0; margin: 0; border-top: 1px solid var(--dsw-alias-border-l2, #e5e7eb); border-bottom: 1px solid var(--dsw-alias-border-l2, #e5e7eb); list-style: none; font-size: 12px; line-height: 1.6; }',
|
|
1169
|
+
'.dshus-detection-samples[data-count="1"] { grid-template-columns: minmax(0, 1fr); }',
|
|
1126
1170
|
'.dshus-detection-sample { display: flex; flex-direction: column; gap: 4px; min-width: 0; overflow-wrap: anywhere; }',
|
|
1127
1171
|
'.dshus-detection-sample strong { font-size: 13px; font-weight: 600; }',
|
|
1172
|
+
'.dshus-detection-sample[data-outcome="scored"] strong { color: var(--dsw-alias-state-success-primary, #16794a); }',
|
|
1173
|
+
'.dshus-detection-sample[data-outcome="sampling"] strong { color: var(--dsw-alias-brand-primary, #3b82f6); }',
|
|
1128
1174
|
'.dshus-detection-sample > span { color: var(--dsw-alias-label-secondary, #4b5563); font-variant-numeric: tabular-nums; }',
|
|
1129
1175
|
'.dshus-detection-sample[data-outcome="incomplete"] strong, .dshus-detection-sample[data-outcome="unavailable"] strong, .dshus-detection-sample[data-outcome="timeout"] strong, .dshus-detection-sample[data-outcome="unparseable"] strong { color: var(--dsw-alias-state-error-primary, #b42318); }',
|
|
1130
1176
|
'.dshus-detection-model, .dshus-detection-cost { font-size: 13px; line-height: 1.6; margin: 8px 0; overflow-wrap: anywhere; }',
|
|
1131
1177
|
'.dshus-detection-model { color: var(--dsw-alias-label-secondary, #4b5563); }',
|
|
1178
|
+
'.dshus-detection-progress { margin: 16px 0 20px; }',
|
|
1179
|
+
'.dshus-detection-progress-head { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 10px; margin-bottom: 10px; }',
|
|
1180
|
+
'.dshus-detection-progress-head p { margin: 0; font-size: 13px; line-height: 1.6; color: var(--dsw-alias-label-secondary, #4b5563); }',
|
|
1181
|
+
'.dshus-detection-progress progress { display: block; width: 100%; height: 6px; overflow: hidden; border: 0; border-radius: 3px; background: var(--dsw-alias-bg-layer-3, #e5e7eb); accent-color: var(--dsw-alias-brand-primary, #3b82f6); }',
|
|
1182
|
+
'.dshus-detection-progress progress::-webkit-progress-bar { background: var(--dsw-alias-bg-layer-3, #e5e7eb); border-radius: 3px; }',
|
|
1183
|
+
'.dshus-detection-progress progress::-webkit-progress-value { background: var(--dsw-alias-brand-primary, #3b82f6); border-radius: 3px; }',
|
|
1184
|
+
'.dshus-detection-progress progress::-moz-progress-bar { background: var(--dsw-alias-brand-primary, #3b82f6); border-radius: 3px; }',
|
|
1185
|
+
'.dshus-detection-empty-title { margin: 0 0 6px; font-size: 16px; line-height: 1.5; font-weight: 500; }',
|
|
1186
|
+
'.dshus-detection-engine > summary { cursor: pointer; font-size: 13px; line-height: 1.6; overflow-wrap: anywhere; border-radius: 4px; }',
|
|
1187
|
+
'.dshus-detection-engine-meta { margin-left: 12px; color: var(--dsw-alias-label-secondary, #4b5563); font-size: 12px; }',
|
|
1188
|
+
'.dshus-detection-engine-notice { display: block; margin-top: 8px; color: var(--dsw-alias-state-warn-label, #946200); font-size: 13px; }',
|
|
1189
|
+
'.dshus-detection-engine[open] > summary { margin-bottom: 12px; }',
|
|
1132
1190
|
'.dshus-disclosure { border-top: 1px solid var(--dsw-alias-border-l2, #e5e7eb); margin-top: 16px; padding-top: 12px; font-size: 13px; }',
|
|
1133
1191
|
'.dshus-disclosure > summary { cursor: pointer; color: var(--dsw-alias-label-secondary, #4b5563); line-height: 24px; }',
|
|
1134
1192
|
'.dshus-disclosure > summary:hover { color: var(--dsw-alias-label-primary, #1f2430); }',
|
|
1135
1193
|
'.dshus-disclosure > summary:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary, #3b82f6); outline-offset: 4px; border-radius: 4px; }',
|
|
1136
|
-
'@container (max-width: 520px) { .dshus-detection-form { grid-template-columns: minmax(0, 1fr); gap: 12px; } }',
|
|
1194
|
+
'@container (max-width: 520px) { .dshus-detection-panel > .dshus-module { padding: 16px; } .dshus-detection-form { grid-template-columns: minmax(0, 1fr); gap: 12px; } .dshus-steps { grid-template-columns: minmax(0, 1fr); gap: 2px; margin-bottom: 16px; padding-bottom: 14px; } .dshus-step { grid-template-columns: 20px minmax(0, 1fr); gap: 8px; padding: 8px 10px; } .dshus-step-mark { width: 20px; height: 20px; font-size: 11px; } .dshus-detection-actions .dshus-btn { flex: 1 1 100%; } .dshus-detection-engine-meta { display: block; margin: 6px 0 0; } }',
|
|
1137
1195
|
'@container (max-width: 520px) { .dshus-detection-headline { grid-template-columns: minmax(0, 1fr); gap: 12px; } .dshus-detection-confidence { text-align: left; } .dshus-detection-headline h4, .dshus-detection-confidence strong { font-size: 24px; } .dshus-detection-rank { grid-template-columns: 20px minmax(0, 1fr) 64px; row-gap: 8px; } .dshus-detection-rank-name { grid-column: 2; grid-row: 1; } .dshus-detection-rank-value { grid-column: 3; grid-row: 1; } .dshus-detection-bar { grid-column: 2 / 4; grid-row: 2; } .dshus-detection-samples { grid-template-columns: minmax(0, 1fr); gap: 12px; } .dshus-detection-sample { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 12px; } .dshus-detection-sample > span:first-of-type { text-align: right; } .dshus-detection-sample > .dshus-detection-sample-limit { grid-column: 1 / -1; } }',
|
|
1196
|
+
'@media (prefers-reduced-motion: reduce) { .dshus-detection-panel .dshus-spin { animation: none; } }',
|
|
1138
1197
|
'@container (max-width: 420px) { .dshus-tab { padding-left: 12px; padding-right: 12px; } }',
|
|
1139
1198
|
'.dshus-saved-query { display: flex; align-items: center; gap: 8px; padding-top: 10px; font-size: 13px; }',
|
|
1140
1199
|
'.dshus-saved-query span { flex: 1; min-width: 0; overflow-wrap: anywhere; }',
|
|
@@ -3123,6 +3182,10 @@ function DetectionPanel(props) {
|
|
|
3123
3182
|
var quote = quoted && quoted.key === quoteKey && quoted.body
|
|
3124
3183
|
var running = job && job.status === 'running'
|
|
3125
3184
|
var selectedReady = providers.some(function (item) { return item.provider === provider }) && modelsProvider === provider && models.some(function (item) { return item.id === model }) && !modelsLoading
|
|
3185
|
+
var jobIsCurrent = job && job.sessionId === sessionId && job.selection.provider === provider && job.selection.model === model && (job.selection.reasoningEffort || '') === effort
|
|
3186
|
+
var savedPlan = job && job.plan || {}, savedOutputLimit = savedPlan.maxTokens || savedPlan.maxOutputTokens && savedPlan.requests && savedPlan.maxOutputTokens / savedPlan.requests
|
|
3187
|
+
var resultMatchesSetup = jobIsCurrent && (!savedPlan.requests || savedPlan.requests === count) && (!savedPlan.budgetTokens || savedPlan.budgetTokens === budget) && (!savedOutputLimit || savedOutputLimit === maxTokens)
|
|
3188
|
+
var currentStep = running || resultMatchesSetup && !quote ? 2 : selectedReady ? 1 : 0
|
|
3126
3189
|
React.useEffect(function () {
|
|
3127
3190
|
if (manualSelection.current || busy || running || !suggested || !suggested.provider || !suggested.model) return
|
|
3128
3191
|
setSelection(function (previous) { return previous.provider === suggested.provider && previous.model === suggested.model && (previous.reasoningEffort || '') === (suggested.reasoningEffort || '') ? previous : suggested })
|
|
@@ -3239,12 +3302,27 @@ function DetectionPanel(props) {
|
|
|
3239
3302
|
}
|
|
3240
3303
|
function field(label, element) { return React.createElement('label', { className: 'dshus-detection-field' }, React.createElement('span', { className: 'dshus-setting-label' }, t(label)), element) }
|
|
3241
3304
|
function probability(value) { return Number.isFinite(value) ? (value * 100).toFixed(1) + '%' : '—' }
|
|
3305
|
+
function stepsView() {
|
|
3306
|
+
var steps = [
|
|
3307
|
+
{ title: '选择检测模型', detail: model || t('尚未选择模型') },
|
|
3308
|
+
{ title: '确认预算', detail: t('{count} 次 · 单次 {tokens} Token', { count: count, tokens: fmt(maxTokens) }) },
|
|
3309
|
+
{ title: '检测结果', detail: t(running ? '检测进行中' : resultMatchesSetup ? job.status === 'cancelled' ? '已取消' : '检测已结束' : '等待检测结果') },
|
|
3310
|
+
]
|
|
3311
|
+
return React.createElement('ol', { className: 'dshus-steps', 'aria-label': t('检测步骤') }, steps.map(function (step, index) {
|
|
3312
|
+
var state = index === currentStep ? 'current' : index < currentStep ? 'done' : 'upcoming'
|
|
3313
|
+
return React.createElement('li', { key: step.title, className: 'dshus-step', 'data-state': state, 'aria-current': state === 'current' ? 'step' : undefined },
|
|
3314
|
+
React.createElement('span', { className: 'dshus-step-mark', 'aria-hidden': true }, index + 1),
|
|
3315
|
+
React.createElement('div', { className: 'dshus-step-body' },
|
|
3316
|
+
React.createElement('span', { className: 'dshus-step-title' }, t(step.title)),
|
|
3317
|
+
React.createElement('span', { className: 'dshus-step-detail' }, step.detail)))
|
|
3318
|
+
}))
|
|
3319
|
+
}
|
|
3242
3320
|
function samplesView(results, plan, validSamples) {
|
|
3243
3321
|
var labels = { scored: '有效', incomplete: '输出截断', unparseable: '格式无效', unavailable: '请求失败', timeout: '超时', cancelled: '已取消', sampling: '采样中', pending: '未采样' }
|
|
3244
3322
|
var total = plan.requests || 3
|
|
3245
3323
|
return React.createElement(React.Fragment, null,
|
|
3246
3324
|
React.createElement('div', { className: 'dshus-detection-list-title' }, React.createElement('h4', null, t('采样状态')), React.createElement('span', null, t('有效样本 {valid} / {total}', { valid: validSamples, total: total }))),
|
|
3247
|
-
React.createElement('ol', { className: 'dshus-detection-samples', 'aria-label': t('采样状态') }, Array.from({ length: total }, function (_, index) {
|
|
3325
|
+
React.createElement('ol', { className: 'dshus-detection-samples', 'aria-label': t('采样状态'), 'data-count': total }, Array.from({ length: total }, function (_, index) {
|
|
3248
3326
|
var item = results[index], outcome = item ? item.outcome : running && index === results.length && job.phase !== 'scoring' ? 'sampling' : 'pending'
|
|
3249
3327
|
var expected = item ? item.expected : plan.numbers && plan.numbers[index]
|
|
3250
3328
|
return React.createElement('li', { key: index, className: 'dshus-detection-sample', 'data-outcome': outcome },
|
|
@@ -3254,26 +3332,33 @@ function DetectionPanel(props) {
|
|
|
3254
3332
|
})))
|
|
3255
3333
|
}
|
|
3256
3334
|
function jobView() {
|
|
3257
|
-
var historical =
|
|
3335
|
+
var historical = !running && !resultMatchesSetup
|
|
3258
3336
|
var identity = job.identity, candidates = identity && identity.candidates || []
|
|
3259
3337
|
var summary = job.conclusion || { verdict: running ? 'running' : 'inconclusive', reason: job.status === 'cancelled' ? 'cancelled' : 'unfinished' }
|
|
3260
3338
|
var titles = { running: '检测运行中', 'candidate-consistent': '首选候选与请求模型一致', 'candidate-different': '首选候选与请求模型不同', 'ranking-only': '候选排序', inconclusive: '无法判定' }
|
|
3261
3339
|
var explanations = { 'model-not-enrolled': '请求模型不在参考库中,候选仅供比较。', 'merged-class': '参考库将这些型号合并为同一类,无法区分具体型号。', 'low-confidence': '置信度不足,候选仅供比较。', cancelled: '检测已取消,已发生的用量仍会统计。', interrupted: '宿主重启时检测尚未完成,请重新检测。', budget: '已达到 Token 预算,检测未完成。', timeout: '请求超时,检测未完成。', 'request-failed': '通道请求失败,检测未完成。', truncated: '随机数输出被截断;请提高单次输出上限,重新查看预算后检测。', format: '有效随机数不足,已停止后续请求。', distribution: '随机数分布异常,本次结果无法判定。', unfinished: '尚未取得足够指纹数据,无法判定。' }
|
|
3262
3340
|
var calibrated = !!(identity && identity.usedSamples === 3 && !identity.unusualDistribution && Number.isFinite(identity.probability))
|
|
3263
3341
|
var results = job.results || [], plan = job.plan || {}, validSamples = results.filter(function (item) { return item.outcome === 'scored' }).length
|
|
3342
|
+
var totalRequests = plan.requests || 3, progress = Math.max(0, Math.min(totalRequests, job.progress || 0))
|
|
3264
3343
|
var perRequestLimit = plan.maxTokens || plan.maxOutputTokens && plan.requests && plan.maxOutputTokens / plan.requests
|
|
3265
3344
|
var providerName = providers.find(function (item) { return item.provider === job.selection.provider })
|
|
3266
3345
|
var usage = job.usage || {}, jobTokens = (usage.inputTokens || 0) + (usage.outputTokens || 0) + (usage.cacheReadTokens || 0) + (usage.cacheWriteTokens || 0)
|
|
3267
3346
|
return React.createElement('div', { className: 'dshus-module dshus-detection-summary', role: 'region', 'aria-label': t('检测结果'), ref: resultRef },
|
|
3268
3347
|
React.createElement('h3', { title: historical ? t('历史结果,仅对应下方列出的模型和参数。') : undefined }, t(historical ? '上次检测结果' : '检测结果')),
|
|
3348
|
+
historical && React.createElement('p', { className: 'dshus-setting-help' }, t('历史结果,仅对应下方列出的模型和参数。')),
|
|
3269
3349
|
React.createElement('p', { className: 'dshus-detection-model' }, job.selection.model, ' · ', providerName ? providerName.name : job.selection.provider),
|
|
3270
3350
|
candidates.length > 0 && React.createElement('div', { className: 'dshus-detection-headline' },
|
|
3271
3351
|
React.createElement('h4', { 'aria-label': t('首选候选') }, candidates[0].name),
|
|
3272
3352
|
React.createElement('div', { className: 'dshus-detection-confidence' }, React.createElement('span', null, t(calibrated ? '库内置信度' : '仅排序')), calibrated && React.createElement('strong', null, probability(identity.probability)))),
|
|
3273
3353
|
React.createElement('p', { className: 'dshus-detection-verdict', 'data-verdict': summary.verdict, role: 'status' }, t(titles[summary.verdict] || '无法判定')),
|
|
3274
|
-
explanations[summary.reason] && React.createElement('p', { className: 'dshus-setting-help' }, t(explanations[summary.reason])),
|
|
3354
|
+
explanations[summary.reason] && !(running && summary.reason === 'unfinished') && React.createElement('p', { className: 'dshus-setting-help' }, t(explanations[summary.reason])),
|
|
3275
3355
|
candidates.length > 0 && identity.usedSamples < 3 && React.createElement('p', { className: 'dshus-setting-help' }, t('仅基于 {count} 个有效样本展示排名;3 个有效样本才显示库内置信度。', { count: identity.usedSamples })),
|
|
3276
|
-
calibrated && identity.probability < .75 && React.createElement('p', { className: 'dshus-setting-help dshus-detection-warning' }, t('置信度不足(低于 75%)')),
|
|
3356
|
+
calibrated && identity.probability < .75 && summary.reason !== 'low-confidence' && React.createElement('p', { className: 'dshus-setting-help dshus-detection-warning' }, t('置信度不足(低于 75%)')),
|
|
3357
|
+
running && React.createElement('div', { className: 'dshus-detection-progress' },
|
|
3358
|
+
React.createElement('div', { className: 'dshus-detection-progress-head' },
|
|
3359
|
+
React.createElement('p', { role: 'status' }, job.phase === 'scoring' ? t('正在分析指纹…') : t('已完成 {progress} 次请求,上限 {requests} 次', { progress: progress, requests: totalRequests })),
|
|
3360
|
+
React.createElement('button', { type: 'button', className: 'dshus-btn', disabled: cancelling, onClick: cancel }, t(cancelling ? '正在取消…' : '取消检测'))),
|
|
3361
|
+
React.createElement('progress', { max: totalRequests, value: progress, 'aria-label': t('检测进度') })),
|
|
3277
3362
|
candidates.length > 0 && React.createElement(React.Fragment, null,
|
|
3278
3363
|
React.createElement('div', { className: 'dshus-detection-list-title' }, React.createElement('h4', null, t('候选排名')), React.createElement('span', null, t(calibrated ? '库内置信度' : '指纹得分'))),
|
|
3279
3364
|
React.createElement('ol', { className: 'dshus-detection-rankings', 'aria-label': t('候选排名') }, candidates.map(function (candidate, index) {
|
|
@@ -3284,8 +3369,6 @@ function DetectionPanel(props) {
|
|
|
3284
3369
|
React.createElement('span', { className: 'dshus-detection-rank-value', 'aria-label': t(calibrated ? '库内置信度' : '指纹得分') }, calibrated ? probability(candidate.probability) : Number(candidate.score).toFixed(3)))
|
|
3285
3370
|
}))),
|
|
3286
3371
|
samplesView(results, plan, validSamples),
|
|
3287
|
-
running && React.createElement('p', { className: 'dshus-setting-help' }, t('已完成 {progress} 次请求,上限 {requests} 次', { progress: job.progress, requests: job.plan.requests })),
|
|
3288
|
-
running && React.createElement('button', { type: 'button', className: 'dshus-btn', disabled: cancelling, onClick: cancel }, t(cancelling ? '正在取消…' : '取消检测')),
|
|
3289
3372
|
job.usageReported && React.createElement('p', { className: 'dshus-detection-cost', title: fmtExact(jobTokens) }, t(job.usageSaved ? '本次消耗 {tokens} Token · 已计入统计' : '本次已上报消耗 {tokens} Token', { tokens: fmt(jobTokens) })),
|
|
3290
3373
|
job.usageIncomplete && React.createElement('p', { className: 'dshus-setting-help' }, t('部分检测用量尚未上报,可能已产生费用。')),
|
|
3291
3374
|
job.message && React.createElement('p', { className: 'dshus-setting-help' }, uiError(job.message)),
|
|
@@ -3302,8 +3385,10 @@ function DetectionPanel(props) {
|
|
|
3302
3385
|
React.createElement('tbody', null, candidates.map(function (candidate) { return React.createElement('tr', { key: candidate.id }, React.createElement('td', null, candidate.name), React.createElement('td', null, Number(candidate.score).toFixed(3)), React.createElement('td', null, probability(calibrated ? candidate.probability : null))) })))),
|
|
3303
3386
|
job.channel && React.createElement('p', null, t('本次通道表现'), ' · TPS ', Number.isFinite(job.channel.tps) ? job.channel.tps.toFixed(1) : '—', ' tok/s · TTFT ', Number.isFinite(job.channel.ttftMs) ? (job.channel.ttftMs / 1000).toFixed(2) + ' s' : '—')))
|
|
3304
3387
|
}
|
|
3305
|
-
return React.createElement(
|
|
3388
|
+
return React.createElement('div', { className: 'dshus-detection-panel' },
|
|
3306
3389
|
React.createElement('div', { className: 'dshus-module' }, React.createElement('h3', null, t('模型检测')),
|
|
3390
|
+
React.createElement('p', { className: 'dshus-detection-intro' }, t('检测会在参考库中排序候选模型;结果为参考排名,不证明模型身份。')),
|
|
3391
|
+
stepsView(),
|
|
3307
3392
|
React.createElement('div', { className: 'dshus-detection-form' },
|
|
3308
3393
|
field('检测供应商', React.createElement('select', { id: 'dshus-detection-provider', 'aria-label': t('检测供应商'), className: 'dshus-field', value: provider, disabled: busy || running || providersLoading, onChange: selectProvider },
|
|
3309
3394
|
React.createElement('option', { value: '' }, t(providersLoading ? '正在加载供应商…' : providers.length ? '选择已有供应商' : '没有已配置的供应商')),
|
|
@@ -3311,28 +3396,39 @@ function DetectionPanel(props) {
|
|
|
3311
3396
|
field('检测模型', React.createElement('select', { id: 'dshus-detection-model', 'aria-label': t('检测模型'), className: 'dshus-field', value: model, disabled: busy || running || modelsLoading || !provider, onChange: selectModel },
|
|
3312
3397
|
React.createElement('option', { value: '' }, t(modelsLoading ? '正在加载模型…' : models.length ? '选择检测模型' : '没有可用模型')),
|
|
3313
3398
|
models.map(function (item) { return React.createElement('option', { key: item.id, value: item.id }, item.name) })))),
|
|
3314
|
-
React.createElement('p', { className: 'dshus-setting-help' }, t('可选择任意已配置模型;检测选择不会更改会话模型。')),
|
|
3315
|
-
React.createElement('p', { className: 'dshus-setting-help' }, t('使用 LM Fingerprint 官方随机数指纹,默认 3 次请求;不发送会话内容。'))),
|
|
3399
|
+
React.createElement('p', { className: 'dshus-setting-help' }, t('可选择任意已配置模型;检测选择不会更改会话模型。'))),
|
|
3316
3400
|
error && React.createElement('div', { className: 'dshus-error', role: 'alert' }, uiError(error)),
|
|
3317
3401
|
job && jobView(),
|
|
3318
3402
|
React.createElement('div', { className: 'dshus-module' }, React.createElement('h3', null, t('随机数指纹检测')),
|
|
3403
|
+
React.createElement('p', { className: 'dshus-detection-intro' }, t('使用 LM Fingerprint 官方随机数指纹,默认 3 次请求;不发送会话内容。')),
|
|
3319
3404
|
React.createElement('div', { className: 'dshus-detection-form dshus-detection-limits' },
|
|
3320
3405
|
field('采样次数', React.createElement('select', { id: 'dshus-detection-samples', className: 'dshus-field', value: count, disabled: busy || running, onChange: function (event) { setCount(Number(event.target.value)) } },
|
|
3321
3406
|
React.createElement('option', { value: 3 }, t('标准检测(3 次)')), React.createElement('option', { value: 1 }, t('低耗初筛(1 次,仅排序)')))),
|
|
3322
3407
|
field('单次输出上限', React.createElement('input', { id: 'dshus-detection-output-limit', type: 'number', className: 'dshus-field', min: 1024, max: 16384, step: 1, value: maxTokens, disabled: busy || running, onChange: function (event) { setMaxTokens(Number(event.target.value)) } })),
|
|
3323
3408
|
field('已上报 Token 预算', React.createElement('input', { id: 'dshus-detection-budget', type: 'number', className: 'dshus-field', min: 1024, max: 50000, step: 1, value: budget, disabled: busy || running, onChange: function (event) { setBudget(Number(event.target.value)) } }))),
|
|
3324
3409
|
React.createElement('p', { className: 'dshus-setting-help' }, t('输出上限限制每次响应;总预算在每次请求结束后检查,达到后停止后续请求。')),
|
|
3325
|
-
React.createElement('div', { className: 'dshus-
|
|
3326
|
-
React.createElement('
|
|
3327
|
-
React.createElement('button', { type: 'button', className: 'dshus-btn', onClick: start, disabled: busy || running || !quote }, t('开始检测(会消耗 Token)'))),
|
|
3328
|
-
quote && React.createElement('div', { className: 'dshus-detection-reference', role: 'status' }, fields(quote.testSelection),
|
|
3410
|
+
quote && React.createElement('div', { className: 'dshus-detection-reference', role: 'status' },
|
|
3411
|
+
React.createElement('p', { className: 'dshus-detection-ready' }, t('已确认预算,可开始检测。')),
|
|
3329
3412
|
React.createElement('p', { className: 'dshus-cost-note' }, t('请求最多 {requests} 次 · 输入约 {estimatedInputTokens} Token · 输出上限 {maxOutputTokens} Token', Object.fromEntries(Object.entries(quote.plan).map(function (entry) { return [entry[0], typeof entry[1] === 'number' ? fmtExact(entry[1]) : entry[1]] })))),
|
|
3330
|
-
React.createElement('p', { className: 'dshus-setting-help' }, t('
|
|
3331
|
-
React.createElement('
|
|
3332
|
-
|
|
3333
|
-
|
|
3413
|
+
React.createElement('p', { className: 'dshus-setting-help' }, t('预算按已上报用量检查;推理、未上报用量及供应商重试按通道规则计费。')),
|
|
3414
|
+
React.createElement('details', { className: 'dshus-detection-quote-details', key: quote.id },
|
|
3415
|
+
React.createElement('summary', null, t('本次检测参数')),
|
|
3416
|
+
fields(quote.testSelection),
|
|
3417
|
+
React.createElement('p', { className: 'dshus-setting-help' }, t('每次最多 {maxTokens} Token · 所有请求输出最多 {maxOutputTokens} Token', { maxTokens: fmtExact(quote.plan.maxTokens), maxOutputTokens: fmtExact(quote.plan.maxOutputTokens) })))),
|
|
3418
|
+
React.createElement('div', { className: 'dshus-detection-actions' },
|
|
3419
|
+
React.createElement('button', { type: 'button', className: 'dshus-btn' + (!quote ? ' dshus-btn-primary' : ''), onClick: preview, disabled: busy || running || !selectedReady || !catalog }, t(busy ? '正在处理…' : '查看检测预算')),
|
|
3420
|
+
React.createElement('button', { type: 'button', className: 'dshus-btn' + (quote ? ' dshus-btn-primary' : ''), onClick: start, disabled: busy || running || !quote }, t('开始检测(会消耗 Token)'))),
|
|
3421
|
+
!running && React.createElement('p', { className: 'dshus-setting-help' }, t(quote ? '更改模型或参数后,需要重新查看检测预算。' : '先查看检测预算,确认后再开始。'))),
|
|
3422
|
+
!job && React.createElement('div', { className: 'dshus-module dshus-detection-empty', role: 'region', 'aria-label': t('检测结果') },
|
|
3423
|
+
React.createElement('h3', null, t('检测结果')),
|
|
3424
|
+
React.createElement('p', { className: 'dshus-detection-empty-title' }, t('尚未检测本模型')),
|
|
3425
|
+
React.createElement('p', { className: 'dshus-setting-help' }, t('确认预算并开始后,这里会显示采样进度与候选排名。'))),
|
|
3426
|
+
React.createElement('details', { className: 'dshus-module dshus-detection-engine' },
|
|
3427
|
+
React.createElement('summary', null, t('指纹引擎与参考库'),
|
|
3428
|
+
catalog && React.createElement('span', { className: 'dshus-detection-engine-meta' }, 'lmfpd ', catalog.version || '—', catalog.builtAt && ' · ' + String(catalog.builtAt).slice(0, 10), Number.isFinite(catalog.modelCount) && ' · ' + t('{count} 个参考模型', { count: catalog.modelCount })),
|
|
3429
|
+
catalog && catalog.warning && React.createElement('span', { className: 'dshus-detection-engine-notice', role: 'status' }, uiError(catalog.warning)),
|
|
3430
|
+
(updating || catalog && catalog.updating) && React.createElement('span', { className: 'dshus-detection-engine-notice', role: 'status' }, t('正在检查更新…'))),
|
|
3334
3431
|
React.createElement('p', { className: 'dshus-setting-help' }, t('每日检查上游更新,校验成功后启用;更新失败继续使用本地版本。')),
|
|
3335
|
-
catalog && catalog.warning && React.createElement('p', { className: 'dshus-setting-help', role: 'status' }, uiError(catalog.warning)),
|
|
3336
3432
|
React.createElement('div', { className: 'dshus-control-actions' },
|
|
3337
3433
|
React.createElement('button', { type: 'button', className: 'dshus-btn', disabled: updating || running || busy || !!(catalog && catalog.updating), onClick: updateEngine }, t(updating || catalog && catalog.updating ? '正在检查更新…' : '检查上游更新')),
|
|
3338
3434
|
React.createElement('a', { className: 'dshus-btn', href: 'https://lm.ikale.io/docs/', target: '_blank', rel: 'noreferrer' }, t('官方文档')))))
|
|
@@ -5477,7 +5573,14 @@ function registerLocale(ctx) {
|
|
|
5477
5573
|
}
|
|
5478
5574
|
|
|
5479
5575
|
function apply(ctx) {
|
|
5480
|
-
|
|
5576
|
+
// DSH Desktop marks its renderer through the preload bridge dshDesktop.
|
|
5577
|
+
// 0.2.0-rc.2 exposes only { protocolVersion: 1 }; older builds carried a
|
|
5578
|
+
// deviceInfo() function. Accept either marker so the settings section
|
|
5579
|
+
// registers on both, while plain browser tabs (no bridge) still bail out.
|
|
5580
|
+
if (typeof window === 'undefined' || !window.dshDesktop) return
|
|
5581
|
+
var hasDeviceInfo = typeof window.dshDesktop.deviceInfo === 'function'
|
|
5582
|
+
var hasProtocolVersion = typeof window.dshDesktop.protocolVersion === 'number'
|
|
5583
|
+
if (!hasDeviceInfo && !hasProtocolVersion) return
|
|
5481
5584
|
var slots = ctx.get('slots'); if (!slots) return
|
|
5482
5585
|
registerLocale(ctx)
|
|
5483
5586
|
var api = new UsageApi()
|
package/locale/en.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
3
|
"title": "Usage statistics",
|
|
4
|
-
"description": "Usage statistics, provider quotas, model detection and controls for DSH Desktop 0.2.1-alpha.2 and 0.2.0-rc.
|
|
4
|
+
"description": "Usage statistics, provider quotas, model detection and controls for DSH Desktop 0.2.1-rc.2, 0.2.1-rc.1, 0.2.1-alpha.2, 0.2.0-rc.2 and 0.2.0-rc.1."
|
|
5
5
|
}
|
|
6
6
|
}
|
package/locale/ja.json
CHANGED
package/locale/zh.json
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sligqoer/dsh-usage-stats",
|
|
3
3
|
"description": "DSH Desktop 的用量统计、供应商配额、模型检测与控制插件。",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.4",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"license": "Apache-2.0",
|
|
55
55
|
"icon": "screenshots/icon.svg",
|
|
56
56
|
"peerDependencies": {
|
|
57
|
-
"@deepseek-ai/dsh": "0.2.1-alpha.2 || 0.2.0-rc.2"
|
|
57
|
+
"@deepseek-ai/dsh": "0.2.1-rc.2 || 0.2.1-rc.1 || 0.2.1-alpha.2 || 0.2.0-rc.2 || 0.2.0-rc.1"
|
|
58
58
|
},
|
|
59
59
|
"peerDependenciesMeta": {
|
|
60
60
|
"@deepseek-ai/dsh": {
|