AI-video-lifeplan-demo/.qoder/repowiki/zh/content/数据模型与契约.md

15 KiB
Raw Permalink Blame History

数据模型与契约

**本文引用的文件** - [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,确保前后端对同一份数据结构达成一致。
graph TB
subgraph "后端"
PY_MAIN["main.py<br/>构建与保存 render_props.json"]
PY_DB["backend/video_processor/data_builder.py<br/>财务模拟与图表数据生成"]
end
subgraph "前端"
TS_TYPES["frontend/src/render-props-types.ts<br/>RenderPropsSchema 定义与运行时校验"]
REACT_LPC["src/LifePlanChart.tsx<br/>资产枯竭曲线图"]
REACT_CFC["src/CashFlowChart.tsx<br/>现金流分解图"]
TYPES_TS["src/types.ts<br/>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

图表来源

章节来源

核心组件

本节从“数据契约”的角度,系统梳理 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 两个辅助函数,分别用于强制校验与类型守卫

章节来源

架构总览

RenderPropsSchema 作为 Python 后端与 Remotion 前端之间的“数据契约”,贯穿以下流程:

  • 后端根据 PDF 输入与财务模拟器生成 render_props.json
  • 前端读取 render_props.json,使用 Zod Schema 进行运行时校验
  • 校验通过后,前端组件(如 LifePlanChart、CashFlowChart)消费数据并渲染视频
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 : "输出视频帧"

图表来源

详细组件分析

RenderPropsSchema 设计与运行时校验

  • 设计要点
    • 严格嵌套结构:meta、charts、script、assets 四大块,每块内部字段一一对应
    • 类型精确:数值、字符串、枚举、可选字段均有明确约束
    • 元信息与数据一致性:charts.meta 携带货币单位与起始年份,保证图表显示一致
  • 运行时校验
    • parse:失败即抛异常,适合强约束场景
    • safeParse:返回成功/失败,便于条件分支处理
    • 辅助函数:validateRenderProps 与 isRenderProps 提供统一入口
flowchart TD
Start(["开始"]) --> Load["读取 render_props.json"]
Load --> Parse["调用 RenderPropsSchema.parse/safeParse"]
Parse --> Valid{"校验通过?"}
Valid --> |否| Throw["抛出错误/返回失败"]
Valid --> |是| Use["前端组件消费数据"]
Use --> End(["结束"])
Throw --> End

图表来源

章节来源

YearlySnapshot 与 CashFlowData 的字段语义与业务逻辑

  • YearlySnapshot
    • 年度视角的财务快照,支持代表者与配偶双人年龄,便于双人财务规划可视化
    • financials.income/expenditure/assetBalance 三元组构成资产枯竭曲线的核心
    • events 与 isCritical 用于标注重大事件与风险节点
  • CashFlowData
    • 将 YearlySnapshot 转换为更利于“收入-支出”分解展示的数据形式
    • expenses 细分五类,便于堆叠柱状图呈现
    • totalExpense、netCashFlow、assetBalance 为派生字段,便于 HUD 展示与动画控制
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"

图表来源

章节来源

ScriptSegment 与 AssetCollection 的脚本与媒体资源

  • ScriptSegment
    • 类型枚举覆盖旁白、图表介绍/高亮、视频片段、转场等场景
    • chartSync 支持与图表联动,实现高亮年份与动画起始帧的同步
  • AssetCollection
    • broll 关键词到视频资源的映射,便于按主题检索
    • videoClips 记录剪辑片段的来源与裁剪参数,便于复用与导出
    • ttsAudio 为可选的人工合成语音路径
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 : "包含"

图表来源

章节来源

前端消费与可视化组件

  • LifePlanChart(资产枯竭曲线)
    • 使用 YearlySnapshot 渲染面积图,支持插值与渐变色(正负资产区域)
    • HUD 展示当前年份、资产余额、收支差额
  • CashFlowChart(现金流分解)
    • 使用 CashFlowData 渲染堆叠柱状图与收入线,支持分段顺序增长动画
    • HUD 展示当前年份、收入、总支出、净现金流
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 : "渲染现金流帧"

图表来源

章节来源

依赖关系分析

  • 后端到前端的数据流
    • main.py 负责组装 render_props.json 并保存
    • data_builder.py 生成 charts 数据(资产枯竭与现金流)
    • 前端 render-props-types.ts 以 Zod Schema 对齐数据结构
  • 前端组件对数据的依赖
    • LifePlanChart 依赖 YearlySnapshot 类型
    • CashFlowChart 依赖 CashFlowData 类型
    • 两者均依赖 RenderPropsSchema 的校验结果
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

图表来源

章节来源

性能考量

  • 数据规模与渲染开销
    • 大时间序列(如多代人、长周期)会增加 Recharts 渲染压力
    • 建议在后端进行数据采样或聚合,减少前端渲染负担
  • 动画与插值
    • 插值与顺序增长动画需谨慎使用,避免在长序列上产生过多帧级计算
  • 校验成本
    • Zod 校验在开发阶段建议开启,生产环境可考虑缓存校验结果或仅在首帧执行

[本节为通用指导,不直接分析具体文件]

故障排查指南

  • 校验失败
    • 现象:validateRenderProps 抛错;isRenderProps 返回 false
    • 排查:检查字段类型(数字/字符串)、可选字段是否遗漏、枚举值是否正确
    • 参考:Zod Schema 定义与辅助函数
  • 数据不一致
    • 现象:图表显示货币单位不一致、起始年份错位
    • 排查:确认 charts.meta.currencyUnit 与 charts.meta.startYear 是否与 timeline 对齐
  • 脚本与媒体资源不匹配
    • 现象:ScriptSegment.chartSync 未生效或 assetUrl 无法加载
    • 排查:确认 chartId、highlightYear、animationStart 与 assets.broll/videoClips 的键值一致

章节来源

结论

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

章节来源