feat(packages): 为 usage 增加输出 token 趋势指令#895
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a new "tokens" command to visualize ChatLuna token usage trends and plugin breakdowns, rendering charts via Puppeteer. Feedback highlights a potential call stack overflow risk in "index.ts" when using "Math.max" with the spread operator on large datasets. Additionally, in "renderer.ts", it is recommended to make the "__dirname" resolution safer for ESM environments and to delete temporary HTML files immediately in the "finally" block rather than using a delayed "setTimeout" to prevent disk clutter and memory leaks.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
Walkthrough新增 token 报表与趋势功能:定义数据类型与时间计算、实现报表聚合与趋势点生成、新增 JSX 运行时用于 HTML 构建、生成 SVG 图表与页面、通过 Puppeteer 截图,并在命令/配置中集成 /tokens。 ChangesToken 趋势图渲染功能
序列图sequenceDiagram
participant User
participant TokensCommand as /tokens 命令
participant tokenReport
participant Database as chatluna_usage
participant renderTokenTrend
participant Response
User->>TokensCommand: /tokens day/week/month/all [plugin]
TokensCommand->>tokenReport: 调用 tokenReport(range, withPlugins)
tokenReport->>Database: 按 createdAt 范围查询记录
Database-->>tokenReport: 返回使用数据
tokenReport-->>TokensCommand: 返回 TokenReport
TokensCommand->>Response: 发送文本统计结果
alt 有 Puppeteer
TokensCommand->>renderTokenTrend: 渲染趋势图(theme: light/dark/auto)
renderTokenTrend-->>TokensCommand: 返回图片 buffer
TokensCommand->>Response: 发送图片
end
🎯 4 (复杂) | ⏱️ ~45 分钟
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
- 在 chatluna-usage 中新增 tokens 指令,支持 day、week、month、all 统计范围及插件明细参数。 - 基于 chatluna_usage 表聚合 total、input、output token 与请求峰值,按不同范围生成分桶趋势数据。 - 新增 puppeteer HTML 图表渲染模板,支持浅色和深色主题以及颜色图例。 - 将 puppeteer 声明为可选依赖服务,未启用时保留文字统计输出。
1efe8d3 to
fb89391
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/extension-usage/src/index.ts (1)
469-488:range === 'all'会全表扫描,建议加上观测/治理手段。当
range为all时time = { $lt: end },相当于把chatluna_usage全表拉进内存再聚合。随着记录增长,单次tokens -a可能造成明显的内存与延迟峰值。表上已有createdAt索引,但无范围过滤时索引无济于事。可考虑:为all设定一个上限时间窗(或最大行数),或在数据库侧做聚合统计而非全量取回。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/extension-usage/src/index.ts` around lines 469 - 488, The tokenReport method currently sets time = { $lt: end } for range === 'all', causing a full-table fetch of chatluna_usage by createdAt; change tokenReport to avoid full-table scans by applying a sensible cap or DB-side aggregation: either compute a start = end - MAX_TOKEN_REPORT_WINDOW (configurable, e.g. using Time constants) or add a limit/aggregation in the database query (e.g. request aggregated token sums or top-N rows instead of pulling all records) before calling createTokenReport; ensure the change references tokenReport, createTokenReport, chatluna_usage, createdAt and use a configurable MAX_ROWS or MAX_WINDOW so future growth is governed and include a warning/log when the “all” request is capped.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@packages/extension-usage/src/index.ts`:
- Around line 469-488: The tokenReport method currently sets time = { $lt: end }
for range === 'all', causing a full-table fetch of chatluna_usage by createdAt;
change tokenReport to avoid full-table scans by applying a sensible cap or
DB-side aggregation: either compute a start = end - MAX_TOKEN_REPORT_WINDOW
(configurable, e.g. using Time constants) or add a limit/aggregation in the
database query (e.g. request aggregated token sums or top-N rows instead of
pulling all records) before calling createTokenReport; ensure the change
references tokenReport, createTokenReport, chatluna_usage, createdAt and use a
configurable MAX_ROWS or MAX_WINDOW so future growth is governed and include a
warning/log when the “all” request is capped.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: f33ed7f6-cc8e-48e0-acb4-596d7be53841
⛔ Files ignored due to path filters (1)
packages/extension-usage/package.jsonis excluded by!**/*.json
📒 Files selected for processing (3)
packages/extension-usage/resources/token-trend/template.htmlpackages/extension-usage/src/index.tspackages/extension-usage/src/renderer.ts
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/extension-usage/src/index.ts`:
- Line 66: The assignment to variable from mixes a ternary and nullish
coalescing without grouping, which triggers prettier; update the expression in
index.ts so the conditional is wrapped in parentheses (i.e., parenthesize the
RHS ternary so the nullish coalescing binds as intended) for the declaration
using range, sorted, start and end.
In `@packages/extension-usage/src/renderer.ts`:
- Around line 240-244: Compute dirname without referencing __dirname at
evaluation time: replace the current __dirname?.length check with a safe runtime
check like typeof __dirname !== 'undefined' ? __dirname :
path.dirname(fileURLToPath(import.meta.url)), and then build templatePath using
path.resolve(dirname, '..', 'resources', 'token-trend', 'template.html') (use
path.dirname(fileURLToPath(import.meta.url)) for ESM) so that the resolved
templatePath points to
packages/extension-usage/resources/token-trend/template.html rather than
src/resources/..., referencing the existing symbols __dirname,
fileURLToPath(import.meta.url), dirname, templatePath, and path.resolve to
locate the change.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 38469b34-be9c-432c-a787-978f51cfda8c
⛔ Files ignored due to path filters (1)
packages/extension-usage/package.jsonis excluded by!**/*.json
📒 Files selected for processing (3)
packages/extension-usage/resources/token-trend/template.htmlpackages/extension-usage/src/index.tspackages/extension-usage/src/renderer.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/extension-usage/resources/token-trend/template.html
- 调整 chatluna-usage tokens 报表中 TPM 与 RPM 的计算方式,在统计循环内维护单分钟峰值,避免大量分钟桶通过参数展开传入 Math.max。 - 修复 token 趋势图渲染模块在 ESM 环境下的目录解析逻辑,使用 import.meta.url 时转换为所在目录。 - 调整 puppeteer 渲染临时 HTML 的清理时机,在渲染流程结束后立即删除临时文件,避免延迟定时器残留。
|
接着改啊,问题不大,改完下周再合并就行了,下周我继续做新功能 |
- 将 tokens 指令参数解析、报表聚合、格式化和趋势分桶逻辑移动到独立 tokens 模块,减少 index.ts 复杂度。 - 将 tokens 指令 action 下沉到 ChatLunaUsage.sendTokens,并保留 tokenReport 负责数据库查询。 - 将趋势图渲染器改为 TSX 和包内 HTML JSX runtime,改用 page.setContent 直接渲染截图,移除资源模板依赖。 - 增加 auto/light/dark tokensTheme;auto 通过控制台客户端同步的色彩模式解析,light/dark 保持强制主题。 - 保留原有 range 简写、plugin 明细、先发送文本和未启用 puppeteer 时提示的行为。
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/extension-usage/src/index.ts`:
- Around line 26-27: The code currently stores theme in a single process-wide
field private _theme, causing 'auto' to reflect the last-reported client theme
across all sessions; change this to a session-scoped theme mapping and use that
instead: replace the single _theme with a Map keyed by connection/session id (or
attach theme to the existing session object), update the code that records
client-reported theme (the handler that writes to _theme at the reported site
around lines ~121-124) to set the session-specific entry, and update the /tokens
rendering path (the code that reads _theme around lines ~333-336) to read the
theme from the current request's session/connection key; if a session key is
unavailable, compute 'auto' per-request (e.g., from request headers or default)
rather than falling back to a process-level shared value. Ensure all
reads/writes reference the new session-scoped lookup (Map.get/Map.set or
session.theme) and remove reliance on the global _theme.
In `@packages/extension-usage/src/tokens.ts`:
- Around line 148-158: The trend buckets are misaligned because the loop starts
from the raw start timestamp but labels (and later idx math) assume
whole-hour/whole-day boundaries; fix by computing an alignedStart (floor start
to the hour when range === 'day' or to midnight when range === 'month'/'year' as
appropriate) and use that alignedStart as the initial value for the for-loop
variable `at` (instead of `+start`), and use the same aligned reference when
computing labels and the `idx` logic later (functions/vars to edit: the `hourly`
flag, `tokenStep`, the `for (let at = +start; ...)` initialization, the
`result.push({... label: ...})` label generation, and the idx calculation around
lines 165-167) so buckets and displayed labels share the same boundary origin.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 364ecb63-2677-4400-bf39-3aa20db84fca
⛔ Files ignored due to path filters (1)
packages/extension-usage/package.jsonis excluded by!**/*.json
📒 Files selected for processing (5)
packages/extension-usage/client/index.tspackages/extension-usage/src/html/jsx-runtime.tspackages/extension-usage/src/index.tspackages/extension-usage/src/renderer.tsxpackages/extension-usage/src/tokens.ts
|
got |
移除 usage 控制台向后端同步主题的逻辑,并删除服务端进程级主题状态,避免 tokens 命令在 auto 主题下受其他控制台连接影响。 调整 tokens 趋势分桶的起始时间对齐逻辑,使分桶基准与图表标签保持一致,避免整点或整日标签与实际桶范围错位。
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/extension-usage/src/index.ts (1)
24-24: 💤 Low value可选优化:考虑内联常量。
DEFAULT_TOKEN_THEME仅在 329 行使用一次。根据编码规范,未被多次复用的常量建议内联。不过当前写法通过类型Exclude<UsageTokenTheme, 'auto'>明确文档化了 'auto' 的回退语义,也具有合理性。♻️ 如选择内联的参考实现
-const DEFAULT_TOKEN_THEME: Exclude<UsageTokenTheme, 'auto'> = 'light'然后在 329 行:
- ? DEFAULT_TOKEN_THEME + ? 'light'🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/extension-usage/src/index.ts` at line 24, DEFAULT_TOKEN_THEME is declared but only used once; inline it at its single use site to reduce indirection while preserving the documented type. Replace the reference to DEFAULT_TOKEN_THEME with the literal 'light' and, if necessary to satisfy typing, annotate or cast it as Exclude<UsageTokenTheme, 'auto'> (referencing the UsageTokenTheme type) where the value is currently consumed; remove the standalone DEFAULT_TOKEN_THEME declaration afterwards.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@packages/extension-usage/src/index.ts`:
- Line 24: DEFAULT_TOKEN_THEME is declared but only used once; inline it at its
single use site to reduce indirection while preserving the documented type.
Replace the reference to DEFAULT_TOKEN_THEME with the literal 'light' and, if
necessary to satisfy typing, annotate or cast it as Exclude<UsageTokenTheme,
'auto'> (referencing the UsageTokenTheme type) where the value is currently
consumed; remove the standalone DEFAULT_TOKEN_THEME declaration afterwards.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 81fc166c-e060-4d9d-bf2f-7ff21c4d3691
📒 Files selected for processing (2)
packages/extension-usage/src/index.tspackages/extension-usage/src/tokens.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/extension-usage/src/tokens.ts
|
拉取最新提交测一下看看有无问题,没问题我明天合并 |
|
got,有点晚了,明早测 |
修复 extension-usage 插件入口导出方式,移除默认导出以避免 Koishi loader 优先解析默认导出时丢失模块级 Config。 为 extension-usage 声明 @satorijs/element 运行时依赖,并在包级 tsconfig 中显式加载其 JSX 类型,确保 renderer.tsx 使用的 Satori JSX 属性能够被正确识别。 影响文件包括 packages/extension-usage/package.json、packages/extension-usage/src/index.ts 和 packages/extension-usage/tsconfig.json。
修复 usage 插件 tokens 图表渲染中的装饰元素闭合问题。 修正 packages/extension-usage/src/renderer.tsx: - 为图例、插件色点和进度条填充元素加入显式文本子节点,避免普通 HTML 元素被序列化为自闭合标签。 - 为装饰元素设置零字号和零行高,保持原有视觉尺寸。 - 修复浏览器解析自闭合普通 HTML 标签时导致的图例换行、插件名称覆盖和进度条裁切问题。
概览
chatluna-usage增加tokens指令,支持day、week、month、all范围参数,以及可选插件用量明细chatluna_usage表生成 token 用量统计,包含累计 token、累计请求、TPM、RPMpuppeteer作为可选服务接入;未启用时仍返回文字统计并提示需要启用 puppeteer验证
yarn workspace @root/chatluna-koishi fast-build extension-usage