|
14 | 14 | - **公共凭证池**:admin 集中维护、全员共享、加密入库(`APP_SECRET`);设备码登录、多账号切换、额度探测、每日签到、token 预刷新。 |
15 | 15 | - **三角色账号体系**:`admin` / `operator` / `viewer`,用户存 SQLite;一次性激活链接自设密码、首登强制改密、改角色/停用即时吊销会话;登录与写操作留审计。 |
16 | 16 | - **成长中心**(仅 CodeBuddy):自动领 Buddy 旅行礼物、派 Buddy、领任务奖、断登补登、连登兑换、开盲盒;不可逆动作可用 `GROWTH_IRREVERSIBLE_ACTIONS=false` 关停;管理台可手动执行。 |
17 | | -- **脱敏统计**:不存对话内容;明细 90 天、小时汇总永久;按人/渠道/模型/凭证可视化;按 OpenRouter 刊例价估算成本(人民币为主);按「总输出 token ÷ 生成时间总和」给出输出速度(tok/s);明细面板带「实时」开关(SSE 推送刚落库的请求)。 |
| 17 | +- **脱敏统计**:不存对话内容;明细 90 天、小时汇总永久;按人/渠道/模型/凭证可视化;按 OpenRouter 刊例价估算成本(人民币为主);按「正文 token ÷ 生成时间总和」与「总产出 token ÷ 生成时间总和」两口径给出输出速度(tok/s,剔除批到达的不可测样本;概览卡片、分组表与逐请求明细同源);明细面板带「实时」开关(SSE 推送刚落库的请求)。 |
18 | 18 | - **上游状态聚合**:把各模型 / 网关提供方的官方状态页(OpenCode Zen、Kilo、DeepSeek、Together、Moonshot、MiniMax、OpenAI、Anthropic)归一化后并排展示,用于区分「上游整体故障」与「本服务凭证 / 额度问题」。只做解释、不参与选号 / 熔断;快照只存内存、重启归零。 |
19 | 19 | - **侧栏数据提醒**:侧栏对应项上显示待办计数角标(凭证需重登/耗尽、未恢复告警、上次失败任务、异常上游源、待激活账号、本人将到期 Key、模型目录陈旧),不点进去也能看到;只数「待办」、按角色裁剪,见[下文](#侧栏数据提醒导航角标)。 |
20 | 20 | - **管理台安全加固**:登录限流、CSRF 校验、请求体上限、Host 白名单。 |
@@ -541,17 +541,17 @@ OpenRouter 收录数百条,其中多数本服务没接。每行带 `available` |
541 | 541 |
|
542 | 542 | ### 分组维度与重新汇总 |
543 | 543 |
|
544 | | -**分组统计**面板用 tabs 切四个维度(按渠道 / 按模型 / 按用户 / 按凭证),共用同一张表(渠道 / 请求(请求数 · 成功率,悬停看成功数)/ Credit / 成本 / Token(输入 ÷ 输出 · 命中率,悬停看命中 token)/ 速度(tok/s)/ 平均延迟(耗时 ÷ 首字)/ P95 延迟(耗时 ÷ 首字)),共 8 列。对应端点 `GET /api/stats/by-provider|by-model|by-user|by-credential`。默认按请求数降序,点列头可切换排序;请求 / Token / 平均延迟 / P95 延迟四个合并列点列头弹菜单选子列再排序(`sort=requests|ok_count|input_tokens|output_tokens|cached_tokens|avg_latency_ms|avg_ttfb_ms|p50_latency_ms|p90_latency_ms|p95_latency_ms|p99_latency_ms|p50_ttfb_ms|p90_ttfb_ms|p95_ttfb_ms|p99_ttfb_ms`,速度列另有独立排序键 `sort=tps`),成功率与命中率是派生只读值不参与排序。**延迟分位可切换**:P95 列的表头有 P50 / P90 / P95 / P99 四档切换(默认 P95,不铺开四列以免表头拥挤);四档由同一次窗口函数子查询算出,取整口径一致(nearest-rank,n 为**有值**样本数)。**按用户 / 按凭证**只对 admin 与 operator 展示。**口径差异**:渠道 / 模型 / 用户三维读**小时汇总**(永久保留,最近 5 分钟内的请求尚未计入);**凭证维度读明细表**(小时汇总主键里没有 `credential_id`),故只覆盖**最近 90 天**。 |
| 544 | +**分组统计**面板用 tabs 切四个维度(按渠道 / 按模型 / 按用户 / 按凭证),共用同一张表(渠道 / 请求(请求数 · 成功率,悬停看成功数)/ Credit / 成本 / Token(输入 ÷ 输出 · 命中率,悬停看命中 token)/ 速度(正文 ÷ 总产出,tok/s,悬停看两口径)/ 平均延迟(耗时 ÷ 首字)/ P95 延迟(耗时 ÷ 首字)),共 8 列。对应端点 `GET /api/stats/by-provider|by-model|by-user|by-credential`。默认按请求数降序,点列头可切换排序;请求 / Token / 速度 / 平均延迟 / P95 延迟五个合并列点列头弹菜单选子列再排序(`sort=requests|ok_count|input_tokens|output_tokens|cached_tokens|avg_latency_ms|avg_ttfb_ms|p50_latency_ms|p90_latency_ms|p95_latency_ms|p99_latency_ms|p50_ttfb_ms|p90_ttfb_ms|p95_ttfb_ms|p99_ttfb_ms|tps_visible|tps`),成功率与命中率是派生只读值不参与排序。**延迟分位可切换**:P95 列的表头有 P50 / P90 / P95 / P99 四档切换(默认 P95,不铺开四列以免表头拥挤);四档由同一次窗口函数子查询算出,取整口径一致(nearest-rank,n 为**有值**样本数)。**按用户 / 按凭证**只对 admin 与 operator 展示。**口径差异**:渠道 / 模型 / 用户三维读**小时汇总**(永久保留,最近 5 分钟内的请求尚未计入);**凭证维度读明细表**(小时汇总主键里没有 `credential_id`),故只覆盖**最近 90 天**。 |
545 | 545 |
|
546 | 546 | **延迟两类口径**:**只统计成功请求**(失败请求的耗时会拉偏「典型耗时」)。**平均延迟列** = 平均耗时 / 平均首字 = `latency_sum ÷ 成功数`(读小时汇总,与总览卡片、图表同口径,永久保留);**P95 延迟列** = P95 耗时 / P95 首字 = 第 95 百分位,按 **nearest-rank**(第 `⌈0.95·n⌉` 小的值,n = 该组有值样本数)从**逐请求明细**算出——小时汇总只有和与计数,数学上还原不出分布,故分位列只覆盖**最近 90 天**。P50 / P90 / P99 与 P95 同一套 SQL(一次子查询算完四档),口径完全一致,只是百分位参数不同。`ttfb_ms` 对非流式 / 未产出首字的成功请求为 `NULL`,两列各自独立排名(只数有值样本)。无成功样本 / 未上报延迟时显示 `—`(不拿 0 冒充)。 |
547 | 547 |
|
548 | 548 | **失败归因**:分组表下方另有「失败归因」面板,`GET /api/stats/errors`(operator+)按 `(渠道, 模型, 错误类型)` 聚合窗口内 `ok=0` 的明细,给出失败次数与最近失败时刻(按失败数降序,`limit` ≤ 5000)。点任意一行即**钻取**到下方明细并自动加上「只看失败」(`GET /api/stats/events?ok=0`,与 `provider`/`model`/`credential_id` 叠加);键盘 Enter / Space 同样触发。该面板只在 admin/operator 下渲染与请求。`/metrics` 的 `upstream_errors_total` 仍取进程内计数(重启归零),与这里的 90 天明细口径不同,两者不合并。 |
549 | 549 |
|
550 | 550 | **点行钻取**:点分组表任意一行,下方「请求明细」即按该行钻取(渠道 / 模型 / 凭证按同名列过滤,用户维度走作用域参数),条件叠加、可多个维度层层收窄,面板上方显示当前过滤标签并可一键清除。`GET /api/stats/events` 因此接受 `provider` / `model` / `credential_id` 三个过滤参数(`AND` 语义),另有 `ok=0` 只看失败。 |
551 | 551 |
|
552 | | -**明细表列合并**:请求明细把同类列并成一列,默认值一眼可读、悬停展开全部子项:**Token**(默认「输入 / 输出 · 命中率」,悬停含命中 token)、**延迟**(默认「耗时 / 首字」)。列数从 14 压到约 10,窄屏卡片也少一半字段。排序能力不丢:点合并列头弹出下拉选子列(Token → 输入 / 输出 / 命中 / 命中率,延迟 → 耗时 / 首字),选中即按该子列排序;**命中率**子列走后端 `sort=cache_rate`(命中 ÷ 输入,输入为 0 或未上报时为 `NULL`,与其它可空列同排序语义)。 |
| 552 | +**明细表列合并**:请求明细把同类列并成一列,默认值一眼可读、悬停展开全部子项:**Token**(默认「输入 / 输出 · 命中率」,悬停含命中 token)、**延迟**(默认「耗时 / 首字」)、**速度**(默认「正文 / 总产出」,tok/s,悬停写全两口径)、**渠道 / 凭证**(凭证名在上、渠道 icon + 名在下,悬停看完整凭证 ID——同渠道常挂多个账号,先认账号)。**时间列拆成两行**(`20:17:09` / `2026-10-21`,**具体时刻优先**、日期次要色,等宽数字各自纵向对齐,窄屏不折行),请求 ID 提示仍挂在这一格。列数从 15 压到约 10,窄屏卡片也少一半字段。排序能力不丢:点合并列头弹出下拉选子列(Token → 输入 / 输出 / 命中 / 命中率,延迟 → 耗时 / 首字,速度 → 正文 / 总产出,渠道 / 凭证 → 渠道 / 凭证),选中即按该子列排序;**命中率**子列走后端 `sort=cache_rate`(命中 ÷ 输入,输入为 0 或未上报时为 `NULL`,与其它可空列同排序语义),速度子列走 `sort=tps_visible` / `sort=tps`,渠道子列走 `sort=provider` / `sort=credential`。 |
553 | 553 |
|
554 | | -**导出 CSV**:明细面板右上「导出 CSV」(仅 admin / operator)按**当前时间范围 + 当前钻取过滤**导出逐请求明细,`GET /api/stats/events?format=csv`。文件带 UTF-8 BOM(Excel 认编码)、`\r\n` 换行、时间列 ISO 8601(UTC),并对以 `= + - @`(及制表符/回车)开头的**文本**单元格加前导单引号防公式注入(数值含负数原样)。单次导出上限 10000 行,超出截断并在响应头 `X-Export-Truncated: 1` 标出,页面提示收窄条件。 |
| 554 | +**导出 CSV**:明细面板右上「导出 CSV」(仅 admin / operator)按**当前时间范围 + 当前钻取过滤**导出逐请求明细,`GET /api/stats/events?format=csv`。列与页面明细表同口径,含**逐请求速度**(`正文速度 tok/s` / `总产出速度 tok/s`,与页面同规则:只算生成窗口可测的成功请求,不可测的行留空——空不是 0)。文件带 UTF-8 BOM(Excel 认编码)、`\r\n` 换行、时间列 ISO 8601(UTC),并对以 `= + - @`(及制表符/回车)开头的**文本**单元格加前导单引号防公式注入(数值含负数原样)。单次导出上限 10000 行,超出截断并在响应头 `X-Export-Truncated: 1` 标出,页面提示收窄条件。 |
555 | 555 |
|
556 | 556 | **实时流(SSE)**:明细面板右上「实时」开关打开后,`EventSource` 订阅 `GET /api/stats/events/stream`,展示**当前筛选范围内刚落库**的请求(与下方翻页的历史明细分开展示,避免混成一张会跳动的表)。事件在 `StatsCollector.record` **事务提交后**由进程内 `LiveEventHub` 广播(不轮询数据库),前端只保留最近 50 条、新→旧排列;关闭开关即断开连接。 |
557 | 557 |
|
|
0 commit comments