@lijinzhao8/opencode-usage 1.1.1 → 1.1.3
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 +35 -69
- package/cli/index.js +7 -7
- package/config.json +2 -2
- package/dist/tui.js +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# opencode-usage
|
|
2
2
|
|
|
3
|
-
OpenCode
|
|
3
|
+
OpenCode 插件:在 TUI 底部实时显示 API 用量和费用统计。
|
|
4
4
|
|
|
5
5
|
## 功能
|
|
6
6
|
|
|
7
7
|
- 实时显示 token 用量(输入/输出/缓存)
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
8
|
+
- 按模型计算费用,支持自定义费率
|
|
9
|
+
- 支持中转共享组(多个 Provider 共享费率配置)
|
|
10
|
+
- 支持时间段倍率(高峰时段加价)
|
|
11
|
+
- 显示每条消息的增量费用和会话累计总量
|
|
12
|
+
- 自带 Web 管理界面,可视化编辑费率配置
|
|
13
13
|
|
|
14
14
|
## 安装
|
|
15
15
|
|
|
@@ -17,47 +17,39 @@ OpenCode 插件:实时显示 API 用量和费用统计,完全复制 API-Prox
|
|
|
17
17
|
opencode plugin @lijinzhao8/opencode-usage@latest
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
##
|
|
20
|
+
## 使用
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
### 启动管理界面
|
|
23
23
|
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
"plugin": [
|
|
27
|
-
"@lijinzhao8/opencode-usage@latest"
|
|
28
|
-
]
|
|
29
|
-
}
|
|
24
|
+
```bash
|
|
25
|
+
npx @lijinzhao8/opencode-usage
|
|
30
26
|
```
|
|
31
27
|
|
|
32
|
-
|
|
28
|
+
浏览器打开 http://localhost:3456 即可可视化编辑费率配置。
|
|
33
29
|
|
|
34
|
-
|
|
30
|
+
### 配置说明
|
|
35
31
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
```
|
|
32
|
+
配置文件为插件目录下的 `config.json`,也可通过管理界面编辑。
|
|
33
|
+
|
|
34
|
+
#### 中转共享组
|
|
40
35
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
`,
|
|
56
|
-
},
|
|
57
|
-
];
|
|
36
|
+
多个 Provider 可以共享同一套费率配置:
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"groups": [
|
|
41
|
+
{
|
|
42
|
+
"id": "grp_main",
|
|
43
|
+
"name": "主力组",
|
|
44
|
+
"enabled": true,
|
|
45
|
+
"provider_ids": ["api-proxy", "xiaomi-token-plan"],
|
|
46
|
+
"rates_text": "* input=0.15 output=0.60 cache_hit=0.03 cache_create=0.15"
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}
|
|
58
50
|
```
|
|
59
51
|
|
|
60
|
-
|
|
52
|
+
#### 费率格式(rates_text)
|
|
61
53
|
|
|
62
54
|
每行一个模型规则,格式:`model_name key=value ...`
|
|
63
55
|
|
|
@@ -70,13 +62,13 @@ DEFAULT_GROUPS = [
|
|
|
70
62
|
| `calls` | 按次计费次数 | 次 |
|
|
71
63
|
| `call_value` | 每次费用 | 美元 |
|
|
72
64
|
| `multiplier` | 全局倍率 | 倍数 |
|
|
73
|
-
| `time_mult` | 时间段倍率 |
|
|
65
|
+
| `time_mult` | 时间段倍率 | `HH:MM-HH:MM=倍率;...` |
|
|
74
66
|
|
|
75
67
|
`*` 匹配所有未明确列出的模型。
|
|
76
68
|
|
|
77
|
-
|
|
69
|
+
#### 时间段倍率
|
|
78
70
|
|
|
79
|
-
```
|
|
71
|
+
```
|
|
80
72
|
# 北京时间 22:00-02:00 加价 50%
|
|
81
73
|
time_mult=22:00-02:00=1.5
|
|
82
74
|
|
|
@@ -84,36 +76,10 @@ time_mult=22:00-02:00=1.5
|
|
|
84
76
|
time_mult=22:00-02:00=1.5;08:00-20:00=1.0
|
|
85
77
|
```
|
|
86
78
|
|
|
87
|
-
## 费用计算公式
|
|
88
|
-
|
|
89
|
-
完全复制 API-Proxy 的 `calculateAllowanceDebitUnits`:
|
|
90
|
-
|
|
91
|
-
```
|
|
92
|
-
normalInput = max(0, input - cacheHit - cacheCreate)
|
|
93
|
-
cost = (normalInput / 1M × rate.input
|
|
94
|
-
+ output / 1M × rate.output
|
|
95
|
-
+ cacheHit / 1M × rate.cache_hit
|
|
96
|
-
+ cacheCreate / 1M × rate.cache_create)
|
|
97
|
-
× multiplier × timeMultiplier
|
|
98
|
-
```
|
|
99
|
-
|
|
100
79
|
## 显示位置
|
|
101
80
|
|
|
102
|
-
-
|
|
103
|
-
-
|
|
104
|
-
|
|
105
|
-
## 开发
|
|
106
|
-
|
|
107
|
-
```bash
|
|
108
|
-
# 安装依赖
|
|
109
|
-
npm install
|
|
110
|
-
|
|
111
|
-
# 构建
|
|
112
|
-
bun run build
|
|
113
|
-
|
|
114
|
-
# 类型检查
|
|
115
|
-
bun run typecheck
|
|
116
|
-
```
|
|
81
|
+
- 侧边栏底部(session 视图)
|
|
82
|
+
- 首页底部(home 视图)
|
|
117
83
|
|
|
118
84
|
## License
|
|
119
85
|
|
package/cli/index.js
CHANGED
|
@@ -102,7 +102,7 @@ function getAdminHTML() {
|
|
|
102
102
|
|
|
103
103
|
<div class="header">
|
|
104
104
|
<h1>opencode-usage 管理界面</h1>
|
|
105
|
-
<span class="badge">v1.1.
|
|
105
|
+
<span class="badge">v1.1.3</span>
|
|
106
106
|
</div>
|
|
107
107
|
|
|
108
108
|
<div class="container">
|
|
@@ -133,11 +133,11 @@ function getAdminHTML() {
|
|
|
133
133
|
<div class="form-row">
|
|
134
134
|
<div class="form-group">
|
|
135
135
|
<label>货币符号</label>
|
|
136
|
-
<input id="cfg-currency" type="text" placeholder="
|
|
136
|
+
<input id="cfg-currency" type="text" placeholder="¥">
|
|
137
137
|
</div>
|
|
138
138
|
<div class="form-group">
|
|
139
139
|
<label>费用小数位数</label>
|
|
140
|
-
<input id="cfg-decimals" type="number" min="0" max="8" placeholder="
|
|
140
|
+
<input id="cfg-decimals" type="number" min="0" max="8" placeholder="2">
|
|
141
141
|
</div>
|
|
142
142
|
</div>
|
|
143
143
|
<div class="form-row">
|
|
@@ -160,7 +160,7 @@ function getAdminHTML() {
|
|
|
160
160
|
</div>
|
|
161
161
|
|
|
162
162
|
<script>
|
|
163
|
-
let config = { groups: [], providers: [], currency: "
|
|
163
|
+
let config = { groups: [], providers: [], currency: "¥", cost_decimals: 2, show_per_message: true, show_session_totals: true };
|
|
164
164
|
|
|
165
165
|
// ── Tabs ──
|
|
166
166
|
document.querySelectorAll(".tab").forEach(tab => {
|
|
@@ -178,8 +178,8 @@ async function loadConfig() {
|
|
|
178
178
|
config = await res.json();
|
|
179
179
|
renderGroups();
|
|
180
180
|
renderProviders();
|
|
181
|
-
document.getElementById("cfg-currency").value = config.currency || "
|
|
182
|
-
document.getElementById("cfg-decimals").value = config.cost_decimals ??
|
|
181
|
+
document.getElementById("cfg-currency").value = config.currency || "¥";
|
|
182
|
+
document.getElementById("cfg-decimals").value = config.cost_decimals ?? 2;
|
|
183
183
|
document.getElementById("cfg-per-msg").checked = config.show_per_message !== false;
|
|
184
184
|
document.getElementById("cfg-totals").checked = config.show_session_totals !== false;
|
|
185
185
|
}
|
|
@@ -230,7 +230,7 @@ function renderGroups() {
|
|
|
230
230
|
<input value="\${(g.provider_ids||[]).join(', ')}" onchange="config.groups[\${i}].provider_ids=this.value.split(',').map(s=>s.trim()).filter(Boolean)" placeholder="api-proxy, xiaomi-token-plan">
|
|
231
231
|
</div>
|
|
232
232
|
<div class="form-group">
|
|
233
|
-
|
|
233
|
+
<label>初始余额(¥)</label>
|
|
234
234
|
<input type="number" step="0.01" value="\${g.initial_balance||0}" onchange="config.groups[\${i}].initial_balance=parseFloat(this.value)||0">
|
|
235
235
|
</div>
|
|
236
236
|
<div class="form-group">
|
package/config.json
CHANGED
package/dist/tui.js
CHANGED
|
@@ -66,8 +66,8 @@ var tui_default = {
|
|
|
66
66
|
tui: async (api, options, meta) => {
|
|
67
67
|
const t = api.theme.current;
|
|
68
68
|
const fileConfig = getConfig();
|
|
69
|
-
const currency = options?.currency ?? fileConfig.currency ?? "
|
|
70
|
-
const costDecimals = options?.cost_decimals ?? fileConfig.cost_decimals ??
|
|
69
|
+
const currency = options?.currency ?? fileConfig.currency ?? "¥";
|
|
70
|
+
const costDecimals = options?.cost_decimals ?? fileConfig.cost_decimals ?? 2;
|
|
71
71
|
const showPerMsg = options?.show_per_message ?? fileConfig.show_per_message ?? true;
|
|
72
72
|
const showTotals = options?.show_session_totals ?? fileConfig.show_session_totals ?? true;
|
|
73
73
|
const groups = options?.groups ?? fileConfig.groups ?? [];
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lijinzhao8/opencode-usage",
|
|
3
|
-
"version": "1.1.
|
|
4
|
-
"description": "OpenCode plugin
|
|
3
|
+
"version": "1.1.3",
|
|
4
|
+
"description": "OpenCode plugin for real-time API usage and cost tracking in the TUI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|