455 lines
14 KiB
Markdown
455 lines
14 KiB
Markdown
# 架构设计
|
||
|
||
<cite>
|
||
**本文档中引用的文件**
|
||
- [main.py](file://main.py)
|
||
- [render-props-types.ts](file://frontend/src/render-props-types.ts)
|
||
- [data_builder.py](file://backend/data_builder.py)
|
||
- [extractor.py](file://backend/extractor.py)
|
||
- [scripter.py](file://backend/scripter.py)
|
||
- [media_fetcher.py](file://backend/media_fetcher.py)
|
||
- [Root.tsx](file://src/Root.tsx)
|
||
- [LifePlanChart.tsx](file://src/LifePlanChart.tsx)
|
||
- [CashFlowChart.tsx](file://src/CashFlowChart.tsx)
|
||
- [DualChartView.tsx](file://src/DualChartView.tsx)
|
||
</cite>
|
||
|
||
## 目录
|
||
1. [简介](#简介)
|
||
2. [项目结构](#项目结构)
|
||
3. [核心架构模式](#核心架构模式)
|
||
4. [后端处理流程](#后端处理流程)
|
||
5. [数据契约与类型定义](#数据契约与类型定义)
|
||
6. [前端渲染架构](#前端渲染架构)
|
||
7. [组件间数据流](#组件间数据流)
|
||
8. [架构优势分析](#架构优势分析)
|
||
9. [可扩展性与性能考量](#可扩展性与性能考量)
|
||
10. [结论](#结论)
|
||
|
||
## 简介
|
||
本项目是一个混合式Python/Node.js系统,能够将静态的财务规划报告(PDF)和访谈视频自动转换为动态、个性化的解释性视频。系统采用管道-过滤器架构模式,将后端作为"导演"负责数据提取、AI推理和媒体处理,生成`render_props.json`数据契约,前端作为"渲染引擎"消费该数据生成最终视频。
|
||
|
||
## 项目结构
|
||
项目采用清晰的分层结构,将后端Python模块与前端Remotion组件分离,通过`assets`目录共享中间处理文件。
|
||
|
||
```mermaid
|
||
graph TD
|
||
subgraph "根目录"
|
||
main[main.py]
|
||
requirements[requirements.txt]
|
||
package[package.json]
|
||
assets[assets/]
|
||
end
|
||
subgraph "后端"
|
||
backend[backend/]
|
||
extractor[extractor.py]
|
||
scripter[scripter.py]
|
||
media_fetcher[media_fetcher.py]
|
||
data_builder[data_builder.py]
|
||
end
|
||
subgraph "前端"
|
||
frontend[frontend/src/]
|
||
Root[Root.tsx]
|
||
render_props[render-props-types.ts]
|
||
end
|
||
subgraph "资源"
|
||
input[0_input/]
|
||
processed[1_processed/]
|
||
output[2_output/]
|
||
end
|
||
main --> backend
|
||
backend --> processed
|
||
main --> frontend
|
||
processed --> frontend
|
||
input --> backend
|
||
frontend --> output
|
||
style backend fill:#f0f8ff,stroke:#333
|
||
style frontend fill:#fff0f0,stroke:#333
|
||
style assets fill:#f0fff0,stroke:#333
|
||
```
|
||
|
||
**图示来源**
|
||
- [main.py](file://main.py)
|
||
- [backend/](file://backend/)
|
||
- [frontend/src/](file://frontend/src/)
|
||
- [assets/](file://assets/)
|
||
|
||
## 核心架构模式
|
||
系统采用管道-过滤器架构模式,将视频生成流程分解为一系列独立的处理阶段,每个阶段专注于特定任务。
|
||
|
||
```mermaid
|
||
graph LR
|
||
A[输入] --> B[数据提取]
|
||
B --> C[AI推理]
|
||
C --> D[媒体处理]
|
||
D --> E[数据构建]
|
||
E --> F[render_props.json]
|
||
F --> G[视频渲染]
|
||
subgraph "后端: 导演"
|
||
B
|
||
C
|
||
D
|
||
E
|
||
end
|
||
subgraph "前端: 渲染引擎"
|
||
G
|
||
end
|
||
style B fill:#e6f3ff,stroke:#333
|
||
style C fill:#e6f3ff,stroke:#333
|
||
style D fill:#e6f3ff,stroke:#333
|
||
style E fill:#e6f3ff,stroke:#333
|
||
style G fill:#ffe6e6,stroke:#333
|
||
```
|
||
|
||
**图示来源**
|
||
- [main.py](file://main.py#L52-L80)
|
||
- [PROJECT_README.md](file://PROJECT_README.md#L132-L141)
|
||
|
||
## 后端处理流程
|
||
后端作为系统的"导演",负责协调整个视频生成流程,从数据提取到最终渲染。
|
||
|
||
### 主要处理步骤
|
||
后端处理流程在`main.py`中通过`VideoGeneratorPipeline`类实现,包含六个主要步骤:
|
||
|
||
1. **PDF数据提取**:使用Gemini Pro从PDF报告中提取结构化数据
|
||
2. **视频处理**:使用Whisper从访谈视频中提取转录和时间戳
|
||
3. **脚本生成**:使用Gemini Pro生成自然日语叙述脚本
|
||
4. **B-Roll获取**:从Pexels API获取相关背景视频素材
|
||
5. **渲染属性构建**:生成`render_props.json`数据契约
|
||
6. **视频渲染**:调用Remotion生成最终视频
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant CLI as 命令行
|
||
participant Pipeline as VideoGeneratorPipeline
|
||
participant Extractor as PDFExtractor
|
||
participant Scripter as ScriptGenerator
|
||
participant Fetcher as MediaFetcher
|
||
participant Builder as FinancialSimulator
|
||
participant Remotion as Remotion
|
||
CLI->>Pipeline : run()
|
||
Pipeline->>Extractor : extract_pdf()
|
||
Extractor-->>Pipeline : PDF数据
|
||
Pipeline->>Extractor : extract_video()
|
||
Extractor-->>Pipeline : 视频数据
|
||
Pipeline->>Scripter : generate_script()
|
||
Scripter-->>Pipeline : 叙述脚本
|
||
Pipeline->>Fetcher : fetch_broll()
|
||
Fetcher-->>Pipeline : B-Roll素材
|
||
Pipeline->>Builder : build_render_props()
|
||
Builder-->>Pipeline : render_props.json
|
||
Pipeline->>Remotion : render_video()
|
||
Remotion-->>CLI : 最终视频
|
||
```
|
||
|
||
**图示来源**
|
||
- [main.py](file://main.py#L48-L83)
|
||
- [extractor.py](file://backend/extractor.py)
|
||
- [scripter.py](file://backend/scripter.py)
|
||
- [media_fetcher.py](file://backend/media_fetcher.py)
|
||
- [data_builder.py](file://backend/data_builder.py)
|
||
|
||
**本节来源**
|
||
- [main.py](file://main.py#L33-L225)
|
||
- [extractor.py](file://backend/extractor.py)
|
||
- [scripter.py](file://backend/scripter.py)
|
||
- [media_fetcher.py](file://backend/media_fetcher.py)
|
||
- [data_builder.py](file://backend/data_builder.py)
|
||
|
||
## 数据契约与类型定义
|
||
`render_props.json`是连接Python后端和Remotion前端的关键数据契约,定义了前后端之间的接口规范。
|
||
|
||
### 数据契约结构
|
||
数据契约在`frontend/src/render-props-types.ts`中通过TypeScript接口定义,确保类型安全和数据一致性。
|
||
|
||
```mermaid
|
||
classDiagram
|
||
class RenderProps {
|
||
+meta : Meta
|
||
+charts : Charts
|
||
+script : ScriptSegment[]
|
||
+assets : AssetCollection
|
||
}
|
||
class Meta {
|
||
+title : string
|
||
+currencyUnit : string
|
||
+duration : number
|
||
+clientName? : string
|
||
+generatedAt? : string
|
||
}
|
||
class Charts {
|
||
+assetDepletion : AssetDepletionChartData
|
||
+cashFlow : CashFlowChartData
|
||
}
|
||
class AssetDepletionChartData {
|
||
+timeline : YearlySnapshot[]
|
||
+meta : ChartMeta
|
||
}
|
||
class CashFlowChartData {
|
||
+timeline : CashFlowData[]
|
||
+meta : ChartMeta
|
||
}
|
||
class ScriptSegment {
|
||
+id : number
|
||
+text : string
|
||
+duration : number
|
||
+type : ScriptSegmentType
|
||
+assetUrl? : string
|
||
+chartSync? : ChartSync
|
||
}
|
||
class AssetCollection {
|
||
+broll : Record~string,string~
|
||
+videoClips : VideoClipReference[]
|
||
+ttsAudio? : string
|
||
}
|
||
RenderProps --> Meta : 包含
|
||
RenderProps --> Charts : 包含
|
||
RenderProps --> ScriptSegment : 包含
|
||
RenderProps --> AssetCollection : 包含
|
||
Charts --> AssetDepletionChartData : 包含
|
||
Charts --> CashFlowChartData : 包含
|
||
ScriptSegment --> ChartSync : 可选
|
||
AssetCollection --> VideoClipReference : 包含
|
||
```
|
||
|
||
**图示来源**
|
||
- [render-props-types.ts](file://frontend/src/render-props-types.ts)
|
||
- [main.py](file://main.py#L152-L197)
|
||
|
||
### 运行时验证
|
||
系统使用Zod库在运行时验证数据契约的完整性,确保前后端数据的一致性。
|
||
|
||
```typescript
|
||
export const RenderPropsSchema = z.object({
|
||
meta: z.object({
|
||
title: z.string(),
|
||
currencyUnit: z.string(),
|
||
duration: z.number(),
|
||
clientName: z.string().optional(),
|
||
generatedAt: z.string().optional(),
|
||
}),
|
||
charts: z.object({
|
||
assetDepletion: z.object({
|
||
timeline: z.array(YearlySnapshotSchema),
|
||
meta: z.object({
|
||
currencyUnit: z.string(),
|
||
startYear: z.number(),
|
||
}),
|
||
}),
|
||
cashFlow: z.object({
|
||
timeline: z.array(CashFlowDataSchema),
|
||
meta: z.object({
|
||
currencyUnit: z.string(),
|
||
}),
|
||
}),
|
||
}),
|
||
script: z.array(ScriptSegmentSchema),
|
||
assets: z.object({
|
||
broll: z.record(z.string()),
|
||
videoClips: z.array(
|
||
z.object({
|
||
id: z.string(),
|
||
sourcePath: z.string(),
|
||
startTime: z.number(),
|
||
duration: z.number(),
|
||
outputPath: z.string().optional(),
|
||
}),
|
||
),
|
||
ttsAudio: z.string().optional(),
|
||
}),
|
||
});
|
||
```
|
||
|
||
**本节来源**
|
||
- [render-props-types.ts](file://frontend/src/render-props-types.ts#L139-L231)
|
||
- [main.py](file://main.py#L73-L75)
|
||
|
||
## 前端渲染架构
|
||
前端作为"渲染引擎",消费`render_props.json`数据契约,使用Remotion框架生成最终视频。
|
||
|
||
### 组件注册与组合
|
||
前端通过`Root.tsx`文件注册所有可渲染的组件组合,每个组合对应一个视频片段。
|
||
|
||
```mermaid
|
||
graph TD
|
||
Root[Root.tsx] --> Composition1[Composition: LifePlanSimulation]
|
||
Root --> Composition2[Composition: LifePlanBarChart]
|
||
Root --> Composition3[Composition: CashFlowChart]
|
||
Root --> Composition4[Composition: DualChartView]
|
||
Composition1 --> LifePlanChart[LifePlanChart.tsx]
|
||
Composition2 --> LifePlanBarChart[LifePlanBarChart.tsx]
|
||
Composition3 --> CashFlowChart[CashFlowChart.tsx]
|
||
Composition4 --> DualChartView[DualChartView.tsx]
|
||
DualChartView --> LifePlanChart
|
||
DualChartView --> CashFlowChart
|
||
DualChartView --> UnifiedHUD[UnifiedHUD.tsx]
|
||
style Root fill:#ffebcd,stroke:#333
|
||
style Composition1 fill:#e6f3ff,stroke:#333
|
||
style Composition2 fill:#e6f3ff,stroke:#333
|
||
style Composition3 fill:#e6f3ff,stroke:#333
|
||
style Composition4 fill:#e6f3ff,stroke:#333
|
||
```
|
||
|
||
**图示来源**
|
||
- [Root.tsx](file://src/Root.tsx)
|
||
- [LifePlanChart.tsx](file://src/LifePlanChart.tsx)
|
||
- [CashFlowChart.tsx](file://src/CashFlowChart.tsx)
|
||
- [DualChartView.tsx](file://src/DualChartView.tsx)
|
||
|
||
### 动画与时间控制
|
||
前端组件使用Remotion的`useCurrentFrame`和`useVideoConfig`钩子实现精确的动画控制。
|
||
|
||
```typescript
|
||
const frame = useCurrentFrame();
|
||
const { durationInFrames } = useVideoConfig();
|
||
|
||
// 计算动画进度
|
||
const exactIndex = interpolate(
|
||
frame,
|
||
[0, durationInFrames - 30],
|
||
[0, timeline.length - 1],
|
||
{ extrapolateRight: "clamp" }
|
||
);
|
||
```
|
||
|
||
**本节来源**
|
||
- [Root.tsx](file://src/Root.tsx)
|
||
- [LifePlanChart.tsx](file://src/LifePlanChart.tsx#L78-L88)
|
||
- [CashFlowChart.tsx](file://src/CashFlowChart.tsx#L83-L92)
|
||
- [DualChartView.tsx](file://src/DualChartView.tsx#L28-L39)
|
||
|
||
## 组件间数据流
|
||
系统中的数据流遵循单向数据流原则,从后端到前端,确保数据的一致性和可预测性。
|
||
|
||
### 数据流路径
|
||
```mermaid
|
||
flowchart TD
|
||
A[PDF/视频输入] --> B[后端数据提取]
|
||
B --> C[AI推理与脚本生成]
|
||
C --> D[B-Roll素材获取]
|
||
D --> E[财务模拟与数据构建]
|
||
E --> F[render_props.json]
|
||
F --> G[前端组件渲染]
|
||
G --> H[最终视频输出]
|
||
subgraph "数据转换"
|
||
B
|
||
C
|
||
D
|
||
E
|
||
end
|
||
subgraph "数据消费"
|
||
G
|
||
end
|
||
style B fill:#e6f3ff,stroke:#333
|
||
style C fill:#e6f3ff,stroke:#333
|
||
style D fill:#e6f3ff,stroke:#333
|
||
style E fill:#e6f3ff,stroke:#333
|
||
style G fill:#ffe6e6,stroke:#333
|
||
```
|
||
|
||
**图示来源**
|
||
- [main.py](file://main.py#L52-L80)
|
||
- [data_builder.py](file://backend/data_builder.py)
|
||
- [render-props-types.ts](file://frontend/src/render-props-types.ts)
|
||
- [Root.tsx](file://src/Root.tsx)
|
||
|
||
### 双向图表同步
|
||
`DualChartView`组件展示了如何在多个图表之间同步动画状态。
|
||
|
||
```typescript
|
||
// 统一的动画逻辑(两个图表同步)
|
||
const exactProgress = interpolate(
|
||
frame,
|
||
[0, animationEndFrame - 30],
|
||
[0, cashflowData.timeline.length - 1],
|
||
{ extrapolateRight: "clamp" }
|
||
);
|
||
|
||
const dataEndIndex = Math.floor(exactProgress);
|
||
const yearProgress = exactProgress - dataEndIndex;
|
||
|
||
// 将现金流数据转换为资产图表格式
|
||
const lifePlanTimeline: YearlySnapshot[] = useMemo(
|
||
() => cashflowData.timeline.map((item) => ({
|
||
year: item.year,
|
||
ages: { rep: item.age },
|
||
financials: {
|
||
income: item.income.total,
|
||
expenditure: item.totalExpense,
|
||
assetBalance: item.assetBalance,
|
||
},
|
||
events: [],
|
||
isCritical: item.assetBalance < 0,
|
||
})),
|
||
[cashflowData.timeline]
|
||
);
|
||
```
|
||
|
||
**本节来源**
|
||
- [DualChartView.tsx](file://src/DualChartView.tsx#L34-L67)
|
||
- [LifePlanChart.tsx](file://src/LifePlanChart.tsx)
|
||
- [CashFlowChart.tsx](file://src/CashFlowChart.tsx)
|
||
|
||
## 架构优势分析
|
||
这种前后端分离的架构设计带来了多项显著优势。
|
||
|
||
### 关注点分离
|
||
系统将不同的职责清晰地分配给后端和前端:
|
||
|
||
- **后端**:专注于数据处理、AI推理和业务逻辑
|
||
- **前端**:专注于视觉呈现、动画效果和用户体验
|
||
|
||
这种分离使得团队可以并行开发,提高开发效率。
|
||
|
||
### 技术栈独立演进
|
||
前后端使用不同的技术栈,可以独立演进:
|
||
|
||
- **后端**:Python + AI服务(Gemini、Whisper)
|
||
- **前端**:TypeScript + React + Remotion
|
||
|
||
这种独立性允许团队根据需求选择最适合的技术,而不受另一端的限制。
|
||
|
||
### 可测试性
|
||
分离的架构提高了系统的可测试性:
|
||
|
||
- **后端**:可以独立测试数据提取、脚本生成等逻辑
|
||
- **前端**:可以使用Remotion Studio进行可视化开发和测试
|
||
- **集成**:通过`render_props.json`契约进行集成测试
|
||
|
||
**本节来源**
|
||
- [PROJECT_README.md](file://PROJECT_README.md#L14-L32)
|
||
- [main.py](file://main.py)
|
||
- [render-props-types.ts](file://frontend/src/render-props-types.ts)
|
||
|
||
## 可扩展性与性能考量
|
||
系统设计考虑了未来的可扩展性和性能优化。
|
||
|
||
### 可扩展性设计
|
||
系统通过模块化设计支持未来的功能扩展:
|
||
|
||
- **新的数据源**:可以添加新的提取器(如Excel、数据库)
|
||
- **新的AI服务**:可以集成其他LLM服务
|
||
- **新的视频效果**:可以添加新的Remotion组件
|
||
|
||
### 潜在性能瓶颈
|
||
系统可能存在以下性能瓶颈:
|
||
|
||
1. **AI API调用延迟**:Gemini和Whisper的API调用可能成为瓶颈
|
||
2. **大文件处理**:长视频的处理需要大量计算资源
|
||
3. **网络带宽**:B-Roll素材的下载依赖网络速度
|
||
|
||
### 优化策略
|
||
针对潜在瓶颈,可以采取以下优化策略:
|
||
|
||
- **缓存机制**:缓存AI推理结果和下载的素材
|
||
- **并行处理**:并行执行独立的处理任务
|
||
- **流式处理**:对大文件进行分块处理
|
||
|
||
**本节来源**
|
||
- [main.py](file://main.py)
|
||
- [extractor.py](file://backend/extractor.py)
|
||
- [media_fetcher.py](file://backend/media_fetcher.py)
|
||
- [data_builder.py](file://backend/data_builder.py)
|
||
|
||
## 结论
|
||
本项目采用管道-过滤器架构模式,通过清晰的前后端分离设计,实现了从静态财务报告到动态解释视频的自动化转换。后端作为"导演"负责数据提取、AI推理和媒体处理,生成`render_props.json`数据契约;前端作为"渲染引擎"消费该数据,生成最终视频。这种架构设计实现了关注点分离、技术栈独立演进和良好的可测试性,为系统的可扩展性和维护性奠定了坚实基础。 |