97 lines
7.7 KiB
JSON
97 lines
7.7 KiB
JSON
{
|
||
"module": "usage_collector",
|
||
"version": "3.0",
|
||
"purpose": "OpenCode Go 订阅用量采集脚本 — Hybrid v3.0。混合采集:主模式 HTTP + stored cookies(4 个账号同时采集),辅助模式 CDP(仅 Chrome 当前登录账号补充/验证)。从 opencode.ai SSR HTML 解析 rolling/weekly/monthly 用量百分比和倒计时,写入 temp/usage_stats.json。支持 --daemon 持续采集(每 5 分钟)。",
|
||
"ui_location": "Infrastructure tab → OpenCode Go Usage section(通过 dashboard.py 的 /api/usage 和 /api/usage/refresh)",
|
||
|
||
"human_help": {
|
||
"title": "OpenCode Go Usage Collector — 用量采集脚本",
|
||
"description": [
|
||
"usage_collector.py 是一个 Python 脚本,从 opencode.ai 的 SSR HTML 中解析 4 个订阅账号的用量数据(5h rolling / weekly / monthly),写入 JSON 缓存供 dashboard 展示。",
|
||
"混合采集模式:① 主模式 — HTTP + stored cookies,可同时采集所有账号(无需 Chrome 登录态切换),快但需要预先提取 cookies ② 辅助模式 — CDP 通过 Chrome tab 获取,只能采集当前登录账号,慢但不需要预先提取 cookies(httpOnly cookies 由浏览器自动携带)。",
|
||
"Cookie 提取:一次性操作 — python extract_cookies.py key1 --workspace-id wrk_XXX → cookies/key1.json。每个账号登录后执行一次。",
|
||
"SSR 解析:主模式用 per-metric regex 解析 HTML 中的 usagePercent + resetInSec(处理嵌套 $R[N]={} 格式);CDP 辅助模式通过 CDP /eval 执行 JS fetch 获取完整 HTML 并解析。"
|
||
],
|
||
"usage": [
|
||
"1. 首次配置: 逐个登录 4 个 opencode 账号 → python extract_cookies.py key{N} --workspace-id wrk_XXX",
|
||
"2. 采集: python usage_collector.py(一次性采集全部账号)",
|
||
"3. 守护: python usage_collector.py --daemon(每 5 分钟自动采集)",
|
||
"4. 仅 CDP: python usage_collector.py --cdp-only(仅采集 Chrome 当前登录账号)",
|
||
"5. 打印结果: python usage_collector.py --print",
|
||
"6. Dashboard: GET /api/usage(读缓存)/ POST /api/usage/refresh(触发采集)"
|
||
],
|
||
"troubleshooting": [
|
||
"如果某账号采集失败: 检查 cookies/{key_id}.json 是否存在且有效 — Session 可能已过期",
|
||
"如果 CDP 模式不可用: 确认 Chrome 以 --remote-debugging-port=9222 启动 + cdp-proxy.mjs (3456) 在运行",
|
||
"如果 SSR 解析失败: opencode.ai 的 SSR hydration 格式可能已变更 — 需要更新 regex",
|
||
"如果 usage_stats.json 为空: 检查脚本是否有文件写入权限 + TEMP_DIR 是否存在",
|
||
"如果采集结果过旧: 检查 --daemon 是否在运行,或手动触发 Refresh"
|
||
]
|
||
},
|
||
|
||
"ai_spec": {
|
||
"apis": [
|
||
{"method": "N/A (CLI)", "path": "python usage_collector.py [--daemon|--cdp-only|--print]", "returns": "写 temp/usage_stats.json + stdout 日志", "note": "CLI 脚本,非 HTTP API"},
|
||
{"method": "CDP call", "path": "localhost:3456/targets + /eval", "returns": "SSR HTML (CDP mode)", "note": "通过 cdp-proxy.mjs 与 Chrome 通信"},
|
||
{"method": "HTTP GET", "path": "https://opencode.ai/workspace/{ws_id}/go", "returns": "SSR HTML (HTTP mode)", "note": "带 Cookie header (从 cookies/{key_id}.json 读取)"}
|
||
],
|
||
"dependencies": [
|
||
"usage_monitor/accounts.json — 账号 workspace ID × key_id × label 配置 (.gitignore)",
|
||
"usage_monitor/cookies/{key_id}.json — 存储的 cookies (httpOnly auth cookie, .gitignore)",
|
||
"cdp-proxy.mjs (localhost:3456) — Chrome 远程调试代理 (CDP 辅助模式)",
|
||
"Chrome (Windows) with --remote-debugging-port=9222 — 浏览器 + 登录态",
|
||
"Python 3.10+ (stdlib only: urllib, json, re, logging, http.cookiejar)",
|
||
"temp/usage_stats.json — 输出缓存 (dashboard.py 直接读取)",
|
||
"opencode.ai API — 无公开 API,唯一数据来源是 SSR hydration script"
|
||
],
|
||
"architecture": {
|
||
"flow": "主模式: 遍历 accounts.json → 读取 cookies/{key_id}.json → HTTP GET opencode.ai workspace page → 正则解析 SSR HTML → CDP 辅助: Chrome tab → fetch(location.href) → 解析 → 合并结果 → 写 usage_stats.json",
|
||
"dual_collection": "主模式(HTTP cookies)可同时采所有账号 / CDP 辅助(Chrome browser)仅当前登录账号 / 两种结果合并: CDP 优先,HTTP 补充",
|
||
"regex_parsing": "per-metric regex 匹配 rollingUsage:$R[N]={status,usagePercent,resetInSec} — 处理嵌套 $R[N]={} 而非简单 blob regex",
|
||
"daemon_mode": "每 5 分钟自动采集 — time.sleep(300) 循环",
|
||
"cookie_rotation": "不同账号有独立 cookie 文件 — cookies/key1.json, cookies/key2.json, ... — cookie 文件通过 extract_cookies.py 生成"
|
||
},
|
||
"constraints": [
|
||
"accounts.json 不可提交 git — 已加入 .gitignore",
|
||
"cookies/*.json 不可提交 git — 含 httpOnly auth cookie",
|
||
"采集频率 ≥ 5min — 过密会触发 opencode.ai 风控",
|
||
"不要用 blob regex 解析 SSR — 嵌套 $R[N]={} 会导致 [^}]* 在内层 } 处断",
|
||
"CDP 辅助模式仅在主模式失败或需验证时使用 — 依赖 Chrome 登录态",
|
||
"Cookie 过期后需重新提取 — extract_cookies.py 每个账号执行一次"
|
||
],
|
||
"must_not": [
|
||
"不要把 accounts.json 或 cookies/*.json 提交到 git",
|
||
"不要在采集脚本中硬编码 workspace ID — 必须从 accounts.json 读取",
|
||
"不要尝试用 Python requests + 提取的 cookies 单独采集 — httpOnly cookies 无法通过 document.cookie 提取",
|
||
"不要用 blob regex 解析 SSR — 用 per-metric regex"
|
||
],
|
||
"related_modules": [
|
||
{"module": "usage_monitor", "relation": "usage_collector 是 usage_monitor 模块的数据采集层 — 采集结果供 dashboard 的 usage_monitor 展示"},
|
||
{"module": "dashboard", "relation": "dashboard 通过 /api/usage/refresh 触发采集 + /api/usage 读取缓存 + auto-timer 自动触发"},
|
||
{"module": "xmpp_bot", "relation": "xmpp_bot 的 /usage 端点也可触发采集(旧版用法,新版 dashboard 直接 subprocess 调用)"}
|
||
],
|
||
"tests": [
|
||
{"id": "UC01", "name": "accounts.json 解析正确", "endpoint": "读取 accounts.json → 过滤出有 workspace_id 的记录"},
|
||
{"id": "UC02", "name": "HTTP 主模式采集返回有效数据", "endpoint": "带 cookie 的 HTTP GET → 解析 usagePercent > 0"},
|
||
{"id": "UC03", "name": "CDP 辅助模式在 Chrome 启动时可用", "endpoint": "CDP /targets → 找到 opencode.ai tab"},
|
||
{"id": "UC04", "name": "输出 usage_stats.json 格式正确", "endpoint": "采集后检查 JSON schema: accounts 数组 + last_refresh_iso"},
|
||
{"id": "UC05", "name": "--daemon 模式每 5 分钟采集", "endpoint": "--daemon 启动后连续 2 次采集间隔 ≈ 300s"}
|
||
],
|
||
"known_issues": [
|
||
"opencode.ai Go 用量目前无公开 API — PR #16513 未上线,数据唯一来源是 SSR hydration script",
|
||
"Cookie 有效期: opencode.ai session cookies 可能随时过期 → session_expired 标记提醒用户重新登录",
|
||
"CDP proxy 依赖: 若 Chrome 关闭或 cdp-proxy.mjs 未运行,CDP 辅助模式将失败",
|
||
"HTML 返回大小: CDP /eval 返回完整 SSR HTML (~16KB),可用带宽消耗"
|
||
],
|
||
"related_files": [
|
||
"gateway/scripts/usage_collector.py — 本文件 (742行, v3.0)",
|
||
"gateway/scripts/usage_monitor/accounts.json — 账号配置 (.gitignore)",
|
||
"gateway/scripts/usage_monitor/cookies/{key_id}.json — Cookie 文件 (.gitignore)",
|
||
"gateway/scripts/usage_monitor/extract_cookies.py — Cookie 提取工具",
|
||
"gateway/temp/usage_stats.json — 采集结果缓存",
|
||
"gateway/scripts/specs/usage_collector.json — 本 spec",
|
||
".opencode/skills/web-access/scripts/cdp-proxy.mjs — CDP proxy (3456)"
|
||
]
|
||
}
|
||
}
|