# 数据模型与契约 **本文引用的文件** - [render-props-types.ts](file://frontend/src/render-props-types.ts) - [types.ts](file://src/types.ts) - [data_builder.py](file://backend/video_processor/data_builder.py) - [main.py](file://main.py) - [CashFlowChart.tsx](file://src/CashFlowChart.tsx) - [LifePlanChart.tsx](file://src/LifePlanChart.tsx) - [mock-data.json](file://src/mock-data.json) - [mock-cashflow.json](file://src/mock-cashflow.json) ## 目录 1. [引言](#引言) 2. [项目结构](#项目结构) 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [详细组件分析](#详细组件分析) 6. [依赖关系分析](#依赖关系分析) 7. [性能考量](#性能考量) 8. [故障排查指南](#故障排查指南) 9. [结论](#结论) 10. [附录](#附录) ## 引言 本文件聚焦于“核心数据模型与系统间数据契约”,围绕 render-props-types.ts 中定义的 RenderPropsSchema 设计进行深入解析。该契约是 Python 后端与 Remotion 前端之间的唯一通信桥梁:后端生成 render_props.json,前端通过 Zod 运行时校验确保数据完整性,再驱动可视化组件渲染视频内容。本文将逐层拆解 YearlySnapshot、CashFlowData、ScriptSegment、AssetCollection 等关键数据结构的字段语义、类型约束与业务逻辑;阐明 Zod 如何在运行时保障数据一致性;并通过示例文件展示 render_props.json 的实际形态,帮助初学者理解数据契约的重要性与最佳实践。 ## 项目结构 本项目采用前后端分离的模块化组织: - 前端(Remotion)位于 src 与 frontend/src,负责渲染与可视化; - 后端(Python)位于 backend,负责数据模拟与 render_props.json 生成; - 契约文件 render-props-types.ts 定义了 TypeScript 接口与 Zod Schema,确保前后端对同一份数据结构达成一致。 ```mermaid graph TB subgraph "后端" PY_MAIN["main.py
构建与保存 render_props.json"] PY_DB["backend/video_processor/data_builder.py
财务模拟与图表数据生成"] end subgraph "前端" TS_TYPES["frontend/src/render-props-types.ts
RenderPropsSchema 定义与运行时校验"] REACT_LPC["src/LifePlanChart.tsx
资产枯竭曲线图"] REACT_CFC["src/CashFlowChart.tsx
现金流分解图"] TYPES_TS["src/types.ts
YearlySnapshot 等类型"] end PY_MAIN --> PY_DB PY_DB --> PY_MAIN PY_MAIN --> TS_TYPES TS_TYPES --> REACT_LPC TS_TYPES --> REACT_CFC TYPES_TS --> REACT_LPC ``` **图表来源** - [main.py](file://main.py#L145-L199) - [data_builder.py](file://backend/video_processor/data_builder.py#L150-L200) - [render-props-types.ts](file://frontend/src/render-props-types.ts#L117-L231) - [LifePlanChart.tsx](file://src/LifePlanChart.tsx#L1-L349) - [CashFlowChart.tsx](file://src/CashFlowChart.tsx#L1-L441) - [types.ts](file://src/types.ts#L1-L30) **章节来源** - [main.py](file://main.py#L145-L199) - [render-props-types.ts](file://frontend/src/render-props-types.ts#L117-L231) ## 核心组件 本节从“数据契约”的角度,系统梳理 RenderProps 及其子结构,明确字段含义、类型与业务约束,并说明 Zod Schema 的作用。 - RenderProps(顶层契约) - meta:视频元信息,包含标题、货币单位、总时长、可选客户名与生成时间戳 - charts:两类图表数据 - assetDepletion:资产枯竭曲线的时间序列与元信息(货币单位、起始年份) - cashFlow:现金流分解的时间序列与元信息(货币单位) - script:脚本段落数组,描述旁白、图表介绍/高亮、视频片段、转场等 - assets:媒体资源集合,包含 B-Roll 映射、视频片段引用、可选 TTS 音频路径 - YearlySnapshot(年度快照) - year:年份 - ages:代表者年龄与可选配偶年龄 - financials:收入、支出、资产余额 - events:当年事件标签列表 - isCritical:资产余额是否为负(标记风险临界点) - CashFlowData(年度现金流) - year、age:年份与年龄 - income.total:年度总收入 - expenses:生活、住房、教育、税金、事件等细项 - totalExpense、netCashFlow、assetBalance:派生或补充字段(由后端计算) - ScriptSegment(脚本段落) - id、text、duration:段落标识、日文旁白文本、时长(秒) - type:段落类型枚举(旁白、图表介绍、图表高亮、视频片段、转场) - assetUrl:B-Roll 或视频片段 URL/路径 - chartSync:可选的图表同步参数(图表 ID、高亮年份、动画起始帧) - AssetCollection(媒体资源集合) - broll:关键词到视频 URL/路径的映射 - videoClips:视频片段引用数组(id、源路径、起止时间、输出路径) - ttsAudio:可选的 TTS 语音文件路径 - Zod Schema(运行时校验) - YearlySnapshotSchema、CashFlowDataSchema、ScriptSegmentSchema、RenderPropsSchema - 提供 parse/safeParse 两种校验方式,前者失败抛错,后者返回布尔判断 - validateRenderProps/isRenderProps 两个辅助函数,分别用于强制校验与类型守卫 **章节来源** - [render-props-types.ts](file://frontend/src/render-props-types.ts#L18-L231) - [types.ts](file://src/types.ts#L1-L30) ## 架构总览 RenderPropsSchema 作为 Python 后端与 Remotion 前端之间的“数据契约”,贯穿以下流程: - 后端根据 PDF 输入与财务模拟器生成 render_props.json - 前端读取 render_props.json,使用 Zod Schema 进行运行时校验 - 校验通过后,前端组件(如 LifePlanChart、CashFlowChart)消费数据并渲染视频 ```mermaid sequenceDiagram participant Backend as "Python 后端" participant Builder as "data_builder.py" participant Main as "main.py" participant Frontend as "Remotion 前端" participant Schema as "render-props-types.ts" participant Charts as "LifePlanChart/CashFlowChart" Backend->>Builder : "输入PDF数据" Builder->>Builder : "财务模拟与图表数据生成" Builder-->>Main : "返回 charts 财务数据" Main->>Main : "拼装 meta/script/assets" Main-->>Frontend : "render_props.json" Frontend->>Schema : "validateRenderProps/isRenderProps" Schema-->>Frontend : "校验结果" Frontend->>Charts : "传入 RenderProps 渲染" Charts-->>Frontend : "输出视频帧" ``` **图表来源** - [data_builder.py](file://backend/video_processor/data_builder.py#L150-L200) - [main.py](file://main.py#L145-L199) - [render-props-types.ts](file://frontend/src/render-props-types.ts#L194-L250) - [LifePlanChart.tsx](file://src/LifePlanChart.tsx#L1-L349) - [CashFlowChart.tsx](file://src/CashFlowChart.tsx#L1-L441) ## 详细组件分析 ### RenderPropsSchema 设计与运行时校验 - 设计要点 - 严格嵌套结构:meta、charts、script、assets 四大块,每块内部字段一一对应 - 类型精确:数值、字符串、枚举、可选字段均有明确约束 - 元信息与数据一致性:charts.meta 携带货币单位与起始年份,保证图表显示一致 - 运行时校验 - parse:失败即抛异常,适合强约束场景 - safeParse:返回成功/失败,便于条件分支处理 - 辅助函数:validateRenderProps 与 isRenderProps 提供统一入口 ```mermaid flowchart TD Start(["开始"]) --> Load["读取 render_props.json"] Load --> Parse["调用 RenderPropsSchema.parse/safeParse"] Parse --> Valid{"校验通过?"} Valid --> |否| Throw["抛出错误/返回失败"] Valid --> |是| Use["前端组件消费数据"] Use --> End(["结束"]) Throw --> End ``` **图表来源** - [render-props-types.ts](file://frontend/src/render-props-types.ts#L237-L250) **章节来源** - [render-props-types.ts](file://frontend/src/render-props-types.ts#L194-L250) ### YearlySnapshot 与 CashFlowData 的字段语义与业务逻辑 - YearlySnapshot - 年度视角的财务快照,支持代表者与配偶双人年龄,便于双人财务规划可视化 - financials.income/expenditure/assetBalance 三元组构成资产枯竭曲线的核心 - events 与 isCritical 用于标注重大事件与风险节点 - CashFlowData - 将 YearlySnapshot 转换为更利于“收入-支出”分解展示的数据形式 - expenses 细分五类,便于堆叠柱状图呈现 - totalExpense、netCashFlow、assetBalance 为派生字段,便于 HUD 展示与动画控制 ```mermaid classDiagram class YearlySnapshot { +number year +ages +financials +string[] events? +boolean isCritical? } class CashFlowData { +number year +number age +income +expenses +number totalExpense? +number netCashFlow? +number assetBalance? } class incomes { +number total } class expenses { +number living +number housing +number education +number tax +number event } YearlySnapshot --> incomes : "financials.income" YearlySnapshot --> expenses : "financials.expenditure" CashFlowData --> incomes : "income" CashFlowData --> expenses : "expenses" ``` **图表来源** - [render-props-types.ts](file://frontend/src/render-props-types.ts#L18-L49) - [types.ts](file://src/types.ts#L1-L18) **章节来源** - [render-props-types.ts](file://frontend/src/render-props-types.ts#L18-L49) - [types.ts](file://src/types.ts#L1-L18) ### ScriptSegment 与 AssetCollection 的脚本与媒体资源 - ScriptSegment - 类型枚举覆盖旁白、图表介绍/高亮、视频片段、转场等场景 - chartSync 支持与图表联动,实现高亮年份与动画起始帧的同步 - AssetCollection - broll 关键词到视频资源的映射,便于按主题检索 - videoClips 记录剪辑片段的来源与裁剪参数,便于复用与导出 - ttsAudio 为可选的人工合成语音路径 ```mermaid classDiagram class ScriptSegment { +number id +string text +number duration +string type +string assetUrl? +chartSync? } class AssetCollection { +Record~string,string~ broll +VideoClipReference[] videoClips +string ttsAudio? } class VideoClipReference { +string id +string sourcePath +number startTime +number duration +string outputPath? } ScriptSegment --> AssetCollection : "引用媒体资源" AssetCollection --> VideoClipReference : "包含" ``` **图表来源** - [render-props-types.ts](file://frontend/src/render-props-types.ts#L74-L111) - [render-props-types.ts](file://frontend/src/render-props-types.ts#L99-L111) **章节来源** - [render-props-types.ts](file://frontend/src/render-props-types.ts#L74-L111) ### 前端消费与可视化组件 - LifePlanChart(资产枯竭曲线) - 使用 YearlySnapshot 渲染面积图,支持插值与渐变色(正负资产区域) - HUD 展示当前年份、资产余额、收支差额 - CashFlowChart(现金流分解) - 使用 CashFlowData 渲染堆叠柱状图与收入线,支持分段顺序增长动画 - HUD 展示当前年份、收入、总支出、净现金流 ```mermaid sequenceDiagram participant Frontend as "Remotion 前端" participant Schema as "RenderPropsSchema" participant LPC as "LifePlanChart" participant CFC as "CashFlowChart" Frontend->>Schema : "校验 render_props.json" Schema-->>Frontend : "校验通过" Frontend->>LPC : "传入 assetDepletion 数据" Frontend->>CFC : "传入 cashFlow 数据" LPC-->>Frontend : "渲染资产曲线帧" CFC-->>Frontend : "渲染现金流帧" ``` **图表来源** - [render-props-types.ts](file://frontend/src/render-props-types.ts#L194-L231) - [LifePlanChart.tsx](file://src/LifePlanChart.tsx#L1-L349) - [CashFlowChart.tsx](file://src/CashFlowChart.tsx#L1-L441) **章节来源** - [LifePlanChart.tsx](file://src/LifePlanChart.tsx#L1-L349) - [CashFlowChart.tsx](file://src/CashFlowChart.tsx#L1-L441) ## 依赖关系分析 - 后端到前端的数据流 - main.py 负责组装 render_props.json 并保存 - data_builder.py 生成 charts 数据(资产枯竭与现金流) - 前端 render-props-types.ts 以 Zod Schema 对齐数据结构 - 前端组件对数据的依赖 - LifePlanChart 依赖 YearlySnapshot 类型 - CashFlowChart 依赖 CashFlowData 类型 - 两者均依赖 RenderPropsSchema 的校验结果 ```mermaid graph LR PY["main.py"] --> DB["data_builder.py"] DB --> JSON["render_props.json"] JSON --> TS["render-props-types.ts"] TS --> LPC["LifePlanChart.tsx"] TS --> CFC["CashFlowChart.tsx"] TYPES["types.ts"] --> LPC ``` **图表来源** - [main.py](file://main.py#L145-L199) - [data_builder.py](file://backend/video_processor/data_builder.py#L150-L200) - [render-props-types.ts](file://frontend/src/render-props-types.ts#L117-L231) - [LifePlanChart.tsx](file://src/LifePlanChart.tsx#L1-L349) - [CashFlowChart.tsx](file://src/CashFlowChart.tsx#L1-L441) - [types.ts](file://src/types.ts#L1-L30) **章节来源** - [main.py](file://main.py#L145-L199) - [data_builder.py](file://backend/video_processor/data_builder.py#L150-L200) - [render-props-types.ts](file://frontend/src/render-props-types.ts#L117-L231) ## 性能考量 - 数据规模与渲染开销 - 大时间序列(如多代人、长周期)会增加 Recharts 渲染压力 - 建议在后端进行数据采样或聚合,减少前端渲染负担 - 动画与插值 - 插值与顺序增长动画需谨慎使用,避免在长序列上产生过多帧级计算 - 校验成本 - Zod 校验在开发阶段建议开启,生产环境可考虑缓存校验结果或仅在首帧执行 [本节为通用指导,不直接分析具体文件] ## 故障排查指南 - 校验失败 - 现象:validateRenderProps 抛错;isRenderProps 返回 false - 排查:检查字段类型(数字/字符串)、可选字段是否遗漏、枚举值是否正确 - 参考:Zod Schema 定义与辅助函数 - 数据不一致 - 现象:图表显示货币单位不一致、起始年份错位 - 排查:确认 charts.meta.currencyUnit 与 charts.meta.startYear 是否与 timeline 对齐 - 脚本与媒体资源不匹配 - 现象:ScriptSegment.chartSync 未生效或 assetUrl 无法加载 - 排查:确认 chartId、highlightYear、animationStart 与 assets.broll/videoClips 的键值一致 **章节来源** - [render-props-types.ts](file://frontend/src/render-props-types.ts#L194-L250) ## 结论 RenderPropsSchema 通过严格的类型与运行时校验,将 Python 后端的 render_props.json 与 Remotion 前端的可视化组件紧密耦合,形成稳定、可演进的数据契约。YearlySnapshot 与 CashFlowData 的清晰边界,配合 ScriptSegment 与 AssetCollection 的脚本与媒体资源管理,使得系统在保持前后端松耦合的同时,具备良好的扩展性与可维护性。建议在后续迭代中持续对齐契约版本,确保前后端同步更新。 [本节为总结性内容,不直接分析具体文件] ## 附录 ### render_props.json 实例与字段对照 - 示例文件 - mock-data.json:资产枯竭曲线的 timeline 与 meta - mock-cashflow.json:现金流分解的 timeline 与 meta - 字段对照 - meta.title、meta.currencyUnit、meta.duration、meta.clientName、meta.generatedAt - charts.assetDepletion.timeline、charts.assetDepletion.meta.currencyUnit、charts.assetDepletion.meta.startYear - charts.cashFlow.timeline、charts.cashFlow.meta.currencyUnit - script[].id、script[].text、script[].duration、script[].type、script[].assetUrl、script[].chartSync - assets.broll、assets.videoClips[]、assets.ttsAudio **章节来源** - [mock-data.json](file://src/mock-data.json#L1-L61) - [mock-cashflow.json](file://src/mock-cashflow.json#L1-L800) - [render-props-types.ts](file://frontend/src/render-props-types.ts#L117-L231)