Files
simonkoson 1c3963d17c doco: v2说话人分段模式 — ASR说话人分离+大block拆分+三维动画解说识别
- asr_adapter: 新增roleType=1说话人分离参数,新增parse_order_result_with_speaker(),write_asr_result自动输出asr_v2_timed_spk.txt

- fusion_align: 新增speaker-aware alignment v2流程(_annotate_b_lines_with_speakers区间匹配、_detect_speaker_blocks、SYSTEM_PROMPT_SPEAKER_ALIGN大block拆分prompt、_build_broadcast_segments支持block内多段拆分)

- cli: 兼容v1/v2 stats字典

- 新增convert_to_md.py(20期融合A稿docx转md+YAML frontmatter)

- backup_before_spk/: 修改前代码备份
2026-06-24 16:26:05 +08:00

226 lines
8.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Doco - TPS 工作台 · 终版文稿生成子模块
> 央视《军事科技》栏目 - 终版文稿自动融合流水线
## 项目状态
**✅ 20期全部出稿完成,流水线验证通过。** 16/16批量跑零失败(847分钟)。下一步:制片人逐期核验分段标签 → 带成品回归 TPS 主项目知识库。
---
## 功能概述
《军事科技》每期节目播出后,需要产出一份最接近实际播出的终版文稿。过去靠人工核对,**单期 4-6 小时**。
Doco 把**同一期节目**的三个文本来源自动融合,产出终版文稿:
| 文本来源 | 说明 | 权威范围 |
|---|---|---|
| **A稿**(编导定稿) | 编导剧本的书面结构与分段 | 段落骨架、专业术语规范写法 |
| **B稿v2**(屏幕字幕 OCR) | 视频画面中"黑底白字"字幕的OCR识别结果 | 屏幕术语/型号/番号(≈A稿并列权威) |
| **ASR**(口语转写) | 音轨经讯飞转写的口语实录 | 实际语音、语气、临场措辞 |
**铁律**:正文**汉字零改**——所有正文内容100%来自B稿v2,AI只负责纠错OCR错字、语义对齐分段、按语义插入标点,绝不改任何一个汉字。
最终产出两个**内容一致、形态不同**的交付物:
| 交付物 | 给谁 | 形态 |
|---|---|---|
| **融合B稿** | 爱德华(字幕/片段定位) | 碎句 + 密集字幕级时间戳 `[XmYs] 文本` |
| **融合A稿** | 编导存档 | 公文格式 docx,保留【导视】【主持人N】【解说N】【专家N】【隔断】分段 |
一致性约束:融合A稿**由融合B稿生成**(按A稿分段归拢 + 套格式),不是事后比对硬凑。
---
## 六阶段流水线架构
```
A稿 docx ──► ① 术语提取(C1) ──► 本期热词表
视频 mp4 ──► ② 音频分离 ──► 讯飞ASR(C2) ──► ASR文本(带时间戳)
(黑底白字+ │ │
干净人声) 抽帧+OCR(P1)──► 文本去重(P2)──► B稿v2(碎句+时间戳)
B稿v2 ⊕ ASR ──► ③ 交叉复审(C3) ──► 融合B稿
融合B稿 + A稿骨架 ──► ④ 语义对齐(C4) ──► 融合A稿.docx
```
| 阶段 | 子命令 | 做什么 | 产物 |
|---|---|---|---|
| **P1** | `doco split` | ffmpeg抽帧 + OCR识别屏幕字幕 | 关键帧、音频WAV |
| **P2** | (模板脚本自动) | 字幕文本去重、格式化 | B稿v2.txt(约700-870行) |
| **C1** | `doco terms` | 从A稿提取专有名词 → 累积词典 → 热词表 | 本期热词表(给ASR用) |
| **C2** | `doco asr` | 音频分离 → 讯飞ASR转写 | asr_v2_timed.txt |
| **C3** | `doco fuse` | B稿⊕ASR 交叉复审,AI纠错 | 融合B稿.txt + fusion_review.csv |
| **C4** | `doco compose` | 按A稿分段骨架语义对齐 → 套公文格式 | 融合A稿.docx + c4_alignment.csv |
---
## 系统依赖
### ffmpeg(必须)
**Windows 用户:**
1. 从 https://www.gyan.dev/ffmpeg/builds/ 下载 ffmpeg(建议用 essentials 版本)
2. 解压到本地目录(如 `C:\ffmpeg`
3.`C:\ffmpeg\bin` 加入系统 PATH
4. 打开 cmd,验证:`ffmpeg -version`
**Mac / Linux 用户:**
```bash
# Mac
brew install ffmpeg
# Linux
apt install ffmpeg
```
### Python >= 3.12
---
## 安装
```bash
# 1. 进入 doco 目录
cd doco
# 2. 安装(可编辑模式)
pip install -e .
# 3. 配置凭证(见下节)
cp .env.example .env
```
## 凭证配置
`doco/.env` 中配置以下变量(**已在 .gitignore 中,不会入库**):
| 变量名 | 用途 |
|---|---|
| `LLM_API_KEY` | LLM融合层API密钥(当前用小米 MiMo 2.5 Pro |
| `LLM_BASE_URL` | LLM API地址(OpenAI兼容端点) |
| `LLM_MODEL` | 模型名称(如 `mimo-v2.5-pro` |
| `XFYUN_APP_ID` | 讯飞开放平台 APP ID |
| `XFYUN_SECRET_KEY` | 讯飞开放平台 SECRET KEY |
> ⚠️ 讯飞要用「录音文件转写**标准版**」,不要用"大模型版"(免费包阉割 `language` 参数,会报误导性错误)。
---
## 使用方式
### 一键全流程(推荐)
```bash
doco run \
--episode-id ep001_20260612_fangkong_fandao \
--a-script programs/ep001_20260612_fangkong_fandao/source/a_draft.docx \
--input-video programs/ep001_20260612_fangkong_fandao/source/video.mp4
```
串联 P1→P2→C1→C2→C3→C4 六个阶段,中间产物自动落盘,各阶段可断点续跑(已有产物自动跳过)。
**可选参数:**
- `--skip-p1`:跳过P1/P2(已有B稿v2时使用)
- `--batch-size 25`C4对齐每批行数(默认25,可调)
> ⚠️ C4 开始前要求骨架文件已存在,需**先手动**运行 `doco skeleton` 并人工核验:
> ```bash
> doco skeleton --episode-id <id> --a-script <a_draft.docx>
> # 检查输出的骨架预览表,确认无误后再跑 doco run
> ```
### 各子命令(可单独运行)
```bash
# P1: 视频拆分(抽帧 + OCR + 音频分离)
doco split --episode-id <id> --input-video <mp4> --output-dir <dir>
# C1: 术语提取
doco terms --episode-id <id> --a-script <docx>
# C2: 讯飞ASR转写
doco asr --episode-id <id> --input-video <mp4> --output-dir <dir>
# C3: 交叉复审融合
doco fuse --episode-id <id> [--batch-size 35]
# C4: 对齐出稿
doco compose --episode-id <id> [--batch-size 25]
```
> ⚠️ `--output-dir` 务必传**绝对路径**,否则产物会落到当前工作目录,与 doco 产物分家。
---
## 目录结构
```
doco/
├── src/doco/
│ ├── __init__.py
│ ├── cli.py # CLI 入口(doco run/split/terms/asr/fuse/skeleton/compose
│ ├── video_split.py # P1: 抽帧 + 音频分离(ffmpeg
│ ├── llm.py # LLM 统一客户端(OpenAI兼容)
│ ├── term_extract.py # C1: 规则层+AI层术语提取
│ ├── asr_adapter.py # C2: 讯飞ASR适配层
│ ├── fusion_review.py # C3: B稿⊕ASR交叉复审
│ ├── fusion_align.py # C4: A稿骨架抽取+语义对齐+出稿
│ └── templates/ # P1/P2 模板脚本
│ ├── stage_a_extract_ocr.py # P1 抽帧+OCR
│ └── stage_b_dedup_output.py # P2 文本去重
├── programs/ # 每期节目产物(按 episode_id 分目录)
│ └── <episode_id>/
│ ├── source/ # 输入(video.mp4 + a_draft.docx
│ ├── B稿_v2.txt # P2 产出的OCR字幕文本
│ ├── audio_16k.wav # 分离的音频(16kHz/单声道/16bit
│ ├── asr_v2_timed.txt # ASR转写结果(带时间戳)
│ ├── <id>_a_skeleton.json # A稿分段骨架
│ ├── 融合B稿.txt # C3 产出
│ ├── fusion_review.csv # C3 复审留痕
│ ├── 融合A稿.docx # C4 最终交付物
│ └── c4_alignment.csv # C4 对齐留痕
├── data/
│ └── term_dict.json # 累积术语词典(逐期更新)
├── deliverables/ # 已完成的融合A稿展示
├── note/ # 设计文档、PRD、决策记录
├── tests/ # 测试
├── CLAUDE.md # 项目协作主控文件(交接、决策、状态)
├── pyproject.toml
└── .env.example # 凭证模板
```
---
## 设计原则
- **汉字零改**:正文100%来自B稿v2,AI只做OCR纠错+语义对齐+标点插入,绝不改任何一个汉字。`strip_punct()`硬校验守门。
- **有序无阻塞**:全自动产出,拿不准的地方全部进 `fusion_review.csv` 留痕,绝不卡出稿。
- **各阶段解耦**:中间产物落缓存,可断点续跑,可单独重跑,失败不影响已完成阶段。
- **专名铁律**:厂名/型号/番号/国名/人名/机构名,B稿与ASR同音异写时**一律以B稿为准**,零容忍采ASR。
- **OCR漏字不补**:缺的字是真实信息丢失,不让LLM补词(LLM补词=猜词=破红线)。
---
## 相关文档
- **项目协作主控文件**`CLAUDE.md`(状态、交接、关键决策,新接手者首选阅读)
- **子项目Brief**`note/Doco子项目_Brief.md`(红线、技术栈、出入口接口)
- **PRD**`note/PRD_doco_文稿整理子项目_v2.md`(需求规格、方案选型)
- **P3设计稿**`note/doco_P3_设计稿.md`(三方融合架构设计)
- **快照与决策记录**`note/` 目录下其他文件
---
## 技术栈
- **语言**Python ≥ 3.12
- **LLM**:小米 MiMo 2.5 ProOpenAI兼容端点,`openai` SDK
- **OCR**:本地 Ollama + DeepSeek-OCR 模型
- **ASR**:讯飞开放平台 录音文件转写(标准版)
- **视频处理**ffmpegsubprocess调用)
- **文档生成**python-docx
- **CLI框架**Click