|
|
@@ -0,0 +1,216 @@
|
|
|
+---
|
|
|
+name: smartbadge-ops
|
|
|
+description: 智能工牌录音管道全功能运维技能。当用户提到录音归档、录音下载、管道巡检、转录重试、每日录音任务、smartbadge 运维、归档失败、转录失败、录音清洗、讯飞转录、OSS 同步、分析任务状态、线上部署核验、健康检查、列表数据、故障自诊断、月报、年报、周报、日报汇总、报告解读、历史数据对比、区间数据聚合时使用。提供对服务器定时管道(归档→清洗→讯飞转录→DeepSeek 报告)的巡检、手动触发、补跑、重试、故障诊断、列表排查、月报/年报按需聚合分析、线上部署核验与浏览器走查。交互特色:先复述问题与方案,回问用户确认后再执行。
|
|
|
+---
|
|
|
+
|
|
|
+# 智能工牌录音管道运维(smartbadge-ops)
|
|
|
+
|
|
|
+服务器(`server/index.js`)常驻运行每日定时管道,**无需人工值守**;本技能是控制面:巡检、诊断、补跑、重试、部署核验、区间(月报/年报)按需聚合分析。所有作业逻辑在服务器端,技能只调用其 REST API 与直连 OSS。
|
|
|
+
|
|
|
+本技能为独立仓库,脚本全部在 `./scripts/`(零依赖,Node >=18;verify-online.py 需本机 playwright)。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## §1 交互协议:确认门(第一优先,不可跳过)
|
|
|
+
|
|
|
+无论用户请求什么,先走确认门:
|
|
|
+
|
|
|
+### 重档(默认,适用于一切「有生产影响」或「参数不明确」的请求)
|
|
|
+
|
|
|
+- **写操作永远重档**:`archive/run`、`analysis/run`、`retry`、`retry-transcribe`、`repair-oss`、`config` PUT、任何 DELETE。
|
|
|
+- 步骤:
|
|
|
+ 1. **复述**:用 1-3 句话复述我理解的问题、时间窗、对象(哪些设备/日期)、期望产物(如「月报 Markdown」)。
|
|
|
+ 2. **方案**:列出将执行的脚本与命令序列,并一句话说明**是否会写数据**。
|
|
|
+ 3. **回问**:"是这个意思吗?" 等待用户确认(或纠正)。
|
|
|
+- 用户纠正后:只用一句更新复述,再确认一次即执行,不重复长篇。
|
|
|
+- 已确认动作链中的后续复查步骤(如补跑后复跑 `report-aggregate`/`reconcile` 归零验证)视为同一确认,无需再问。
|
|
|
+
|
|
|
+### 轻档(预授权:纯只读且参数齐全)
|
|
|
+
|
|
|
+以下场景视为用户已授权,可`一句话备案`后直接执行(备案格式:`我将执行:…(若与预期不符请中断)`,不强制等待回答):
|
|
|
+- `get`/`list` 查询、`check-online.mjs` 巡检、`oss.mjs` 列举、`reconcile` 对账、`report-aggregate` 聚合、`fetch-report-text` 正文拉取、`verify-online.py` 走查。
|
|
|
+- 用户说「巡检」「跑 check-online」等明确指令,直接执行。
|
|
|
+
|
|
|
+### 确认门例外
|
|
|
+
|
|
|
+- 用户明确说「直接跑」「不用问」或已确认过相同模式请求 → 跳过回问,执行并在首句说明。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## §2 连接与凭据
|
|
|
+
|
|
|
+```bash
|
|
|
+export MSYS_NO_PATHCONV=1 # Windows Git Bash: 以 / 开头的路径参数先防止被转成 Windows 路径
|
|
|
+```
|
|
|
+- **接口地址**:默认线上 `https://recording.sh-lami.com`;本地开发:环境变量 `SMARTBADGE_API_BASE=http://localhost:3002`(或各脚本 `--base`)。
|
|
|
+- **登录**:`node scripts/api.mjs login <密码>`,token 缓存到 `scripts/.token`(各脚本自动共享)。
|
|
|
+- **凭据回退链**(OSS 等):`--env 参数` > `SMARTBADGE_ENV_FILE` > 自动发现(向上扫本仓库同级/兄弟目录含 `server/.env` 的项目,如 `D:\1\device-management-backend`) > 已存在的 `OSS_*` 进程环境变量。
|
|
|
+- 敏感凭据只存在于项目 `server/.env`(OSS/讯飞/DeepSeek/masterKey),本技能仓库**不含任何密钥**。
|
|
|
+
|
|
|
+## §3 能力矩阵与编排表
|
|
|
+
|
|
|
+| 脚本 | 能力 | 典型参数 |
|
|
|
+|---|---|---|
|
|
|
+| `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 处置表)。
|
|
|
+- 「昨天的数据/录音列表不对」→ §8 列表诊断。
|
|
|
+- **「给我上月月报」(月报/年报 == 同流程换窗口)** → 确认门(窗口+产物形态)→ `report-aggregate --start 月初 --end 月末 --json` → 必要时补跑缺失日(§10)→ `fetch-report-text` 选 3-5 篇读正文 → 按 `templates/monthly-report.md` 八段模板产出 → 产物形态加工(Markdown/HTML/PPT)。
|
|
|
+- 「上线后核验一下」→ §12(`check-online` + `verify-online.py` + `nginx -t` + `pm2 logs`)。
|
|
|
+- 「OSS 里有哪些东西」→ `oss.mjs`(顶层)或 `oss.mjs recordings/` 等按前缀。
|
|
|
+
|
|
|
+## §4 架构与每日流程
|
|
|
+
|
|
|
+```
|
|
|
+每天 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 分钟指数退避) → 耗尽才进入错误展示;重试零残留
|
|
|
+```
|
|
|
+
|
|
|
+**边界事实(设计依据)**:
|
|
|
+- 归档窗口 ≤7 天(上游自动删除录音)→ 错过即丢;>`6` 天前的缺失**不可补**。
|
|
|
+- `POST /api/analysis/run` 窗口上限 `MAX_WINDOW_DAYS=7`、start 晚于今天报错、全局互斥 1 个任务(冲突 429)→ 区间聚合/补跑严格遵守:一次最多 7 天,或逐日。
|
|
|
+- 录音列表默认本地库(截至昨日);`endDate >= 今天` 走上游实时分流。
|
|
|
+- 转录消耗讯飞额度(每文件一次;清洗已滤约 90% 无效音频;周报/聚合复用已转录段落不重复计费)。
|
|
|
+
|
|
|
+## §5 接口命令速查(经 api.mjs)
|
|
|
+
|
|
|
+| 命令 | 用途 |
|
|
|
+|---|---|
|
|
|
+| `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 时须加。
|
|
|
+
|
|
|
+## §6 每日巡检 SOP(营业前一次)
|
|
|
+
|
|
|
+1. `node scripts/check-online.mjs` → **12 项全 PASS 即健康**;0 FAIL 跳第 5 步汇报。
|
|
|
+2. 有 FAIL:进 §7 定位——先 `api.mjs get /api/analysis/health` 看 `retryingCount`(>0=引擎自动重试中,别急)。
|
|
|
+3. `api.mjs get /api/analysis/reconcile?date=<昨天>` 核对缺项;`oss.mjs` 核对四类目录数量(`recordings/ cleansed/ transcripts/ reports/`)。
|
|
|
+4. `<昨天>` 有 `missingCleansed`/`missingTranscript` → `repair-oss '{"date":"<昨天>"}'` 补传,复跑验证归零。
|
|
|
+5. 三行简报:正常项 / 异常项(及原因分类)/ 采取的动作。
|
|
|
+6. 周一额外:`jobs?pageSize=5` 见 week 任务 + `get /api/reports?type=week` 有周报。
|
|
|
+
|
|
|
+## §7 故障自诊断 SOP
|
|
|
+
|
|
|
+```bash
|
|
|
+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 → 真错误。
|
|
|
+> **无害告警**:health `warnings` 中「最近任务无待转录文件(属正常)」是无害告警(当日无录音或全部被三级过滤),不影响健康判定;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,不要凭猜回复。**
|
|
|
+
|
|
|
+## §8 列表问题诊断 SOP
|
|
|
+
|
|
|
+1. 本地列表(默认窗)`recordings/list` → total>0 且无 failed/capped?缺失日 = 归档失败日:查 `archive/status?date=` 与 `archive/missing`。
|
|
|
+2. 「包含今日」开关走实时——`failed`/`capped` 非空 = 上游个别设备失败/超 2000 条截断;等 60s 缓存或缩小筛选。
|
|
|
+3. `startTime` 全为 `-`:上游 `/audio/list` 最后一条元数据未结算(数据源属性);旧行缺字段可跑回填脚本 `server/scripts/maintenance/backfill-recording-meta.js`。
|
|
|
+4. 上游误返全量:服务端已有近 7 天缺省窗,**勿**移除。
|
|
|
+
|
|
|
+## §9 补跑与重试 SOP
|
|
|
+
|
|
|
+- 昨天断电/失败 → `post /api/archive/run '{"dates":["<昨天>"]}'`(仅收 今天-6 ~ 今天)。
|
|
|
+- 部分文件下载失败 → `post /api/archive/retry '{}'`(按日期/设备过滤更精准)。
|
|
|
+- 转录失败 → `post /api/archive/retry-transcribe '{"date":"<日期>"}'`。
|
|
|
+- 报告失败(任务 error 含「报告生成失败」)→ `post /api/analysis/run '{"period":"yesterday","type":"day"}'`(已转录增量跳过,只补报告)。
|
|
|
+- 互斥 429 → 已有任务运行中:先 `get /api/analysis/jobs` 看进度;分析有超时兜底(20 分钟),等待即可。
|
|
|
+- **跨 >6 天窗口的缺失:上游已删,不可补**,在汇报中披露。
|
|
|
+
|
|
|
+## §10 月报/年报 SOP(按需聚合,不建永久管道)
|
|
|
+
|
|
|
+系统仅自动产生 day/week 报告;月报/年报 = **运行时拉取窗口数据自动聚合分析**。执行步骤:
|
|
|
+
|
|
|
+1. **确认门(重档无关,但必须问)**:
|
|
|
+ - 窗口:如「2026 年 8 月」= `--start 2026-08-01 --end 2026-08-31`;年报同理 `01-01 ~ 12-31`;或自定义区间。
|
|
|
+ - 内容范围:仅数据(录音/转录/报告清单)还是含智能分析(读报告正文提炼)?默认含。
|
|
|
+ - **产物形态**由用户选择:① Markdown(默认,回复正文+可存文件)② HTML(模板 `templates/report-html.html` + markdown 最小转换)③ PPT(使用全局 weekly-report-pptx 技能承接)。
|
|
|
+2. **拉数据**:`node scripts/report-aggregate.mjs --start <起> --end <止> --json`(可 `--type week` 只看周报;`--deviceNo` 单设备;`--no-reconcile` 跳过逐日对账)。得到:报告清单、逐日明细、**缺失三类清单(无报告日/转录=0 日/对账异常日)**、补跑建议命令。
|
|
|
+3. **补缺失(过确认门)**:对 `daysAgo<=6` 的无报告日,执行聚合输出里的建议命令(逐日 `analysis/run`,`{"period":{"start":D,"end":D},"type":"day"}`);复跑聚合验证归零。
|
|
|
+4. **读正文(需要智能分析时)**:`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"`)。
|
|
|
+5. **产出**:按 `templates/monthly-report.md` 八段(总体概览/设备活跃/录音量与转录效率/趋势/异常与缺失/报告要点摘录/结论与建议)成稿;形态按第 1 步选择。
|
|
|
+6. **披露**:超 6 天的缺失日标注「上游已清理,不可补」;`summary=「无待转录文件」` 的任务属正常(三级过滤)。
|
|
|
+
|
|
|
+**注意**:`report-aggregate` 是只读(轻档权限);「补缺失」是写操作,必须重档确认。
|
|
|
+
|
|
|
+## §11 报告解读
|
|
|
+
|
|
|
+- 列表/详情无正文:正文经 `ossUrl`(OSS 公开直链)或 `downloadUrl`(302 OSS / 本地回源)获取 → 推荐 `fetch-report-text.mjs`。
|
|
|
+- 阅读视角(KPI 指标卡、客户画像表、关键事件时间线、销售策略、VOC 原话、风险提示);报告只含转录文本与指标,不内嵌录音 URL。
|
|
|
+- 报告 HTML 是 DeepSeek 提炼物(含 VOC 引用 6-9 条),非全文转录;需要全文 → §13。
|
|
|
+
|
|
|
+## §12 上线/部署核验 SOP
|
|
|
+
|
|
|
+```bash
|
|
|
+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 自动拉取。
|
|
|
+- **双进程提醒**:共享 Parse 只允许一个后端常驻跑 cron——本地(3002)与线上(3007)不要同时在线。
|
|
|
+
|
|
|
+## §13 转录原文获取(边界)
|
|
|
+
|
|
|
+- 转录原文**无 HTTP 接口**,数据在 Parse `SbTranscriptSegment`(CLP 仅 masterKey,技能侧不可直读)。
|
|
|
+- OSS 有转录文本对象:`transcripts/{deviceNo}/{Y}/{M}/{D}/*.txt` → `node scripts/oss.mjs transcripts/` 列举,经 `publicDomain` 拼直链可下载。
|
|
|
+- 需逐条查原文时,在企业内用服务器 masterKey 侧(如维护脚本),不在本技能承诺。
|
|
|
+
|
|
|
+## §14 注意事项
|
|
|
+
|
|
|
+1. **归档窗口 ≤7 天**:错过即丢,巡检每天执行。
|
|
|
+2. 写操作(归档/分析/重试/补传/配置)一律先确认门,并提示互斥 429 可能性。
|
|
|
+3. 凭据只存 `server/.env`(讯飞/DeepSeek/OSS/masterKey),本仓库零密钥;git 提交需用户明确同意。
|
|
|
+4. **禁止直接在 `server/recordings/` 下手动跑 `process.py`**:对输入文件是**移动/删除**语义;排查过滤请用工作区副本或 `repair-oss`。
|
|
|
+5. Windows 本机 `PYTHON_BIN` 需指向真实 python.exe(生产默认 `python3`)——Python 相关仅服务器需要。
|
|
|
+6. `.token`/`out/`/`__pycache__` 已 gitignore,不提交。
|
|
|
+
|
|
|
+## §15 结束协议(每任务收尾)
|
|
|
+
|
|
|
+输出三行:① 做了什么(命令序列)② 结果(数据或 PASS/FAIL + 异常项)③ 遗留与建议下一步。有「未验证项/已知限制」要显式披露。
|
|
|
+
|
|
|
+## 相关技能
|
|
|
+
|
|
|
+- 报告人工解读模板细节见项目内 `smartbadge-report`(执行报告解读时可调用)。
|
|
|
+- PPT 产物:全局 `weekly-report-pptx` 技能。
|