- 首页:OCGO用量卡与服务卡「查看用量详情」右侧新增 Token 活动快捷入口 - 首页入口描述改为「OCGO Token 活动」;统计卡片改 2×2 布局 - 多语言:热力图月份/日期/数字单位 locale-aware(英文 K/M/B + MMM d) - 浮层/读数条句子走 stringResource;月份名资源数组(三语言) - 遗留修复:Codex 窗口标签中性化(weekly/usage)、Ollama plan 空串兜底、 isFiveHourLabel 语言无关判断、字段标签资源化、Widget usageLabel - 单测同步:Codex/Ollama/FormatUtils/FormatCodexPrimaryLabel 全绿(119 用例)
8.8 KiB
8.8 KiB
Token 活动热力图 — 设计方案
参考实现:
reference/react-activity-calendar(grubersjoe/react-activity-calendar,MIT) 该库为 React/SVG Web 组件,本项目用 Jetpack Compose Canvas 重新实现,仅参考其布局逻辑和数据结构。
一、入口与数据源
- 主页 OCGO 用量卡片「查看详情」右侧新增「Token 活动」快捷入口,点击进入独立的 Token 活动热力图页面(另有独立入口卡片)
- 首页入口卡片标题「OCGO Token 活动」、副标题「OCGO 每日 Token 使用热力图」(数据来源更准确)
- 只统计 OCGO 服务的数据,不涉及 CCGO / Codex / Ollama
二、页面布局
- 标题左对齐:「Token 活动」
- 标题右侧视图切换:每日 / 每周 / 累计
- 选中项:主要文字颜色 + 中等字重
- 未选中项:弱文字颜色
- 不使用大号按钮背景或明显的 Tab 胶囊样式
三、每日视图(默认)
- GitHub Contribution Calendar 结构:
- 53 列 × 7 行
- 每列代表一周,每行代表星期中的一天
- 越靠右越接近当前日期
- 按所选自然年显示:今年 = 1月1日 ~ 今天;往年 = 1月1日 ~ 12月31日(完整自然年,取代早期「最近滚动 365 天」窗口,详见「十一、年份选择器」)
- 格子参数:
- 尺寸 10~12dp
- 间距 3dp
- 圆角 3dp
- 月份标签:12sp,底部显示
- 不显示左侧星期标签
注:2026-08 起已改为**年份选择器(自然年)**取代固定滚动 365 天窗口,详见「十一、年份选择器」。
四、颜色等级
- 6 级:Level 0(空白)+ Level 1~5(逐渐加深的粉色)
- 使用项目现有配色(Color.kt 中的粉色系)
- 映射方案:分位数法
- 收集所有非零日 Token 数,排序,计算分位阈值
- Level 0:token = 0(空白)
- Level 1:0 ~ 25% 分位
- Level 2:25% ~ 50% 分位
- Level 3:50% ~ 75% 分位
- Level 4:75% ~ 95% 分位
- Level 5:95% 以上
- 颜色会随数据变化是预期行为(与 GitHub 热力图一致)
五、每周视图
- 与每日视图共用同一 7 行 × 约 53 列网格尺寸(列数按所选自然年浮动 52~54),切换视图时布局保持一致
- 语义为离散柱状图:横轴 = 自然周,每一列 = 一周,纵向高度 = 该周 Token 用量
- 每列从底部向上填充格子,用量越多填充越高;整列 7 格全部绘制:底部 barHeight 格 = 该周等级颜色(柱),其余格 = Level 0 浅色(空白格不隐藏,网格完整),最大高度 = 7 格满柱
- 高度映射:非零周按 token 去重排序的排名比例映射 2~7 格(height = 2 + rankIndex×5/(uniqueCount-1),排名不同高度必不同,如 3.7亿 → 2 格、10.7亿 → 7 格;唯一非零值时满柱 7 格)
- 填充格使用该周的等级颜色(6 级粉色分位,与图例"少→多"一致)
- 列内格子不表示周日~周六(与每日视图的日期语义解耦)
- 周列与日视图一致按周日对齐;第一列 = 该年 1月1日 所在周(可能含去年 12 月空位),最后一列 = 结束日所在周(今年 = 今天所在周,往年可能跨到次年 1 月初)
- 点击:每周视图列内任意格子可点击查看该周浮层("X月X日-X月X日 使用了X token"),含 0 用量周(显示"使用了0token");选中周整列加主题色描边强调(再次点击或点击其他周取消)
六、累计视图
- 和每日视图同样的小格子风格
- 53 列 × 7 行
- 每个格子的颜色代表从起始日到该日的累计 Token 总量
- 同样用分位数法映射到 6 级
七、格子交互
- 滑动查看(三种视图,OCGO 风格):在图表上手指拖动或长按,按速度/时长仲裁两种模式:
- 长按(按住不动 ≥ 系统长按时长)→ 查看模式:手指所在格子直接高亮预览(所见即所得),底部读数条显示该格数据;按住期间拖动可切换预览格子,抬起后保留
- 慢速横向拖动(< 约150dp/s)→ 查看模式:图表锁定不滚动(保证稳定),所见即所得——手指所在格子加主题色边框高亮预览,底部读数条实时显示该格数据(抬起后保留,切换视图/年份清除)
- 快速横向拖动(≥ 约150dp/s)→ 滚动模式:放行给图表正常左右滚动浏览(含惯性)
- 读数条语义与视图一致:每日/累计=该天"X月X日 使用了X token"(累计视图 tokens 为累计值);每周=该周范围"X月X日-X月X日 使用了X token"(与周浮层同口径,末周夹取到数据最后一天、跨年带年份前缀)
- 点击格子显示浮层,内容为日期和当天使用的 Token 数
- 浮层格式示例:
(Token 数按数量级自然中文读法显示)7月9日 使用了1.9亿token 7月10日 使用了1124.5万token 7月11日 使用了11.2万token 7月12日 使用了16783token - 浮层保留卡片外观,但不拦截图表交互(Popup focusable=false):点击/滑动直接作用于图表——点其他格子即切换浮层,再次点击同一格子关闭,手指滑动查看图表不受浮层影响
- 图表支持手指横向滑动查看(配合年份选择器浏览任意年份),页面纵向滚动
- 不需要"查看详情"按钮
- 热力格支持键盘聚焦,提供日期与 Token 数的无障碍描述
八、视图切换动画
- 切换视图使用约 150ms 的淡入淡出
- 不要明显的滑动或弹跳动画
九、Token 定义
- 热力图中的「使用 token」=
inputTokens + cacheReadTokens + reasoningTokens + outputTokensinputTokens:未命中缓存的输入 tokencacheReadTokens:命中缓存的输入 tokenreasoningTokens:推理 token(思维链 CoT)outputTokens:输出 token
- 不包含
cacheWrite5mTokens和cacheWrite1hTokens(缓存写入 token)
十、Token 数显示格式
- 按数量级自然转换为中文读法(locale-aware):
- 中文:亿级 1.9亿 / 千万级 1124.5万 / 万级 11.2万 / 万以下原始数字(繁体用 萬/億)
- 非中文:≥1e9 → 1.9B / ≥1e6 → 11.2M / ≥1e3 → 16.8K / 否则原数字
- 日期格式同理:中文 "7月9日"(跨年 "2024年7月9日");非中文 "Jul 9"(跨年 "Jul 9, 2024")
- 浮层/读数条句子("X月X日 使用了X token")走 stringResource(heatmap_day_used/heatmap_week_used),按语言拼接
十一、年份选择器(2026-08 新增)
- 标题「Token 活动」右侧为年份下拉选择器(「2026 ▾」),点击弹出年份列表
- 语义:按自然年查看
- 今年:1月1日 ~ 今天(默认选中年份)
- 往年:1月1日 ~ 12月31日(完整自然年)
- 取代原先固定「最近滚动 365 天」窗口
- 可选年份范围:最早有数据的年份 ~ 今年
- 三种视图(每日/每周/累计)均跟随所选年份,分位数按所选年份独立计算(颜色随年份数据变化是预期行为)
- 周视图按自然年时列数浮动(52~54 列,闰年且 1月1日 为周六时可达 54 列):
- 第一列为该年 1月1日 所在周(可能含去年 12 月空位)
- 最后一列为结束日所在周(今年=今天所在周;往年可能跨到次年 1 月初)
- 浮层日期:日期所在年份与今年不同时前缀加年份(如「2024年7月9日 使用了1.9亿token」)
十二、图例与滚动(2026-08 新增)
- 底部「少 → 多」颜色图例固定显示,不随热力图横向滚动
- 页面打开 / 切换视图 / 切换年份时,热力图横向滚动自动定位到最右(最新数据)
- 0 token 的天可以点击查看浮层(显示「7月9日 使用了0token」);每周视图 0 用量周显示 1 格 Level 0 浅色格、同样可点击(柱状图语义,见「五、每周视图」)
十三、年度统计(2026-08 新增)
- 视图切换器下方 2×2 网格 4 个统计卡片(每行 2 个,窄屏友好),按所选年份计算(切换年份跟随变化),与图表口径一致
- 累计 token:当年全部天之和(= 累计视图最后一天的累计值)
- 峰值 token:当年单日最大 token(无数据=0)
- 当前连续:从数据最后一天往前数连续 >0 的天数(最后一天为 0 则=0)
- 最长连续:当年内连续 >0 的最大天数
- 实现:HeatmapViewModel 的
computeStats(dailyData)(companion 内,internal),结果存于HeatmapUiState.stats;加载与切换年份时随 dailyData 一起更新 - 连续天数的"有 token"判定:当日 token > 0(0 token 的天视为断档);数据为 1月1日~结束日的完整日序列,含 0 token 的天
- Token 数值显示沿用「十、Token 数显示格式」(亿/万中文读法);天数显示为「N 天」