fix: 完成 doco src layout 重构,文件移至 src/doco/ 子目录

This commit is contained in:
simonkoson
2026-06-12 17:13:32 +08:00
parent 0508bd8f23
commit 89d59f6f03
29 changed files with 3676 additions and 0 deletions
Binary file not shown.
+11
View File
@@ -0,0 +1,11 @@
**本文件是制片人刘通与 Claude(Opus 4.7 高级技术顾问)的协作原则,与项目宪法(.clinerules / project_plan.md / dev_plan.md / docs/git_workflow.md)并列。新对话接手时,请连同宪法一并阅读本文件。**
------
**Claude 与我交流、沟通、协作时需要注意的原则**
1. 全程使用简体中文。
2. 我不懂代码编程,给我的解释说明和理由要尽量简明扼要。不要堆叠大量技术语言,说人话。
3. 请参阅宪法文件中你(Claude)的定位:写具体 Plan 是 Cline 的事,不要架空 Cline 的 Plan 模式。除非特别必要(Cline 反复修改都过不去的坎)可以上手,以及制片人明确指定你可以操刀的具体工作。
4. 给 Cline 的指令要用代码块封装起来,方便复制。
5. 给我的回复要简明扼要,不要解释太多的中间过程和理由和分析,有不懂的我会问你。
@@ -14,6 +14,10 @@
有沉淀、有权限、可检索的系统。核心价值 = 经验从"靠人"变"靠系统"。 有沉淀、有权限、可检索的系统。核心价值 = 经验从"靠人"变"靠系统"。
- 现有克制选择(不用 TS / 不用 Alembic / pgvector 不用独立向量库 / - 现有克制选择(不用 TS / 不用 Alembic / pgvector 不用独立向量库 /
Session 不用 JWT)方向正确,保持。 Session 不用 JWT)方向正确,保持。
- ⚠️ 更新(2026-06-12):看板分析升级相关待办(原 F1-F8)已整体迁移到
**TPS 看板分析升级子项目**。主 project 这边不再维护这部分待办。
子项目状态见 `寄存条_看板升级已外迁.md`
- doco 相关条目已外迁
--- ---
@@ -0,0 +1,364 @@
# 主 project 答复 — 分钟收视回放子板块
> 版本:v1
> 日期:2026-06-11
> 作者:TPS 主 project 顾问 (Claude Opus 4.7) + 制片人 刘通
> 状态:已采纳,待秒级 chat 接收并按本文件推进实现
> 上一版:无
> 对应文档:秒级收视 project《军事科技_分钟收视回放_子板块需求规格.md》v12026-06-10
---
## 一、本文件用途
回复秒级 chat 那份 PRD 第八节的 6 个对接问题,并把主 project 这边的**红线、修订建议、交付物期待**全部白纸黑字写下来。本文件是子板块继续推进的**最终输入**,秒级 chat 这边可基于此开干。
子板块结束前,要按本文件第九节的清单产出**五份交付物**给主 project。主 project 这边的 Cline 拿着五份交付物落代码,完成最终整合。
---
## 二、对 6 个对接问题的最终答复
### 1. TPS 工作台有没有"每期节目详情页"?
**没有。子板块需要附带把详情页骨架建起来。**
现状:仪表盘 (Dashboard) 是聚合视角,责编录入页 (EditorDesk) 是表单 + 列表,**没有"看单期 + 该期所有维度"的页面**。分钟收视回放需要这个容器,整个工作台早晚也需要这个页面,借这次一起做掉。
入口规划:
- 仪表盘柱图每根柱子点进去 → 详情页
- EditorDesk 列表行点进去 → 详情页
- 路由建议:`/episodes/:id``:id``episodes.id`SERIAL 主键)
详情页骨架要预留位置承载未来其他维度(审片意见、文稿、外拍信息等),分钟收视回放是其中**第一个模块**。
### 2. 数据库技术栈
**PostgreSQL 16 + pgvector1536 维)**ORM 是 **SQLModel(同步,非 async**
手写 SQL 走 `backend/sql/00X_*.sql`,不用 Alembic。
第五节那两张表的接入方式见第四节"数据模型修改建议"——简短版:**别新建"节目期次表",复用现有 `episodes` 表**;分钟数据表新建,命名 `episode_minute_ratings`,外键挂到 `episodes.id`
### 3. 视频和截图存储方案
**最终决策:视频不入工作台。**
- 视频本体由制片人在本地/百度网盘/极空间多渠道自存
- 工作台只接收**截图**(27 张 jpg)
- 不再讨论服务端 ffmpeg、视频压缩、转码删源片等服务端方案
截图处理走**本地切图工具**(子板块产出,详见第五节):
- 责编本地双击工具 → 拖入源片 → 自动切 27 张 480p 截图 + 命名好
- 责编打开工作台 → 一键多文件上传截图(~5 MB 一次传完)
截图存储:服务器文件系统 `/screenshots/{episode_id}/{分钟序号_两位数}.jpg`,数据库只存 URL。
### 4. 前端技术栈
**React 18 + Vite + Ant Design 5 + Zustand**JavaScript(不用 TS),项目宪法锁定。
图表库选型:
- **优先 @ant-design/charts**:与现有 AntD 5 视觉血缘最近,配色和圆角自然贴合
- **次选 ECharts**:自定义 tooltip 模板灵活成熟
- **已用过 Recharts**:仪表盘柱图已采用
**不要再引第三方图表库**。三选一即可,最终选哪个由 Cline 在 Plan 阶段定。
### 5. 后台异步任务怎么跑
**在"视频不入工作台 + 本地切图工具"决策下,服务端没有重型异步任务。**
工作台后端只接收截图入库 + 跑数据校验(见第四节建议 E),都是毫秒级同步操作,**FastAPI BackgroundTasks 都用不上**。
如果未来某个新场景确实需要异步任务,再启用 FastAPI BackgroundTasks。**不引 Celery、不引 Redis 队列**——8 人栏目用这些是过度工程。
### 6. 录入身份/权限
**有完整用户系统**Session + Cookie 认证,三角色拼音枚举锁定(`zhipianren` / `zebian` / `biandao`)。
写权限规则参照 `yearly_targets` 既有口径平移:
- **POST/PATCH/DELETE 录入分钟数据 + 上传截图**:`zhipianren` + `zebian` 可写,`biandao` 返回 403
- **GET 查看分钟回放**:三角色均可读
**实现细节**FastAPI 后端直接从 session 拿 user_id 写入 `created_by` 字段,**前端不要把"录入人"作为字段提交**。
字段命名用 `created_by INTEGER REFERENCES users(id)`**不要用 string 类型的"录入人姓名"**——主 project backlog 里有一条 "操作留痕 schema"(待办池 B2),分钟收视这张新表作为落地先例。
---
## 三、视频/截图最终方案(决策落地)
### 责编一周一期的标准流程(最终版)
```
周二 21:20-21:47 节目播出
周二 22:00 后 责编到总编室账号抄 27 个份额数字(保留原方案)
次日 责编打开本地切图工具
拖入当期源片 mp4 → 工具自动切 27 张 480p jpg
+ 自动命名为 01.jpg ~ 27.jpg
责编登录工作台 → 进入"节目期次"管理
→ 选择当期 episode(基于已录入的 episodes 记录)
→ 进入分钟收视模块
上传 27 张截图(多文件选择 / 拖拽)
→ 服务器存到 /screenshots/{episode_id}/
→ 数据库写入 27 条 episode_minute_ratings 记录
录入 27 个份额数字
(推荐:"批量粘贴一列数字"输入框,
从 Excel 复制 27 个数字粘贴后系统按行切分)
→ 系统软校验(数据齐全?范围合理?均值与已录全期均值吻合?)
→ 保存
该期详情页里"分钟收视回放"模块即刻可看
```
### 主 project 这边不做的事
- 服务端 ffmpeg(不需要)
- 视频上传接口(不需要)
- 视频压缩转码(不需要)
- 异步任务队列(不需要)
- 视频删除/清理脚本(不需要)
---
## 四、数据模型修改建议(主 project 在此明确给出)
> 任何 schema 改动**必须经主 project 顾问 (Opus) 审、配回补方案,Cline 不得自行动手**。这是项目红线。下面是建议方案,最终落地前还会过一遍审查。
### 建议 A:复用现有 `episodes` 表,**不新建"节目期次表"**
现有 episodes 表已涵盖你需要的全部"节目期次"信息:
| 你的字段 | 对应现有 episodes 字段 |
|---|---|
| 期次主键 | `id`SERIAL |
| 期数显示 | 前端从 `air_date` + `episode_number` 拼,不入库 |
| 节目名称 | `program_name` |
| 播出日期 | `air_date` |
| 播出时段 | 不入库,前端常量 "21:20-21:47" |
| 备注 | `notes` |
理由:新建一张冗余表会割裂 episodes 与其他模块(收视成绩、外拍、未来选题、审片意见)的关联,破坏单一事实源。
### 建议 B:用 `episodes.id`INTEGER)做外键,**不用"播出日期 string"做主键**
秒级 chat v1 文档建议"期次主键用 `2026-06-09` 字符串"。这与 `episodes.id SERIAL` 体系冲突。
最终方案:分钟数据表用 `episode_id INTEGER REFERENCES episodes(id)` 外键,所有展示字符串("2026 年第 23 期 · 2026-06-09")由前端从 episodes 数据拼出,不入库。
### 建议 C`收视份额` 用 `NUMERIC(6,4)`**不用 float**
与现有 `episodes.audience_share NUMERIC(6,4)` 类型对齐,避免浮点比较的怪事。
### 建议 D:新表 `episode_minute_ratings` 建议 schema
```sql
CREATE TABLE IF NOT EXISTS episode_minute_ratings (
id SERIAL PRIMARY KEY,
episode_id INTEGER NOT NULL REFERENCES episodes(id) ON DELETE CASCADE,
minute_index INTEGER NOT NULL CHECK (minute_index BETWEEN 1 AND 27),
audience_share NUMERIC(6,4) NOT NULL,
screenshot_url VARCHAR(500),
created_by INTEGER NOT NULL REFERENCES users(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(episode_id, minute_index)
);
CREATE INDEX idx_minute_ratings_episode ON episode_minute_ratings (episode_id);
```
P1+ 扩展(多期对比、批注/标签):1.0 不建表,到 P1 触发时再说。当前 UNIQUE 复合键和外键设计已留好扩展空间。
### 建议 E:工作流补一个"软校验"环节
录入 27 个分钟份额时,系统应做**非阻塞**的合理性提示:
- 27 个数字是否齐?
- 最大值/最小值是否在合理区间(如 0-3)?
- 27 个数字的平均值是否与已录的 `episodes.audience_share`(该期全期均值)大致吻合?误差 > 30% 给"数据可能录错"提示
不阻塞保存,只是温柔提醒。理由:分钟数据是栏目考核依据,权重最高,录错一个小数点不发现就一直错。
### 建议 F:批量导入接口复用现有 ExcelService
23 期历史数据一次性导入:复用主 project 已有的 ExcelService 框架(Phase 2 Task 2 跑通),但单开一个 endpoint:
- 上传一份"期次 × 27 列分钟份额"的 Excel
- 按行展开成 23 × 27 = 621 条 `episode_minute_ratings` 入库
- 截图 URL 字段第一次导入时留空,后续走本地工具补传
### 建议 Gepisodes 表是否要加视频 URL 字段?
**不加。**
因为视频不入工作台。如果未来某天想记录"这一期视频存在哪个网盘 / 哪个本地路径",可以走 `episodes.notes` 字段写自由文本,不需要专门字段。
---
## 五、本地切图工具规格(子板块产出物之一)
子板块的 Claude 负责设计与实现这个工具。
### 5.1 形态
- 一个 Windows 上能跑的可执行文件(py 源码 + pyinstaller 打包成 exe
- 双击即用,无安装步骤
- 不依赖网络,不依赖工作台,完全离线
- 不需要责编装 Python 环境
### 5.2 用户界面
简洁到极致:
- 一个窗口,拖文件进去即可(或"选择文件"按钮)
- 接收 mp4 / mov / mkv 等常见格式
- 进度条显示切图进度
- 完成后弹"已生成 27 张截图于 [输出文件夹]"
- 自动打开输出文件夹
### 5.3 切图规则(与秒级 chat v1 文档保持一致)
```bash
# 27 张截图,每分钟第 30 秒位置,480p (854 × 480)
for i in $(seq 0 26); do
sec=$((i*60+30)) # 0:30, 1:30, 2:30, ..., 26:30
ffmpeg -i 源片.mp4 -ss $sec -vframes 1 -vf scale=854:480 \
"$(printf "%02d" $((i+1))).jpg" -y
done
```
输出文件名规则:**`01.jpg` ~ `27.jpg`**(两位数,零填充,便于排序)。
### 5.4 输出文件夹组织
工具自动新建一个文件夹,命名建议:`截图_{源片文件名去后缀}_{日期}/`,里面 27 张 jpg。
### 5.5 ffmpeg 依赖
打包时把 ffmpeg.exe 一并塞进 exe,或者用 `imageio-ffmpeg` 包自动下载。**绝对不要让责编手动装 ffmpeg**。
### 5.6 错误处理
- 源片读不到 → 弹窗"文件无法读取,请检查格式"
- 源片时长 < 26 分 30 秒 → 弹窗"视频时长不足 27 分钟,是否继续?"(允许跳过缺失分钟)
- 输出文件夹已存在 → 自动加时间戳后缀
### 5.7 给责编的使用说明
子板块产出一份 `使用说明.md`,傻瓜级,要有截图。预期长度 200-400 字 + 3-5 张截图。
---
## 六、主 project 红线(不可越)
子板块设计与实现过程中,下面这几条是**主 project 宪法**,任何方案不得违反:
1. **改 schema 须主 project 顾问 (Opus) 审**:包括新建表、改字段、加字段。Cline / 子板块 Claude 不得自行动手。
2. **角色枚举锁定拼音值**`zhipianren` / `zebian` / `biandao`,不许新增枚举,不许用英文别名。
3. **AI 给方向不给答案**:分钟收视回放的 P1+ 功能(多期对比找规律、批注 AI 建议等)若涉及 AI,必须保持"建议草稿 + 制片人审核"的三档置信度,不得 AI 直接拍板。
4. **编导关联用"软引用 + 快照"**:本子板块如需展示编导信息,沿用 `episodes.editor_id` + `episodes.editor_name_snapshot` 双字段,不许新增编导关联字段。
5. **收视颜色判定**:红=优秀(>摸高目标)/ 蓝=达标 / 绿=待提升(<基础目标)。反直觉规约,分钟收视回放折线图如果上色,按此规则。
6. **AI 输出必须有"忽略 / 我来改写"否决权**:任何 AI 建议(如本子板块 P1+ 的 AI 找规律功能)必须给编导否决入口。
7. **不引新依赖**:图表库三选一(@ant-design/charts / ECharts / Recharts),不引第四个;后端不引 Celery / Redis 队列。
---
## 七、子板块产出物清单(最终交付包)
子板块结束前,请凝结成以下**五份交付物**,作为整体交付给主 project:
### 产物 1:决策摘要 md
记录子板块全程的关键决策。每条决策三句话:
```
决策 X[一句话决策内容]
- 背景:为什么需要这个决策
- 拍板理由:选这条不选那条的理由
- 拍板人:[制片人 / 主 project 顾问 / 子 project Claude 建议+制片人采纳]
```
10-20 条决策足以讲清整个子板块"为什么这么做"。
### 产物 2:接口约定 md(最技术、最精确)
把子板块与主 project 接驳的所有"接口"白纸黑字写出来:
- **数据接口**:新建表 / 字段 / 类型 / 约束(细化到 SQL DDL 级别)
- **API 接口**:新增 endpoint URL / 方法 / 请求体 / 响应体 / 错误码
- **UI 接口**:在主 project 哪个页面挂载、入口、路由
- **权限接口**:哪些角色可以做什么操作
- **存储接口**:截图存到哪个目录、命名规则、URL 拼接规则
要具体到"主 project 的 Cline 拿着这份就能写代码"的程度。**这是子 project 给主 project 的"合同"**。
### 产物 3:本地切图工具完整包
- `screenshot_tool.py`:源码,注释齐全
- `screenshot_tool.exe`:打包好的可执行文件,责编双击即用
- `使用说明.md`:傻瓜级文档 + 截图
工具规格见本文件第五节。
### 产物 4:未尽事项 backlog
诚实写出"子板块讨论中提到但没做的事"。每条三行:
- 是什么
- 为什么没做(暂缓 / P1+ / 等条件成熟)
- 触发时机(什么时候应该捡起来)
放进主 project 的 backlog 池子里。
### 产物 5:给主 project Claude 的"接手提示词"
一两段话,告诉主 project 顾问"如果你是接手这件事的 Claude,最重要的三件事是 X、Y、Z"。
这次至少要包含:
- 复用 episodes 表,不新建节目期次表
- 权限沿用 yearly_targets 口径
- 本地切图工具与工作台零耦合,不在工作台 UI 里给它留接口
---
## 八、跨 project 协作规矩(子板块这边也要遵守)
1. **不动主 project 代码**:子板块产出文档 + 独立工具,不写主 project 的实际代码。代码合入由主 project 的 Cline 完成。
2. **遇到吃不准的事回主 project 问**:本次 v1 文档第八节就是好榜样,继续保持。
3. **每份跨 project 文档顶部带元信息块**:版本、日期、作者、状态、上一版、主要变化(v2 以上必填)。
4. **一份文档只谈一件事**:不要在分钟收视回放交付包里夹带其他议题。
---
## 九、给秒级 chat Claude 的明确动作清单
收到本文件后,请按下面顺序推进:
1. **吸收本文件所有决策与红线**,回到秒级 chat 的 PRD v1,把不一致处标注出来(如果有)
2. **如有需要修订的地方,出 PRD v2**,顶部元信息块写明跟 v1 的变化点
3. **设计本地切图工具**:与制片人讨论用户体验细节,定稿后凭工具规格让秒级 chat 的 Cline 实现(如果有)或制片人自己找 v0/Lovable 等工具生成 demo
4. **凝结成最终五份交付物**(第七节清单)
5. **交付给制片人**,由制片人带回主 project,主 project 顾问 (Opus) 审一遍,无冲突后主 project 的 Cline 落实施
---
## 十、附:版本演进规约
本文件未来如修订(v2+),顶部元信息块"主要变化"必须写清楚改了什么。
历史版本不覆盖,旧文件保留在 `docs/cross_project/` 目录(主 project 这边)以便回看决策史。
---
*本文件由主 project 顾问 (Claude Opus 4.7) 于 2026-06-11 基于与制片人刘通的两轮对话整理生成,供秒级收视项目接收使用。*
@@ -0,0 +1,119 @@
# 子项目立项备忘 — 分钟收视回放
> 文档类型:子项目立项备忘
> 子项目名称:分钟收视回放
> 立项日期:2026-06-11
> 子项目所在:秒级收视 project(Claude.ai 网页版的另一个 project
> 当前状态:**推进中**(设计已收敛,进入子板块内部实现阶段)
> 主 project 联系人:制片人刘通 + Claude Opus 4.7 顾问
---
## 一、文档用途
未来主 project 这边新开 chat 时(必然会发生 Claude 失忆),新 Claude 通过此文件快速恢复"分钟收视回放子项目"的上下文。**它不重复 v1 答复 md 里的细节,只留指针 + 关键决策摘要**。
---
## 二、立项缘由
制片人在另一个 project(秒级收视)里讨论分钟收视数据怎么进工作台、怎么呈现。那边 Claude 写了一份 PRD(需求规格 v1, 2026-06-10),向主 project 这边提了 6 个对接问题。
主 project 这边讨论两轮后采纳"以子项目模式独立推进",并把答复凝结成正式 md 带回子项目。**这次是项目里第一次完整使用"子项目模式"**——既是分钟收视回放本身的立项,也是这套跨 project 协作工作流的首次实操。
---
## 三、关键决策摘要(已采纳,不要重复讨论)
1. **视频不入工作台**:制片人多渠道自存(极空间/百度网盘/本地),工作台只接收截图
2. **本地切图工具**:子板块产出,py + exe + 使用说明,与工作台零耦合
3. **复用现有 episodes 表**:不新建"节目期次表",分钟数据表 `episode_minute_ratings` 外键挂到 `episodes.id`
4. **录入人字段用 `created_by INTEGER REFERENCES users(id)`**:不用 string,顺手落地 backlog B2 操作留痕
5. **后端不上 Celery/Redis**:异步任务在视频不入库后基本消失,必要时用 FastAPI BackgroundTasks
6. **图表库三选一**@ant-design/charts / ECharts / Recharts,不引第四个,最终由 Cline Plan 阶段定
7. **详情页 `/episodes/:id` 骨架由本子板块附带建起来**:早晚要做,借这次一起
8. **权限沿用 yearly_targets 口径**zhipianren + zebian 可写,biandao 只读
---
## 四、子板块要交付什么(五份产物)
子项目结束时,那边凝结以下交付包带回主 project:
1. 决策摘要 md
2. 接口约定 md(含 SQL DDL、API endpoint、UI 接入点、权限规则、存储路径规则)
3. 本地切图工具完整包(py 源码 + exe + 使用说明)
4. 未尽事项 backlog
5. 给主 project Claude 顾问的"接手提示词"
详见《分钟收视回放_主project答复_v1.md》第七节。
---
## 五、主 project 要做的事
**现在(推进期)**:不做事,不接收过程文档,等收交付包。
**收到交付包后**
1. 主 project 顾问 (Opus) 审一遍,看跟主项目红线有没有冲突
2. 无冲突 → 主 project workspace 里让 Cline 落代码
3. 有冲突 → 标出冲突点,回子项目修,循环
---
## 六、相关文档(指针)
**外部输入**(子项目发来的):
- 秒级 chat 的 PRD v1:《军事科技_分钟收视回放_子板块需求规格.md》(2026-06-10
- 已在主 project files 中(制片人 2026-06-11 上传)
**主 project 输出**(咱们这边给子项目的):
- 《分钟收视回放_主project答复_v1.md》(2026-06-11
- 建议归档位置:`docs/cross_project/分钟收视回放/分钟收视回放_主project答复_v1.md`
**配套文档**
- 《跨project协作提示单_v1.md》(2026-06-11,制片人随身保存)
- 不在主 project 仓库内,是制片人个人工作流手册
---
## 七、预计回归时间
未明确锁定。子项目那边的 Claude 表示"没有什么不清楚的了",已在内部推进。
**触发主 project 这边介入的信号**
- 子项目带交付包过来(正常路径)
- 子项目过程中遇到吃不准的事 → 单点咨询主 project 顾问(不要整份过程稿上传)
- 超过 4 周还没收敛 → 主动 ping 一下,看是不是要重新切分
---
## 八、给未来失忆接手 Claude 的提示
如果你是几周后接手主 project 的 Claude,看到这份备忘,请记住:
1. **分钟收视回放是一个独立推进的子项目**,主 project 不掺合其内部讨论
2. **复用 episodes 表,不要新建节目期次表**——这是已经定死的决策,不重新讨论
3. **改 schema 必须经 Opus 顾问审**,子项目交付包带 schema 修改建议时严守这条
4. **本地切图工具与工作台零耦合**,工作台 UI 里不要给它留接口
5. **视频不入工作台**——任何提议加视频上传接口的方案都已被否决
6. **审查交付包是必经环节**,发现子项目设计违反主项目红线(如角色枚举、收视颜色判定)时直接打回
---
## 九、版本演进
本文件未来如需更新(v2+):
- 子项目交付包接收后:更新"当前状态"为"已交付,整合中"
- Cline 实施完成后:更新"当前状态"为"已完成",加一节"实施回顾"
- 实施过程中如有重大决策变更:v2 顶部"主要变化"写明
---
*本立项备忘由主 project 顾问 (Claude Opus 4.7) 于 2026-06-11 制片人立项动作后随手生成。轻量、精简,未来失忆接手时由此恢复上下文。*
@@ -0,0 +1,65 @@
# 寄存条:看板升级已外迁
> 留在主 project,让未来的 Claude 一眼知道:看板分析升级已经拉出去单独立项了。
> 外迁时间:2026-06-12
---
## 外迁了什么
**TPS 看板分析升级**整体作为子项目,搬到独立 Claude project。
子项目聚焦:三层信息架构、双引擎象限图、AI 打标流水线、编导能力地图、本期诊断小结、看板 UI 设计。
子项目持有的核心资产:主项目签发的 Brief + 三份续接快照 + ground-truth 基准集 + 23 期文稿等。
---
## 主 project 不再讨论的话题
聊到下面这些词,**先问一句"这是子项目的事还是主 project 的事?"**——是子项目的事,提醒制片人切到子项目 chat。
关键词:看板升级 / 双引擎象限图 / 题材热度 / 叙事结构(作为字段)/ AI 打标 / Prompt 1/2/3 / ground-truth / episodes 加字段 / 23 期回填 / 能力地图 / 置信度三档 / 本期诊断小结
---
## 主 project 仍在管什么
- Phase 0-3 已落地的主干代码(episodes、editors、收视诊断基础)
- backend 全部 schema、API、迁移脚本
- 前端全部 React 代码实施
- 主干 Bug、性能优化、新需求(看板升级以外的)
- Cline 的全部 Plan + Act 操作
---
## 接收子项目交付物的接口
子项目交付物的具体接口约定,见**子项目主 Brief §六**(交付什么)。简要回顾:
- **Schema 变更**:子项目出字段定义文档 → 主 project Cline 切 Plan + Opus 审 + 制片人批准 Act → `pg_dump` 备份 → 跑迁移
- **前端实施**:子项目出设计 token + HTML mock + 视觉规范 → 主 project Cline 落 React
- **AI 打标**:沙盒 `ai-labeling/` 由子项目自治,主 project 不碰
- **回填**:子项目出脚本设计 → 主 project 跑 + 制片人审 staging
**纪律**:
- 只接稳定版,草稿不实施
- 实施前 `pg_dump` 备份
- 实施完成后回访子项目登记状态
---
## 开局口径
进主 project 新 chat:
> "续接 TPS 主项目。读 `寄存条_看板升级已外迁.md`。当前要做 [具体任务]。"
---
## 万一子项目记录丢了
降级方案:
1. 主 project 这边还保留资产副本(xlsx + 11 份 docx + 部分 UI 参考图)
2. 决策史在 Gitea 有 git 历史(关键 commit `38f3728` 等)
3. 制片人本地应有副本
4. **主 project 这边不要凭记忆重建子项目内容**——找制片人或重建子项目
@@ -0,0 +1,50 @@
# 看板升级子项目 — 入口
> 这是 TPS 主 project 拆出来的子项目,聚焦"看板分析升级"。
> 立项时间:2026-06-12
> 顾问:Claude Opus 4.7 制片人:刘通
---
## 开局必读(顺序)
1. `看板升级子项目_Brief.md` — 主项目签发的"交接宪法"(红线、技术栈、出入口接口)。**不在子项目内修改。**
2. `续接快照_看板分析升级_设计讨论_v4.md` — 最新决策史(往前可回溯 v3 / v1)
3. 上面两份读完,就有完整上下文了
---
## 已有资产
**决策史**:
- 续接快照 v1 / v3 / v4 — 整个看板升级讨论的完整记录
**数据基础**:
- `军事科技栏目收视诊断分析_v2.xlsx` — 双引擎模型源数据(主项目也留一份)
- 11 份节目文稿 `.docx` — AI 打标基准集源稿(主项目也留一份)
**UI 参考**:
- `dashiboard首页原版.jpg` — 首屏改造起点(主项目也留一份)
- `dashiboard首页_拷贝.jpg` — 制片人批注稿
- `色调字体倒角.webp` — 整体视觉资产(主项目也留一份)
- `简洁风_清晰.jpg` — DataEase 风格参考
**协作纪律**:
- `Claude协作原则.md` — 与主项目同源,沿用
**沙盒**:
- `ai-labeling/` 工作区(物理上仍在 `E:\tps-dashboard\ai-labeling\`)
- Prompt 2 v0.2 已锁,MiniMax M3 选定,ground-truth v0.2.1 锁定
---
## 子项目自由度
读完 Brief 你会注意到 §八"未决项"——那是子项目可自由发挥的部分。
Brief 里没明确禁止、没在续接快照里拍板的事,都是讨论空间。
---
## 新 chat 开局第一句
> "续接 TPS 看板分析升级子项目。先读主 Brief 和续接快照 v4。本 project 是设计+PRD 产出,不动主 project 的 backend 代码。当前推进到 [具体任务]。"
@@ -0,0 +1,143 @@
# 看板升级子项目 Brief
> 主项目 → 子项目的"交接宪法":红线、技术栈、出入口接口
> 起草日期:2026-06-12
> 状态:子项目立项时由主项目顾问(Opus)签发,子项目内部不修改
---
## 一、为什么做
**痛点**:制片人和编导团队拿到的"收视成绩单"只能看到结果(均值、走势、单期高低),
看不到结构性原因。每次复盘要靠人工拼诊断(21 期那次花了若干周),无法持续。
**升级目标**:把仪表盘从"看成绩"升级为"能分析"——
让"双引擎模型(题材热度 × 叙事结构)"这个一次性人工产出的分析框架,
变成一台**持续运转的诊断仪**。
---
## 二、做什么(功能边界,只列名)
| 模块 | 简述 |
|---|---|
| 三层信息架构 | 纯算 / 打标后 / AI 起草,分层呈现 |
| 双引擎象限图 | 招牌视觉,题材热度 × 叙事结构 |
| AI 打标流水线 | Prompt 1/2/3 + MiniMax M3 + ground-truth |
| 编导能力地图 | 反排名,正反馈 |
| 本期诊断小结 | AI 起草 + 制片人审改后发布 |
| 时间选择器 | 实时脉搏 vs 周期复盘,边界永远可调 |
**具体怎么做,子项目内部讨论,本 Brief 不预设方案。**
---
## 三、怎么用(目标流程)
- **每周**:制片人看"实时脉搏"——核心指标卡 + 近 9 期走势
- **每月**:制片人看"题材分析"——题材汇总,关注异动
- **每季**:制片人看"双引擎象限图 + 本期诊断小结"——周期复盘
- **新节目入库**:AI 打标草稿 → staging 表 → 制片人审 → 落库
- **编导维度**:制片人查能力地图,把强项做成全组可复用模板
- **离职编导**:历史保留,面向当下视图可筛掉
---
## 四、不做什么(红线)
子项目设计任何方案,**绝不**触碰以下:
-**不做深色大屏**(留给 2.0 数据大屏蓝本)
-**不做编导排名**(团队视角走能力地图)
-**AI 不自动盖章下结论**(永远是"AI 出草稿,人拍板")
-**不引入新图表库**(继续 ECharts / @ant-design/charts)
-**不引入主 project 没有的技术栈**
-**不动主 project 已有的 schema**(改字段必须走 §六交付协议)
-**不做"未审字段直接上看板"**(置信度三档必须可辨)
-**不写 / 不改 AI 打标 Prompt 由 Cline 完成**(Cline 是执行者不是作者)
---
## 五、技术栈约束(继承主 project)
子项目所有设计必须能落在以下栈上,不引入新依赖:
- **前端**:React 18 + Vite + AntD 5 + Zustand + ECharts / @ant-design/charts
- **后端**:FastAPI + SQLModel + PG 16 + pgvector
- **配色**:米色底 `#fbf9f1` + 深绿主色 `#6b8e6b`
- **三色色板**:红 `#c0584f` / 蓝 `#5b8db8` / 绿 `#7aa874`
- **基准线**:基础线 0.6448 / 摸高线 0.8989(2026)
- **AI 打标**:沙盒 `ai-labeling/`,生产模型 MiniMax M3,openai==1.55.0 锁版本
- **部署**:腾讯云 4 核 8G(性能上限,凡是吃不动的方案直接否决)
---
## 六、交付什么(出口接口)
子项目产出最终要回到主 project 实施,**交付物必须满足以下接口**:
### 6.1 Schema 变更类
- 子项目出:**字段定义文档**(命名 / 类型 / 枚举 / nullable / 约束 / 回滚方案)
- 主 project 实施:**Cline 切 Plan → Opus 审 → 制片人批准 Act → `pg_dump` 备份 → 跑迁移**
- 不接受:子项目自己改主 project schema 或 `backend/` 任何代码
### 6.2 前端实施类
- 子项目出:**设计 token JSON + HTML mock + 视觉规范文档**
- 主 project 实施:**Cline 按设计稿落 React 组件**
- 不接受:子项目自己写主 project 的 React 代码
### 6.3 AI 打标类
- 子项目在 `ai-labeling/` 沙盒自治,**沙盒内 Cline 可直接 Act**
- 子项目出:**Prompt 文件 + ground-truth.json + 模型选型结论**
- 主 project 实施:**episodes_staging 表 schema 落库 + 审稿 UI 落地**
### 6.4 回填类
- 子项目出:**回填脚本设计文档 + 23 期回填策略**
- 主 project 实施:**Cline 跑脚本 + 制片人审 staging**
### 6.5 通用约束
- 子项目**不主动 push** 文件到主 project,**所有交付物由制片人决定时机**
- 主 project 只接**稳定版**,子项目内部草稿不交付
---
## 七、入口接口(子项目要知道的主 project 现状)
- **Phase 0-3 已落地**:episodes / editors / 收视诊断基础数据,23 期 2026 年数据已入库
- **现有视觉语言**:米色 + 深绿,卡片圆角 12px,AntD 5 默认行高
- **现有 backlog**:主 project 这边的 backlog 已标注"看板升级条目已外迁"
- **现有沙盒**:`ai-labeling/` 工作区已搭建,Prompt 2 v0.2 已锁,MiniMax M3 已选定
- **现有 git**:Gitea 落库,关键 commit `38f3728`
---
## 八、未决项(归子项目自己拍板)
以下不在本 Brief 内预设,**由子项目和制片人讨论决定**:
- 横轴量化方法的具体公式
- AI 打标 Prompt 1 / Prompt 3 的具体写法
- 看板各屏幕的具体布局和交互
- 双引擎象限图的具体视觉细节
- 能力地图的具体可视化方案
- episodes 新字段的最终命名 / 类型 / 是否多对多关联表
- 置信度是单字段还是分字段
- 时间窗口取多大 / 小样本怎么兜底等具体口径
---
## 九、决策史指向(不重复内容)
子项目讨论前应该读的:
- `续接快照_看板分析升级_设计讨论.md`(v1,2026-06-09)
- `续接快照_看板分析升级_设计讨论_v3.md`(v3,2026-06-11 上午)
- `续接快照_看板分析升级_设计讨论_v4.md`(v4,2026-06-11 晚)
- `军事科技栏目收视诊断分析_v2.xlsx`(双引擎模型源数据)
---
## 十、本 Brief 自身的修订规则
- 本 Brief 不在子项目内修改
- 红线 / 技术栈如有变更,**主 project 这边发新版**,通过寄存条同步
- 子项目可在自己的 chat 里讨论"建议主 project 调整某条红线",但调整动作只能在主 project 发生
@@ -0,0 +1,95 @@
# 迁移清单 — 主 project 操作指南
> 用途:看板升级子项目立项时,主 project 这边的文件操作清单
> 操作完即可丢弃
> 制定时间:2026-06-12
---
## 资产分两类处理
### 🔵 子项目独有(主 project 这边删)
纯决策记录性质,主 project 不再需要:
1. `续接快照_看板分析升级_设计讨论.md`(v1)
2. `续接快照_看板分析升级_设计讨论_v3.md`
3. `续接快照_看板分析升级_设计讨论_v4.md`
4. `dashiboard首页_拷贝.jpg`(批注稿)
5. `简洁风_清晰.jpg`(参考图)
### 🟢 两边都留(各保留一份)
资产类性质,主 project 将来也可能用得到:
1. `军事科技栏目收视诊断分析_v2.xlsx` — 数据基础
2. 11 份节目文稿 `.docx`(硅基大脑、潜艇仿生 等) — 节目原始资料
3. `dashiboard首页原版.jpg` — 主 project 实施 React 时要看
4. `色调字体倒角.webp` — 整体视觉资产
---
## 主 project 这边的其他动作
### 新增
- 上传 `寄存条_看板升级已外迁.md`
### 更新
- `backlog_md_TPS_工作台待办池_不丢视野_非排期_.md` 顶部加一段:
```markdown
> ⚠️ 更新(2026-06-12):看板分析升级相关待办(原 F1-F8)已整体迁移到
> **TPS 看板分析升级子项目**。主 project 这边不再维护这部分待办。
> 子项目状态见 `寄存条_看板升级已外迁.md`。
```
### 保留(不动)
主干文档(README、Claude协作原则、phase 日志、doco 系列、git_workflow、_clinerules、_gitignore、001_init.sql、dev_plan、project_plan、Phase 3 续接快照系列)全部保留。
---
## 操作步骤
**Step 1 ─ 建子项目**
1. 新建 Claude project,名为 `TPS看板分析升级`
2. 上传 4 份新文件:`INDEX.md` + `看板升级子项目_Brief.md` + 拷贝一份 `Claude协作原则.md`
3. 上传 🔵 5 份子项目独有的文件
4. 上传 🟢 14 份资产文件(主 project 也保留同名副本)
**Step 2 ─ 清主 project + 寄存**
5. 删除 🔵 5 份文件
6. 上传 `寄存条_看板升级已外迁.md`
7. 更新 `backlog` 顶部标注
**Step 3 ─ 验证**
8. 进主 project 新 chat:"读寄存条" → 看 Claude 是否懂"这部分外迁了,不在我这里讨论"
9. 进子项目新 chat:按 INDEX 开局口径 → 看 Claude 是否能正确进入顾问角色
---
## 操作后的拓扑
```
TPS 主 project TPS 看板升级子项目
───────────────────── ─────────────────────
├─ 主干文档(README/协作原则/phase 等) ├─ INDEX.md ★
├─ doco/migration/git/init/dev/plan ├─ 看板升级子项目_Brief.md ★
├─ Phase 3 续接快照系列 ├─ Claude协作原则.md(拷贝)
├─ backlog(顶部加标注) ├─ 续接快照 v1/v3/v4
├─ 寄存条_看板升级已外迁.md ★ ├─ xlsx + 11 份 docx(副本)
├─ xlsx + 11 份 docx(副本) ├─ dashboard 首页原版(副本)
├─ dashboard 首页原版(副本) ├─ 色调字体倒角(副本)
└─ 色调字体倒角(副本) ├─ dashboard 首页_拷贝.jpg
└─ 简洁风_清晰.jpg
```
★ = 新增
---
## 拿不准的就先不动
任何一份文件去留拿不准的,**先保留**。文件保留比误删容易处理。
@@ -0,0 +1,151 @@
# F3 横轴量化方法 PRD v1.0
> 子项目交付物 · 看板分析升级
> 状态:**v1.0 已锁**(2026-06-12 通哥审过 §2/§3/§4 决策)
> 起草时间:2026-06-12
> 顾问:Claude Opus 4.7 制片人:刘通
> 类型:薄 PRD(只解 v2 之后留下的开放点,已锁部分仅引用)
---
## §1 引用已锁结论(不重述)
本 PRD 是对已有结论的**补丁/收敛**,不替换。已锁部分直接参见以下来源:
| 来源 | 已锁内容 |
|---|---|
| 续接快照 v2 §3 | 横轴公式 `X = 该题材在分析窗口内的均值份额 − 栏目均值份额`,零点 = 栏目均值,单位 = 收视份额绝对差 |
| 续接快照 v2 §4 | 双引擎象限图视觉规格:气泡大小 = 收视份额、气泡颜色 = 收视判定三色、气泡边框 = 开篇钩子三档、重叠用 jitter 解 |
| 主 project Claude 示意图(2026-06-10) | 23 期实际数据 + 模拟纵轴/钩子已可视化,制片人认可"不挤、不堆叠" |
| 续接快照 v3 §1.1 / v4 §3 | 纵轴从 3 档收为 2 档(主线演进 / 并列结构),Prompt 2 v0.2 + ground-truth v0.2.1 M3 100% 锁定 |
| 续接快照 v2 §2 字段二 | `equipment_domain` 多选 9 类:陆战装备 / 海军舰船 / 航空航天 / 导弹与反导 / 信息化 / 后勤保障 / 轻武器 / 跨域 / 其他 |
本 PRD 解决 v2 之后留下的三个开放点:**多标签横轴取值规则、小样本兜底、视觉规格刷新到 2 档纵轴**。
---
## §2 决策一:多标签 → 横轴单点取值规则(Path A 全额法)
`equipment_domain` 字段为多选(至少 1 项),但横轴一期只能落一个点。
### 2.1 规则
**每个 `equipment_domain` 标签独立维护自己的累计均值;一期节目标了 N 个标签,就把该期完整 share 直接记进**每一个**沾上的标签的均值池(全额、不瓜分、不加权)。**
### 2.2 数学定义
```
对每个 equipment_domain 标签 i:
base_i = 所有沾标签 i 的节目的 share 的算术平均
= Σ(share_j, ∀ j 沾标签 i) / count(j 沾标签 i)
栏目均值:
base_全栏目 = 所有节目的 share 的算术平均(单期单算)
每期 ep 的横轴位置:
X(ep) = mean(base_i, ∀ i ∈ ep.equipment_domain) base_全栏目
```
### 2.3 示例
设当前 `海军舰船` 桶均值 = 0.69,`跨域` 桶均值 = 0.79,栏目均值 = 0.72。
- 一期标 `海军舰船 + 跨域`,share = 0.71
- 该期 X 位置 = (0.69 + 0.79) / 2 0.72 = **+0.02**(略偏热)
- 这期 share = 0.71 同时记入 `海军舰船` 均值池(下次 base 重算用)和 `跨域` 均值池
**两点说明**:
1. **均值更新方向自洽**:0.71 < 0.72(栏目均值),也低于"跨域 0.79"。记入两个桶后,两个桶的均值都会被这期略往下拉,符合"低于均值的样本拉低均值"的直觉。
2. **不存在 ×N 放大**:之前讨论过的"按基值加权 × 标签数"方案因方向 bug(低于均值的样本可能反向拉高均值)被否决,详见 2026-06-12 续接讨论。
### 2.4 适用范围
本规则**仅用于横轴 X 值计算**。其他统计(能力地图、编导对比、scene_tags 分布等)的多标签处理另议。
---
## §3 决策二:小样本兜底规则
`equipment_domain` 桶若在当前分析窗口内样本量 n 较小,均值统计意义弱。视觉上需可辨。
### 3.1 兜底分档
| 桶样本量 | 视觉处理 |
|---|---|
| **n ≥ 3** | 正常显示,base 值直接入横轴坐标 |
| **n = 1 或 2** | 桶名右侧显示 `(n=X)` 灰色小字;桶内气泡描边改为虚线浅灰;tooltip 警示"样本不足,横轴位置参考价值有限" |
| **n = 0** | 桶不出现在横轴坐标系上(如 `陆战装备` 在 21 期场景下属此类,预留枚举值但暂不画) |
### 3.2 阈值出处
n = 3 阈值的取法:统计上方差估计起码需 2 自由度,记录方便取 3。**这是初值,后续看实际分布可调**。
### 3.3 当前 21 期场景的小样本桶预测
按 v2 §2 九类 + 我对 21 期的初步映射(见配套回填提案表):
- `导弹与反导` n=1(ep15 一期),**小样本桶**
- `信息化` n=1 或 2(取决于 ep03 是否归这里 vs 跨域),**可能小样本**
- `陆战装备` n=0,**不出现在坐标系**
- `后勤保障` n=0,**不出现在坐标系**
- `其他` n=0,**不出现在坐标系**
其余 4 个桶(`海军舰船` / `航空航天` / `轻武器` / `跨域`)预计 n ≥ 3,正常显示。
---
## §4 决策三:视觉规格刷新(纵轴 3 档 → 2 档)
v2 §4 视觉规格除以下差异外,**全部沿用**:
| 元素 | v2 §4(3 档,旧) | 本版(2 档,新) |
|---|---|---|
| 纵轴档位 | 强主线悬念 / 主线演进 / 并列结构 | **主线演进 / 并列结构**(v3 §1.1 收为 2 档) |
| 纵轴坐标 | 三个水平基线 | 两个水平基线 |
| 同档内 jitter | ±0.3 | ±0.4(档少了,jitter 可适当加大避免聚拢) |
| 中线视觉 | 两条次级分隔 | **一条主分隔线显著加粗**,强调"主线 vs 并列"对照 |
| 上下区视觉重点 | 三层等权 | **两区中性等权**——纵轴不暗示偏好方向,呈现客观对照(2026-06-12 通哥拍板) |
横轴部分全部沿用 v2 §4,无变化。
---
## §5 配套交付清单(子项目本轮其余产出)
- [✅ 本文件] `F3_横轴量化方法_PRD_v1.0草稿.md`
- [⏳ 下批] `双引擎象限图_HTML_mock_v1.0.html`——基于本 PRD 的纵轴 2 档版可视化,可浏览器直开看交互
- [⏳ 下批] `F3_算法验证脚本.py`——在子项目沙盒里跑通完整计算流程,输入 23 期 equipment_domain 多选 + share,输出各桶 base + 23 期 X 值表 + 数据校验报告
- [⏳ 下批] `equipment_domain_字段定义文档.md`——按 Brief §6.1 格式,主 project Cline 拿去做 schema 迁移
- [⏳ 下批] `23期_equipment_domain_回填提案表.md`——给制片人审,或转 Prompt 1a 的 ground-truth 输入
---
## §6 落地依赖(主 project Cline 工作清单)
子项目这边的 5 份交付物全部锁定后,主 project Cline 可接手以下工作(均需切 Plan + Opus 审):
1. **Schema 迁移**:`backend/sql/00X_add_equipment_domain.sql`(基于字段定义文档)
2. **23 期回填**:Prompt 1a 跑批结果落库 + 制片人审过的 8 期标题推断低置信度样本
3. **后端 API endpoint**:横轴聚合数据接口 `GET /api/v1/episodes/quadrant-data`(或类似)
4. **前端 React/ECharts 组件**:基于本 PRD 的 HTML mock 1:1 翻译
---
## §7 后续可能调整项(本版不解,留入 backlog)
- **时间窗口选择**:滚动窗口 vs 全部历史 vs 季度,默认设"全部历史",后续 UI 加切换器
- **n ≥ 3 阈值的实际验证**:用 23 期 + 新片陆续入库 6 个月后看分布,必要时调阈值
- **多标签规则是否升级**:本版用全额路 A,运行半年若发现不妥(如某桶均值长期被高频跨域期数刷高)再议升级到带权或 1/N 守恒版
- **n=1/2 视觉表达细节**:虚线浅灰 vs 描边淡化 vs 加图例,等 HTML mock 出来后定
---
## §8 修订规则
本 PRD 锁定 v1.0 后:
- v1.x 微调(视觉细节、阈值小动)在本子项目内修改
- v2.0 重大变更(规则换路 B、取消纵轴 2 档等)需主 project 同步审,通过新一版续接快照固化
修订必留 changelog,谁、何时、改了什么、为什么改。
@@ -0,0 +1,151 @@
# F3 横轴量化方法 PRD v1.0(草稿)
> 子项目交付物 · 看板分析升级
> 状态:**草稿**,等制片人审 + 锁定后转正式 v1.0
> 起草时间:2026-06-12
> 顾问:Claude Opus 4.7 制片人:刘通
> 类型:薄 PRD(只解 v2 之后留下的开放点,已锁部分仅引用)
---
## §1 引用已锁结论(不重述)
本 PRD 是对已有结论的**补丁/收敛**,不替换。已锁部分直接参见以下来源:
| 来源 | 已锁内容 |
|---|---|
| 续接快照 v2 §3 | 横轴公式 `X = 该题材在分析窗口内的均值份额 − 栏目均值份额`,零点 = 栏目均值,单位 = 收视份额绝对差 |
| 续接快照 v2 §4 | 双引擎象限图视觉规格:气泡大小 = 收视份额、气泡颜色 = 收视判定三色、气泡边框 = 开篇钩子三档、重叠用 jitter 解 |
| 主 project Claude 示意图(2026-06-10) | 23 期实际数据 + 模拟纵轴/钩子已可视化,制片人认可"不挤、不堆叠" |
| 续接快照 v3 §1.1 / v4 §3 | 纵轴从 3 档收为 2 档(主线演进 / 并列结构),Prompt 2 v0.2 + ground-truth v0.2.1 M3 100% 锁定 |
| 续接快照 v2 §2 字段二 | `equipment_domain` 多选 9 类:陆战装备 / 海军舰船 / 航空航天 / 导弹与反导 / 信息化 / 后勤保障 / 轻武器 / 跨域 / 其他 |
本 PRD 解决 v2 之后留下的三个开放点:**多标签横轴取值规则、小样本兜底、视觉规格刷新到 2 档纵轴**。
---
## §2 决策一:多标签 → 横轴单点取值规则(Path A 全额法)
`equipment_domain` 字段为多选(至少 1 项),但横轴一期只能落一个点。
### 2.1 规则
**每个 `equipment_domain` 标签独立维护自己的累计均值;一期节目标了 N 个标签,就把该期完整 share 直接记进**每一个**沾上的标签的均值池(全额、不瓜分、不加权)。**
### 2.2 数学定义
```
对每个 equipment_domain 标签 i:
base_i = 所有沾标签 i 的节目的 share 的算术平均
= Σ(share_j, ∀ j 沾标签 i) / count(j 沾标签 i)
栏目均值:
base_全栏目 = 所有节目的 share 的算术平均(单期单算)
每期 ep 的横轴位置:
X(ep) = mean(base_i, ∀ i ∈ ep.equipment_domain) base_全栏目
```
### 2.3 示例
设当前 `海军舰船` 桶均值 = 0.69,`跨域` 桶均值 = 0.79,栏目均值 = 0.72。
- 一期标 `海军舰船 + 跨域`,share = 0.71
- 该期 X 位置 = (0.69 + 0.79) / 2 0.72 = **+0.02**(略偏热)
- 这期 share = 0.71 同时记入 `海军舰船` 均值池(下次 base 重算用)和 `跨域` 均值池
**两点说明**:
1. **均值更新方向自洽**:0.71 < 0.72(栏目均值),也低于"跨域 0.79"。记入两个桶后,两个桶的均值都会被这期略往下拉,符合"低于均值的样本拉低均值"的直觉。
2. **不存在 ×N 放大**:之前讨论过的"按基值加权 × 标签数"方案因方向 bug(低于均值的样本可能反向拉高均值)被否决,详见 2026-06-12 续接讨论。
### 2.4 适用范围
本规则**仅用于横轴 X 值计算**。其他统计(能力地图、编导对比、scene_tags 分布等)的多标签处理另议。
---
## §3 决策二:小样本兜底规则
`equipment_domain` 桶若在当前分析窗口内样本量 n 较小,均值统计意义弱。视觉上需可辨。
### 3.1 兜底分档
| 桶样本量 | 视觉处理 |
|---|---|
| **n ≥ 3** | 正常显示,base 值直接入横轴坐标 |
| **n = 1 或 2** | 桶名右侧显示 `(n=X)` 灰色小字;桶内气泡描边改为虚线浅灰;tooltip 警示"样本不足,横轴位置参考价值有限" |
| **n = 0** | 桶不出现在横轴坐标系上(如 `陆战装备` 在 21 期场景下属此类,预留枚举值但暂不画) |
### 3.2 阈值出处
n = 3 阈值的取法:统计上方差估计起码需 2 自由度,记录方便取 3。**这是初值,后续看实际分布可调**。
### 3.3 当前 21 期场景的小样本桶预测
按 v2 §2 九类 + 我对 21 期的初步映射(见配套回填提案表):
- `导弹与反导` n=1(ep15 一期),**小样本桶**
- `信息化` n=1 或 2(取决于 ep03 是否归这里 vs 跨域),**可能小样本**
- `陆战装备` n=0,**不出现在坐标系**
- `后勤保障` n=0,**不出现在坐标系**
- `其他` n=0,**不出现在坐标系**
其余 4 个桶(`海军舰船` / `航空航天` / `轻武器` / `跨域`)预计 n ≥ 3,正常显示。
---
## §4 决策三:视觉规格刷新(纵轴 3 档 → 2 档)
v2 §4 视觉规格除以下差异外,**全部沿用**:
| 元素 | v2 §4(3 档,旧) | 本版(2 档,新) |
|---|---|---|
| 纵轴档位 | 强主线悬念 / 主线演进 / 并列结构 | **主线演进 / 并列结构**(v3 §1.1 收为 2 档) |
| 纵轴坐标 | 三个水平基线 | 两个水平基线 |
| 同档内 jitter | ±0.3 | ±0.4(档少了,jitter 可适当加大避免聚拢) |
| 中线视觉 | 两条次级分隔 | **一条主分隔线显著加粗**,强调"主线 vs 并列"对照 |
| 上下区视觉重点 | 三层等权 | 上区(主线演进)略亮、下区(并列结构)略灰,**视觉上暗示偏好方向**(可选,等通哥决) |
横轴部分全部沿用 v2 §4,无变化。
---
## §5 配套交付清单(子项目本轮其余产出)
- [✅ 本文件] `F3_横轴量化方法_PRD_v1.0草稿.md`
- [⏳ 下批] `双引擎象限图_HTML_mock_v1.0.html`——基于本 PRD 的纵轴 2 档版可视化,可浏览器直开看交互
- [⏳ 下批] `F3_算法验证脚本.py`——在子项目沙盒里跑通完整计算流程,输入 23 期 equipment_domain 多选 + share,输出各桶 base + 23 期 X 值表 + 数据校验报告
- [⏳ 下批] `equipment_domain_字段定义文档.md`——按 Brief §6.1 格式,主 project Cline 拿去做 schema 迁移
- [⏳ 下批] `23期_equipment_domain_回填提案表.md`——给制片人审,或转 Prompt 1a 的 ground-truth 输入
---
## §6 落地依赖(主 project Cline 工作清单)
子项目这边的 5 份交付物全部锁定后,主 project Cline 可接手以下工作(均需切 Plan + Opus 审):
1. **Schema 迁移**:`backend/sql/00X_add_equipment_domain.sql`(基于字段定义文档)
2. **23 期回填**:Prompt 1a 跑批结果落库 + 制片人审过的 8 期标题推断低置信度样本
3. **后端 API endpoint**:横轴聚合数据接口 `GET /api/v1/episodes/quadrant-data`(或类似)
4. **前端 React/ECharts 组件**:基于本 PRD 的 HTML mock 1:1 翻译
---
## §7 后续可能调整项(本版不解,留入 backlog)
- **时间窗口选择**:滚动窗口 vs 全部历史 vs 季度,默认设"全部历史",后续 UI 加切换器
- **n ≥ 3 阈值的实际验证**:用 23 期 + 新片陆续入库 6 个月后看分布,必要时调阈值
- **多标签规则是否升级**:本版用全额路 A,运行半年若发现不妥(如某桶均值长期被高频跨域期数刷高)再议升级到带权或 1/N 守恒版
- **n=1/2 视觉表达细节**:虚线浅灰 vs 描边淡化 vs 加图例,等 HTML mock 出来后定
---
## §8 修订规则
本 PRD 锁定 v1.0 后:
- v1.x 微调(视觉细节、阈值小动)在本子项目内修改
- v2.0 重大变更(规则换路 B、取消纵轴 2 档等)需主 project 同步审,通过新一版续接快照固化
修订必留 changelog,谁、何时、改了什么、为什么改。
@@ -0,0 +1,224 @@
# 跨 project 协作 — 制片人随身提示单
> 用途:每次想在主项目之外单开子 project 讨论某个模块时,照此提示单走一遍,避免漏环节、避免版本错位、避免子项目设计违反主项目宪法。
> 适用:刘通在 Claude 网页版多 project 工作流下的所有"主项目 + 子项目"场景。
> 维护人:刘通 + 主 project 顾问 (Claude Opus 4.7)
> 首版日期:2026-06-11
---
## 〇、什么是 PRD
**PRD = Product Requirements Document,产品需求文档**
把"我想要个东西"翻译成"工程师可以照着做的具体规格"。一份合格的 PRD 回答:
- 为什么做:解决谁的什么痛点
- 做什么:功能边界、必做/不做
- 怎么用:用户走完流程的样子
- 数据形态:输入什么、输出什么、字段怎样
- 不做什么:明确划红线,防止范围蔓延
子项目立项时,请那边的 Claude 写一份 PRD 跟主项目对接——这就是工程界的标准操作。
---
## 一、先判断:这事适不适合分子 project?
分之前先想三个问题。三条都满足才适合分:
1. **这个模块与主项目耦合深不深?** 耦合深的(改用户体系、改权限)就别分,分了沟通成本比省下的还高。
2. **这个模块边界清不清?** 输入输出明确的(如分钟收视回放)分得开;边界模糊的(如"优化整体视觉风格")分不开。
3. **工作量够不够大?** 特别小的事(改个字段名)直接在主项目谈完即可。三五次对话讨论不完的,才值得分。
**反例**:未来想做"AI 自动生成报题单"——这件事跟主项目的 TPS 模块、知识库、收视数据、编导画像全打通,**强耦合**,分子 project 反而割裂上下文。这种就在主项目里推进。
**正例**:分钟收视回放、本地切图工具、外拍资源管理子模块——边界清晰,可独立设计。
---
## 二、流程(四步)
### 步骤 1:在主项目立"项"——先打招呼
子项目开干**之前**,先在主项目 chat 里跟 Claude 顾问说一声:
> "我要开一个子 project 讨论 X 模块,目标是 Y。"
主项目 Claude 会做两件事:
- 检查 X 是否真的适合分出去(参照第一节三问)
- 把主项目跟 X 相关的红线、技术栈、宪法摘出来给你
**实操**:把这些"开局材料"打包好,作为子项目的 files 上传过去(至少包括 `.clinerules``project_plan.md``dev_plan.md`,必要时加相关的 phase log)。子项目 Claude 能读到这些,就能少犯错。
**这一步不能省**。子项目 Claude 看不到主项目宪法时,会本能地按自己的最佳实践设计——很可能违反主项目某条红线。
### 步骤 2:在子项目讨论、迭代、收敛
要点:
- 子项目**不写主项目的代码**,只输出文档、demo、独立小工具
- 子项目**不改主项目的 schema**,所有涉及主项目数据库结构的提议,回主项目让 Claude 顾问审
- 子项目**遇到吃不准的事,回主项目问**——以提问列表的形式(参考秒级 chat 那份 PRD 第八节的 6 问)
### 步骤 3:子项目凝结成"交付包"
讨论完不能就这么散了。要凝结成可以跨 chat、跨 project、被未来任何人接手的产物。**详见下面第四节五份交付物**。
**关键认知**Claude 的 chat 越长,判断力越下降(上下文太满);而且新 chat 一开就丢了。**md 文档才是真正的产物,chat 只是过程**。讨论一收敛,赶紧让子项目 Claude 凝结成 md。
### 步骤 4:回主项目整合
带着交付包回主项目:
- 主项目 Claude 顾问审一遍交付包,看跟主项目红线有没有冲突
- 没冲突 → 在主项目 workspace 里让 Cline 落代码
- 有冲突 → 标出冲突点,回子项目修,循环
**主项目顾问对子项目交付物有否决权**。听起来霸道,但必要——子项目 Claude 不知道主项目全部红线。这一步省不掉。
---
## 三、规范:跨 project 文档怎么写
做对四件事,文档传递不会乱。
### 规范 1:文件名带版本号
`分钟收视需求规格.md`
`分钟收视需求规格_v1.md`
下次改了就 v2。**绝对不要原地覆盖**——历史版本要留着,方便回看"我们当时为什么这么定"。
### 规范 2:文档顶部固定"元信息块"
每份跨 project 文档第一段必须有:
```
> 版本:v1
> 日期:2026-06-11
> 作者:[谁写的]
> 状态:[草稿 / 待主项目审 / 已采纳 / 已作废]
> 上一版:[v0 或"无"]
> 主要变化:[v2 才需要写]
```
这块 6 行,写起来不累,但是救命。**没有这个块的跨 project 文档,主项目这边可以拒收**。
### 规范 3:一份文档只谈一件事
不要在"分钟收视需求规格"里顺带讨论"用户管理优化"。串了就乱。
### 规范 4:主项目这边定期回收
子项目讨论完、文档传过来、整合完成后,把最终采纳的那份 md 放到主项目的 `docs/cross_project/` 目录里。这是主项目的"对外接口档案库"。
---
## 四、最终交付物:子项目结束时该产出什么(五份)
子项目结束时,告诉那边的 Claude:
> "请把所有讨论凝结成最终交付包,包含以下五份产物。"
### 产物 1:决策摘要 md
记录子项目全程的关键决策。每条三句话:
```
决策 X[一句话决策内容]
- 背景:为什么需要这个决策
- 拍板理由:选这条不选那条的理由
- 拍板人:[制片人 / 主项目顾问 / 子项目 Claude 建议+制片人采纳]
```
不需要"我们讨论了 47 轮"的过程,只要最终结论。10-20 条就把整个子项目的"为什么这么做"讲清。
### 产物 2:接口约定 md(最技术、最精确)
把子板块与主项目接驳的所有"接口"白纸黑字写出来。"接口"是广义的,包括:
- **数据接口**:要新建哪些表、哪些字段、字段类型、约束
- **API 接口**:要新增哪些后端 endpoint、URL、方法、请求体、响应体、错误码
- **UI 接口**:要在主项目哪个页面挂载这个模块、入口在哪、路由怎么走
- **权限接口**:哪些角色可以做什么操作
- **存储接口**:文件存到哪个目录、命名规则、URL 怎么拼
每一条都要具体到"主项目的 Cline 拿着这份就能写代码"的程度。**这份是子项目给主项目的"合同"**。
### 产物 3:实物交付(独立工具、demo、设计稿)
子项目特有的产物。视模块性质不同:
- 分钟收视回放子项目 → 本地切图工具 (py + exe + 使用说明)
- 视觉重设计子项目 → 设计稿(Figma / HTML demo
- 数据分析子项目 → 离线分析脚本 + 示例输出
这些东西**与主项目零耦合**,自己能独立运行。
### 产物 4:未尽事项 backlog
诚实写出"子项目讨论中提到但没做的事"。每条三行:
- 是什么
- 为什么没做(暂缓 / P1+ / 等条件成熟)
- 触发时机
放进主项目的 backlog 池子里,未来某个 Phase 收尾时回看,决定哪条捞进下个 Phase。
### 产物 5:给主项目 Claude 顾问的"接手提示词"
一两段话,告诉主项目顾问"如果你是接手这件事的 Claude,最重要的三件事是 X、Y、Z"。
这段相当于一份"防止主项目这边犯傻"的备忘,往往是最有价值的一份。
---
## 五、操作过程中的实操注意点
### 注意 1:永远以 md 为准,不要口头转述
❌ "那边 Claude 说 XX",然后跟那边说"主项目这边说 YY"
✅ 所有跨项目沟通**以 md 文档为准**
口头转述会丢细节、会失真,连续转两次就跟最初的意思差很远。
### 注意 2chat 是过程,md 是产物
子项目 chat 长了之后,Claude 自己的判断力会下降(上下文太满),换新 chat 就丢了。**讨论一收敛,赶紧让子项目 Claude 凝结成 md。chat 可以扔,md 不能扔**。
### 注意 3:主项目顾问的"审查"环节不能省
子项目 Claude 不知道主项目的全部红线,可能输出违规方案。**拿到子项目交付包后,先来主项目让顾问审一遍,再让 Cline 落实施**。这一步省不掉。
### 注意 4:每个子项目最长不要超过 3-4 周
时间越长,跟主项目脱节越严重(主项目可能在这期间已经迭代)。如果一个子项目超过 4 周还没收敛,应该停下来重新评估:是不是分得太大?要不要切成更小的子子项目?
### 注意 5:交付包归档到主项目仓库
交付完成后,五份交付物放到主项目的 `docs/cross_project/{子项目名}/` 目录里。**版本号文件全部保留**,未来回看决策史时会用到。
---
## 六、一句话总结
> **子项目专心做事不出主项目;主项目负责审查与整合,不掺合子项目讨论;md 文档是跨项目通信的唯一介质;版本号 + 元信息块永远不省。**
---
## 七、复盘提示(每次子项目结束后回看一次)
子项目结束,回过头来问自己:
1. 这次分子项目是不是真的提高了效率?还是反而增加了沟通成本?
2. 主项目顾问审查时发现了多少个违规设计?说明子项目立项时给的"开局材料"够不够?
3. 五份交付物齐了吗?哪份最有用?哪份没人看?
4. 这次的经验,要不要加进本提示单的下一版?
**本提示单本身也按版本管理**。每次复盘有沉淀就出 v2。
---
*v1 由主 project 顾问 (Claude Opus 4.7) 协助刘通于 2026-06-11 整理成稿。下次修订时机:第一次完整跑完一个子项目(分钟收视回放)之后。*
+144
View File
@@ -0,0 +1,144 @@
# Doco 文稿整理子项目 Brief
> 主项目 → 子项目的"交接宪法":红线、技术栈、出入口接口
> 起草日期:2026-06-12
> 状态:主项目签发,子项目内部不修改
---
## 一、为什么做
**痛点**:《军事科技》每期节目播出后,产出一份贴近实际播出的终版文稿,过去靠人工对照 A 稿(编导定稿)+ 录音转写 + OCR 字幕反复核对,**单期 4-6 小时**,且容易遗漏错字、整段重写、编导笔误。
**升级目标**:把"三方文本 → 终版文稿 + 差异报告"做成可自动化的流水线模块。
**现状起点**:demo 已用《现代防空反导大对决》一期跑通,效果达标。栏目组改变了素材输出方式——直接产出"黑底白字+干净人声"的特殊视频——使物理输入从 3 路(A 稿+B 稿+ASR)收敛到 2 路(A 稿+视频),但**逻辑上仍然三方融合**(A 稿+B 路视频字幕 OCR+音轨 ASR)。
---
## 二、做什么(功能边界,只列名)
| 模块 | 简述 |
|---|---|
| 视频双路拆分 | ffmpeg 抽帧+字幕变化检测+OCR → B 稿;ffmpeg 抽音轨 → 16k WAV |
| 讯飞 ASR 适配层 | 复用 demo 跑通的 `xfyun_asr_standard.py`,替换凭证 |
| 三方融合引擎 | 规则层(Python)+ AI 层(Claude Sonnet 4.6),demo 已锁 |
| 单期处理接口 | CLI + Python API,契约见主项目回复 §Q3 |
| Golden test | 用 demo 那期视频做零回归验证 |
| 23 期批量调度入口 | 单期接口的批量调用方式,具体编排不在本子项目 |
**具体怎么做,子项目内部讨论,本 Brief 不预设方案。**
---
## 三、怎么用(目标流程)
**单期处理**:
1. 责编/编排层在 episodes 表落库该期,拿到 INT 主键
2. 拼出 episode_id:`ep{NNN}_{YYYYMMDD}_{slug}`
3. 把视频和 A 稿放进 `programs/{episode_id}/source/`
4. 调 doco:`doco.process_episode(episode_id, video_path, a_draft_path, output_dir)`
5. 产物落 `programs/{episode_id}/output/`:终版 docx + 差异报告 + needs_review JSON
6. 编导/制片人审 needs_review 队列,决定接受 / 拒绝 / 编辑
**23 期批量**:用同一接口循环调用 23 次,失败重试 + 进度跟踪由调用方负责。
**降级回退**:若某期视频不符合"黑底白字+干净人声"条件,通过 feature flag 切换到旧流程(独立 mp3 + 上游 OCR)。
---
## 四、不做什么(红线)
子项目设计任何方案,**绝不**触碰以下:
-**不动 demo 已锁的算法层**(三方融合优先级 / 时间戳容忍 ±5s / 口语清理三档 / 改动确信度阈值 0.85/0.6 三段)
-**不引入 `ffmpeg-python` 等 wrapper**(用 subprocess 调系统 ffmpeg)
-**不替换 AI 融合层模型**(Claude Sonnet 4.6 已锁,不临时换 DeepSeek 等)
-**不复用主 project 那把 DeepSeek key**(Cline 工具用的 key 跟生产业务分开)
-**不把凭证写进主 project 的 `backend/.env`**(子模块自治,各自 .env)
-**不假设 episode_id 命名规则**(由调用方给定,doco 只当字符串用)
-**不引入主 project 没有的技术栈**(继续 Python 3.x + Claude API + 讯飞 API)
-**不自己实现批量调度**(失败重试 / 并发控制 / 进度跟踪属于编排层职责)
-**不在子项目里写中台密钥服务**(那不属于 doco 范围)
---
## 五、技术栈约束(继承主 project)
- **运行环境**:Python 3.x(版本对齐 backend),Windows / Linux 都可跑
- **系统依赖**:ffmpeg ≥ 4.x(子模块文档明确列出)
- **AI 融合**:Anthropic Claude API,模型 `claude-sonnet-4-6`
- **OCR**:DeepSeek Vision API(主项目已批,Q1)
- **ASR**:讯飞开放平台 录音文件转写标准版(**不要用大模型版**——`language` 参数被阉割)
- **音频规格**:16kHz / 单声道 / 16bit WAV(讯飞规格)
- **数据格式**:句子级时间戳统一 `[Nm Ns] 句子` 格式
---
## 六、交付什么(出口接口)
子项目最终交付物以下面形式回到主 project,**必须满足以下接口**:
### 6.1 模块交付物
- `doco/` Python 包,可被主 project 编排层 import
- CLI 入口:`doco process ...`
- 单元测试 + golden test(demo 那期零回归)
- `README.md`:系统依赖、安装、使用、配置
### 6.2 配置与凭证
- doco 自己的 `.env`(讯飞 + DeepSeek + Claude 三套 key 各自管)
- 主项目仓库根目录的 `docs/api_credentials_inventory.md` 登记一行 doco 的凭证元信息(不存真实 key)
### 6.3 数据资产沉淀(可入 TPS 中台共享)
- A 稿术语表(每期处理时从 A 稿提取,可入主 project 数据库的 terms 维度)
- OCR 错字映射表(demo 已整理,固定字形混淆对)
### 6.4 不接受
- 子项目自己改主 project 的 backend 代码、schema、迁移
- 子项目自己写主 project 的前端 UI(编导确认 UI 属于上层,不在 doco 范围)
- 子项目自己定 episode_id 命名规则(由主项目给定)
---
## 七、入口接口(子项目要知道的主 project 现状)
- **主项目没有 OCR 子模块**(已确认,Q1)
- **主项目没有视频处理服务**(已确认,Q2)
- **主项目没有节目素材批量编排层**(已确认,Q3)
- **主项目没有中台密钥服务**(已确认,Q4)
- **主项目没有节目素材目录规约**(已确认,Q5,本子项目带头定 `programs/{episode_id}/...`)
- **主项目有 episodes 表**(INT 自增主键),doco 用 episode_id 时假定调用方已落库
---
## 八、未决项(归子项目自己拍板)
以下不在本 Brief 内预设,**由子项目和制片人讨论决定**:
- 视频抽帧的具体策略(关键帧检测算法 / 抽帧密度 / 字幕变化阈值)
- DeepSeek Vision 调用的具体 prompt 设计
- 规则层 OCR 错字映射表的具体扩展机制
- AI 融合层的具体提示词迭代
- needs_review JSON 的具体字段(在 demo 基础上演化)
- 单元测试覆盖率目标
- 子项目内部的 git 分支策略 / 版本号约定
---
## 九、决策史指向(不重复内容)
子项目讨论前必读:
- `doco_project_design.md / .docx`(三方融合算法层,demo 沉淀,已锁)
- `doco_xfyun_integration_notes.md / .docx`(讯飞 ASR 接入 15 个坑)
- `doco_handoff_to_opus_chat.md / .docx`(子项目立项前的 opus 接手提示)
- `PRD_doco_文稿整理子项目_v2.md`(当前子项目的请求稿)
- `主project对Doco_PRDv2的回复.md`(主项目的批复)
---
## 十、本 Brief 自身的修订规则
- 本 Brief 不在子项目内修改
- 红线 / 技术栈如有变更,**主 project 这边发新版**,通过寄存条同步
- 子项目可在自己的 chat 里讨论"建议主 project 调整某条红线",调整动作只能在主 project 发生
- 子项目每次出新版 PRD,主项目顾问发新版回复;两者形成 PRD vN ↔ 回复 vN 的对照关系
@@ -0,0 +1,295 @@
# PRD · Doco 文稿整理模块 · 视频源改造方案
> 版本:v2
> 日期:2026-06-12
> 作者:子 project ClaudeOpus 4.7
> 状态:草稿 / 待主项目审
> 上一版:v1(2026-06-12 同日,更早一稿)
> 主要变化:
> 1. **子模块正式定名为「Doco 文稿整理模块」**(v1 沿用旧称"TPS 三方融合子模块",本版起全部改用 Doco;Q6 已由制片人拍板,不再列为待决问题)
> 2. **Q1(OCR 选型)方向更新**:制片人确认"软件离线刚需"已不成立,云端方案可接受。补充查清的关键事实:**讯飞 OCR 与 STT 共享鉴权凭证但套餐/余额各自独立**——按制片人原判据"如果能通用 token 订阅和余额就选讯飞"不成立。**新推荐方案:DeepSeek API**(制片人手上已有),并向主项目确认是否已有 OCR 能力或 LLM 视觉调用基础设施
> 3. 其他 QQ2/Q3/Q4/Q5)保持不变
---
## 〇、一段话摘要(给主 project 顾问的最短摘要)
Doco 文稿整理模块(前称"TPS 三方融合子模块")此前的物理输入是 A 稿 docx + B 稿 OCR txt + ASR txt(mp3→讯飞)。栏目组现在改了素材输出方式:责编一次性输出 23 期"特殊视频"——画面是黑底白字唱词字幕、声音是无 BGM/音效的干净人声(极少同期声杂音)。**B 稿与 ASR 现在同源派生于一个视频文件**,物理输入从 3 个收敛到 2 个(A 稿 + 视频)。
**核心判断**:下游"三方融合引擎"(规则层 + AI 层)算法**零侵入**——只要新增的"视频双路拆分"模块输出与旧版 B 稿/ASR txt 格式完全一致(`[Nm Ns] 句子`),下游所有逻辑不动。**逻辑上仍然是三方融合**——A 稿术语权威 + B 路视频字幕 OCR + 音轨 ASR,三路独立验证的关系没破。
子项目这边需要主 project 在开工前对 5 件影响接口/数据形态的事拍板。详见 §4。
---
## 一、变更前后对照
### 旧设计(demo 已验证)
```
[A 稿 docx] ──────────────────────┐
[上游既有 OCR 流程] ── B 稿 txt ──┤
├─► [三方融合引擎] ─► 终版.docx + 差异报告.docx
[节目纯净人声 mp3] │
│ │
└─► [讯飞 ASR] ── ASR txt ─┘
```
### 新设计(本 PRD 提出)
```
[A 稿 docx] ─────────────────────────────────────┐
[节目特殊视频文件] │
画面:黑底白字字幕 │
声音:干净人声 │
│ │
├─► [视频双路拆分子模块 · NEW] │
│ │ │
│ ├─► ffmpeg 抽帧+字幕变化检测 │
│ │ │ │
│ │ └─► [OCR] ── B 稿 txt ──────┤
│ │ (待 Q1 拍板用 DeepSeek) ├─► [三方融合引擎] ─► 终版 + 差异
│ └─► ffmpeg 抽音轨 → 16k/mono WAV │ (复用)
│ │ │
│ └─► [讯飞 ASR · 复用] │
│ └────── ASR txt ──────┘
└─ (后续接 23 期批量调度)
```
### 关键变化清单
| 项 | 旧 | 新 |
|---|---|---|
| 子模块名称 | TPS 三方融合子模块 | **Doco 文稿整理模块** |
| 物理输入 | A 稿 + B 稿 + ASR | A 稿 + 视频 |
| 逻辑融合方 | 三方 | **仍然三方**A / B 路 / ASR 路) |
| B 稿来源 | 上游既有 OCR 流程 | 视频抽帧 → OCR |
| ASR 来源 | 节目 mp3 | 视频音轨 |
| 算法层 | 规则层 + AI 层 | **不变** |
| 新增模块 | — | 视频双路拆分(ffmpeg + OCR |
| 处理粒度 | 单期 | 单期接口 + 23 期批量调度 |
---
## 二、子项目这边已经拍板的事(不需要主 project 决策,仅告知)
### 2.1 制片人已明确的决策
1. **子模块定名****Doco 文稿整理模块**"Doco" 取意"Documentation Consolidation"——文稿整合)。本 PRD 起所有引用旧称("TPS 三方融合子模块"、"三方融合")的地方都用新名替换。
2. **离线不再是刚需**:原 v1 推荐 PaddleOCR 本地的核心理由(离线刚需)失效;OCR 选型转向云端。
### 2.2 demo 已验证或设计文档已定义的事
不变:
1. **三方融合优先级**(A 稿术语权威 / ASR 口吻 / B 稿验证)—— 见 project_design.md §5.1
2. **时间戳容忍度 ±5 秒** —— project_design.md §5.2
3. **口语清理三档**keep_all / medium / clean)—— project_design.md §5.3
4. **改动确信度阈值**0.85 自动 / 0.60.85 黄标 / <0.6 待确认)—— project_design.md §5.4
5. **AI 融合层模型**Claude Sonnet 4.6 起步
6. **差异报告格式**demo 黄金对照已落定
7. **A 稿术语表数据结构**project_design.md §9.1
8. **OCR 错字映射表**:复用 demo 整理的字形混淆对
---
## 三、子项目这边的开发计划草案(待主 project 审)
| Phase | 内容 | 产物 | 主依赖 |
|---|---|---|---|
| P1 | 视频双路拆分预处理(单期)| `video_split.py`:视频 → 抽帧+字幕变化检测+OCR → B稿.txt;视频 → 音轨 → 16k WAV | ffmpeg、OCR(待 Q1 拍板,倾向 DeepSeek API |
| P2 | 讯飞 ASR 适配层 | 复用 `xfyun_asr_standard.py`,替换新凭证、做成可被 P1 流水线调用的模块 | 讯飞开发端密钥(待 Q4 拍板) |
| P3 | Doco 融合引擎 | 规则层 Python + AI 层 Claude API;输入 A/B/ASR 三方 txt,输出终版 docx + 差异报告 + needs_review JSON | Claude API |
| P4 | 单期端到端 golden test | 用 demo 那期《现代防空反导大对决》的视频跑一遍,与 demo 产物比对,确认零回归 | 上面三 phase |
| P5 | 23 期批量 | 单期模块包成可被批量调度调用的接口(CLI / Python API 二选一,待 Q3 拍板) | — |
---
## 四、需要主项目决策的 5 个问题
> 每条都给了子项目这边的推荐答案 + 理由。主项目顾问可以照单批,也可以推翻。
### Q1. OCR 方案选型?
**问题**:B 路 OCR 用什么?这是新引入的依赖,绕不开。
#### Q1.A 关键事实(更新自 v1
子项目这边查清了几件事,供主项目决策参考:
1. **讯飞 OCR 与 STT 的共享情况**
- 鉴权凭证(开发者账号、APPID、APIKey、APISecret**可共享**,一组凭证可同时调用多个服务
- 但**套餐/计费/余额各自独立**:STT 是"5 小时免费试用包"独立购买;OCR 是另一套计费体系(参考 SaaS 零售价 4.9 元/10 张、9.9 元/50 张)。**不存在用 STT 的余额跑 OCR 这种事**
- **按制片人原判据("如果能通用 token 订阅和余额就选讯飞")此条件不成立**
2. **制片人手上已有的 API**
- **DeepSeek**:有专门的 `DeepSeek-OCR` 模型(OCR 2.0 方案,对中文文档识别准确率行业领先)+ DeepSeek Vision 识图模式(官方 API endpoint)。**推荐**
- **MiniMax**:有 MiniMax-VL 视觉模型,理论上可 OCR,但 OCR 专项优化不如 DeepSeek-OCR
- **小米 MiMo**:主推推理模型,未见明确的视觉/OCR 能力
3. **本场景的 OCR 难度评估**
- 输入图像是**黑底白字纯字幕画面**——OCR 最简单的子集(高对比度、印刷体、无图案干扰、无版面分析)
- LLM 视觉模型在此场景几乎不会出错;用 LLM 做 OCR 在这里不是杀鸡用牛刀,因为成本极低且无新增依赖
4. **成本估算(23 期总量)**
- 单期约 300 条字幕(demo 数据),23 期 ≈ 6900 张图
- DeepSeek Vision API 单张成本约几厘到一分,**总成本预估 50–150 元**
- 对比讯飞 OCR SaaS 零售价:6900 张 × 0.198 元/张 ≈ 1370 元
- 对比 PaddleOCR 本地:0 元但需要维护本地环境(已不是刚需)
#### Q1.B 选项与推荐
**选项**
- A. **DeepSeek API(视觉模型)**——制片人已有 API,无新增订阅
- B. **讯飞 OCR**——与 STT 同账号但余额独立
- C. **PaddleOCR 本地**——零成本但需本地环境
- D. **主 project 已有的 OCR 服务**——如果存在
**子项目推荐**ADeepSeek API
**理由**
- 满足制片人"用现有 API 资源"的方向
- 黑底白字字幕是 LLM 视觉模型的舒适区,识别质量有保障
- 与讯飞 STT 解耦,单点故障范围小
- 成本最低(除 PaddleOCR)且无本地环境维护成本
**请主项目确认**
- 主 project 是否已有 OCR 子模块/能力?(制片人初步判断"主 project 应该没有 OCR 配置",请顾问最终确认)
- 主 project 的密钥管理体系是否已经接入 DeepSeek?还是需要 Doco 子模块自行管理 DeepSeek 凭证?
- 6900 张图调用 DeepSeek 是否会影响主 project 其他模块的 DeepSeek 配额/限流?
---
### Q2. 视频处理依赖(ffmpeg)的入口?
**问题**:抽帧与抽音轨都依赖 ffmpeg。
**选项**
- A. Doco 子模块自带 ffmpeg 系统依赖 + Python 封装(`ffmpeg-python` 或 subprocess
- B. 主 project 有统一的视频处理服务/适配层
**子项目推荐**A,使用 subprocess 调用系统 ffmpeg
**理由**:ffmpeg 是标准工具,独立部署足够简单。
**请主项目确认**:是否已经有视频处理子模块/服务在规划中?如有,应改走中台接口。
---
### Q3. 23 期批量 vs 单期接口?
**问题**:本次实际场景是 23 期,Doco 子模块的接口应该长什么样?
**选项**
- A. 子模块只负责单期,输入 = 1 视频 + 1 A 稿;批量调度交给主 project 编排层
- B. 子模块内部支持批量,输入 = 视频目录 + A 稿目录
- C. 两者都提供
**子项目推荐**A(子模块只对单期负责)
**理由**
- 单一职责原则。批量调度涉及失败重试、进度跟踪、并发控制——属于编排层职责
- 单期接口在出错时定位简单(哪期失败、失败在哪个 phase 一目了然)
- 主 project 未来可能有节目档案库流水线、报题单流水线等,统一在编排层做并发更合理
**请主项目确认**
- 主 project 是否计划做"节目素材批量处理编排层"?如有,Doco 的单期接口应满足什么样的契约(CLI?Python API?返回值结构?)
- 23 期这次是先单期跑通再批量,还是要求一次性 batch?
---
### Q4. 讯飞密钥更新/续费策略?
**问题**:demo 凭证可能已过期(制片人提示"讯飞试用可能也过了"),且需要区分**消费端**(讯飞听见 App)与**开发端**(开放平台)。
**选项**
- A. Doco 子模块各自申请新凭证、各自管理
- B. 接入中台统一密钥服务(如果有)
- C. 申请新凭证 + 写入"中台密钥资产文档"作为登记
**子项目推荐**C
**理由**:现阶段中台密钥服务可能未完成,但密钥归属、过期日期、所属子模块应该有统一登记入口。
**请主项目确认**
- 中台是否已有密钥管理子模块?
- 新申请的讯飞开发端密钥(包括 APP_ID、SECRET_KEY、5 小时免费试用包激活状态)应该登记在哪里?
- 如果 Q1 拍板用 DeepSeekDeepSeek API key 是否也按同样规则登记?
---
### Q5. 目录结构与命名规约?
**问题**:23 期素材、抽帧产物、wav、终版 docx 的存储路径需要规约,否则后期归档混乱。
**子项目草案**
```
programs/
└── {episode_id}/ # 例:20260612_防空反导
├── source/
│ ├── video.mp4 # 原始特殊视频(黑底白字+干净人声)
│ └── a_draft.docx # A 稿(编导定稿)
├── work/ # 中间产物(可清理)
│ ├── frames/ # 抽出的字幕关键帧
│ ├── audio_16k.wav # 抽音轨标准化产物
│ ├── b_draft.txt # OCR 产物(带 [Nm Ns] 时间戳)
│ ├── asr_result.txt # 讯飞 ASR 产物
│ └── asr_result_raw.json # 讯飞原始返回
└── output/ # 主产物(入档案库)
├── final.docx # 终版文稿
├── diff_report.docx # 差异报告
└── needs_review.json # 待编导确认队列
```
**请主项目确认**
- TPS 中台是否对节目素材的目录有统一规约?
- `episode_id` 命名规则是什么?(日期+栏目+期号?UUID?编导给定?)
- `work/` 中间产物保留多久?是否要自动清理?
---
## 五、不向主项目提问、但需要告知的事
1. **demo 的 5 份 fixture 仍然有效**A 稿 / B 稿 / ASR / 终版 / 差异报告 在新流程下都可作为单元测试与集成测试的黄金对照
2. **讯飞 ASR 脚本仍然有效**`xfyun_asr_standard.py` 只需替换凭证、把"音频文件路径"参数从"独立 mp3"改为"视频抽音轨产物 wav"
3. **23 期之后的常态化问题**:栏目组以后是否每期都按"黑底白字+干净人声"特殊视频出素材?还是只这一批 23 期是特例?这影响 Doco 子模块要不要保留旧的 mp3+独立 OCR 流程作为回退路径。**建议主项目顾问直接跟栏目组确认**
---
## 六、给主项目顾问的"接手提示词"
如果主 project 顾问要审这份 PRD,最重要的三件事:
1. **算法层零侵入是 demo 验证过的硬保证**。任何改动如果会让 P3(Doco 融合引擎)必须改算法,需要警惕——大概率是输入数据形态没对齐。
2. **OCR 选型(Q1)和目录规约(Q5)是会广泛影响其他子模块的事**,主项目顾问视野更大,应该是这两条的最终拍板人。如果主 project 有 OCR 能力或 DeepSeek 集成基础设施,Q1 的子项目推荐随时可被覆盖。
3. **23 期是一次性还是常态化(§5 第 3 条)是个产品问题,不是技术问题**,建议主项目顾问直接跟栏目组确认后再批 PRD。
---
## 七、回复期望
子项目这边等以下确认才正式开干:
- Q1(OCR 选型)—— 必须先答,否则 P1 不能开始
- Q4(讯飞密钥)—— 必须先答,否则 P2 不能开始
- Q5(目录规约)—— 必须先答,否则 P1 输出无处可放
- Q3(接口契约)—— P5 之前必须答
- Q2 —— Doco 子模块可以先按推荐方案开干,主项目随后批
收到主项目 Claude 顾问的回复 md 后,Doco 子项目这边出 PRD v3(含元信息块标注"上一版:v2"),再启动 P1。
---
## 八、版本变更摘要
| 版本 | 日期 | 主要变化 |
|---|---|---|
| v1 | 2026-06-12 | 首版。6 个待决问题(含子模块命名 Q6)。OCR 选型推荐 PaddleOCR 本地 |
| **v2** | **2026-06-12** | 子模块定名"Doco 文稿整理模块"Q1 改推荐 DeepSeek API(基于讯飞 OCR/STT 余额独立的事实查清 + 制片人手上已有 API 资源);Q6 已拍板移出待决列表;剩余 5 个待决问题 |
---
*v2 由 Doco 子 project ClaudeOpus 4.7)于 2026-06-12 拟稿,遵照《跨 project 协作提示单 v1》§三的规范。*
+103
View File
@@ -0,0 +1,103 @@
# Handoff to opus_chat · TPS三方融合子模块
> 这份是发给中台 opus_chat 的最短交接说明。完整设计见 `project_design.md`。
---
## 这是什么
《军事科技》TPS(终版文稿生成中台)下的一个子模块,叫"三方融合"。
**它做的事**:把三份资料合并成一份贴近实际播出的终版 docx 文稿,并生成一份差异报告。
三份资料是:
1. **A 稿** — 编导手写定稿(docx,有【主持人N】【解说N】【专家N】【动画N】结构标签)
2. **B 稿** — OCR 扒词(txt,带 `[Nm Ns]` 时间戳,有 OCR 错字)
3. **ASR** — 讯飞录音文件转写结果(txt,带 `[Nm Ns]` 时间戳,有同音误识)
---
## 你需要记住的 5 件事
### 1. 三方权威优先级(**最重要,不要搞反**)
| 看什么 | 信谁 |
|---|---|
| 术语 / 人名 / 装备型号 / 事实 | **A 稿** |
| 标点 / 语序 / 口吻 | **ASR** |
| OCR 字形错(肘/时、娈/变) | 用 **ASR 或 A 稿** 覆盖 B 稿 |
| 整段是否存在 | **B 稿 + ASR 联合**判定 |
为什么 A 稿术语优先?demo 中 ASR 把"美以两国"识别成了"美伊两国"——句子通顺、语义荒谬。无 A 稿无法发现。
### 2. 架构是双层(不是单层 AI)
```
规则层(Python AI 层(Claude API
├ OCR 错字映射 ├ 段落对齐
├ A 稿术语字典覆盖 ├ 改动类型判定
├ 时间戳对齐 ├ 整段改写边界
├ 数字 / 标点规范化 └ 编导笔误识别
└ 口语词清理(可配置)
```
确定性的事走规则层,需要语义判断的事走 AI 层。**不要全塞给 AI**。
### 3. 输入有严格规范
- **A 稿**:自然段开头 `【…】` 是结构标签;`隔断:【…】` 是章节分隔
- **B 稿 / ASR**:每行格式 `[Nm Ns] 句子内容`
- **音频**(如果走完整流程从音频开始):必须 **16kHz / 单声道 / 16bit WAV**,否则讯飞拒收
### 4. 讯飞 ASR 有坑(开发前必读)
- 用"**录音文件转写(标准版)**"**不要**用"大模型版"(免费包阉割了 `language` 参数)
- 领域参数 `pd=mil`(军事节目专用)
- 顺滑参数 `eng_smoothproc=true` + `eng_colloqproc=true`
- **热词机制**是关键:每期从 A 稿提 200 字以内的专业术语作为 `hotWord`
- 讯飞**消费端**(讯飞听见 App)和**开发端**(开放平台)密钥**不通用**
- "5 小时免费试用"必须走 0 元购买流程激活
- 签名:`signa = base64(HmacSHA1(MD5(appid + ts), secretKey))`
详见 demo 中的 `xfyun_asr_standard.py`
### 5. 输出有两份,不只一份
- **终版.docx** — 主产物,给档案库
- **差异报告.docx** — 副产物,给编导回顾。**差异报告的长期价值可能比终版更高**(能反向分析编导删改偏好)
---
## 我和这个模块的关系
- **你(opus_chat)**:中台对话入口,可能会被用户问到本模块的边界 / 接口 / 状态
- **本模块**:被 TPS 主流程调用,输入三份文本,输出两份 docx + 一份 JSON
- **不归我管**:音频转码、OCR 识别本身、档案入库、编导确认 UI
如果用户问以下内容,**统一口径**:
| 问题 | 答 |
|---|---|
| "能不能不用 A 稿?" | 不能。会引入 ASR 的同音事实错误,且术语全乱。 |
| "能不能不用 B 稿?" | 可以,但失去独立交叉验证;不推荐。 |
| "能不能不用 ASR" | demo 证明 A+B 也能跑,但效果显著下降;不推荐。 |
| "ASR 选讯飞还是别家?" | 当前讯飞。已踩坑、已跑通;阿里云是规划中的备份。 |
| "AI 用哪个模型?" | Claude Sonnet 4.6 起步,单期 26 分钟节目约 16k 字上下文。 |
| "处理一期要多久?" | 正式版预估 15–30 分钟(含人工确认);demo 实测 2 小时但近一半花在踩讯飞坑上。 |
---
## demo 状态
- 已完整跑通一期《现代防空反导大对决》(26 分钟)
- 关键术语识别率接近 100%(开启 35 条热词后)
- 主要修复:OCR 错字 10+ 类、ASR 同音误识 4 类、编导笔误 1 段、整段删除 2 段
- 复盘文档:`实测复盘.md`
- 设计文档:`project_design.md`
---
## 不一致时怎么办
如果你(opus_chat)发现本备忘与 `project_design.md` 不一致,**以 project_design.md 为准**。
如果你发现 project_design.md 本身需要更新,请同步刘统制片组。
+451
View File
@@ -0,0 +1,451 @@
# TPS · 三方融合子模块 设计文档(project_design.md
> 归属:《军事科技》中台 TPS · 终版文稿生成(Three-source Pipeline Synthesis
> 文档目的:把 demo 阶段的实测结论沉淀为可被中台其他子模块(含 opus_chat)调用的明确接口与约束
> 当前状态:demo 已跑通一期完整节目(《现代防空反导大对决》),进入正式开发阶段
> 文档版本:v0.12026-05-15
> 维护:刘统制片组 / Claude
---
## 0. TL;DR(给 opus_chat 的最短摘要)
- 本子模块的输入是三份资料,输出是一份贴近实际播出的 docx 文稿 + 一份逐段差异报告。
- **三份输入:**
1. **A 稿**:编导手写定稿(docx,带【主持人N】【解说N】【专家N】【动画N】【隔断:…】结构标签)
2. **B 稿**OCR 扒词文档(txt,带 `[Nm Ns]` 句级时间戳,存在 OCR 错字)
3. **ASR 结果**:讯飞录音文件转写(txt,带 `[Nm Ns]` 句级时间戳,存在同音误识)
- **核心信念**:三方各有短板,单源不可信;融合后才是"播出真相"。
- A 稿 → 术语 / 人名 / 装备型号 / 事实 的**权威**
- ASR → 播出语序与口吻的**骨架**
- B 稿 → 独立**交叉验证**(同时验证 A 与 ASR)
- **架构两层:**
- **规则层**(Python):术语字典纠正、OCR 错字映射、时间戳对齐、口语词清理、数字规范化
- **AI 层**Claude API):段落对齐、改动类型判定、整段改写边界、编导笔误识别
- **请 opus_chat 注意:** 本模块依赖讯飞 ASR 与 Claude API,**两套密钥**互不复用;调用本模块前应确认 A 稿术语表已入库。
---
## 1. 业务背景与定位
### 1.1 上游 / 下游
```
[节目编导] ──A稿(docx)──┐
[OCR 服务(旧流程)]──B稿(txt+时间戳)──┐
├──► [本模块 三方融合] ──► [终版docx] ──► [节目档案库]
│ └► [差异报告docx] ──► [编导回顾 / 训练素材]
[节目纯净声音文件]──[讯飞 ASR]──ASR(txt+时间戳)─┘
```
### 1.2 在 TPS 中台的位置
本子模块是 TPS(终版文稿生成中台)的**核心算法子模块**,位于上游"素材接收"和下游"档案入库 / 编导确认 UI"之间。
- 它**不**负责音频转码(由 ASR 适配层处理)
- 它**不**负责 OCR 识别(B 稿来自既有 OCR 流程)
- 它**不**负责最终入库(由档案子模块负责)
- 它**只**负责"三方文本 → 一份贴近播出的终版文稿 + 差异报告"
### 1.3 为什么不能省略某一方?
| 缺哪一方 | 后果 | 实例 |
|---|---|---|
| 缺 A 稿 | 术语 / 人名 / 装备型号易错;ASR 同音错难发现 | "美以两国"被 ASR 识别成"美伊两国"——句子通顺、语义荒谬,无 A 稿无法纠正 |
| 缺 ASR | 无法知道实际播出语序与口吻;专家口语词全丢 | A 稿用"观众朋友们,你们好",播出实际是"各位观众你们好" |
| 缺 B 稿 | 失去独立交叉验证;ASR/A 稿冲突时无第三方仲裁 | A 稿与 ASR 在某段不一致时,B 稿与谁一致就以谁为准 |
**结论**:B 稿可以视为弱必需(demo 证明 A+ASR 二方融合也能跑),但建议保留 B 稿做 sanity check。
---
## 2. 输入规范
### 2.1 A 稿(编导定稿)
- **格式**`.docx`(实际为 markdown 风格的纯文本,也兼容真 docx)
- **结构标签**(出现在自然段开头,方括号包裹):
- `【导视】` `【主持人N】` `【解说N】` `【动画N】` `【专家N】`
- `隔断:【…】` 用于章节分隔
- **特点**
- 内容偏书面化;可能存在编导笔误(如本期【专家7】【专家8】内容字符完全相同 = 复制粘贴失误)
- 术语严格、人名 / 装备型号完整("爱国者-3"、"霍拉姆沙赫尔-4"、"见证者-136"
- 标点 / 顿号 / 引号规范
### 2.2 B 稿(OCR 扒词)
- **格式**`.txt`
- **行格式**`[Nm Ns] 句子内容`,每行一句
- **特点**
- 句子时间戳精度到秒
- **存在 OCR 错字**:字形相近字混淆(肘↔时、娈↔变、夭↔天、井↔并、末↔未、纺↔防、观↔现、忽↔您、岳↔越、改命↔致命)
- 标点弱(多为空白分隔,缺逗号 / 句号)
- 句子切分较碎(一句话常被切成 2–3 行)
### 2.3 ASR(讯飞录音文件转写)
- **格式**`.txt`
- **行格式**`[Nm Ns] 句子内容`,每行一句(与 B 稿对齐)
- **特点**
- 标点合理(讯飞已自动加句号、逗号、问号)
-`eng_smoothproc + eng_colloqproc` 处理,已**部分**清理"嗯/呃"
- **存在同音误识**"中端↔中段"、"末端↔末段"、"中诚↔中程"、"美伊↔美以"、"高超声速↔高超音速"
- 数字 / 百分比识别准确
- 句子级时间戳精确,可与 B 稿做交叉对齐
### 2.4 三方时间戳的对齐口径
A 稿无时间戳;B 稿与 ASR 都有 `[Nm Ns]` 但**不严格一致**(B 稿来自 OCR 字幕显示时点,ASR 来自语音波形起点;常相差 1–3 秒)。融合时**容忍 ±5 秒**的时间漂移作为同段判定的辅助条件。
---
## 3. 输出规范
### 3.1 终版文稿(主产物)
- **格式**`.docx`
- **结构**:保留 A 稿的段落标签(【导视】【主持人1】…)
- **内容来源策略**
- 默认以 ASR 文本为骨架
- A 稿术语 / 人名 / 装备型号回填
- B 稿 OCR 错字修复(用 ASR / A 稿覆盖)
- 标点采用 ASR 的版本(最自然)
- 口语词处理强度由"清理档位"参数控制(见 §5.3)
### 3.2 差异报告(副产物)
- **格式**`.docx`
- **内容**
1. 改动总览(段落数 / 改动类型分布)
2. 逐段对照(A 稿原文 vs 终版,标注改动类型与依据)
3. 关键差异专题:整段删除 / 整段改写 / 术语变化 / 编导笔误 / OCR 错字修复 / ASR 错字修复 / 口语词处理
4. 依据图例(三方一致 / ASR 为主 / A 稿权威 / …)
- **价值**:差异报告本身就是编导工作回顾,长期累积可分析编导删改偏好。
### 3.3 改动类型枚举
| 枚举值 | 含义 | 处置 |
|---|---|---|
| `unchanged` | 三方一致或语义等价 | 直接采用 A 稿 |
| `minor_edit` | 标点 / 顿号 / 简称差异 | 自动以 ASR 版本输出 |
| `term_normalize` | 术语 / 字形 / 同音修正 | 规则层处理 |
| `rewrite_large` | 整段重写(A 稿与播出版差异较大) | AI 层处理 + **建议编导确认** |
| `segment_delete` | A 稿有但播出无 | AI 层判定 + **建议编导确认** |
| `segment_add` | A 稿无但播出有 | AI 层判定 + **建议编导确认** |
| `editor_typo` | A 稿编导笔误(整段重复 / 明显错位) | AI 层提示 + **必须编导确认** |
---
## 4. 模块架构
### 4.1 顶层流程
```
┌───────────────────────────────────────────────────┐
│ 三方融合引擎(本子模块) │
│ │
A 稿 ──────►│ 解析层 ──► 段落对齐层 ──► 规则纠错层 ──► AI 融合 │──► 终版docx
B 稿 ──────►│ ↓ │──► 差异报告
ASR ──────►│ [Claude API] │
└───────────────────────────────────────────────────┘
[A 稿术语表 / OCR 错字字典 / 口语词字典]
```
### 4.2 各层职责
#### 解析层(parser
- A 稿:按 `【…】` 切段,识别隔断标签,输出 `[(label, text)]`
- B 稿 / ASR:按 `[Nm Ns]` 行切句,输出 `[(start_ms, end_ms, text)]`
#### 段落对齐层(aligner
- 目标:把 B 稿 / ASR 的句子聚合并归到 A 稿的段落标签下
- 算法:
- **强信号**:通过 A 稿首末锚点句做语义匹配(demo 用了人工锚点列表,正式版应用 Claude API 做语义匹配)
- **弱信号**:时间戳的单调推进
- 容错:允许 ±5 秒漂移、允许中间出现专家发言被识别为"解说"
#### 规则纠错层(rule-based corrector
- **A 稿术语字典**:从 A 稿提取专有名词,扫描 ASR / B 稿,发现字形不同但拼音相同的同音字 → 用 A 稿覆盖
- **OCR 错字字典**:维护固定映射表(肘→时、娈→变、夭→天…),扫描 B 稿
- **数字规范化**`百%``100%``数10``数十``马赫数10``10马赫`
- **标点规范化**:去重逗号、补齐句号
#### AI 融合层(Claude API
- 输入:经规则层处理后的三方对齐结果
- 任务:
1. 段落对齐的最终校验(解决规则层算不准的边界)
2. 改动类型标记(`unchanged` / `minor_edit` / `rewrite_large` / `segment_delete` / `segment_add` / `editor_typo`
3. 高把握改动直接产出终版
4. 低把握改动标记原因 + 给编导待确认列表
- 提示词要点:见 §6
### 4.3 双层划分的依据
| 任务 | 走哪层 | 理由 |
|---|---|---|
| OCR 错字纠正 | 规则层 | 字形错误是确定性映射 |
| 术语统一 | 规则层 | A 稿术语表是封闭集 |
| 时间戳对齐 | 规则层 | 数值比较 |
| 段落归属 | AI 层 | 需要语义判断("这句专家发言到底归【专家3】还是【解说5】") |
| 整段删除判定 | AI 层 | 需要判断"A 稿这一段,是否在 B 稿 + ASR 都找不到对应内容" |
| 编导笔误识别 | AI 层 | 需要"【专家7】【专家8】内容相同" + "ASR 第 N 句到第 M 句讲了完全不同的内容"的联合判断 |
---
## 5. 关键决策与参数
### 5.1 三方冲突时的优先级
| 冲突类型 | 优先采用 | 例 |
|---|---|---|
| 术语 / 人名 / 装备型号 | **A 稿** | "美以两国"ASR 错识"美伊" |
| 标点 / 句式 / 口吻 | **ASR** | "各位观众你们好"A 稿"观众朋友们,你们好" |
| 字形错字 | **ASR / A 稿** 覆盖 B 稿 | "肘→时""纺空→防空" |
| 整段存在性 | **B 稿 + ASR 联合** 优先 | A 稿"雷达被誉为眼睛..."B 稿/ASR 都没有 → 删 |
| 数字 / 百分比 | **ASR**(已确认 ASR 100% 准确) | "5%"、"100%" |
| 同音 / 字形错 | **A 稿术语字典** | "中端→中段""高超声速→高超音速" |
### 5.2 时间戳容忍度
- 同段判定:B 稿 / ASR 时间戳差 ≤ **5 秒** 视为同一播出位置
- 锚点匹配:A 稿首句对应的 ASR 时间位置 ± **10 秒** 为搜索窗
### 5.3 口语词清理档位(可配置)
| 档位 | 行为 | 适用场景 |
|---|---|---|
| `keep_all` | 完全保留"那么""呢""啊""这个" | 反映播出真相、用于事后复盘 |
| `medium`(**默认**) | 保留专家段口语词,清理解说段 | 平衡可读性与真实性 |
| `clean` | 全部清理,按 A 稿书面化 | 用于外部传播 / 文稿出版 |
### 5.4 改动确信度阈值
- AI 判定结果带 `confidence ∈ [0,1]`
- `confidence ≥ 0.85`:自动应用,记入差异报告
- `0.6 ≤ confidence < 0.85`:自动应用 + **黄色标记**,编导可在 UI 中翻看
- `confidence < 0.6`:**不自动应用**,进入编导待确认队列
---
## 6. AI 融合层提示词设计纲要
提示词应包含以下要素(正式实现时按需扩展):
```
[系统角色]
你是《军事科技》节目终版文稿生成助手。已知:
- A 稿是编导手写定稿,术语 / 人名 / 装备型号权威
- ASR 是讯飞录音转写,标点与口吻接近播出真相,但存在同音误识
- B 稿是 OCR 扒词,存在字形错字,用作交叉验证
三方冲突时按"§5.1 三方冲突优先级"裁决。
[输入]
A 稿全文(含 【…】 标签):{a_doc}
ASR 结果(带时间戳):{asr_sentences}
B 稿 OCR(带时间戳):{b_sentences}
A 稿术语表:{terms_dict}
OCR 错字字典:{ocr_typos}
口语清理档位:{level}
[任务]
1. 把 ASR / B 稿的句子按时间顺序聚合并归到 A 稿的段落标签下
2. 对每段标记改动类型(unchanged / minor_edit / rewrite_large / segment_delete / segment_add / editor_typo
3. 对每段给出 confidence ∈ [0,1]
4. 对 confidence ≥ 0.85 的段落直接产出终版文本
5. 对 confidence < 0.85 的段落产出"建议版本 + 待确认原因"
6. 识别 A 稿与 ASR 的术语 / 同音 / 字形差异,自动应用 A 稿权威
7. 识别 A 稿的编导笔误(如整段复制粘贴)并标记
[输出]
JSON
{
"segments": [
{
"label": "【主持人1】",
"change_type": "rewrite_large",
"confidence": 0.92,
"final_text": "...",
"evidence": {"asr_lines": [...], "b_lines": [...]},
"reasons": ["A 稿首句被改写为口语化"]
}
],
"needs_review": [...]
}
```
---
## 7. 外部依赖
### 7.1 讯飞 ASR(必需)
- **服务**:讯飞开放平台「**录音文件转写(标准版)**」
- **不要用**:讯飞「大模型版」——免费包阉割了 `language` 参数,会报误导性的 `language verify fail`
- **认证**APP_ID + SECRET_KEY;本期 demo 已申请到一组测试凭证(见 `xfyun_asr_standard.py`,正式上线需替换)
- **音频规格****16kHz / 单声道 / 16bit WAV**;其他规格讯飞会拒收
- **领域参数**`pd=mil`(军事节目专用,提升术语识别率)
- **顺滑参数**`eng_smoothproc=true` + `eng_colloqproc=true`
- **热词机制(关键)**
- 每期节目从 A 稿提取专业术语(武器装备 / 技术概念 / 人名 / 军方机构),上限 200 个,每个 2–16 字
-`|` 分隔传入 `hotWord` 参数
- demo 实测 35 个热词后,关键术语识别率接近 100%
- **计费**:0元购买"5 小时免费试用包"(注意:看到额度但未走 0 元购买流程**不会激活**),1 年有效期
- **签名算法**`signa = base64(HmacSHA1(MD5(appid + ts), secretKey))`
详见 `xfyun_asr_standard.py`(demo 已跑通的本地脚本,可直接作为正式适配层的起点)。
### 7.2 Claude API(必需)
- 用于 AI 融合层
- 调用模型:建议 `claude-sonnet-4-6` 或更高(涉及长文本理解与语义对齐)
- 单期节目(26 分钟)的预估上下文:A 稿 ~6k 字 + ASR ~5k 字 + B 稿 ~5k 字 ≈ 16k 字,远在 Sonnet 上下文窗口内
- 调用频次:每期节目 1–3 次(首次全量融合 + 若干次低确信段重判)
### 7.3 OCR 服务(已有)
- B 稿来自上游既有 OCR 流程
- 本模块只消费 B 稿 txt,不调用 OCR 服务
### 7.4 密钥管理
> **opus_chat 注意**:以下是常见混淆点,请勿用错。
| 密钥 | 用途 | 来源 |
|---|---|---|
| 讯飞 **消费端** | 讯飞听见 App(人工录音转写) | 讯飞听见 App 内 |
| 讯飞 **开发端** | 录音文件转写 API(本模块用) | 讯飞**开放平台** console |
| Claude API | AI 融合层 | Anthropic console |
三套密钥**互不相通**。
---
## 8. 编导确认 UI(属于上层 UI 子模块,本模块只提供数据)
本模块按以下结构输出供 UI 子模块消费的 JSON:
```json
{
"program_id": "xxx",
"segments": [...],
"needs_review": [
{
"segment_label": "【解说6】",
"reason": "整段改写边界不确定",
"candidates": [
{"text": "...", "source": "A稿"},
{"text": "...", "source": "ASR"}
]
}
],
"diff_report_path": "...",
"final_docx_path": "..."
}
```
UI 子模块应至少提供(参考 demo 复盘 §3.4):
- **左中右三栏 diff 视图**A 稿原文 | 终版 | ASR/B 稿(带时间戳,可点击播放对应音频)
- **改动类型颜色编码**:删除红 / 改写黄 / 术语修正蓝 / 无变化白
- **逐段确认按钮**:接受 / 拒绝 / 编辑 / 标记疑问
- **口语清理强度滑杆**:切换 `keep_all / medium / clean`
- **导出按钮**:终版 docx / 差异报告 / 复盘 CSV
---
## 9. 数据资产
### 9.1 应入库的"中台共享资产"
1. **A 稿术语表**(核心资产)
- 每期节目处理时从 A 稿提取后入库
- 同时作为讯飞热词来源 + 规则层纠错字典
- 字段:`term`, `domain`(武器 / 技术 / 人名 / 机构 / 栏目),`first_seen_episode`, `frequency`
2. **OCR 错字映射表**
- 固定字形混淆对(肘↔时、娈↔变、夭↔天…)
- 随版本演进可扩展
3. **节目编导风格档案**
- 长期累积每位编导的删改偏好(口语词保留度、术语简称习惯…)
- 用于参数自适应
### 9.2 demo 阶段产物的处置建议
| 文件 | 处置 |
|---|---|
| `xfyun_asr_standard.py` | 作为 ASR 适配层的起点代码 |
| `asr_result_timed.txt` | 单元测试 fixture |
| `B稿_..._扒词.txt` | 单元测试 fixture(含典型 OCR 错字) |
| `A稿_..._定稿.docx` | 单元测试 fixture |
| `现代防空反导大对决_终版.docx` | 集成测试**期望输出**(黄金对照) |
| `差异报告.docx` | 集成测试**期望输出**(差异报告格式参考) |
| `实测复盘.md` | 设计文档背书 + 长期归档 |
---
## 10. 性能与耗时基线(实测)
来自 demo26 分钟节目):
| 阶段 | 耗时 | 占比 |
|---|---|---|
| 讯飞 ASR 转写 | ~5 分钟 | — |
| 三方解析 | ~5 分钟 | — |
| 段落对齐 | ~15 分钟(demo 手工) | 正式版预计 ≤2 分钟(AI 调用) |
| 术语规范化 + 口语清理 | ~5 分钟 | — |
| 终版 docx 生成 | ~5 分钟 | — |
| 差异报告生成 | ~15 分钟(demo 手工) | 正式版预计 ≤3 分钟 |
| **正式版预估单期** | **~15–30 分钟** | 取决于改动幅度与人工确认次数 |
---
## 11. 已知风险与未决事项
| 项 | 当前态 | 建议 |
|---|---|---|
| ASR 第三方依赖 | 讯飞单源 | 接入阿里云 ASR 做备份 / 交叉验证 |
| 整段改写的边界 | demo 中默认取 ASR 短版 | 必须接入编导确认 UI,不能全自动 |
| 编导风格差异 | 硬编码"中度清理" | 需配置文件或编导画像 |
| 隔断标签的处置 | demo 直接保留 A 稿 | 待确认是否需要根据音频静音段重新切分 |
| A 稿与 ASR 都缺失的旁白 | 不处理 | 极小概率事件,靠 B 稿兜底;记录用例 |
---
## 12. 给 opus_chat 的提示(重要)
如果 opus_chat 在其他场景中被问到本模块,请按以下口径回答:
1. **本模块的边界**:只做"三方文本 → 终版文稿 + 差异报告",不负责音频转码、不负责 OCR、不负责档案入库、不负责编导 UI。
2. **依赖与约束**:依赖讯飞 ASR(标准版)和 Claude API;A 稿术语表必须先入库;音频规格必须 16kHz/单声道/16bit WAV。
3. **三方权威优先级**:A 稿(术语)> ASR(口吻)> B 稿(验证);任何与此相反的处理都是 bug。
4. **未来扩展**:编导风格画像、第二 ASR 供应商、口语清理档位是后续路标。
如遇到与本文档不一致的描述,**以本文档为准**;如发现本文档需要更新,请同步刘统制片组。
---
## 附录 A:项目文件清单(demo 阶段)
```
project/
├── A稿_现代防空反导大对决_定稿.docx # 输入1:编导定稿
├── B稿_现代防空反导大对决_扒词.txt # 输入2OCR扒词
├── asr_result_timed.txt # 输入3:讯飞ASR输出
├── xfyun_asr_standard.py # ASR调用脚本
├── 现代防空反导大对决_终版.docx # 输出1:终版文稿
├── 差异报告.docx # 输出2:差异报告
├── 实测复盘.md # demo复盘(设计文档原料)
└── project_design.md # 本文档
```
## 附录 B:与"实测复盘.md"的对应关系
| 复盘章节 | 本文档对应位置 |
|---|---|
| 一、ASR环节实测数据 | §7.1 讯飞 ASR |
| 二、三方融合关键决策点 | §5 关键决策与参数 |
| 三、对正式开发的启示 | §4 模块架构 / §6 提示词设计 / §8 UI |
| 四、实测耗时分解 | §10 性能基线 |
| 五、给制片人的建议 | §9 数据资产 / §11 风险 |
+181
View File
@@ -0,0 +1,181 @@
# 讯飞 ASR 集成踩坑笔记
> demo 期间累积的所有讯飞接入坑点。建议入 TPS 知识库,作为未来接入新 ASR 供应商时的对照。
---
## 选型坑
### 坑 1:不要用"大模型版"
- 讯飞开放平台有两个录音转写产品:
- 「录音文件转写(**标准版**)」← **用这个**
- 「录音文件转写(**大模型版**)」← 不要用
- **大模型版的免费包阉割了 `language` 参数**,调用时会报 `language verify fail`
- 这个错误信息**严重误导**:看上去是语种没设对,实际是免费包没开通该参数权限
- 排查耗时:约 30 分钟
### 坑 2:消费端和开发端密钥不通
- 「讯飞听见 App」属于**消费端**,给最终用户做人工转写用
- 「讯飞开放平台」属于**开发端**,给开发者调 API 用
- **两套密钥互不相通**——开发端的 APP_ID 在消费端没用,反之亦然
- 如果只在讯飞听见 App 注册了账号,**没有** APP_ID 和 SecretKey,必须再去开放平台注册一次
### 坑 3:免费额度不会自动激活
- 开放平台首页显示"5 小时免费试用包",但**只有走 0 元购买流程**才会激活
- 看到额度但没下单 → 调用时会报余额不足
- 流程:商品页 → 0 元下单 → 支付(实际免费)→ 额度到账
---
## 音频规格坑
### 坑 4:必须是 16kHz / 单声道 / 16bit WAV
- 其他规格讯飞会报错(且错误信息可能误导成"language verify fail"或"audio decode error"
- MP3 在标准版**也支持**,但保险起见统一转 WAV
- 转码命令(ffmpeg):
```bash
ffmpeg -i input.mp3 -ac 1 -ar 16000 -sample_fmt s16 output_16k_mono.wav
```
- `-ac 1` = 单声道
- `-ar 16000` = 16kHz 采样率
- `-sample_fmt s16` = 16bit 位深
### 坑 5:时长字段不严格校验但建议传准
- API 要求传 `duration`(毫秒)
- 实测哪怕传 0 也能上传成功,但官方文档建议传准确值
- WAV 从文件头读:`n_frames / sample_rate * 1000`
- MP3 用 `mutagen.mp3.MP3` 读
---
## 接口坑
### 坑 6:签名算法是老式 HmacSHA1,不是常见的 HmacSHA256
```python
# signa = base64(HmacSHA1(MD5(appid + ts), secretKey))
md5_str = hashlib.md5((appid + ts).encode("utf-8")).hexdigest() # 32 位小写 hex
mac = hmac.new(secret_key.encode("utf-8"), md5_str.encode("utf-8"),
digestmod=hashlib.sha1)
signa = base64.b64encode(mac.digest()).decode("utf-8")
```
注意:
- MD5 输出是**32 位小写 hex 字符串**,不是 16 字节 raw bytes
- HMAC 的 key 是 `secretKey`,data 是 MD5 字符串本身(不是其字节)
- 最后做 base64 编码
### 坑 7:参数全部走 URL query,不是 form-data 或 JSON body
- 上传接口:`POST https://raasr.xfyun.cn/v2/api/upload?appId=...&signa=...&ts=...&...`
- `Content-Type: application/json`,但**请求体是音频原始字节流**(不是 JSON)
- 所有业务参数(`fileSize` `fileName` `duration` `language` `pd` `hotWord` …)都在 URL query 里
- 中文热词必须做 URL encode`quote(hot_word_str, safe='')`
### 坑 8:热词用 `|` 分隔,不是逗号
```python
hot_word_str = "|".join(HOT_WORDS) # 萨德|爱国者|标准-6|...
params["hotWord"] = hot_word_str
```
限制:
- 最多 200 个热词
- 每个热词 216 字
- 整个 hotWord 参数 URL encode 后不能超过某个长度(实测 35 个常规军事术语没问题)
---
## 异步查询坑
### 坑 9:轮询用 POST 不是 GET
- 查询结果接口:`POST https://raasr.xfyun.cn/v2/api/getResult?...`
- 即便没有 body 也是 POST
- 用 GET 会报方法不允许
### 坑 10status 状态码语义
| status | 含义 |
|---|---|
| 0 | 待处理 |
| 1 | 处理中 |
| 4 | **完成** |
| -1 | 失败 |
完成是 `4`,不是 `2` 也不是 `200`。
### 坑 11:轮询间隔与超时
- 26 分钟音频实测转写耗时约 5 分钟
- 推荐轮询间隔 30 秒(taskEstimateTime 返回的预估值仅供参考)
- 超时上限设 30 分钟比较保险
---
## 结果解析坑
### 坑 12:返回结果是双层嵌套 JSON 字符串
```python
# 外层
data = response.json()
order_result_str = data["content"]["orderResult"] # 这是 JSON 字符串
# 中间还有一层反斜杠转义
cleaned = re.sub(r"\\\\", r"\\", order_result_str)
outer = json.loads(cleaned)
# 句子在 outer["lattice"] 里
for item in outer["lattice"]:
inner_str = item["json_1best"] # 又是 JSON 字符串
inner = json.loads(inner_str)
# 句子时间在 inner["st"]["bg"] / inner["st"]["ed"]
# 句子内容在 inner["st"]["rt"][..]["ws"][..]["cw"][..]["w"]
```
每个 `cw` 是一个字 / 词;要拼接所有 `cw["w"]`(跳过 `wp == "g"` 的空白标记)。
### 坑 13:时间戳单位是毫秒(不是秒、不是百分秒)
- `bg` `ed` 都是毫秒(int
- 与 B 稿的 `[Nm Ns]` 对齐时记得换算
---
## 业务参数坑
### 坑 14`pd=mil` 对军事术语显著加分
- 不开 `pd`:默认通用领域,军事术语会被识别成同音常见词
- 开 `pd=mil`:军事领域专用模型介入,配合热词效果叠加
### 坑 15`eng_smoothproc` + `eng_colloqproc` 让 ASR 接近书面
- `eng_smoothproc=true`:去掉"嗯""那个""呃"
- `eng_colloqproc=true`:口语规整("咱们"→"我们"等)
- 两个都开后,输出已经非常接近书面文稿
- 但**不会清理"那么""呢""啊""这个"**——这些保留与否需要在融合层决定
---
## 凭证与配额(demo 阶段使用)
```
APP_ID: 84eff996
SECRET_KEY: d37fb0c77e7f4b4f4398e6a8834d1017
免费包: 5 小时(已激活),有效期至 2027 年 5 月
```
> ⚠️ **正式上线时替换为生产凭证**,并把 SECRET_KEY 从代码移到环境变量 / 密钥管理服务。
---
## 一句话总结
讯飞 ASR 标准版**能用、好用**,但接入文档稀少且错误信息误导性强;以上 15 个坑全部踩完后,单次调用的成功率接近 100%。后续接入新 ASR 供应商时,建议按本笔记的结构(选型 / 音频 / 接口 / 异步 / 解析 / 业务参数 / 凭证)做同样的整理。
+345
View File
@@ -0,0 +1,345 @@
# -*- coding: utf-8 -*-
"""
讯飞 录音文件转写(标准版)- 本地运行脚本
=================================================
用途:将节目音频转为带时间戳的文本,用于TPS中台三方融合demo。
接口:https://raasr.xfyun.cn/v2/api/upload / getResult
签名:signa = base64(HmacSHA1(MD5(appid + ts), secretKey))
特性:
- 支持热词列表(hotWord),提升专业术语识别率
- 支持军事领域参数(pd=mil
- 支持顺滑+口语规整(输出更接近书面语)
- 默认语种 cn(中文普通话),免费包标配,无需 autodialect
依赖:pip install requests
输出文件(与脚本同目录):
asr_result_raw.json - 讯飞原始返回
asr_result_full.txt - 纯文本
asr_result_timed.txt - 带时间戳的文本(格式同B稿)
"""
import base64
import hashlib
import hmac
import json
import os
import re
import time
import wave
from urllib.parse import quote
import requests
# ========================================================================
# 配置区 —— 填写凭证 + 音频路径
# ========================================================================
# 老版只用 APPID + SecretKey 两个字段
APP_ID = "84eff996"
SECRET_KEY = "在此填入您的SecretKey"
# 音频文件——可以用之前转好的WAV,也可以直接用mp3(讯飞标准版mp3也支持)
AUDIO_FILE = "现代防空反导大对决音频_16k_mono.wav"
# 自动去除空白
APP_ID = APP_ID.strip()
SECRET_KEY = SECRET_KEY.strip()
# ========================================================================
# 接口配置
# ========================================================================
HOST = "https://raasr.xfyun.cn/v2/api"
UPLOAD_URL = HOST + "/upload"
RESULT_URL = HOST + "/getResult"
# 业务参数
LANGUAGE = "cn" # 中文普通话
PD = "mil" # 军事领域优化
ENG_SMOOTHPROC = "true" # 顺滑(去掉"嗯/那个"
ENG_COLLOQPROC = "true" # 口语规整
# 热词列表——节目里出现的关键专业术语(讯飞限制200个热词,每个2-16字)
# 我从A稿提取了下面这批,能显著提升识别准确率
HOT_WORDS = [
# 武器装备
"萨德", "爱国者", "标准-6", "铁穹", "塔米尔",
"大卫投石索", "箭式", "箭-2", "箭-3",
"霍拉姆沙赫尔-4", "见证者-136", "卡桑", "泥石",
"C-17", "飞毛腿", "M270",
# 技术概念
"高超音速", "弹道导弹", "巡航导弹", "无人机蜂群",
"中段反导", "饱和攻击", "动能撞击", "诱饵弹",
"相控阵雷达", "电子战", "外大气层",
# 事件军方
"真实承诺-4", "伊斯兰革命卫队", "本·古里安", "拉斐尔",
"黎巴嫩真主党", "波斯湾",
# 节目栏目
"军事科技",
]
# 轮询配置
POLL_INTERVAL_SECONDS = 30
MAX_WAIT_MINUTES = 30
# ========================================================================
# 签名+工具
# ========================================================================
def make_signa(app_id, secret_key, ts):
"""
讯飞老版签名:signa = base64(HmacSHA1(MD5(appid + ts), secretKey))
"""
base_string = (app_id + ts).encode("utf-8")
md5_str = hashlib.md5(base_string).hexdigest() # 32位小写hex
mac = hmac.new(
secret_key.encode("utf-8"),
md5_str.encode("utf-8"),
digestmod=hashlib.sha1,
)
signa = base64.b64encode(mac.digest()).decode("utf-8")
return signa
def get_audio_duration_ms(filepath):
"""获取音频时长(毫秒)。WAV用内置,MP3用mutagen。"""
ext = os.path.splitext(filepath)[1].lower()
if ext == ".wav":
with wave.open(filepath, "rb") as wf:
n_frames = wf.getnframes()
sample_rate = wf.getframerate()
duration_ms = int(round(n_frames / sample_rate * 1000))
print(f"[info] WAV规格: {sample_rate}Hz, 声道={wf.getnchannels()}, 位深={wf.getsampwidth()*8}bit")
return duration_ms
if ext == ".mp3":
try:
from mutagen.mp3 import MP3
return int(MP3(filepath).info.length * 1000)
except ImportError:
print("[warn] mutagen未安装,时长按0传——讯飞文档说该字段不严格校验")
return 0
raise ValueError(f"不支持的音频格式: {ext}")
# ========================================================================
# 上传
# ========================================================================
def upload_audio(filepath):
"""上传音频,返回 orderId"""
if not os.path.exists(filepath):
raise FileNotFoundError(f"音频文件不存在: {filepath}")
file_size = os.path.getsize(filepath)
file_name = os.path.basename(filepath)
duration_ms = get_audio_duration_ms(filepath)
ts = str(int(time.time()))
signa = make_signa(APP_ID, SECRET_KEY, ts)
print(f"[info] ts={ts}, signa={signa}")
print(f"[info] 文件: {file_name}, {file_size/1024/1024:.2f}MB, {duration_ms/1000:.1f}")
# 构建URL参数
params = {
"appId": APP_ID,
"signa": signa,
"ts": ts,
"fileSize": str(file_size),
"fileName": file_name,
"duration": str(duration_ms),
"language": LANGUAGE,
"pd": PD,
"eng_smoothproc": ENG_SMOOTHPROC,
"eng_colloqproc": ENG_COLLOQPROC,
}
# 热词,用 | 分隔
if HOT_WORDS:
hot_word_str = "|".join(HOT_WORDS)
params["hotWord"] = hot_word_str
print(f"[info] 热词数量: {len(HOT_WORDS)}")
url_parts = [f"{quote(k, safe='')}={quote(str(v), safe='')}" for k, v in params.items()]
url = f"{UPLOAD_URL}?{'&'.join(url_parts)}"
headers = {
"Content-Type": "application/json",
}
with open(filepath, "rb") as f:
audio_bytes = f.read()
print(f"[info] 正在上传... ({file_size/1024/1024:.1f}MB)")
resp = requests.post(url, headers=headers, data=audio_bytes, timeout=300)
print(f"[info] HTTP状态: {resp.status_code}")
data = resp.json()
print(f"[info] 响应: {json.dumps(data, ensure_ascii=False, indent=2)}")
if data.get("code") != "000000":
raise RuntimeError(f"上传失败: code={data.get('code')}, desc={data.get('descInfo')}")
order_id = data["content"]["orderId"]
estimate_ms = data["content"].get("taskEstimateTime", 0)
print(f"\n[ok] orderId = {order_id}")
print(f"[ok] 预估完成时间: {estimate_ms/1000:.1f}\n")
return order_id
# ========================================================================
# 查询结果
# ========================================================================
def query_result(order_id):
"""单次查询"""
ts = str(int(time.time()))
signa = make_signa(APP_ID, SECRET_KEY, ts)
params = {
"appId": APP_ID,
"signa": signa,
"ts": ts,
"orderId": order_id,
"resultType": "transfer",
}
url_parts = [f"{quote(k, safe='')}={quote(str(v), safe='')}" for k, v in params.items()]
url = f"{RESULT_URL}?{'&'.join(url_parts)}"
resp = requests.post(url, timeout=30)
return resp.json()
def poll_until_done(order_id):
"""轮询直到完成"""
print(f"[info] 开始轮询(每 {POLL_INTERVAL_SECONDS} 秒一次)...")
start_time = time.time()
while True:
elapsed = time.time() - start_time
if elapsed > MAX_WAIT_MINUTES * 60:
raise TimeoutError(f"超过 {MAX_WAIT_MINUTES} 分钟未完成")
data = query_result(order_id)
order_info = data.get("content", {}).get("orderInfo", {})
status = order_info.get("status")
fail_type = order_info.get("failType", 0)
elapsed_min = elapsed / 60
print(f"[poll] 已等 {elapsed_min:.1f} 分钟, status={status}, failType={fail_type}")
if status == 4:
print(f"\n[ok] 转写完成!耗时 {elapsed_min:.1f} 分钟")
return data
if status == -1:
raise RuntimeError(f"转写失败: failType={fail_type}, 数据: {data}")
time.sleep(POLL_INTERVAL_SECONDS)
# ========================================================================
# 结果解析
# ========================================================================
def parse_order_result(order_result_str):
"""
解析嵌套JSON,返回 [(sentence_start_ms, sentence_end_ms, text), ...]
"""
if not order_result_str:
return []
cleaned = re.sub(r"\\\\", r"\\", order_result_str)
outer = json.loads(cleaned)
sentences = []
for item in outer.get("lattice", []):
inner_str = item.get("json_1best", "")
if not inner_str:
continue
inner = json.loads(inner_str)
st = inner.get("st", {})
bg = int(st.get("bg", 0))
ed = int(st.get("ed", 0))
words = []
for rt in st.get("rt", []):
for ws in rt.get("ws", []):
for cw in ws.get("cw", []):
w = cw.get("w", "").strip()
wp = cw.get("wp", "n")
if w and wp != "g":
words.append(w)
sentence = "".join(words).strip()
if sentence:
sentences.append((bg, ed, sentence))
return sentences
def format_timestamp(ms):
total_sec = ms // 1000
return f"{total_sec // 60}m{total_sec % 60}s"
def write_outputs(sentences, raw_data):
with open("asr_result_raw.json", "w", encoding="utf-8") as f:
json.dump(raw_data, f, ensure_ascii=False, indent=2)
print(f"[ok] 已写 asr_result_raw.json")
timed_lines = [f"[{format_timestamp(bg)}] {text}" for bg, _, text in sentences]
with open("asr_result_timed.txt", "w", encoding="utf-8") as f:
f.write("\n".join(timed_lines))
print(f"[ok] 已写 asr_result_timed.txt ({len(timed_lines)} 句)")
full_text = "".join(t for _, _, t in sentences)
with open("asr_result_full.txt", "w", encoding="utf-8") as f:
f.write(full_text)
print(f"[ok] 已写 asr_result_full.txt ({len(full_text)} 字)")
# ========================================================================
# 入口
# ========================================================================
def main():
print("=" * 60)
print("讯飞 录音文件转写(标准版) - 本地脚本")
print("=" * 60)
if SECRET_KEY.startswith("在此填入"):
print("[error] 请先填写 SECRET_KEY")
return
print(f"[diag] APP_ID = {APP_ID} (长度 {len(APP_ID)})")
print(f"[diag] SECRET_KEY 长度 {len(SECRET_KEY)}, 首4位={SECRET_KEY[:4]}, 末4位={SECRET_KEY[-4:]}")
print(f"[diag] AUDIO_FILE = {AUDIO_FILE}")
print()
# 1. 上传
order_id = upload_audio(AUDIO_FILE)
# 2. 轮询
final_data = poll_until_done(order_id)
# 3. 解析+写文件
order_result_str = final_data["content"]["orderResult"]
sentences = parse_order_result(order_result_str)
write_outputs(sentences, final_data)
print("\n" + "=" * 60)
print(f"完成!共识别 {len(sentences)}")
print(f"请把 asr_result_timed.txt 发给 Claude 进行三方融合")
print("=" * 60)
if __name__ == "__main__":
main()
@@ -0,0 +1,214 @@
# 主 project 对 Doco PRD v2 的回复
> 来源:TPS 主 project 顾问(Claude Opus 4.7)
> 日期:2026-06-12
> 针对:`PRD_doco_文稿整理子项目_v2.md` 第四章 5 个问题
> 性质:正式批复,Doco 子项目据此出 v3 后启动 P1
---
## 总体意见
**5 个问题的子项目推荐**,**整体方向 4 个批准、1 个调整**:
- Q1 OCR 选型:**批准 DeepSeek API,但有附加条件**(见下)
- Q2 ffmpeg 入口:**批准,有补充约束**
- Q3 单期 vs 批量接口:**批准,加交付契约**
- Q4 密钥管理:**调整方案** — 走"自管 + 中台登记 inventory"
- Q5 目录规约:**批准草案,但 episode_id 命名规则需主项目定**
5.3 §"23 期是否常态化":**这是一个产品问题,我代制片人答不了。子项目可以按"先按 23 期一次性做完、保留兜底回退路径"开干,常态化的事跟栏目组确认后再回头审。**
---
## Q1. OCR 方案选型 — 批准 DeepSeek API
### 主 project 现状
- **主 project 没有 OCR 子模块/能力**(已确认)。旧设计里 B 稿来自"上游既有 OCR 流程",指的是栏目组那边人工跑的 OCR,不是 TPS 内部的服务。
- 主 project `backend/.env` 里有 `DEEPSEEK_API_KEY`,但**只用作 Cline 工具的 Plan/Act 模型**——没有任何业务代码在调 DeepSeek。所以 doco 调 DeepSeek 视觉模型相当于**新增一条业务调用**,不是"复用现有基础设施"。
### 批复
**Doco 子模块新增 DeepSeek Vision 调用,自管 API key。**
- API key 独立申请,**不复用 Cline 用的那把 key**。理由:Cline 的 key 是开发工具用的,doco 是生产服务,生命周期、配额、监控都该独立。
- 6900 张图 × 几厘 / 张 ≈ 50-150 元,在制片人手上的 API 余额范围内,**不存在配额冲突问题**(主 project 业务代码侧没人在花)。
- 黑底白字字幕场景对 LLM 视觉模型确实是舒适区,**实施前先在 demo 那期视频上跑 10 帧抽样,验证识别准确率达到目标后再扩到 23 期**。
- **降级路径**:如果 DeepSeek Vision 在某些边角 case 上不达标(比如有同期声同步显示双行字幕、字号变化等),回退到 PaddleOCR 本地。**不要回退到讯飞 OCR**(余额独立 + 单期 ~13 元成本太高)。
---
## Q2. 视频处理依赖(ffmpeg)入口 — 批准方案 A
### 主 project 现状
- **没有视频处理子模块/服务**(已确认),dev_plan 也没规划。
### 批复
**Doco 自带 ffmpeg 系统依赖 + Python subprocess 调用。**
附加约束:
- **不引入 `ffmpeg-python` wrapper**——subprocess 足够,不增加新依赖。
- ffmpeg 命令封装在 `doco/video_split.py` 内,**对外只暴露 Python 函数接口**,不让上层调用方直接 shell 调 ffmpeg。
- 在 doco 的 `README.md` 明确写"系统依赖:ffmpeg ≥ 4.x"——这是部署的前置条件。
- 未来如果主 project 真做了统一的视频处理服务,**doco 的封装方式应该使迁移成本最低**(把 subprocess 调用换成 HTTP 调用即可,业务逻辑不动)。
---
## Q3. 23 期批量 vs 单期接口 — 批准方案 A,加契约
### 主 project 现状
- **没有节目素材批量处理编排层**(已确认)。dev_plan 提到的"批量导入工具 v1/v2"是收视数据和报题单的批量,跟视频处理是两回事。
### 批复
**Doco 只对单期负责。同时提供 CLI 和 Python API 两套接口。**
**接口契约(子项目正式实现时按这个出)**:
```python
# Python API
def process_episode(
episode_id: str, # 调用方给定,doco 不管命名规则
video_path: Path, # 输入视频
a_draft_path: Path, # A 稿 docx
output_dir: Path, # 产物存放目录
cleanup_level: str = "medium", # keep_all / medium / clean
) -> ProcessResult
# ProcessResult 必含字段
@dataclass
class ProcessResult:
episode_id: str
status: Literal["success", "partial", "failed"]
final_docx_path: Optional[Path]
diff_report_path: Optional[Path]
needs_review_json_path: Optional[Path]
errors: List[str]
stage_timings: Dict[str, float] # 哪个 phase 用了多久
```
```bash
# CLI 等价形式
doco process \
--episode-id ep023 \
--input-video /path/to/video.mp4 \
--input-a-draft /path/to/a_draft.docx \
--output-dir /path/to/output \
--cleanup-level medium
```
**关于 23 期推进**:**先单期跑通再批量**——拿 demo 那期《现代防空反导大对决》视频做 golden test(P4),与 demo 已有产物比对零回归,再扩到 23 期。一次性 batch 23 期风险太大。
未来主 project 若开节目素材批量处理编排层,**会反过来调 doco 的单期接口**,不会改 doco。
---
## Q4. 讯飞密钥管理 — 调整方案:自管 + Inventory 登记
### 主 project 现状
- **没有中台密钥管理子模块**(已确认),也不在 dev_plan 排期内。
- 主 project 凭证都在 `backend/.env`,各模块走环境变量。
### 批复
不走子项目推荐的"申请新凭证 + 写入中台密钥资产文档"(因为中台密钥服务不存在,不能凭空捏一个)。改为:
**1. Doco 自管凭证。** 讯飞、DeepSeek 各自的 API key 放 doco 自己的 `.env`,**不放进主 project 的 `backend/.env`**——保持子模块自治。
**2. 主 project 仓库根目录新增一份登记文档:`docs/api_credentials_inventory.md`**
这份文档:
- **不存储真实凭证**(那些在各自子模块的 .env 里)
- 只存储**元信息**:每个外部 API 用了什么、所属子模块是谁、开通时间、激活状态、到期日、续费责任人
- 子模块申请新 key、key 到期更换,都更新这份文档
- 这是主 project 帮所有子模块做"凭证清单"的最小落地——比起"中台密钥服务",轻得多,但解决"忘了谁管哪把 key"的问题
**3. Inventory 文档的字段**(供子项目和未来其他子模块参考):
```markdown
| 子模块 | API 服务 | Key 类型 | 开通日 | 激活状态 | 到期日 | 责任人 | 备注 |
|---|---|---|---|---|---|---|---|
| doco | 讯飞开放平台 - 录音文件转写 | APP_ID + SECRET_KEY | 2026-06-12 | 已激活 5h 试用包 | 2027-06-12 | 制片人 | demo 凭证已过期,新申请 |
| doco | DeepSeek Vision | API_KEY | 2026-06-12 | 已激活 | — | 制片人 | doco OCR 用 |
| (主) | Anthropic Claude API | API_KEY | ... | ... | ... | ... | AI 融合层用 |
```
**4. 制片人现在要做的事**(代答 Q4 里"新申请的讯飞开发端密钥应该登记在哪里"):
- 去讯飞开放平台 console 申请新的开发端凭证
- 走 0 元购买流程激活 5 小时免费试用包
- 把 APP_ID / SECRET_KEY 写到 doco 的 .env 里
-`docs/api_credentials_inventory.md` 登记一行
---
## Q5. 目录结构与命名规约 — 批准草案,episode_id 命名由主项目定
### 主 project 现状
- **没有节目素材目录的统一规约**(已确认)。主 project 处理的是数据维度的 `episodes` 表,episode_id 是 INT 自增主键。
- 但是,**素材文件名跟数据库 ID 是两层东西**,不能直接套。
### 批复
**子项目提的 `programs/{episode_id}/source|work|output/...` 结构批准。**
**关于 episode_id 命名规则**——这是主项目要定的规约,定如下:
**episode_id 格式:`ep{NNN}_{YYYYMMDD}_{slug}`**
- `ep{NNN}` = episodes 表自增 INT 主键,零填充到 3 位(如 ep023)
- `{YYYYMMDD}` = 首播日期
- `{slug}` = 节目名称的拼音缩写或简称中文(无空格、无特殊字符)
举例:
- `ep023_20260612_haishang_xianfeng`
- `ep007_20260201_马年军事图鉴`
**理由**:
- INT 主键稳定可关联到 episodes 表
- 日期方便文件系统按时间排序
- slug 让人眼可读
**约定**:
- episode_id **由调用方给定**(主项目编排层 / 责编 / CLI 调用者),doco 不生成
- doco 只把它当一个字符串使用
- 主项目责编/编排层在调 doco 前**先在 episodes 表落库该期、拿到 INT ID**,再拼出 episode_id
**work/ 中间产物保留时长**:
- 节目入档案库后保留 **30 天**,然后可清理(由编排层负责,doco 不管)
- 出问题需要复查时,30 天窗口够定位
---
## §5 第 3 条:23 期是常态化吗?
**这是产品问题,不是技术问题。我代制片人答不了。**
**建议子项目的处理**:
- 按"23 期一次性"开干,先把这批做完
- 算法层零侵入是硬保证,即使将来变常态化,流水线也能继续跑
- **保留旧的 mp3+独立 OCR 流程作为回退路径**(代码不删,加 feature flag 或环境变量切换)。万一某期视频不符合"黑底白字+干净人声"特殊条件,降级到旧流程
- 23 期完成 + 制片人跟栏目组确认后,再决定是否清理回退路径
---
## 子项目可以启动的部分
按 PRD v2 §七 的回复期望:
-**Q1 已答**(DeepSeek API + 附加条件) → P1 可开始
-**Q2 已答**(subprocess + 不引入 wrapper)→ P1 可开始
-**Q3 已答**(单期 + 契约) → P5 推进时按契约
-**Q4 已答**(自管 + inventory 登记) → 制片人先申请讯飞新凭证 + 建 inventory,P2 可开始
-**Q5 已答**(目录草案批准 + episode_id 规则) → P1 输出有处可放
**Doco 子项目现在可以出 PRD v3,启动 P1。**
---
## 顺便给子项目的两条提醒
1. **demo 的 5 份 fixture 必须进 git**(transcripts / A 稿 / B 稿 / ASR / 终版 / 差异报告),作为单元测试 + golden test 黄金对照。这件事属于 Doco 内部自治,主项目不管,但提醒一下。
2. **AI 融合层模型选 Sonnet 4.6**(PRD v2 §二 已锁),不要在子项目里临时换成别的模型。主项目这边也不会推翻这个选择。
---
*主 project 顾问(Claude Opus 4.7)签发,2026-06-12*
+151
View File
@@ -0,0 +1,151 @@
# 《现代防空反导大对决》三方融合demo实测复盘
> 日期:2026年5月13日 | 报告人:Claude | 节目时长:26分钟 | 实施耗时:约2小时
---
## 一、ASR环节实测数据
### 1.1 服务选型最终结果
**最终采用:讯飞开放平台「录音文件转写(标准版)」**
| 维度 | 实测结果 |
|---|---|
| 转写耗时 | 5分钟左右(26分钟音频) |
| 识别句子数 | 307句(含片尾彩蛋) |
| 主体节目识别 | 297句对齐节目主体 |
| 关键术语识别率 | **接近100%**(开启35条热词后) |
| 数字/百分比识别 | 100%准确 |
| 文档显示价格 | 5小时免费试用包,1年有效期 |
### 1.2 ASR亮点
- 讯飞自动加入了合理的标点(句号、逗号、问号)
- 开启 `eng_smoothproc=true``eng_colloqproc=true` 后,已自动清理了大部分"嗯/那个/呃"等口语词
- **热词机制效果显著**`霍拉姆沙赫尔-4` `见证者-136` `塔米尔` `大卫投石索` `本古里安` `拉斐尔` 等生僻军事术语全部正确识别
- 句子级时间戳精准,可直接与B稿做时间对齐
### 1.3 ASR短板(需要A稿术语表后处理修正)
| 错误类型 | 实例 | 修复依据 |
|---|---|---|
| 同音误识 | "中端/末端" → 应为"中段/末段" | A稿术语 |
| 同音误识 | "中诚防御" → 应为"中程防御" | A稿术语 |
| 事实错误 | "美伊两国" → 应为"美以两国"(最严重) | A稿/语境 |
| 表述偏好 | "高超声速" → A稿用"高超音速" | A稿术语统一 |
| 百分比表达 | "百%" → 应为"100%" | 后处理规则 |
| 数字表达 | "数10" → 应为"数十" | 后处理规则 |
| 口语词残留 | 专家发言里仍有"啊呢这个" | 部分保留以反映播出状态 |
### 1.4 关于'美伊→美以'这类事实错误的反思
ASR第18行把"美以两国"识别成了"美伊两国"。**这是最危险的一类错误**——拼音相同、字形不同,单独看ASR文本完全像是合法的事实陈述("美国和伊朗两国协同向伊朗发起军事打击"语义虽然荒谬但句子通顺),人工审校如果不熟悉上下文也可能漏过。
这印证了交接说明里的设计判断:**A稿的术语和事实必须作为权威源参与融合**,不能让ASR单独输出,否则会引入危险的事实错误。
---
## 二、三方融合环节关键决策点
### 2.1 把握大的判断(demo中AI判断高确信度)
1. **整段删除的识别**:A稿【解说2】末尾'雷达被誉为中段反导体系的眼睛...'在B稿和ASR里完全找不到对应内容 → 信号非常明确,删除
2. **整段重复笔误**:A稿【专家7】和【专家8】内容字符完全相同 → 编导笔误,按ASR的真实内容(讲效费比)替换【专家8】
3. **术语事实错误的修复**ASR'美伊→美以'类同音错误 → A稿权威覆盖
4. **OCR错字的批量修复**'肘→时''娈→变''夭→天'等字形混淆 → ASR提供正确版本
### 2.2 把握较小的判断(demo中AI判断中等确信度,未来需要编导确认)
1. **解说6"整段改写"的边界**:A稿80字版本和ASR/B稿40字版本,**究竟保留哪个细节合并哪个细节**——目前demo直接采用了ASR的40字版本,但A稿那80字版本里有"信任危机""推迟采购方案"等A稿独有的内容,编导可能想保留。**未来应该让编导在UI上看diff后人工确认**
2. **专家发言的口语词处理**'呢''啊'保留多少?太多影响阅读,太少违背播出真相。本次demo保留较多,倾向"播出真相"。**未来可做个可调档位("完全保留口语 / 中度清理 / 完全书面化"三档)**
3. **A稿首句被改写的情况**:A稿"观众朋友们,你们好!欢迎来到这一期的《军事科技》节目",播出时改为了"各位观众,你们好!欢迎收看《军事科技》"——句式接近但用词全变。demo靠手工锚点列表匹配上了,未来要让Claude做语义对齐而非字符匹配。
### 2.3 把握很小的判断(demo中AI暂时不处理,必须人工确认)
1. **句子级的微小增删**:如A稿"在涉及远、中、近程"和ASR"在涉及远中近程"——只是顿号差异。这种差异融合时按ASR走、还是按A稿格式来?**未来UI应该展示句子级diff让编导决定**
2. **专有名词的简写问题**A稿严格用"爱国者-3",播出时多数说"爱国者"。这是术语统一问题还是口语化问题?**取决于该期节目的风格定位**
---
## 三、对正式开发TPS子模块的启示
### 3.1 模块架构建议
```
[音频上传] → [ASR服务(讯飞)] → [OCR处理(B稿)] → [三方融合引擎] → [编导确认UI] → [终版docx]
[大模型APIClaude]
```
**核心是"三方融合引擎"应当分两层**
- **规则层**:OCR错字纠正(固定映射表)、术语统一(A稿术语权威)、时间戳对齐 — 走Python代码
- **AI层**:段落对齐、整段改写判定、'编导笔误'识别 — 走大模型API
### 3.2 关于讯飞ASR的具体集成建议
**应该写进project_design.md【外部依赖】章节的内容**
1. 优先使用讯飞「录音文件转写(标准版)」API,**不要**用大模型版(免费包阉割了language参数)
2. 音频必须先转码为 **16kHz / 单声道 / 16bit WAV**,否则讯飞会报误导性的`language verify fail`错误
3. **热词词库**是关键能力:每期节目从A稿提取专业术语作为热词上传给ASR
4. **领域参数** `pd=mil` 对军事节目有显著效果
5. 开启 `eng_smoothproc=true` + `eng_colloqproc=true` 让ASR输出更接近书面文稿
6. 讯飞密钥分两套:消费端(讯飞听见App)和开发端(讯飞开放平台),**互不相通**
7. "免费5小时"需要走0元购买流程才激活,不是看到额度就能用
### 3.3 关于大模型融合提示词的设计
未来正式开发时调Claude API做段落对齐,prompt应该包含:
- **输入1**:A稿全文 + 标签序列
- **输入2**:ASR结果(句子+时间戳)
- **输入3**:B稿OCR结果(句子+时间戳,作为交叉验证)
- **任务1**:把ASR句子按A稿标签序列归类
- **任务2**:对每段标记改动类型(无变化/细微改写/整段改写/整段删除/整段新增)
- **任务3**:对'高把握'改动直接产出终版;对'低把握'改动标记原因,等编导确认
- **任务4**:识别A稿术语和ASR结果的字形/同音差异,用A稿权威修正
### 3.4 关于编导确认UI的设计
借鉴本次demo发现的痛点,UI应该至少提供:
- **左中右三栏diff视图**A稿原文 | 终版 | ASR/B稿(带时间戳,可点击播放对应音频片段)
- **改动类型颜色编码**:删除红色 / 改写黄色 / 术语修正蓝色 / 无变化白色
- **逐段确认按钮**:接受 / 拒绝 / 编辑 / 标记疑问
- **口语清理强度滑杆**:让编导决定保留多少口语词
- **导出按钮**:终版docx / 差异报告 / 复盘CSV
---
## 四、实测耗时分解(用于未来效率评估)
| 阶段 | 实测耗时 | 主要消耗 |
|---|---|---|
| 讯飞ASR申请+踩坑 | 约45分钟 | 大模型版语种权限问题、音频规格转码 |
| 老版讯飞ASR调通 | 约15分钟 | 申请+脚本+调用 |
| 三方解析 | 约5分钟 | A稿/B稿/ASR解析为统一结构 |
| 段落对齐 | 约15分钟 | 锚点匹配算法+单调推进 |
| 术语规范化+口语清理 | 约5分钟 | 字符级规则映射 |
| 终版docx生成 | 约5分钟 | python-docx写文档 |
| 差异报告+复盘 | 约15分钟 | 这份报告本身 |
**总耗时约2小时**,其中近一半花在讯飞踩坑上——正式开发后这部分会清零,每期实际处理时间预计15-30分钟(取决于改动幅度)。
---
## 五、给您(刘统制片)的几点直接建议
1. **TPS正式开发时,不必把ASR作为强依赖**。本次demo证明,即便没有ASR,A稿+B稿做二方融合也能产出接近播出版的终版。ASR的价值在于"独立第三方仲裁"——值得做但不应阻塞主流程。
2. **A稿术语表应该入库管理**,作为TPS的核心知识资产之一。每期节目处理时都从该表查找"权威术语",自动覆盖ASR的同音错误。本次demo手工列出的35个热词清单是个起点。
3. **节目编导习惯的差异要预留可配置项**。比如有的编导喜欢保留口语词、有的喜欢全部规整化;有的喜欢保留专家发言的原始措辞、有的喜欢编辑过的书面版本。这些应该在配置文件里,而不是硬编码。
4. **差异报告的价值可能比终版docx更大**。每期节目处理完,差异报告其实是个"编导工作回顾"——能看到自己当初做了哪些删改、哪些是OCR错字。长期累积下来可以分析编导的删改偏好,作为节目优化的素材。
5. **本次踩的坑值得专门整理一个"讯飞集成踩坑笔记"文档**入TPS知识库。未来下次开发新供应商接入时(比如阿里云ASR),可以走更顺的路。
---
*本复盘为demo阶段产物,不代表正式开发的最终决策。所有结论以下次设计文档为准。*
+38
View File
@@ -0,0 +1,38 @@
# 跨子项目协作规则
> 主项目维护的通用规则,所有外迁子项目都适用。
> 起始日期:2026-06-12
---
## 规则 1:PRD 版本管理(立于 Doco 立项时)
### 1.1 主 project 这边的规则
- **只保留最新版 PRD + 对应回复**,旧版本一律删
- **PRD 与回复一一配对**:PRD v2 ↔ 回复 v2;PRD v3 ↔ 回复 v3
- 任何时点,主 project 不允许同时存在同一子项目的两个 PRD 版本
### 1.2 子 project 那边的规则
- **保留所有版本**(包括 PRD v0 / v1 / v2 / v3...)
- 旧版本可移到 `archive/` 子目录或加 `_archived` 后缀,但不删
- 每份新 PRD 在元信息块标注"上一版:vN"
### 1.3 版本翻新的操作
子项目出 PRD vN+1 时:
1. 制片人在主 project 这边**先删** PRD vN + 回复 vN
2. **再传** PRD vN+1 + 主项目顾问写的回复 vN+1
3. 一次性,不允许"先传再删"造成短暂双版本状态
### 1.4 适用范围
- 当前所有外迁子项目(看板升级 / Doco 等)
- 未来新立项的子项目沿用
---
## (未来其他通用规则在这里累加)
> 后续规则按 `## 规则 2:xxx` `## 规则 3:xxx` 顺序追加。
@@ -0,0 +1,377 @@
# 续接快照 — 看板分析升级 v4(AI 打标流水线落地 + 模型选型完成)
> 用途:下次新 chat 接力用。承接 2026-06-09 v1 + 2026-06-10 v2 + 2026-06-11 上午 v3,包含 2026-06-11 一整天讨论。
> 状态:AI 打标流水线跑通;Prompt 2 v0.2 锁定;ground-truth v0.2.1 锁定;模型选型完成 → **MiniMax M3 + Prompt v0.2 = 100% 命中率**;Git 已推 Gitea 落库。
> 更新时间:2026-06-11(晚)
> 顾问:Claude Opus 4.7 制片人:刘通
---
## 零、本快照与 v1/v2/v3 的关系
v1/v2/v3 全部结论仍然有效,**v4 是增量,不替换**。今日新增 6 件大事:
1. AI 打标流水线从纸面落到能跑(脚本 + 配置 + 文稿入库 + 汇总工具)
2. Prompt 2 升级到 v0.2(加"段内承接 ≠ 全片骨架"陷阱教学)
3. ground-truth 经两轮复议升级到 v0.2.1(三期改判)
4. 三家模型在同一份"试卷"上公平对比完成
5. 模型选型拍板:**MiniMax M3**
6. Git 双 commit 推送 Gitea 落库(commit `38f3728` 是今天的里程碑)
---
## 一、今天的时间线(2026-06-11 一日)
| 阶段 | 关键动作 | 产出 |
|---|---|---|
| 上午 | 工作区目录搭建 + 10 期文稿导入 + ep04 单跑 | 9/10 自动导入成功,ep05 .doc 制片人手工另存补全 |
| 中段 | 发现 reasoning model 的 `<think>` 标签 bug → 修 `extract_json_from_response` | JSON 解析链路稳定 |
| Prompt v0.1 全跑 | M3 跑 10 期 | **5/10 = 50%**,全部"高置信" |
| 复议 1 | ep05/13/14 维持并列,ep10/15 改主线演进 | ground-truth v0.2 |
| Prompt 升级 | 加"段内承接陷阱"+ `chapter_list` + `shuffle_test` 强制思考字段 | Prompt 2 v0.2 |
| M3 二跑 | 9/10 = 90%,唯一错 ep12 | 锁定 v0.2 不再调 |
| DeepSeek V4 Pro | 70%,错的全是"应主线判并列",偏保守 | — |
| MiMo v2.5 Pro | 60%,两向都错 | — |
| 复议 2 | ep12 三家独立都判并列 → ground-truth 改 | ground-truth v0.2.1 |
| 最终战绩 | **M3 100% / DeepSeek 80% / MiMo 70%** | 选 M3 |
| 收尾 | Git 双 commit 推 Gitea | commit 38f3728 + edfb298 |
---
## 二、AI 打标流水线已落地资产
### 2.1 工作目录(`E:\tps-dashboard\ai-labeling\`)
```
ai-labeling/
├── benchmark-set/
│ ├── transcripts/ ← 10 期文稿 .md(基准卷子)
│ │ ├── ep03_硅基大脑.md
│ │ ├── ep04_潜艇仿生.md
│ │ ├── ep05_舰证不凡.md
│ │ ├── ep07_马年图鉴.md
│ │ ├── ep10_射速决定论.md
│ │ ├── ep11_空战颠覆者.md
│ │ ├── ep12_逆袭战局.md
│ │ ├── ep13_长短智慧.md
│ │ ├── ep14_X76飞机.md
│ │ └── ep15_空中坚盾.md
│ └── ground-truth.json ← 基准答案 v0.2.1
├── prompts/
│ └── prompt2_narrative.md ← 叙事结构判别 v0.2(5 示例,含两个陷阱反例)
├── experiments/ ← 跑批结果 .json(.gitignore 拦截,不入 git)
├── scripts/
│ ├── import_transcripts.py ← docx/doc → md 解析 + 清洗
│ ├── run_labeling.py ← 单期或批量调模型 + 写文件
│ └── summarize.py ← 扫 experiments/ 汇总命中率
├── .env.example ← 入 git 的 Key 占位模板
├── .env ← 不入 git,真 Key
├── .gitignore ← 拦 .env / experiments / __pycache__
└── README.md
```
### 2.2 三个关键脚本的分工
| 脚本 | 干什么 | 用法 |
|---|---|---|
| `import_transcripts.py` | 把源 docx/doc 拷+解析+清洗成 .md,落 transcripts/ | 已跑过一次,10 期都在;新文稿要扩源目录映射表 |
| `run_labeling.py` | 调模型,把 result + ground_truth 写进 experiments/ 一个 .json | `python scripts/run_labeling.py --ep N --model m3` |
| `summarize.py` | 扫 experiments/ 下指定 model 的最新 json,出 10 行命中表 + 汇总 | `python scripts/summarize.py --model m3` |
PowerShell 批量套路(模型选型阶段用,以后可作为标准跑法):
```powershell
cd E:\tps-dashboard\ai-labeling
3, 4, 5, 7, 10, 11, 12, 13, 14, 15 | ForEach-Object { python scripts/run_labeling.py --ep $_ --model m3 }
python scripts/summarize.py --model m3
```
### 2.3 MODEL_CONFIG 已配置的三家(`scripts/run_labeling.py`)
```python
MODEL_CONFIG = {
"m3": {
"base_url": "https://api.minimaxi.com/v1",
"model_name": "MiniMax-M3",
"api_key_env": "MINIMAX_API_KEY",
},
"deepseek-v4-pro": {
"base_url": "https://api.deepseek.com", # 注意:不带 /v1
"model_name": "deepseek-v4-pro",
"api_key_env": "DEEPSEEK_API_KEY",
},
"mimo-v2.5-pro": {
"base_url": "https://api.xiaomimimo.com/v1",
"model_name": "mimo-v2.5-pro",
"api_key_env": "MIMO_API_KEY",
},
}
```
依赖锁定(`scripts/requirements.txt`):
```
openai==1.55.0 # 不能升级,新版自动转 developer 角色,MiniMax 不支持
python-dotenv>=1.0.0
python-docx>=1.1.0
```
---
## 三、Prompt 2 v0.2 核心设计
(完整文件见 `ai-labeling/prompts/prompt2_narrative.md`,以下是要点摘录)
### 3.1 两档定义(收为 2 档,沿用 v3)
- **主线演进**:全片由"贯穿主线"串起来。主线可以是 a) 内在概念 / b) 时间因果链 / c) 性能阶梯
- **并列结构**:章节相互独立、可替换,共性只来自分类共性
### 3.2 关键边界(共 4 条 + 1 条核心新增)
1. 命名共性不构成主线
2. 装备域共性不构成主线
3. 空间方位共性不构成主线
4. **【v0.2 新增,最重要】段内承接 ≠ 全片骨架**——文稿里某段出现"递进""演进""阶梯""奠定基础"字样,**往往只是段内微观承接**,不是全片骨架。先识别全片大章节,再做章际打乱测试。
### 3.3 强制判断流程(v0.2 新增)
模型必须先输出 `chapter_list`(全片 3-5 个大章节)+ `shuffle_test`(打乱测试结论),才能下判断。避免它一看到"递进"两字就秒判主线演进。
### 3.4 5 个示例(2 主线 + 3 并列,平衡分布)
| 示例 | 类型 | 教学重点 |
|---|---|---|
| 潜艇仿生 | 主线演进-内在概念 | 同一命题贯穿全片 |
| 空战颠覆者 | 主线演进-时间线 | 严格按时间序推进 |
| 马年军事图鉴 | 并列结构-命名共性 | 高收视不靠结构,靠节点策划 |
| **舰证不凡** ⚠️ | **并列结构-警惕段内承接陷阱** | "递进式"字样在段内 ≠ 全片主线 |
| **X-76 飞行器** ⚠️ | **并列结构-警惕段内时间线陷阱** | 时间线只在"背景"段里 ≠ 全片骨架 |
### 3.5 JSON 输出 schema(新增两个强制思考字段)
```json
{
"narrative_structure": "主线演进 或 并列结构",
"chapter_list": ["大章节1", "大章节2", ...], v0.2
"shuffle_test": "打乱后观众怎样的一句话", v0.2
"main_thread": "主线演进时点明主线,并列填 null",
"reasoning": "判断理由,如果文稿有'递进'等字样必须说明是段内还是全片",
"key_evidence": ["证据片段1", "证据片段2"],
"confidence": "高 或 中 或 低",
"confidence_reason": "为什么这个置信度"
}
```
---
## 四、ground-truth v0.2.1 锁定的 10 期分布
| ep | 节目 | share | 叙事结构(v0.2.1) | 开篇钩子 | v0.1 → v0.2.1 变迁 |
|---|---|---|---|---|---|
| 3 | 硅基大脑 | 0.85 | 并列结构 | 中 | 未变 |
| 4 | 潜艇仿生 | 0.92 | 主线演进 | 强 | 未变 |
| 5 | 舰证不凡 | 0.72 | 并列结构 | 中 | 未变(经讨论后维持) |
| 7 | 马年军事图鉴 | 0.95 | 并列结构 | 强 | 未变 |
| 10 | 射速决定论 | 0.703 | **主线演进** | 弱 | v0.1 并列 → v0.2 主线(性能阶梯) |
| 11 | 空战颠覆者 | 0.859 | 主线演进 | 中 | 未变 |
| 12 | 逆袭战局 | 0.85 | **并列结构** | 强 | v0.1 主线 → v0.2.1 并列(三家独立都判并列) |
| 13 | 长短智慧 | 0.533 | 并列结构 | 中 | 未变(经讨论后维持) |
| 14 | X-76 飞行器 | 0.873 | 并列结构 | 中 | 未变(经讨论后维持) |
| 15 | 空中坚盾 | 0.875 | **主线演进** | 强 | v0.1 并列 → v0.2 主线(层级承接) |
**最终分布:5 主线 / 5 并列,平衡。** 此前 v0.1 是 3 主线 / 7 并列。
---
## 五、三家模型最终对比(基于 v0.2.1 修订版试卷)
### 5.1 命中率总表
| 期次 | 修订后标准 | **M3** | **DeepSeek V4 Pro** | **MiMo v2.5 Pro** |
|---|---|---|---|---|
| ep03 | 并列 | ✓ | ✓ | ✓ |
| ep04 | 主线 | ✓ | **✗** | ✓ |
| ep05 | 并列 | ✓ | ✓ | **✗** |
| ep07 | 并列 | ✓ | ✓ | ✓ |
| ep10 | 主线 | ✓ | **✗** | **✗** |
| ep11 | 主线 | ✓ | ✓ | ✓ |
| ep12 | 并列 | ✓ | ✓ | ✓ |
| ep13 | 并列 | ✓ | ✓ | ✓ |
| ep14 | 并列 | ✓ | ✓ | ✓ |
| ep15 | 主线 | ✓ | ✓ | **✗** |
| **命中率** | | **10/10 = 100%** | 8/10 = 80% | 7/10 = 70% |
| **错的方向** | | 无 | 全部"应主线判并列",**偏保守** | 两个方向都错 |
### 5.2 选型结论:MiniMax M3 完胜
理由不只在命中率,更在质量层:
| 维度 | M3 | DeepSeek | MiMo |
|---|---|---|---|
| 命中率 | **100%** | 80% | 70% |
| 三种主线识别能力(内在概念/时间线/性能阶梯/层级承接) | **全识别** | 漏识别 ep04(示例 1 直接教过的潜艇仿生都没认出来) | 漏 2 期主线 |
| Few-shot 学习力 | 强 | **弱**(连示例 1 同型的 ep04 都漏) | 中 |
| reasoning 质量 | chapter_list + shuffle_test + 时序验证完整 | 一般 | 一般 |
| 系统偏差 | 无 | **偏保守** | 偏向不稳定 |
**致命差距**:DeepSeek 连 Prompt 里"示例 1 直接教过的潜艇仿生"都没认出来——这说明它对 few-shot 示例的"听话度"较差,以后加再多反例也可能漏。
### 5.3 落地选型(冻结)
- **生产模型**:MiniMax M3
- **Prompt**:Prompt 2 v0.2(`ai-labeling/prompts/prompt2_narrative.md`)
- **基准卷子**:ground-truth v0.2.1(`ai-labeling/benchmark-set/ground-truth.json`)
- **回退方案**:如 M3 服务中断,DeepSeek V4 Pro 备选(虽然命中率较低,但稳定可用)
---
## 六、关键经验教训(下次接力的我必读)
### 6.1 reasoning model 的输出格式坑
MiniMax M3 是 reasoning model,输出格式是:
```
<think>
模型的内部推理过程(英文,几百字)
</think>
{真正的 JSON 输出}
```
直接 `json.loads(content)` 会失败。脚本里 `extract_json_from_response` 用正则剥掉 `<think>...</think>` 后再解析。**未来如果换其他 reasoning model(R1、o1 系列等)同样适用。**
### 6.2 段内承接 vs 全片骨架(Prompt 2 v0.2 的灵魂)
模型最容易栽的跟头是看到"递进""演进""阶梯"几个字就秒判主线演进。但这些字样常常**只在某一段内**(讲两件装备先后、某段背景的时间线等),不是全片骨架。
判别口诀(已写进 Prompt 2):**先看全片大章节(树干),再看段内细节(树叶)**。章节顺序能不能打乱才是主线判别的唯一依据。
### 6.3 ground-truth 是活的,不是写死的
v0.1 → v0.2(改两期)→ v0.2.1(改一期),共改三期。每次修改都因为发现 v0.1 标的判断与 v3 §1.1 自己定的判别规则有冲突,或者多家模型独立得出反向结论。
**纪律**:基准答案集每次升级,changelog 必须详细记录变更原因,不能"悄悄改"。未来用 pgvector 检索做动态示例集时,固化示例必须明确版本号 + 复议历史。
### 6.4 同一份卷子比三家 vs 优化单家
诱惑很大:M3 90% 后只差一题,继续调 Prompt 上 100% 应该不难。但**这样会过度适配 M3 的脾气**——同一个 Prompt 跑 DeepSeek/MiMo 反而下降。
实践证明:v0.2 Prompt 上 M3 100%,DeepSeek 也吃这套教学(从 70% 升 80%),MiMo 也吃(从 60% 升 70%)。**好的 Prompt 不是为某一家定制,而是把判别规则讲清楚,三家都受益。**
### 6.5 MiniMax M2.7(Cline 的 Plan/Act 模型)写长文件不稳定
中段 Cline 改 run_labeling.py 时撞过:
- `write_to_file` 长内容截断
- 改用辅助脚本生成主文件
- 改用 base64 编码绕过
- 触发 MiniMax 自己的 context 限制
**纪律**:涉及 ai-labeling/ 内文件改动,**老文件用 `replace_in_file` 局部改,新文件用 `write_to_file` 整体写**(<200 行才稳)。Prompt 和 ground-truth 这种长文件,**让制片人手工替换最稳**。
### 6.6 边界期是制片人 + 多家模型共审拍板
ep12 是个标志性案例:制片人 v0.1 标主线演进,M3/DeepSeek/MiMo 三家独立都判并列结构,经制片人复读稿后改并列。**这种"多家独立一致 + 人工复审"的双重证据机制,未来扩展示例集时是黄金流程。**
---
## 七、待办池(追加到 `backlog.md`)
继承 v3 §六的 4 条 + v4 新增 4 条:
### 继承 v3 §六
- **F1. AI 打标示例集更新纪律【优先级:中,上线后启用】**
示例集每月集中替换一次,不碎片化更新(吃 prompt 缓存红利)
- **F2. Prompt 1(4 分类字段)+ Prompt 3(开篇钩子)撰写【优先级:中,Prompt 2 已验证通过,可启动】**
按 Prompt 2 同样套路:Opus 写 → M3 跑基准 → 制片人审 → 锁定
- **F3. Decision 3 横轴量化方法落地【优先级:中】**
v2 §3 已基本定(栏目均值偏离),但还没真正算过 23 期具体数值
- **F4. 23 期回填确认(继承 v2 §5.5)**
ep15 空中坚盾原"空军防空"→确认改 `导弹与反导`?
ep16 启程远航装备域缺失,疑似 `海军舰船`
ep18 海上先锋·无人舰艇 → `海军舰船` + tech_tag=`无人作战`
### v4 新增
- **F5. opening_hook 字段尚未跑过 AI 验证【优先级:中,等 Prompt 3】**
10 期 ground-truth 里 opening_hook 是制片人读稿确认的,但还没让 AI 试着判过。Prompt 3 上线后跑一次,对答案看 M3 在开篇钩子上的命中率。
- **F6. 改 episodes schema 加 6 字段【优先级:高,但必须先切 Plan + Opus 审】**
字段:`program_format / equipment_domain / scene_tags / tech_tags / narrative_structure / opening_hook` + 1 个 `confidence` 字段。**纪律**:Cline 不许直接 Act,必须先 Plan + 我审过迁移方案。回补方案包括 23 期已标注的回填脚本。
- **F7. UI 必须区分置信度三档【优先级:中,Phase 4a/4b 看板设计时落地】**
特别警惕"AI 自评高置信但实际错判"的样本(模型不知道自己错了),UI 上要让制片人能一眼分辨"AI 草稿/制片人确认/标题推断"三档。
- **F8. prompt 缓存月度更新机制【优先级:低,上线后启用】**
v3 §3.7 已经写过纪律,执行时机是 AI 打标系统上线后第 1 个月起。
**追加方式**:你看完后告诉我,我给一段 Cline 指令把 F1-F8 这 8 条追加到 `backlog.md`(如果文件不存在就新建)。
---
## 八、纪律红线(沿用 v3 §七 + v4 增补)
沿用:
- 改表须 Opus 审,Cline 不得自行加字段
- AI 只出草稿、给方向,人拍板
- 不做编导排名(团队视角走"能力地图")
- 未审核字段不上看板,编导只看已确认数据
- AI 打标三个 prompt 独立,不合并
- 示例集每月集中更新,不碎片化(吃缓存红利)
- Prompt 内容不让 Cline 创作——Cline 是执行者不是作者,Prompt 由 Opus 写、Cline 落文件
**v4 新增红线**:
- **AI 打标实验工作区(`ai-labeling/`)与生产代码(`backend/`)严格隔离**
- **`ai-labeling/` 内改动允许 Cline 直接 Act**(沙盒,改坏重跑就是)
- **`backend/` 改动必须切 Plan + Opus 审**(生产代码,改 schema 加字段更要严)
- **长文件改动失败时,让制片人手工替换最稳**(避免 Cline 在 write_to_file 截断时套娃式 workaround)
- **改 ground-truth 必须留 changelog**(谁、何时、改了什么、为什么改)
---
## 九、技术备忘(沿用 v3 §八 + 新增)
沿用:
- 栈:React18 + Vite + AntD5 + Zustand FastAPI + SQLModel + PG16 + pgvector
- 图表:ECharts / @ant-design/charts
- 配色固化:米色底 `#fbf9f1`、深绿主色 `#6b8e6b`
- 三色色板:红 `#c0584f` / 蓝 `#5b8db8` / 绿 `#7aa874`
- 基础线 0.6448 / 摸高线 0.8989(2026)
v4 新增:
- AI 打标模型选型:**MiniMax M3** + `ai-labeling/prompts/prompt2_narrative.md` v0.2
- `summarize.py` 是模型选型基准工具,未来切其他模型继续用
- `experiments/*.json` 不进 git(.gitignore 拦截)
- `ground-truth.json` + `transcripts/*.md` 进 git(栏目核心资产)
- `requirements.txt` 锁 openai==1.55.0(不要升级)
---
## 十、Git 状态
里程碑 commit(2026-06-11 晚):
```
edfb298 chore: TPS 主项目素材积累(海报 logo + 样本 md)
38f3728 feat(ai-labeling): AI 打标实验工作区初始化 + 模型选型完成 ← 今天的硬核成果
ae04c7f chore: gitignore 忽略前端测试题图截图
ae9581e docs: 新增 claude 协作原则文件,backlog 待办池入库
b942907 docs: phase3_log 收尾,Task 3/4 记录归位
```
`ai-labeling/` 已在 Gitea 落地,任意时点可回溯。`.env` / `experiments/` / `__pycache__/` 全部被 `.gitignore` 拦住,无敏感泄露。
---
## 十一、下次开局第一句
> "续接 v3 → v4。AI 打标流水线已跑通,**MiniMax M3 + Prompt 2 v0.2 在 ground-truth v0.2.1 上命中率 100%**,模型选型完成。下一步推 Prompt 1(4 分类字段)+ Prompt 3(开篇钩子),按 v4 同样的'Opus 写 Prompt → M3 跑 10 期基准 → 制片人审 → 锁定'三步走。**改 episodes schema 加 6 字段之前必须切 Plan + Opus 审**——这是宪法红线,不能直接 Act。"
---
## 附:今日核心结论一句话总结
> AI 打标流水线从纸面落地;Prompt 2 v0.2 + ground-truth v0.2.1 经两轮复议锁定;三家模型公平对比(M3 100% / DeepSeek 80% / MiMo 70%)后选 MiniMax M3 为生产模型;Git 双 commit 推 Gitea 落库(里程碑 commit `38f3728`)。明天起可以推 Prompt 1 + Prompt 3,但改 episodes schema 必须先 Plan + Opus 审。