diff --git a/README.md b/README.md index 17fb437..b80f624 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ bun run build # type-check + vite build(dist/) ## 使用 -1. 左侧选择接口(6 个,平铺不分组)→ 右侧开 tab +1. 左侧选择接口(9 个,平铺不分组)→ 右侧开 tab 2. tab 内展开「注意事项」看该接口的实证调研坑文档 3. 填 sk-key(每 tab 独立、仅存内存、刷新即重置,不落盘;切换 tab 输入保留) 4. 点「发送请求」→ 响应区显示元信息(状态/耗时/字符数)+ 虚拟滚动高亮 JSON diff --git a/docs/bench交互设计文档.md b/docs/bench交互设计文档.md index c7300f8..49b2c4f 100644 --- a/docs/bench交互设计文档.md +++ b/docs/bench交互设计文档.md @@ -8,21 +8,24 @@ ## 1. 项目定位 -替代 Postman 的专用调试台(bench):左侧选接口 → 右侧 tab 内看文档、填 key、发请求、看原始响应。对接 6 个接口,服务 karpool 拼车项目的接口调试与换算验证。 +替代 Postman 的专用调试台(bench):左侧选接口 → 右侧 tab 内看文档、填 key、发请求、看原始响应。对接 9 个接口,服务 karpool 拼车项目的接口调试与换算验证。 **接口清单**(数据源:`docs/NewAPI-sk-key接口文档.md`,按此顺序展示,不分组): | 序 | 路径 | 鉴权 | 响应特征 | |---|------|------|---------| -| 0 | `GET /api/status` | 无(完全公开) | 站点配置与计费参数:`quota_per_unit`(换算比率权威来源)、`quota_display_type`、汇率等 | -| 1 | `GET /v1/dashboard/billing/subscription` | TokenAuth(严格) | 小 JSON,美元额度(无限额时 1 亿占位) | -| 2 | `GET /v1/dashboard/billing/usage` | TokenAuth(严格) | 小 JSON,累计美分 | -| 3 | `GET /v1/models` | TokenAuth(严格) | 中等 JSON,模型数组 | -| 4 | `GET /api/usage/token` | TokenAuthReadOnly(宽松) | 小 JSON,累计 quota | -| 5 | `GET /api/log/token` | TokenAuthReadOnly(宽松) | **大响应**:最近 1000 条日志,pretty-print 2~4MB | +| 0 | `GET /api/user/groups` | 无(完全公开) | 用户分组与倍率列表;未启用分组时为空对象 | +| 1 | `GET /api/perf-metrics/summary` | 公开门控(默认无需凭证) | 全站模型服务质量:延迟/成功率/TPS/小时级序列;`hours` 参数 | +| 2 | `GET /api/rankings` | 公开门控(默认无需凭证) | 全站模型用量排行:名次/份额/环比增长;`period` 参数 | +| 3 | `GET /api/status` | 无(完全公开) | 站点配置与计费参数:`quota_per_unit`(换算比率权威来源)、`quota_display_type`、汇率等 | +| 4 | `GET /v1/dashboard/billing/subscription` | TokenAuth(严格) | 小 JSON,美元额度(无限额时 1 亿占位) | +| 5 | `GET /v1/dashboard/billing/usage` | TokenAuth(严格) | 小 JSON,累计美分 | +| 6 | `GET /v1/models` | TokenAuth(严格) | 中等 JSON,模型数组 | +| 7 | `GET /api/usage/token` | TokenAuthReadOnly(宽松) | 小 JSON,累计 quota | +| 8 | `GET /api/log/token` | TokenAuthReadOnly(宽松) | **大响应**:最近 1000 条日志,pretty-print 2~4MB | -> 0 完全公开(无需任何凭证,面板隐藏 sk-key 输入行);4、5 宽松鉴权(key 过期/耗尽仍可查);1~3 严格鉴权(key 无效直接被拒)。tab 内标出该差异,避免误判「接口坏了」。 -> 4 与 2 构成换算交叉验证对(total_used ÷ 500000 ≈ total_usage ÷ 100),Tabs 并行对账是核心工作流。0 是换算比率的权威来源(quota_per_unit 可被管理员修改,500000 只是默认值)。 +> 0~3 完全公开或默认公开(面板隐藏 sk-key 输入行);7、8 宽松鉴权(key 过期/耗尽仍可查);4~6 严格鉴权(key 无效直接被拒)。tab 内标出该差异,避免误判「接口坏了」。 +> 7 与 5 构成换算交叉验证对(total_used ÷ 500000 ≈ total_usage ÷ 100),Tabs 并行对账是核心工作流。3 是换算比率的权威来源(quota_per_unit 可被管理员修改,500000 只是默认值)。1、2 是「全站视角」数据——单个 sk-key 日志看不到的服务质量与用量排行,服务模型健康度判断。 --- @@ -53,7 +56,7 @@ 无分组无编号,按清单顺序) ``` -- **左 sider**(~300px):接口列表,**不分组、不编号**,按 §1 清单顺序平铺 6 个路径;选中态高亮 +- **左 sider**(~300px):接口列表,**不分组、不编号**,按 §1 清单顺序平铺 9 个路径;选中态高亮 - **右主区**:`t-tabs` 顶部,激活 tab 内容 = 请求行(method + 路径 + 鉴权徽标)→ 调试行(sk-key 输入 + 发送按钮)→ 响应区(元信息 + 虚拟滚动 JSON) - 暗色默认(TDesign dark theme + CSS 变量) diff --git a/src/api/endpoints.spec.ts b/src/api/endpoints.spec.ts index 871c6b6..ea007d2 100644 --- a/src/api/endpoints.spec.ts +++ b/src/api/endpoints.spec.ts @@ -3,17 +3,20 @@ import { describe, expect, it } from 'vitest'; import { endpointList, findEndpointByPath } from './endpoints'; describe('endpointList 数据完整性', () => { - it('恰好 6 个接口(设计文档 §1 定案的对接清单)', () => { - expect(endpointList).toHaveLength(6); + it('恰好 9 个接口(设计文档 §1 定案的对接清单)', () => { + expect(endpointList).toHaveLength(9); }); it('路径唯一(path 是 tab / queryKey 的唯一标识)', () => { const pathList = endpointList.map((endpoint) => endpoint.path); - expect(new Set(pathList).size).toBe(6); + expect(new Set(pathList).size).toBe(9); }); it('顺序与用户指定清单一致', () => { expect(endpointList.map((endpoint) => endpoint.path)).toEqual([ + '/api/user/groups', + '/api/perf-metrics/summary', + '/api/rankings', '/api/status', '/v1/dashboard/billing/subscription', '/v1/dashboard/billing/usage', @@ -31,8 +34,11 @@ describe('endpointList 数据完整性', () => { } }); - it('鉴权模式分布正确(公开 1 + 严格 3 + 宽松 2)', () => { + it('鉴权模式分布正确(公开 4 + 严格 3 + 宽松 2)', () => { expect(endpointList.map((endpoint) => endpoint.authMode)).toEqual([ + 'none', + 'none', + 'none', 'none', 'strict', 'strict', diff --git a/src/api/endpoints.ts b/src/api/endpoints.ts index 17324b3..0cfa68f 100644 --- a/src/api/endpoints.ts +++ b/src/api/endpoints.ts @@ -2,6 +2,9 @@ * 对接接口的静态元数据 * 数据源:docs/NewAPI-sk-key接口文档.md(源码实证调研) * 顺序即 sider / tab 展示顺序(设计文档 §1 定案,不分组不编号) + * + * 鉴权三态:none = 完全公开(无需任何凭证)→ strict = TokenAuth → lenient = TokenAuthReadOnly + * 公开接口组(/api/user/groups、/api/perf-metrics/summary、/api/rankings、/api/status)排在清单最前 */ export type AuthMode = 'strict' | 'lenient' | 'none'; @@ -24,6 +27,82 @@ export interface EndpointDefinition { } export const endpointList: readonly EndpointDefinition[] = [ + { + path: '/api/user/groups', + method: 'GET', + authMode: 'none', + authMiddlewareName: '无(公开接口)', + responseSummary: '用户分组与倍率列表(未启用分组时为空对象)', + notes: [ + '完全公开:无任何鉴权中间件(本工具对接清单中三个免凭证接口之一)', + '返回站点配置的用户分组(default / vip 等)及其倍率;站点未启用分组时 data 为空对象', + '用途:解释「同一模型为什么计费不同」——分组倍率会影响同一模型的实际消耗', + '与 /api/pricing 的 group_ratio 字段互补:本接口是分组清单,pricing 是模型定价', + ], + sampleResponse: { success: true, message: '', data: {} }, + }, + { + path: '/api/perf-metrics/summary', + method: 'GET', + authMode: 'none', + authMiddlewareName: 'HeaderNavModulePublicOrUserAuth(默认公开)', + responseSummary: '全站模型服务质量汇总(延迟/成功率/TPS)', + notes: [ + '公开接口:管理员未在 HeaderNav 中开启 pricing 模块的 requireAuth 时无需任何凭证', + 'query 参数 hours:统计窗口小时数(默认 24)', + '返回每个模型的 avg_latency_ms(平均延迟)、success_rate(成功率 %)、avg_tps(每秒 token 数)、recent_success_series(按小时采样的成功率时间序列)', + '对拼车工具的意义:单个 sk-key 日志看不到全局服务质量,本接口补上「模型当前健康度」视角——伙伴反馈「慢/报错多」时用它定位是模型问题还是自身问题', + '明细版 /api/perf-metrics?model=xxx 需 query 参数(model 必填,另支持 group/hours),面板暂不支持 query 输入,可用上方注意事项了解参数后经代理手动拼接', + ], + sampleResponse: { + success: true, + data: { + models: [ + { + model_name: 'gpt-5.6-sol', + avg_latency_ms: 16823, + success_rate: 94.73, + avg_tps: 25.81, + recent_success_series: [ + { ts: 1788872400, success_rate: 100 }, + { ts: 1788876000, success_rate: 99.16 }, + ], + }, + ], + }, + }, + }, + { + path: '/api/rankings', + method: 'GET', + authMode: 'none', + authMiddlewareName: 'HeaderNavModulePublicOrUserAuth(默认公开)', + responseSummary: '全站模型用量排行(名次/份额/增长)', + notes: [ + '公开接口:同 perf-metrics,受 HeaderNav 模块开关控制,默认无需凭证', + 'query 参数 period:统计周期(默认 week)', + '返回每个模型的 rank(名次)、previous_rank(上期名次)、total_tokens(总用量)、share(份额)、growth_pct(环比增长 %)', + '对拼车工具的意义:看全站都在用什么模型——车长选「主推模型」(便宜且稳定)的数据依据;配合 perf-metrics 的成功率可识别衰退模型', + ], + sampleResponse: { + success: true, + data: { + models: [ + { + rank: 1, + previous_rank: 2, + model_name: 'gpt-5.6-sol', + vendor: 'OpenAI', + vendor_icon: 'OpenAI', + category: 'all', + total_tokens: 1583845480, + share: 0.6549, + growth_pct: 60.4253, + }, + ], + }, + }, + }, { path: '/api/status', method: 'GET', @@ -31,7 +110,7 @@ export const endpointList: readonly EndpointDefinition[] = [ authMiddlewareName: '无(公开接口)', responseSummary: '站点配置与计费参数(含 quota_per_unit)', notes: [ - '完全公开:无任何鉴权,不持有 sk-key 也能访问(本工具对接清单中唯一)', + '完全公开:无任何鉴权,不持有 sk-key 也能访问(对接清单公开接口组之一)', 'quota_per_unit 是 QuotaPerUnit 当前生效值(默认 500000,NewAPI 以 $0.002 / 1K tokens 的基准定价为锚点设计)——quota ÷ 该值 = 美元,换算比率的唯一权威来源,管理员可改,不要硬编码', '想用 billing 接口(subscription / usage)反推换算比率不可靠:它们内部就是拿 quota ÷ QuotaPerUnit 换算的,站点改了配置它们会跟着变,永远「吻合」——比率唯一权威只有本接口的 quota_per_unit', 'quota_display_type 影响 /v1/dashboard/billing/subscription 与 /v1/dashboard/billing/usage 的语义:USD 直接是美元;CNY 先 ÷QuotaPerUnit 再 ×usd_exchange_rate;TOKENS 是原始 token 数',