Add token usage stats and consolidate credentials in SQLite
build / build (push) Successful in 2m34s
build / build (push) Successful in 2m34s
- New internal/stats (types) and internal/store (SQLite owner: requests + credentials tables, WAL); store implements stats.Recorder. - Stream (SSE tee) and non-stream chat paths parse upstream usage incl. cached_tokens and record per-request; add /api/stats, /api/stats/reset, /admin/stats HTML with cache hit rate. - Drop credentials.json: remove auth file I/O and ZHANLU_CREDENTIALS_FILE; credential precedence is env vars > db row.
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
- 模型 API Key 换取签名逻辑:SM3 摘要 + SM2 签名(`X-Auth-Signature`/`X-Auth-Timestamp`/`X-Auth-Nonce`)。
|
||||
- 上游 SSE 直接透传为 OpenAI SSE;非流式请求在本地聚合为 OpenAI Chat Completion JSON。
|
||||
- OpenAI 函数/工具调用:支持 `tools`、`tool_choice`、流式 `delta.tool_calls`、非流式 `message.tool_calls` 以及 `role: tool` 结果续传。
|
||||
- Token 消耗统计:流式与非流式请求均解析上游 `usage`,按模型/按日/最近明细写入本地 SQLite(`zhanlu.db`),凭据也一并持久化在同一个库中。管理页提供 `GET /admin/stats` 可视化与 `GET /api/stats` JSON 接口。
|
||||
|
||||
## 运行
|
||||
|
||||
@@ -37,17 +38,17 @@ http://127.0.0.1:8080/
|
||||
/opt/zhanlu-proxy/zhanlu-proxy
|
||||
```
|
||||
|
||||
凭据文件放在:
|
||||
数据库放在:
|
||||
|
||||
```text
|
||||
/opt/zhanlu-proxy/credentials.json
|
||||
/opt/zhanlu-proxy/zhanlu.db
|
||||
```
|
||||
|
||||
创建环境变量文件 `/etc/zhanlu-proxy/zhanlu-proxy.env`:
|
||||
|
||||
```env
|
||||
ZHANLU_LISTEN_ADDR=:8080
|
||||
ZHANLU_CREDENTIALS_FILE=/opt/zhanlu-proxy/credentials.json
|
||||
ZHANLU_DB_FILE=/opt/zhanlu-proxy/zhanlu.db
|
||||
ZHANLU_MOBILE_LOGIN_BASE_URL=https://ecloud.10086.cn
|
||||
ZHANLU_MOBILE_MODEL_BASE_URL=https://ecloud.10086.cn/api/query/aigateway
|
||||
ZHANLU_UPSTREAM_TIMEOUT=300s
|
||||
@@ -106,20 +107,22 @@ journalctl -u zhanlu-proxy -f
|
||||
- 使用本次 `secret` AES 解密响应中的 `ak`、`sk`、`license`,得到 `AccessKey`、`SecretKey`、`Token`。
|
||||
- 按插件 v1.4.2 流程调用 `/api/acepilot/zhanlu/v1/login`(RSA+HmacSHA1 签名 URL + `plugin_type=zhanlu_ide` 请求头)获取用户资料(email/组织/团队)。
|
||||
- 用 SM2 私钥签名调用 `{mobileModelBaseUrl}/user/api/v2/external/key/get-or-create` 换取模型 `apiKey`。
|
||||
- 凭据(含 `apiKey`、`modelBaseUrl`、email 等)会写入 JSON 文件,后续 OpenAI 兼容接口自动使用。
|
||||
- 凭据(含 `apiKey`、`modelBaseUrl`、email 等)会写入本地 SQLite 数据库(`zhanlu.db`),后续 OpenAI 兼容接口自动使用。
|
||||
|
||||
默认保存到当前执行目录:
|
||||
默认数据库保存在当前执行目录:
|
||||
|
||||
```text
|
||||
credentials.json
|
||||
zhanlu.db
|
||||
```
|
||||
|
||||
可以通过环境变量覆盖:
|
||||
|
||||
```powershell
|
||||
$env:ZHANLU_CREDENTIALS_FILE="E:\path\to\credentials.json"
|
||||
$env:ZHANLU_DB_FILE="E:\path\to\zhanlu.db"
|
||||
```
|
||||
|
||||
凭据仅持久化在数据库中,不再使用 JSON 文件。
|
||||
|
||||
手机号验证码登录使用 `ZHANLU_MOBILE_LOGIN_BASE_URL`,默认公网地址来自插件配置(兼容旧环境变量 `ZHANLU_SERVER_BASE_URL`):
|
||||
|
||||
```powershell
|
||||
@@ -184,7 +187,8 @@ curl http://127.0.0.1:8080/v1/models `
|
||||
| `ZHANLU_MOBILE_LOGIN_BASE_URL` | `https://ecloud.10086.cn` | 移动云公网登录 Base URL(兼容旧变量 `ZHANLU_SERVER_BASE_URL`) |
|
||||
| `ZHANLU_MOBILE_MODEL_BASE_URL` | `https://ecloud.10086.cn/api/query/aigateway` | 移动云公网模型网关 Base URL |
|
||||
| `ZHANLU_UPSTREAM_PATH` | `/chat/completions` | 模型网关聊天接口路径 |
|
||||
| `ZHANLU_CREDENTIALS_FILE` | `credentials.json` | 凭据 JSON 路径,默认当前执行目录 |
|
||||
| `ZHANLU_DB_FILE` | `zhanlu.db` | 本地 SQLite 数据库路径,凭据与 token 统计均存于此,默认当前执行目录 |
|
||||
| `ZHANLU_STATS_DISABLED` | `false` | 设为 `true` 关闭 token 用量记录(仅停止写入统计,凭据存储不受影响) |
|
||||
| `ZHANLU_ACCESS_KEY` | 空 | 直接从环境变量提供 AccessKey |
|
||||
| `ZHANLU_SECRET_KEY` | 空 | 直接从环境变量提供 SecretKey |
|
||||
| `ZHANLU_TOKEN` | 空 | 直接从环境变量提供 Token |
|
||||
@@ -207,14 +211,33 @@ curl http://127.0.0.1:8080/v1/models `
|
||||
服务启动时按以下优先级加载凭据:
|
||||
|
||||
1. 环境变量 `ZHANLU_ACCESS_KEY`、`ZHANLU_SECRET_KEY`、`ZHANLU_TOKEN` 或 `ZHANLU_API_KEY`。
|
||||
2. `ZHANLU_CREDENTIALS_FILE` 指向的 JSON 文件。
|
||||
2. `ZHANLU_DB_FILE` 数据库中持久化的凭据行。
|
||||
|
||||
登录页面保存后,运行中的服务会立即使用新凭据。若环境中只有 AK/SK/Token 而没有 `apiKey`,首次调用聊天接口时会自动按插件流程换取 API Key 并回写凭据文件。
|
||||
登录页面保存后,运行中的服务会立即使用新凭据并写入数据库。若环境中只有 AK/SK/Token 而没有 `apiKey`,首次调用聊天接口时会自动按插件流程换取 API Key 并回写数据库。
|
||||
|
||||
## Token 消耗统计
|
||||
|
||||
代理在 `/v1/chat/completions` 完成后解析上游 `usage`(流式路径在透传 SSE 的同时旁路解析末块 `usage`,非流式路径在聚合时解析),将以下维度写入 `ZHANLU_DB_FILE`:
|
||||
|
||||
- 时间、模型、流式/非流式
|
||||
- `prompt_tokens` / `completion_tokens` / `total_tokens` / `reasoning_tokens`(思考模型)
|
||||
- `cached_tokens`(来自 `prompt_tokens_details.cached_tokens`,提示缓存命中的 token 数)与缓存命中率
|
||||
- 请求状态(`success` / `upstream_error`)与耗时
|
||||
|
||||
缓存命中率为 `cached_tokens / prompt_tokens`,仅在模型/网关支持 prompt 缓存且上游返回 `cached_tokens` 时非零。
|
||||
|
||||
管理页(需先登录管理页面)提供:
|
||||
|
||||
- `GET /admin/stats`:可视化页面,展示总览、按模型、按日柱状、最近请求明细,带重置按钮。
|
||||
- `GET /api/stats`:JSON 接口,支持 `since`/`until`(RFC3339)、`model`、`limit` 查询参数。
|
||||
- `POST /api/stats/reset`:清空统计(凭据不受影响)。
|
||||
|
||||
设置 `ZHANLU_STATS_DISABLED=true` 可停止写入统计。
|
||||
|
||||
## 安全说明
|
||||
|
||||
- `credentials.json` 包含明文 `AccessKey`、`SecretKey`、`Token` 和 `apiKey`,请不要提交到仓库。
|
||||
- 默认保存在当前执行目录的 `credentials.json`。
|
||||
- `zhanlu.db` 数据库包含明文 `AccessKey`、`SecretKey`、`Token` 和 `apiKey`,请不要提交到仓库。
|
||||
- 默认保存在当前执行目录的 `zhanlu.db`(建议通过 `ZHANLU_DB_FILE` 指向受保护路径)。
|
||||
- 建议设置 `ZHANLU_LOGIN_PASSWORD`,避免公网暴露的 `/admin/login` 被直接访问。
|
||||
- 错误响应默认不会返回签名 URL,避免泄露 `AccessKey`、`authorization`、`Signature`。
|
||||
- `ZHANLU_DEBUG=true` 时会返回更详细错误,但仍会对敏感 query 参数脱敏。
|
||||
|
||||
Reference in New Issue
Block a user