name: smartbadge-ops
服务器(server/index.js)常驻运行每日定时管道,无需人工值守;本技能是控制面:巡检、诊断、补跑、重试、部署核验、区间(月报/年报)按需聚合分析。所有作业逻辑在服务器端,技能只调用其 REST API 与直连 OSS。
本技能为独立仓库,脚本全部在 ./scripts/(零依赖,Node >=18;verify-online.py 需本机 playwright)。
无论用户请求什么,先走确认门:
archive/run、analysis/run、retry、retry-transcribe、repair-oss、config PUT、任何 DELETE。report-aggregate/reconcile 归零验证)视为同一确认,无需再问。以下场景视为用户已授权,可一句话备案后直接执行(备案格式:我将执行:…(若与预期不符请中断),不强制等待回答):
get/list 查询、check-online.mjs 巡检、oss.mjs 列举、reconcile 对账、report-aggregate 聚合、fetch-report-text 正文拉取、verify-online.py 走查。export MSYS_NO_PATHCONV=1 # 仅 Windows Git Bash 需要(防 / 开头参数被转成 Windows 路径);Linux/Docker 无此问题
https://recording.sh-lami.com;本地开发:环境变量 SMARTBADGE_API_BASE=http://localhost:3002(或各脚本 --base)。node scripts/api.mjs login <密码>,token 缓存到 scripts/.token(各脚本自动共享)。.env 提供,缺省脚本报错提示;Docker 容器用 -e SMARTBADGE_USERNAME=/PASSWORD= 或 --env-file 注入。--env 参数 > SMARTBADGE_ENV_FILE > 技能仓库根 .env(npx 安装后复制 .env.example 填值) > 自动发现(向上扫本仓库同级/兄弟目录含 server/.env 的项目,如服务端项目与技能放在同一父目录) > 已存在的 OSS_* 进程环境变量。server/.env(OSS/讯飞/DeepSeek/masterKey),本技能仓库不含任何密钥;node scripts/oss.mjs --find-env 可查看实际采用的 server/.env 路径。verify-online.py 浏览器走查需要 playwright+chromium,容器/无浏览器环境跳过(用 check-online.mjs 替代);日期口径固定 Asia/Shanghai,容器 UTC 时区无需配置。| 脚本 | 能力 | 典型参数 |
|---|---|---|
scripts/api.mjs |
任意接口调用 | login / get <路径> / post <路径> '<JSON>' / env / --raw / --base |
scripts/check-online.mjs |
12 项断言一键核查 | [密码] 或 SMARTBADGE_PASSWORD |
scripts/verify-online.py |
浏览器 5 页走查 + 0 错误断言 | 环境变量 PLAYWRIGHT_BASE_URL/SMARTBADGE_* |
scripts/oss.mjs |
OSS 直连列举统计 | [prefix] --json --env <path> --find-env |
scripts/report-aggregate.mjs |
区间聚合(月报/年报/任意窗口) | --start --end [--type day\|week\|all] [--json] [--no-reconcile] |
scripts/fetch-report-text.mjs |
报告正文拉取(HTML→文本) | --id <reportId> | --url <直链> [--preview] [--json] |
用户需求 → 命令序列(编排参考)
check-online.mjs → 有 FAIL 走 §7 → 按 category 处置 → 汇总。api.mjs get /api/analysis/health + errors?pageSize=20 看 category(§7 处置表)。report-aggregate --start 月初 --end 月末 --json → 必要时补跑缺失日(§10)→ fetch-report-text 选 3-5 篇读正文 → 按 templates/monthly-report.md 八段模板产出 → 产物形态加工(Markdown/HTML/PPT)。check-online + verify-online.py + nginx -t + pm2 logs)。oss.mjs(顶层)或 oss.mjs recordings/ 等按前缀。每天 archive_time(默认 02:00 Asia/Shanghai, 可配 SbSystemConfig)
├─ 归档: 上游 /audio/list → 下载本地 → OSS(ETag 校验) → SbAudioRecording 落库(含音源字段镜像)
├─ 分析: process.py 三级过滤(静默/模糊/短音频) → 讯飞多说话人 → SbTranscriptSegment
├─ 报告: DeepSeek → HTML → reports/ + OSS → SbReport(day/week)
├─ 合并: 按设备×天拼接 MP3(OSS merges/,仅存档收听,不参与转录)
├─ 24h 清理: 已 OSS 同步文件 → canPurge → 删除本地(DB 记录保留)
└─ 保留期兜底清理: 录音 15 天 / 合并 7 天 / 报告 HTML 7 天(删前补同步一次;报告 OSS 补传失败时安全闸保留本地)
每周一(archive_time+30min): 周报(近 7 天聚合, 转录增量跳过不重复计费)
失败任何环节 → 自动入队重试(3 次, 5/15/30 分钟指数退避) → 耗尽才进入错误展示;重试零残留
边界事实(设计依据):
6 天前的缺失不可补。POST /api/analysis/run 窗口上限 MAX_WINDOW_DAYS=7、start 晚于今天报错、全局互斥 1 个任务(冲突 429)→ 区间聚合/补跑严格遵守:一次最多 7 天,或逐日。endDate >= 今天 走上游实时分流。| 命令 | 用途 |
|---|---|
get /api/archive/status?date=&deviceNo= |
当日归档状态(expected/downloaded/ossSynced/failed) |
get /api/archive/missing |
归档失败待重试列表(含 retryCount/lastError) |
post /api/archive/run '{"dates":[...]}' \| '{"dateRange":{"start","end"}}' \| '{"devices":[...]}' |
手动触发归档(默认全部×昨天) |
post /api/archive/retry '{"ids":[...]}' |
重试失败归档(也支持 {date}/{deviceNo}) |
post /api/archive/retry-transcribe '{"date":"YYYY-MM-DD"}' |
仅重跑转录(不重复清洗;互斥 429) |
post /api/analysis/run '{"period":"yesterday"\|"last7days"\|{"start","end"},"type":"day"\|"week"}' |
手动分析(窗口≤7 天,互斥) |
get /api/analysis/jobs?status=&page=&pageSize= |
任务列表(status/progress/summary/reportId/transcriptCount/nextRetryAt/failStage) |
get /api/analysis/reconcile?date= |
三方对账(total/localHit/ossHit/transcribeDone/missingCleansed/missingTranscript) |
post /api/analysis/repair-oss '{"date":"YYYY-MM-DD"}' |
补传缺失 OSS 对象(互斥 429;支持 {ids}) |
get /api/analysis/health |
健康快照(retryingCount/warnings/categoryCounts/ossMissingCount) |
get "/api/analysis/errors?pageSize=20" |
错误汇总(四来源,含 advice;重试中默认隐藏,includeRetrying=true 查) |
post /api/smartbadge/recordings/list '{"page":1,"pageSize":20}' |
录音列表(本地库;支持 deviceNo/startDate/endDate/keyword;endDate>=今天走实时) |
post /api/smartbadge/logs/heartbeat '{"page":1,"pageSize":20}' |
心跳列表(startTime/endTime 代替日期) |
get /api/devices?page=&pageSize=&keyword= |
设备分页(DB 级) |
get /api/config / put /api/config '{"key":"value"}' |
系统配置(archive_time 等;PUT 前必过确认门) |
get /api/reports?type=day\|week&start=&end=&pageSize= |
报告列表(分页;无正文) |
get /api/reports/:id |
报告详情(同样无正文;正文经 ossUrl/downloadUrl) |
写请求必须带
X-Requested-With头——api.mjs 已自动带上;手动 curl 时须加。
node scripts/check-online.mjs → 12 项全 PASS 即健康;0 FAIL 跳第 5 步汇报。api.mjs get /api/analysis/health 看 retryingCount(>0=引擎自动重试中,别急)。api.mjs get /api/analysis/reconcile?date=<昨天> 核对缺项;oss.mjs 核对四类目录数量(recordings/ cleansed/ transcripts/ reports/)。<昨天> 有 missingCleansed/missingTranscript → repair-oss '{"date":"<昨天>"}' 补传,复跑验证归零。jobs?pageSize=5 见 week 任务 + get /api/reports?type=week 有周报。node scripts/api.mjs get /api/analysis/health # retryingCount=自动重试中数;categoryCounts=分类计数
node scripts/api.mjs get "/api/analysis/errors?pageSize=20" # 重试中项默认隐藏(耗尽才出现)
node scripts/api.mjs get "/api/analysis/errors?includeRetrying=true&pageSize=20"
重试语义:失败先自动重试 3 次(5/15/30min,~50 分钟),耗尽才可见。
retryingCount>0→ 等引擎;0 且有 warnings → 真错误。 无害告警:healthwarnings中「最近任务无待转录文件(属正常)」是无害告警(当日无录音或全部被三级过滤),不影响健康判定;check-online 已按此语义断言。
按返回 category 行动(每条自带 advice):
| category | 含义与动作 |
|---|---|
quota(额度/并发) |
讯飞/DeepSeek 额度受限或并发超限(10407/10901/402/429/rate limit):非接口故障,等恢复或联系开通;可稍后 retry-transcribe/analysis/run(增量跳过,成本低) |
network/timeout |
网络抖动/超时(ETIMEDOUT/ECONNREFUSED/socket):重试即可;当日重试 archive/retry/retry-transcribe |
auth(鉴权) |
密钥/令牌错误(401/403/accessKeyId/signature):报修——检查服务器 server/.env 的 OSS*/IFLYTEK*/DEEPSEEK_API_KEY 是否过期,修复后重试 |
server(5xx) |
上游 5xx 或内部错误:报修——查 pm2 logs smartbadge-api 或宝塔日志 |
other |
未知格式:人工看 message;可复现则升级分类器关键词 |
口径示例:「今天的报告为什么没有?」→ errors?source=report → quota:「不是接口问题,额度受限,已自动重试,等待恢复」;auth:「鉴权失败,需检查密钥(报修项)」。先跑命令看 category,不要凭猜回复。
recordings/list → total>0 且无 failed/capped?缺失日 = 归档失败日:查 archive/status?date= 与 archive/missing。failed/capped 非空 = 上游个别设备失败/超 2000 条截断;等 60s 缓存或缩小筛选。startTime 全为 -:上游 /audio/list 最后一条元数据未结算(数据源属性);旧行缺字段可跑回填脚本 server/scripts/maintenance/backfill-recording-meta.js。post /api/archive/run '{"dates":["<昨天>"]}'(仅收 今天-6 ~ 今天)。post /api/archive/retry '{}'(按日期/设备过滤更精准)。post /api/archive/retry-transcribe '{"date":"<日期>"}'。post /api/analysis/run '{"period":"yesterday","type":"day"}'(已转录增量跳过,只补报告)。get /api/analysis/jobs 看进度;分析有超时兜底(20 分钟),等待即可。系统仅自动产生 day/week 报告;月报/年报 = 运行时拉取窗口数据自动聚合分析。执行步骤:
--start 2026-08-01 --end 2026-08-31;年报同理 01-01 ~ 12-31;或自定义区间。templates/report-html.html + markdown 最小转换)③ PPT(使用全局 weekly-report-pptx 技能承接)。node scripts/report-aggregate.mjs --start <起> --end <止> --json(可 --type week 只看周报;--deviceNo 单设备;--no-reconcile 跳过逐日对账)。得到:报告清单、逐日明细、缺失三类清单(无报告日/转录=0 日/对账异常日)、补跑建议命令。daysAgo<=6 的无报告日,执行聚合输出里的建议命令(逐日 analysis/run,{"period":{"start":D,"end":D},"type":"day"});复跑聚合验证归零。node scripts/fetch-report-text.mjs --id <reportId> --preview 选 3-5 篇代表性报告(readme 说选择标准:设备覆盖广、转录量高、异常日),必要时 --json 定位 id(或 api.mjs get "/api/reports?type=day&start=<起>&end=<止>&pageSize=10")。templates/monthly-report.md 八段(总体概览/设备活跃/录音量与转录效率/趋势/异常与缺失/报告要点摘录/结论与建议)成稿;形态按第 1 步选择。summary=「无待转录文件」 的任务属正常(三级过滤)。注意:report-aggregate 是只读(轻档权限);「补缺失」是写操作,必须重档确认。
ossUrl(OSS 公开直链)或 downloadUrl(302 OSS / 本地回源)获取 → 推荐 fetch-report-text.mjs。node scripts/check-online.mjs # 12 项断言: 登录/health/归档/列表/实时分流/心跳/设备/互斥
python scripts/verify-online.py # 浏览器: 5 页走查 + 0 pageerror 断言
nginx -t # 宝塔保存自动校验;配置见 deploy/nginx-recording.sh-lami.com.conf
pm2 logs smartbadge-api --lines 50 # 服务器错误日志
pnpm build → zip 上传解压到线上 dist;后端 .env 用 .env.production 模板(PORT=3007)+ CDN 自动拉取。SbTranscriptSegment(CLP 仅 masterKey,技能侧不可直读)。transcripts/{deviceNo}/{Y}/{M}/{D}/*.txt → node scripts/oss.mjs transcripts/ 列举,经 publicDomain 拼直链可下载。server/.env(讯飞/DeepSeek/OSS/masterKey),本仓库零密钥;git 提交需用户明确同意。server/recordings/ 下手动跑 process.py:对输入文件是移动/删除语义;排查过滤请用工作区副本或 repair-oss。verify-online.py(浏览器走查)需在宿主机执行 pip install playwright && playwright install chromium。.token/out//__pycache__ 已 gitignore,不提交。输出三行:① 做了什么(命令序列)② 结果(数据或 PASS/FAIL + 异常项)③ 遗留与建议下一步。有「未验证项/已知限制」要显式披露。
smartbadge-report(执行报告解读时可调用)。weekly-report-pptx 技能。