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/: 修改前代码备份
This commit is contained in:
+164
-113
@@ -1,175 +1,226 @@
|
||||
# Doco - TPS 中台终版文稿生成子模块
|
||||
# Doco - TPS 工作台 · 终版文稿生成子模块
|
||||
|
||||
> 央视《军事科技》栏目 - 终版文稿自动生成流水线
|
||||
> 央视《军事科技》栏目 - 终版文稿自动融合流水线
|
||||
|
||||
## 项目状态
|
||||
|
||||
**当前 Phase: P1** - 视频双路拆分预处理
|
||||
**✅ 20期全部出稿完成,流水线验证通过。** 16/16批量跑零失败(847分钟)。下一步:制片人逐期核验分段标签 → 带成品回归 TPS 主项目知识库。
|
||||
|
||||
---
|
||||
|
||||
## 功能概述
|
||||
|
||||
Doco 将一期《军事科技》节目视频拆分为两路输入,供下游三方融合(P3)使用:
|
||||
《军事科技》每期节目播出后,需要产出一份最接近实际播出的终版文稿。过去靠人工核对,**单期 4-6 小时**。
|
||||
|
||||
| 输出 | 规格 | 存放位置 |
|
||||
Doco 把**同一期节目**的三个文本来源自动融合,产出终版文稿:
|
||||
|
||||
| 文本来源 | 说明 | 权威范围 |
|
||||
|---|---|---|
|
||||
| B 稿 | 带时间戳的 txt,`[Nm Ns] 句子`格式 | `work/b_manuscript.txt` |
|
||||
| 音频 | 16kHz / 单声道 / 16bit WAV | `work/audio_16k.wav` |
|
||||
| 关键帧索引 | JSON | `work/keyframes.json` |
|
||||
| **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 (必须)
|
||||
### ffmpeg(必须)
|
||||
|
||||
**Windows 用户:**
|
||||
1. 从 https://www.gyan.dev/ffmpeg/builds/ 下载 ffmpeg (建议用 essentials 版本)
|
||||
2. 解压到本地目录(如 `C:\ffmpeg`)
|
||||
**Windows 用户:**
|
||||
1. 从 https://www.gyan.dev/ffmpeg/builds/ 下载 ffmpeg(建议用 essentials 版本)
|
||||
2. 解压到本地目录(如 `C:\ffmpeg`)
|
||||
3. 把 `C:\ffmpeg\bin` 加入系统 PATH
|
||||
4. 打开 cmd,验证: `ffmpeg -version`
|
||||
4. 打开 cmd,验证:`ffmpeg -version`
|
||||
|
||||
**Mac 用户:**
|
||||
**Mac / Linux 用户:**
|
||||
```bash
|
||||
# Mac
|
||||
brew install ffmpeg
|
||||
```
|
||||
|
||||
**Linux 用户:**
|
||||
```bash
|
||||
# Linux
|
||||
apt install ffmpeg
|
||||
```
|
||||
|
||||
### Python >= 3.12
|
||||
|
||||
---
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
# 1. 克隆仓库后进入 doco 目录
|
||||
# 1. 进入 doco 目录
|
||||
cd doco
|
||||
|
||||
# 2. 安装依赖
|
||||
# 2. 安装(可编辑模式)
|
||||
pip install -e .
|
||||
|
||||
# 3. 配置凭证
|
||||
# 3. 配置凭证(见下节)
|
||||
cp .env.example .env
|
||||
# 编辑 .env,填入三组 API 凭证
|
||||
```
|
||||
|
||||
## 凭证配置
|
||||
|
||||
Doco 使用三组独立凭证,互不混用:
|
||||
在 `doco/.env` 中配置以下变量(**已在 .gitignore 中,不会入库**):
|
||||
|
||||
| 服务 | 用途 | 申请地址 |
|
||||
|---|---|---|
|
||||
| 讯飞开放平台 - 录音文件转写(标准版) | 音频转文字 | https://console.xfyun.cn/ |
|
||||
| DeepSeek Vision | OCR 识别 | https://platform.deepseek.com/ |
|
||||
| Anthropic Claude API | AI 融合层(P3) | https://console.anthropic.com/ |
|
||||
| 变量名 | 用途 |
|
||||
|---|---|
|
||||
| `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` 参数,会报误导性错误)。
|
||||
|
||||
## 使用步骤(按顺序,不要跳步)
|
||||
---
|
||||
|
||||
### Step A. 安装 ffmpeg
|
||||
## 使用方式
|
||||
|
||||
见上方"系统依赖"一节。安装后打开 cmd 验证 `ffmpeg -version` 能看到版本号。
|
||||
|
||||
### Step B. 生成迷你测试视频(验证 ffmpeg 装好了)
|
||||
### 一键全流程(推荐)
|
||||
|
||||
```bash
|
||||
ffmpeg -f lavfi -i testsrc=duration=5:size=320x240:rate=1 \
|
||||
-f lavfi -i anullsrc=channel_layout=mono:sample_rate=16000 \
|
||||
-c:v libx264 -c:a aac -shortest \
|
||||
doco/tests/fixtures/mini_test.mp4 -y
|
||||
```
|
||||
|
||||
出现 `mini_test.mp4` 文件即成功。
|
||||
|
||||
### Step C. 把 demo 视频放到指定位置
|
||||
|
||||
```bash
|
||||
# 把 demo 视频文件复制到:
|
||||
programs/ep001_20260612_fangkong_fandao/source/video.mp4
|
||||
```
|
||||
|
||||
> video.mp4 由制片人放入,不放进 git(已加入 .gitignore)
|
||||
|
||||
### Step D. 配置凭证
|
||||
|
||||
```bash
|
||||
cp doco/.env.example doco/.env
|
||||
# 用记事本或 VS Code 编辑 doco/.env,填入三组真实 API key
|
||||
```
|
||||
|
||||
### Step E. 安装 doco 包
|
||||
|
||||
```bash
|
||||
cd doco && pip install -e .
|
||||
```
|
||||
|
||||
### Step F. 跑 dry-run(只裁切,不调 OCR API)
|
||||
|
||||
**重要:先跑 dry-run,确认裁切框包住字幕后再跑正式版。**
|
||||
|
||||
```bash
|
||||
doco split \
|
||||
doco run \
|
||||
--episode-id ep001_20260612_fangkong_fandao \
|
||||
--input-video programs/ep001_20260612_fangkong_fandao/source/video.mp4 \
|
||||
--output-dir programs/ep001_20260612_fangkong_fandao/work/ \
|
||||
--dry-run
|
||||
--a-script programs/ep001_20260612_fangkong_fandao/source/a_draft.docx \
|
||||
--input-video programs/ep001_20260612_fangkong_fandao/source/video.mp4
|
||||
```
|
||||
|
||||
**验收 dry-run 结果:**
|
||||
1. 检查 `work/frames/` 目录下的前 3-5 张关键帧小图
|
||||
2. 确认字幕被完整框住、没有切掉字
|
||||
3. 如果裁切位置不对,停下来反馈
|
||||
串联 P1→P2→C1→C2→C3→C4 六个阶段,中间产物自动落盘,各阶段可断点续跑(已有产物自动跳过)。
|
||||
|
||||
### Step G. 跑正式版(去掉 --dry-run)
|
||||
**可选参数:**
|
||||
- `--skip-p1`:跳过P1/P2(已有B稿v2时使用)
|
||||
- `--batch-size 25`:C4对齐每批行数(默认25,可调)
|
||||
|
||||
dry-run 验收通过后,跑正式版:
|
||||
> ⚠️ C4 开始前要求骨架文件已存在,需**先手动**运行 `doco skeleton` 并人工核验:
|
||||
> ```bash
|
||||
> doco skeleton --episode-id <id> --a-script <a_draft.docx>
|
||||
> # 检查输出的骨架预览表,确认无误后再跑 doco run
|
||||
> ```
|
||||
|
||||
### 各子命令(可单独运行)
|
||||
|
||||
```bash
|
||||
doco split \
|
||||
--episode-id ep001_20260612_fangkong_fandao \
|
||||
--input-video programs/ep001_20260612_fangkong_fandao/source/video.mp4 \
|
||||
--output-dir programs/ep001_20260612_fangkong_fandao/work/
|
||||
# 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 产物分家。
|
||||
|
||||
```
|
||||
programs/ep001_20260612_fangkong_fandao/work/
|
||||
├── frames/ # 抽出的帧(临时)
|
||||
├── audio_16k.wav # 音频(16kHz/单声道/16bit)
|
||||
├── b_manuscript.txt # B 稿([Nm Ns] 句子格式)
|
||||
└── keyframes.json # 关键帧索引(含裁切参数)
|
||||
```
|
||||
|
||||
## P1 验收标准
|
||||
|
||||
1. `work/b_manuscript.txt` 格式为 `[Nm Ns] 句子`,每行一句
|
||||
2. `work/audio_16k.wav` 规格为 16kHz/单声道/16bit,能被讯飞 ASR 接收
|
||||
3. `work/keyframes.json` 字段符合定义
|
||||
---
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
doco/
|
||||
├── src/
|
||||
├── src/doco/
|
||||
│ ├── __init__.py
|
||||
│ ├── cli.py # CLI 入口
|
||||
│ ├── video_split.py # P1 核心:视频双路拆分
|
||||
│ ├── asr_adapter.py # 讯飞 ASR 适配层
|
||||
│ └── ocr_adapter.py # P2:DeepSeek Vision OCR
|
||||
├── tests/
|
||||
│ ├── test_video_split.py # 单元测试
|
||||
│ └── fixtures/
|
||||
│ └── mini_test.mp4 # 迷你测试视频(需 Step B 生成)
|
||||
├── docs/
|
||||
├── .env.example # 凭证模板
|
||||
├── README.md
|
||||
└── pyproject.toml
|
||||
│ ├── 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补词=猜词=破红线)。
|
||||
|
||||
---
|
||||
|
||||
## 相关文档
|
||||
|
||||
- Brief: `docs/doco/Doco子项目_Brief.md`
|
||||
- 设计文档: `docs/doco/doco_project_design.md`
|
||||
- 讯飞接入笔记: `docs/doco/doco_xfyun_integration_notes.md`
|
||||
- 主项目回复: `docs/doco/主project对Doco_PRDv2的回复.md`
|
||||
- **项目协作主控文件**:`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 Pro(OpenAI兼容端点,`openai` SDK)
|
||||
- **OCR**:本地 Ollama + DeepSeek-OCR 模型
|
||||
- **ASR**:讯飞开放平台 录音文件转写(标准版)
|
||||
- **视频处理**:ffmpeg(subprocess调用)
|
||||
- **文档生成**:python-docx
|
||||
- **CLI框架**:Click
|
||||
Reference in New Issue
Block a user