351 lines
14 KiB
Markdown
351 lines
14 KiB
Markdown
# AI解说脚本生成
|
||
|
||
<cite>
|
||
**本文引用的文件列表**
|
||
- [main.py](file://main.py)
|
||
- [scripter.py](file://backend/scripter.py)
|
||
- [extractor.py](file://backend/extractor.py)
|
||
- [schemas.py](file://backend/video_processor/schemas.py)
|
||
- [render-props-types.ts](file://frontend/src/render-props-types.ts)
|
||
- [requirements.txt](file://requirements.txt)
|
||
- [.env.example](file://.env.example)
|
||
- [PROJECT_README.md](file://PROJECT_README.md)
|
||
- [investigate_video_extraction.py](file://backend/investigate_video_extraction.py)
|
||
- [investigate_subtitle_extraction.py](file://backend/investigate_subtitle_extraction.py)
|
||
- [investigate_media_fetch.py](file://backend/investigate_media_fetch.py)
|
||
</cite>
|
||
|
||
## 目录
|
||
1. [简介](#简介)
|
||
2. [项目结构](#项目结构)
|
||
3. [核心组件](#核心组件)
|
||
4. [架构总览](#架构总览)
|
||
5. [详细组件分析](#详细组件分析)
|
||
6. [依赖分析](#依赖分析)
|
||
7. [性能考虑](#性能考虑)
|
||
8. [故障排查指南](#故障排查指南)
|
||
9. [结论](#结论)
|
||
10. [附录](#附录)
|
||
|
||
## 简介
|
||
本文件面向“AI解说脚本生成”模块,聚焦于如何基于结构化财务数据(来自PDF提取)与可选的视频转写结果,通过Google Gemini Pro API生成自然流畅的日语解说词。文档从提示工程设计、API调用流程、重试与解析策略、脚本段落结构与时间轴映射、调试技巧与多语言扩展等方面进行系统化阐述,帮助开发者快速实现并优化该模块。
|
||
|
||
## 项目结构
|
||
当前仓库采用“Python后端 + TypeScript前端”的混合架构:
|
||
- 后端负责:PDF与视频数据抽取、财务模拟、脚本生成、B-Roll抓取、渲染参数构建
|
||
- 前端使用Remotion渲染最终视频,类型定义由Zod校验
|
||
|
||
```mermaid
|
||
graph TB
|
||
A["main.py<br/>主入口与流水线编排"] --> B["backend/scripter.py<br/>脚本生成器"]
|
||
A --> C["backend/extractor.py<br/>PDF/视频抽取"]
|
||
A --> D["backend/data_builder.py<br/>财务模拟与图表数据"]
|
||
A --> E["backend/media_fetcher.py<br/>B-Roll抓取"]
|
||
A --> F["frontend/src/render-props-types.ts<br/>渲染参数类型定义"]
|
||
B --> G["google-generativeai<br/>Gemini API"]
|
||
C --> H["openai/whisper<br/>音频转写"]
|
||
D --> I["FFmpeg/媒体工具"]
|
||
E --> J["Pexels API"]
|
||
```
|
||
|
||
图示来源
|
||
- [main.py](file://main.py#L1-L120)
|
||
- [scripter.py](file://backend/scripter.py#L1-L69)
|
||
- [extractor.py](file://backend/extractor.py#L1-L84)
|
||
- [render-props-types.ts](file://frontend/src/render-props-types.ts#L52-L120)
|
||
- [requirements.txt](file://requirements.txt#L1-L34)
|
||
|
||
章节来源
|
||
- [PROJECT_README.md](file://PROJECT_README.md#L1-L120)
|
||
- [main.py](file://main.py#L1-L120)
|
||
|
||
## 核心组件
|
||
- 脚本生成器(ScriptGenerator)
|
||
- 负责构建提示词、调用Gemini Pro API、解析响应并估算每段时长
|
||
- 当前为占位实现,尚未接入真实API
|
||
- 数据抽取器(PDFExtractor/VideoExtractor)
|
||
- PDFExtractor:计划使用Gemini Pro从PDF中抽取结构化数据
|
||
- VideoExtractor:计划使用Whisper进行音频转写与关键时间戳提取
|
||
- 视频处理数据结构(VideoSegment/KeyMoment/VideoAnalysisResult)
|
||
- 定义视频片段、关键时刻与完整分析结果的数据契约
|
||
- 渲染参数类型(ScriptSegment等)
|
||
- 定义脚本段落结构、图表同步、资产引用等前端消费所需字段
|
||
|
||
章节来源
|
||
- [scripter.py](file://backend/scripter.py#L1-L69)
|
||
- [extractor.py](file://backend/extractor.py#L1-L84)
|
||
- [schemas.py](file://backend/video_processor/schemas.py#L1-L91)
|
||
- [render-props-types.ts](file://frontend/src/render-props-types.ts#L52-L120)
|
||
|
||
## 架构总览
|
||
脚本生成在整体流水线中的位置如下:
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant CLI as "命令行(main.py)"
|
||
participant EX as "PDF/视频抽取(extractor.py)"
|
||
participant SG as "脚本生成(scripter.py)"
|
||
participant GEM as "Gemini Pro API"
|
||
participant CH as "图表数据(data_builder.py)"
|
||
participant OUT as "渲染参数(render-props-types.ts)"
|
||
CLI->>EX : 提取PDF/视频数据
|
||
EX-->>CLI : 返回结构化数据
|
||
CLI->>SG : 生成日语脚本
|
||
SG->>GEM : 发送提示词与上下文
|
||
GEM-->>SG : 返回JSON结构化脚本
|
||
SG-->>CLI : 返回脚本段落与同步点
|
||
CLI->>CH : 构建图表数据
|
||
CH-->>CLI : 返回图表数据
|
||
CLI->>OUT : 组装render_props.json
|
||
OUT-->>CLI : 类型校验通过
|
||
```
|
||
|
||
图示来源
|
||
- [main.py](file://main.py#L80-L160)
|
||
- [scripter.py](file://backend/scripter.py#L20-L69)
|
||
- [extractor.py](file://backend/extractor.py#L1-L84)
|
||
- [render-props-types.ts](file://frontend/src/render-props-types.ts#L116-L140)
|
||
|
||
## 详细组件分析
|
||
|
||
### 脚本生成器(ScriptGenerator)设计
|
||
- 输入
|
||
- pdf_data:结构化财务数据(年龄、收入、支出、资产、重大事件等)
|
||
- video_data:可选的视频转写与时间戳(用于个性化叙述与同步)
|
||
- style:叙述风格(友好/专业/随意),用于提示词风格约束
|
||
- 输出
|
||
- segments:脚本段落列表(包含日语文本、时长、类型、可选图表同步)
|
||
- total_duration:预估总时长(秒)
|
||
- sync_points:建议的图表/视频同步点
|
||
- 当前状态
|
||
- 占位实现,未接入Gemini Pro API;需补充提示工程、API调用、重试与解析逻辑
|
||
|
||
```mermaid
|
||
classDiagram
|
||
class ScriptGenerator {
|
||
+api_key : string
|
||
+generate(pdf_data, video_data, style) Dict
|
||
-_build_prompt(pdf_data, style) str
|
||
}
|
||
class ScriptSegment {
|
||
+id : number
|
||
+text : string
|
||
+duration : number
|
||
+type : string
|
||
+assetUrl? : string
|
||
+chartSync? : object
|
||
}
|
||
ScriptGenerator --> ScriptSegment : "生成并返回"
|
||
```
|
||
|
||
图示来源
|
||
- [scripter.py](file://backend/scripter.py#L14-L69)
|
||
- [render-props-types.ts](file://frontend/src/render-props-types.ts#L74-L93)
|
||
|
||
章节来源
|
||
- [scripter.py](file://backend/scripter.py#L14-L69)
|
||
- [render-props-types.ts](file://frontend/src/render-props-types.ts#L74-L93)
|
||
|
||
### 提示工程(Prompt Engineering)设计原理
|
||
- 系统提示词(System Prompt)
|
||
- 明确角色:作为日语AI解说员,面向普通观众,语气自然、有亲和力
|
||
- 任务目标:将结构化财务数据转化为连贯、易懂的日语解说词
|
||
- 输出格式:严格要求JSON结构,包含segments数组、total_duration、sync_points
|
||
- 长度约束:目标3-5分钟,避免冗长或过短
|
||
- 上下文注入(Context Injection)
|
||
- 将pdf_data中的关键信息(年龄、收入、支出、资产、重大事件年份)注入提示词
|
||
- 可选地注入video_data(转写文本、关键词、时间戳),用于个性化与同步
|
||
- 输出格式控制(Output Formatting Control)
|
||
- 强制要求JSON,避免自然语言混入
|
||
- 对segments的字段进行白名单约束(id、text、duration、type、chartSync等)
|
||
- 示例流程(概念性)
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Start(["开始"]) --> BuildSys["构建系统提示词<br/>角色/目标/格式/长度约束"]
|
||
BuildSys --> InjectPDF["注入PDF结构化数据"]
|
||
InjectPDF --> InjectVideo["可选:注入视频转写与时间戳"]
|
||
InjectVideo --> BuildPrompt["组合最终提示词"]
|
||
BuildPrompt --> CallAPI["调用Gemini Pro API"]
|
||
CallAPI --> ParseResp["解析响应为JSON"]
|
||
ParseResp --> Validate["校验字段完整性"]
|
||
Validate --> |通过| Estimate["估算每段时长与总时长"]
|
||
Validate --> |失败| Retry["重试/修正提示词"]
|
||
Retry --> BuildPrompt
|
||
Estimate --> SyncPts["生成图表/视频同步点"]
|
||
SyncPts --> End(["结束"])
|
||
```
|
||
|
||
[此图为概念流程图,不直接映射具体源码,故无图示来源]
|
||
|
||
### Gemini API调用流程、重试机制与响应解析
|
||
- 调用流程(参考现有视频抽取实现)
|
||
- 初始化客户端与模型(例如使用gemini-3-pro-preview)
|
||
- 准备内容:媒体文件与提示词
|
||
- 发送请求并记录token用量
|
||
- 解析响应:优先从Markdown代码块中提取JSON
|
||
- 错误处理:捕获JSON解析异常,回退到原始文本并记录元数据
|
||
- 重试机制
|
||
- 建议在请求失败或解析失败时进行指数退避重试
|
||
- 设置最大重试次数与超时阈值
|
||
- 响应解析
|
||
- 严格按预期字段解包segments、total_duration、sync_points
|
||
- 对缺失字段进行默认值填充或抛出明确错误
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant SG as "ScriptGenerator"
|
||
participant CL as "Gemini Client"
|
||
participant API as "Gemini API"
|
||
participant PARSE as "响应解析器"
|
||
SG->>CL : 初始化客户端与模型
|
||
SG->>CL : 组装contents(媒体/提示词)
|
||
CL->>API : 发送请求
|
||
API-->>CL : 返回响应
|
||
CL->>PARSE : 提取文本并尝试解析JSON
|
||
PARSE-->>SG : 返回segments/时长/同步点
|
||
alt 解析失败
|
||
PARSE-->>SG : 报错并返回原始文本
|
||
SG->>SG : 触发重试/修正提示词
|
||
end
|
||
```
|
||
|
||
图示来源
|
||
- [investigate_video_extraction.py](file://backend/investigate_video_extraction.py#L1-L232)
|
||
- [investigate_subtitle_extraction.py](file://backend/investigate_subtitle_extraction.py#L228-L256)
|
||
- [investigate_media_fetch.py](file://backend/investigate_media_fetch.py#L111-L136)
|
||
|
||
章节来源
|
||
- [investigate_video_extraction.py](file://backend/investigate_video_extraction.py#L1-L232)
|
||
- [investigate_subtitle_extraction.py](file://backend/investigate_subtitle_extraction.py#L228-L256)
|
||
- [investigate_media_fetch.py](file://backend/investigate_media_fetch.py#L111-L136)
|
||
|
||
### 脚本段落(ScriptSegment)结构与时间轴映射
|
||
- 结构设计
|
||
- 字段:id、text(日语)、duration(秒)、type(narration/chart_intro/chart_highlight/video_clip/transition)、assetUrl(可选)、chartSync(可选)
|
||
- chartSync:支持chartId(assetDepletion/cashFlow)、highlightYear、animationStart等
|
||
- 时间轴映射
|
||
- 每个ScriptSegment包含duration,便于与视频时间轴对齐
|
||
- 可通过chartSync将脚本与图表高亮帧对齐,提升叙事节奏感
|
||
- 与视频时间轴的关系
|
||
- 若存在video_data,可将脚本与视频转写的时间戳对齐,形成“字幕/旁白/画面”的三线同步
|
||
|
||
```mermaid
|
||
erDiagram
|
||
SCRIPT_SEGMENT {
|
||
number id
|
||
string text
|
||
number duration
|
||
string type
|
||
string assetUrl
|
||
object chartSync
|
||
}
|
||
RENDER_PROPS {
|
||
array script
|
||
object charts
|
||
object assets
|
||
}
|
||
SCRIPT_SEGMENT ||--o{ RENDER_PROPS : "组成"
|
||
```
|
||
|
||
图示来源
|
||
- [render-props-types.ts](file://frontend/src/render-props-types.ts#L74-L120)
|
||
|
||
章节来源
|
||
- [render-props-types.ts](file://frontend/src/render-props-types.ts#L74-L120)
|
||
|
||
### 多语言支持与扩展路径
|
||
- 当前目标语言为日语,提示工程已体现“自然日语”与“友好语气”
|
||
- 扩展思路
|
||
- 在提示词中加入语言切换参数(如“输出为英语/中文”)
|
||
- 为不同语言维护独立的系统提示词模板
|
||
- 通过外部翻译服务或多语言模型实现跨语言生成
|
||
- 注意事项
|
||
- 不同语言的句式结构与停顿节奏差异较大,需分别训练与校准每段时长
|
||
- 图表标注与视觉元素需配合目标语言的表达习惯
|
||
|
||
[本节为概念性扩展说明,不直接分析具体源码,故无章节来源]
|
||
|
||
## 依赖分析
|
||
- 外部依赖
|
||
- google-generativeai:Gemini Pro API调用
|
||
- openai:Whisper音频转写(视频抽取阶段)
|
||
- ffmpeg-python:媒体处理
|
||
- requests:网络请求(B-Roll抓取等)
|
||
- 内部耦合
|
||
- main.py编排脚本生成与后续步骤
|
||
- scripter.py与extractor.py、data_builder.py共同构成数据-脚本-图表闭环
|
||
- frontend的类型定义确保前后端数据契约一致
|
||
|
||
```mermaid
|
||
graph LR
|
||
REQ["requirements.txt"] --> GEM["google-generativeai"]
|
||
REQ --> WHIS["openai"]
|
||
REQ --> FF["ffmpeg-python"]
|
||
REQ --> REQ2["requests"]
|
||
MAIN["main.py"] --> SCR["backend/scripter.py"]
|
||
MAIN --> EXT["backend/extractor.py"]
|
||
MAIN --> DAT["backend/data_builder.py"]
|
||
SCR --> GEM
|
||
EXT --> WHIS
|
||
DAT --> FF
|
||
```
|
||
|
||
图示来源
|
||
- [requirements.txt](file://requirements.txt#L1-L34)
|
||
- [main.py](file://main.py#L1-L120)
|
||
|
||
章节来源
|
||
- [requirements.txt](file://requirements.txt#L1-L34)
|
||
- [main.py](file://main.py#L1-L120)
|
||
|
||
## 性能考虑
|
||
- API调用成本控制
|
||
- 通过精简提示词与上下文注入,减少token用量
|
||
- 使用缓存策略(如翻译缓存)降低重复请求
|
||
- 响应解析效率
|
||
- 优先从代码块中提取JSON,避免全量字符串扫描
|
||
- 对大响应进行分段解析与字段校验
|
||
- 时长估算与同步
|
||
- 基于平均语速估算每段时长,结合chartSync进行微调
|
||
- 通过sync_points与视频转写时间戳对齐,减少后期调整工作量
|
||
|
||
[本节提供通用指导,不直接分析具体源码,故无章节来源]
|
||
|
||
## 故障排查指南
|
||
- API密钥问题
|
||
- 确认环境变量GEMINI_API_KEY/OPENAI_API_KEY已正确设置
|
||
- 检查密钥是否过期或被限制
|
||
- API限流与超时
|
||
- 实施指数退避重试,设置合理超时阈值
|
||
- 分批发送请求,避免突发流量
|
||
- JSON解析失败
|
||
- 捕获JSONDecodeError,记录原始响应与token用量
|
||
- 回退到原始文本并人工检查提示词格式
|
||
- 时长与同步偏差
|
||
- 校验segments的duration与chartSync字段
|
||
- 与视频转写时间戳进行交叉验证
|
||
|
||
章节来源
|
||
- [.env.example](file://.env.example#L1-L22)
|
||
- [investigate_video_extraction.py](file://backend/investigate_video_extraction.py#L1-L232)
|
||
- [investigate_subtitle_extraction.py](file://backend/investigate_subtitle_extraction.py#L228-L256)
|
||
- [investigate_media_fetch.py](file://backend/investigate_media_fetch.py#L111-L136)
|
||
|
||
## 结论
|
||
脚本生成模块目前处于占位实现阶段,但其设计已清晰体现了提示工程、API调用、重试与解析、以及脚本段落与时间轴映射的核心要素。结合现有视频抽取与解析实现,可快速补齐Gemini Pro集成,完成从结构化财务数据到自然日语脚本的自动化生成,并为后续多语言扩展打下基础。
|
||
|
||
[本节为总结性内容,不直接分析具体源码,故无章节来源]
|
||
|
||
## 附录
|
||
- 环境变量与API密钥
|
||
- GEMINI_API_KEY:Gemini Pro
|
||
- OPENAI_API_KEY:Whisper
|
||
- PEXELS_API_KEY:B-Roll抓取
|
||
- 关键实现参考
|
||
- 视频抽取与JSON解析流程可作为Gemini脚本生成的参考模板
|
||
|
||
章节来源
|
||
- [.env.example](file://.env.example#L1-L22)
|
||
- [investigate_video_extraction.py](file://backend/investigate_video_extraction.py#L1-L232)
|
||
- [investigate_subtitle_extraction.py](file://backend/investigate_subtitle_extraction.py#L228-L256) |