从文案到成片:AI Video Studio 架构拆解——一个本地优先的分镜级视频工作台
项目: AI Video Studio Community Edition
作者: WoyouWoyou
协议: AGPL-3.0(商业使用需单独授权)
代码: github.com/WoyouWoyou/ai-video-studio
技术栈: FastAPI + React + Vite + GSAP + HyperFrames
一、问题:为什么做一个"视频工作台"?
做知识类视频的人,都踩过这几个坑:
坑1:大模型太贵,生成效果像抽卡
Runway、Pika、可灵……做一次视频,运气好了惊艳,运气差了一堆扭曲的手指和漂移的物体。而且按秒计费,试错成本高到离谱。
坑2:传统剪辑工作流太"重"
Premiere、DaVinci、剪映——这些工具是为"剪辑素材"设计的。但对于知识博主、演讲者、内容创作者,素材不是拍出来的,是"写"出来的。先有文案,再变成画面。传统工具没有这个工作流。
坑3:AI视频工具要么太"黑盒",要么太"零散"
有些工具一键生成,但你控制不了分镜节奏、字幕样式、MG动画。有些工具能控制,但要手动拼接五六个工具:写文案→AI出图→TTS配音→字幕生成→剪辑合成。
AI Video Studio 解决的是:让"文案→分镜→视频"这条管线,可以在一个工具里完成,且成本可控、结果可预期。
二、产品定位:不是"AI一键生成视频",是"分镜级工作台"
这个定位很关键。
市面上大多数AI视频工具,卖点是"输入一句话,输出一段视频"。这听起来很酷,但实际用起来你会发现:
- 你无法控制节奏
- 你无法控制画面和口播的对齐
- 你无法精确控制字幕出现时机
- 改一帧就要重新生成全部
AI Video Studio 选择了另一个方向:把"分镜"作为核心抽象。
每个Scene(分镜)包含:
- 背景:AI生成的图,或HTML模板渲染的画面
- 口播(Narration):TTS配音,带逐字时间戳
- 字幕(Subtitle):逐词高亮,带入场动画
- MG弹窗(Overlay):标题卡、要点列表、进度条等 translucent 浮层
- 时间轴:每个元素在什么时刻出现、持续多久、怎么动
你不是在"生成视频",你是在"导演一组分镜"。每个分镜可以独立编辑、预览、替换,最终组合输出。
三、架构全景:前后端分离 + 本地优先
┌─────────────────────────────────────────────────────────────┐
│ Frontend (React + Vite + GSAP) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 场景列表 │ │ 预览播放器 │ │ 属性检查器 │ │
│ │ (Scene │ │ (Scene │ │ (Scene │ │
│ │ List) │ │ Player) │ │Inspector)│ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ Zustand (useProjectStore / usePlayerStore) │
└────────────────────────┬────────────────────────────────────┘
│ HTTP (REST API)
┌────────────────────────┴────────────────────────────────────┐
│ Backend (FastAPI + Pydantic v2) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ SceneService│ │ScriptService│ │ MediaService │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ImageRegistry│ │ TtsRegistry │ │ HtmlRegistry │ │
│ │ (多Provider)│ │ (Edge TTS) │ │ (Layout Templates) │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ V11 Bridge → HyperFrames CLI → MP4 │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
本地文件系统
studio-projects/<project_id>/
├── plan.json (项目数据)
├── assets/ (图片、音频)
└── exports/ (输出视频)
3.1 前端:三栏布局 + 状态驱动
前端采用经典的三栏工作流:
左栏 - 场景列表(Scene List)
- 显示所有分镜的缩略标题
- 支持拖拽排序、添加/删除/复制
- 每个分镜显示口播文本预览
中栏 - 预览播放器(Scene Player)
- 基于
requestAnimationFrame的时间轴驱动 - 自适应缩放(ResizeObserver),适配不同屏幕尺寸
- 三层叠加:BackgroundLayer → MgOverlayLayer → SubtitleLayer
- 音频同步(HTML5 Audio API)
右栏 - 属性检查器(Scene Inspector)
- 根据选中面板动态渲染不同的编辑器
- BackgroundPanel:选择图片/HTML模板
- NarrationPanel:编辑口播文本
- TtsPanel:选择语音、语速、音调
- SubtitlePanel:字幕样式配置
- MgOverlayPanel:MG弹窗的内容、位置、动画
状态管理
使用 Zustand 三个Store:
useProjectStore:项目数据(Plan)、自动保存(800ms防抖)usePlayerStore:播放状态、当前时间、播放/暂停useUiStore:UI状态(面板展开、对话框、主题)
3.2 后端:Service + Registry 分层
后端采用清晰的分层架构:
数据层
PlanStore:基于本地JSON文件的CRUD,每个项目一个目录plan_schema.py:Pydantic v2 强类型模型,Plan v2 Schema
服务层
SceneService:分镜的CRUD、排序、Overlay管理ScriptService:脚本导入、AI拆分、审核门MediaService:图像生成、TTS、HTML渲染
提供者注册表(Registry Pattern)
这是后端最有意思的设计。所有外部AI服务都通过注册表管理:
class ImageRegistry:
def __init__(self, providers: list):
self.providers = {provider.name: provider for provider in providers}
# 初始化时注入所有Provider
image_registry = ImageRegistry([
GeminiBananaProvider(),
BailianWanxProvider(),
StableDiffusionProvider(),
])
同理有 TtsRegistry、HtmlRegistry。这种设计让新增Provider变得非常简单——实现一个BaseProvider接口,注册到Registry即可。
导出管线
Plan (Python Pydantic Model)
↓ V11Bridge.materialize_export_project()
HTML+iframe+GSAP 合成项目
↓ HyperFrames CLI render()
MP4 视频文件
四、核心设计思想拆解
4.1 "Plan v2":一切围绕一个JSON
整个项目的核心数据模型是一个Pydantic Schema:Plan v2。
class Plan(BaseModel):
schema_version: Literal[2] = 2
global_settings: GlobalSettings
scenes: list[Scene]
script_review_draft: ScriptReviewDraft | None = None
GlobalSettings 包含:
- 项目元数据(名称、ID、格式、分辨率、帧率)
- 默认语音(Edge TTS的Voice ID)
- 主题配置
- AI模型设置(LLM、图像Provider、脚本拆分模型)
Scene 是一个分镜的完整描述:
scene_id,scene_title,scene_kicker,scene_summarybackground:image(AI生成图)或 html(HTML模板)narration_text:口播原文narration_segments:分段口播(带时间戳)tts_config:语音配置audio:TTS生成的音频文件路径、时长、逐字时间戳subtitle_config:字幕样式mg_overlays:MG弹窗列表(标题、内容、位置、出现时机、动画)
为什么这个设计重要?
因为所有功能——编辑、预览、导出、AI辅助——都操作同一个数据模型。没有数据库迁移问题,没有ORM复杂度,没有数据不一致风险。
项目数据就是一个JSON文件 + 资产文件夹。你可以用Git管理版本,可以用Python脚本批量处理,可以写插件扩展。
4.2 "时间轴解析":自动计算一切时机
timing.py 里的 resolve_timeline() 是核心算法:
def resolve_timeline(plan: Plan) -> Plan:
cursor = 0.0
for scene in plan.scenes:
# Scene时长 = 音频时长(或默认3秒)
duration = max(scene.audio.duration_seconds or 3.0, 1.2)
scene.scene_start_seconds = cursor
scene.scene_duration_seconds = duration
cursor += duration
# Segment时间分配:按文本长度加权
total_weight = sum(segment_weight(seg.voiceover_text) for seg in segments)
for segment in segments:
segment.start_seconds = inner_cursor
inner_cursor += usable * (segment_weight / total_weight)
# Overlay出现时机:基于segment时间自动计算
for overlay in scene.mg_overlays:
_resolve_overlay(overlay, segment_map, duration, reveal_lead)
这个设计很聪明:
- Scene时长由音频决定:口播多长,分镜就多长。不需要手动设置。
- Segment按文本长度分配时间:口播文本越长,分配的时间越多。
- Overlay自动对齐Segment:MG弹窗的出现时机,基于它所关联的Segment的start时间,减去一个reveal_lead(提前量)。
这意味着:你改了口播文本,整个时间轴自动重算。你调整了Segment顺序,Overlay自动跟随。不需要手动拖拽时间轴。
4.3 "V11 Bridge":从数据模型到视频文件
导出管线的核心是 V11Bridge,它把Plan序列化为一个可渲染的Web项目。
每个Scene → 一个独立的HTML文件:
- 如果是HTML背景:使用模板渲染(cover、bullents、timeline等)
- 如果是图片背景:用
<img>标签 - 注入字幕层(基于WordTimestamp的逐词高亮)
- 注入MG弹窗层(基于reveal_at_seconds的显隐控制)
然后生成 index.html,用GSAP Timeline驱动所有Scene的iframe:
<main class="composition" data-duration="total_duration">
<iframe class="scene-frame" src="scenes/scene_1.html" data-start="0" data-duration="7.5">
<iframe class="scene-frame" src="scenes/scene_2.html" data-start="7.5" data-duration="5.2">
<!-- ... -->
<audio class="clip" src="assets/audio/scene_1.mp3" data-start="0" data-duration="7.5">
</main>
<script>
// GSAP Timeline 驱动整体时间轴
const rootTimeline = gsap.timeline({ paused: true });
// 通过 postMessage 同步每个iframe的局部时间
function syncSceneIframes() {
const time = rootTimeline.time();
document.querySelectorAll(".scene-frame").forEach(frame => {
const localTime = Math.max(0, Math.min(duration, time - start));
frame.contentWindow.postMessage({ type: "studio:set-time", time: localTime }, "*");
});
}
</script>
这个设计有几个好处:
- Scene之间完全隔离:每个Scene是独立的HTML,不会互相影响。
- 渲染引擎无关:HyperFrames只需要渲染一个普通的网页,不需要理解复杂的视频合成格式。
- 可调试:你可以直接用浏览器打开index.html,用GSAP的调试工具查看时间轴。
- 可扩展:如果你想自定义Scene的动画逻辑,直接改HTML模板就行。
4.4 "AI脚本审核门":人在回路中
这是产品层面很用心的设计。
当你导入一篇长文案,选择"AI拆分"时,流程不是直接生成分镜,而是:
文案 → AI拆分为Scene Specs → 生成ScriptReviewDraft → 人工审核 → 确认/修改/丢弃 → 生成分镜
ScriptReviewDraft 包含:
- 原始文案
- AI生成的Scene列表(标题、摘要、口播、建议布局)
- 信息池(每段的关键信息点)
- 演示计划(建议的视觉呈现方式)
用户可以在确认前查看、编辑每个Scene的内容。这避免了"AI黑盒生成一堆我不满意的东西"的问题。
4.5 "Provider注册表":解耦AI依赖
后端通过注册表模式,把所有外部AI服务抽象为统一的接口:
# Image Provider接口
class BaseImageProvider:
name: str
requires_env: list[str]
def is_available(self) -> bool: ...
async def generate(self, prompt: str, **kwargs) -> bytes: ...
# 具体实现
class GeminiBananaProvider(BaseImageProvider): ...
class BailianWanxProvider(BaseImageProvider): ...
class StableDiffusionProvider(BaseImageProvider): ...
用户可以在设置里切换Provider,系统会自动检测哪些Provider可用(检查环境变量)。
同样的模式用于:
- TTS(目前只有Edge TTS,但架构预留了扩展)
- HTML模板(cover、bullents、timeline等Layout)
- AI脚本拆分(任何OpenAI-compatible API)
五、前端技术细节
5.1 ScenePlayer:RAF驱动的播放器
// 播放逻辑:RAF tick
const tick = (now: number) => {
const delta = (now - last) / 1000;
const next = Math.min(duration, currentTime + delta);
setCurrentTime(next);
if (next >= duration) {
pause();
return;
}
rafRef.current = requestAnimationFrame(tick);
};
// 音频同步
useEffect(() => {
if (audio && Math.abs(audio.currentTime - currentTime) > 0.35) {
audio.currentTime = currentTime;
}
}, [currentTime]);
用RAF而不是setInterval,因为RAF和屏幕刷新率同步,动画更平滑。音频通过onTimeUpdate事件同步,但如果偏差超过0.35秒,强制seek。
5.2 自适应缩放
const update = () => {
const rect = frame.getBoundingClientRect();
setScale(Math.min(
rect.width / settings.resolution.width,
rect.height / settings.resolution.height
));
};
const observer = new ResizeObserver(update);
observer.observe(frame);
播放器容器大小变化时,自动计算scale,保持16:9或9:16的宽高比。这是响应式设计的关键——你在笔记本上编辑,在手机上预览,画面比例不会变形。
5.3 自动保存:800ms防抖
patchPlan: (updater) => {
const current = structuredClone(get().plan);
updater(current);
set({ plan: current, dirty: true });
window.clearTimeout(saveTimer);
saveTimer = window.setTimeout(() => get().saveNow(), 800);
},
每次编辑后800ms自动保存。用structuredClone深拷贝,避免直接修改状态。dirty标志显示未保存状态。
六、后端技术细节
6.1 Pydantic v2:类型即文档
整个后端大量使用Pydantic v2:
class Scene(BaseModel):
scene_id: str
scene_title: str
narration_text: str
background: Background = Field(default_factory=Background)
# ...
API的Request/Response、数据模型、配置文件,全部用Pydantic。类型定义即API文档,即验证逻辑,即序列化规则。
6.2 本地文件存储
class PlanStore:
def load(self, pid: str) -> Plan:
path = self.project_dir(pid) / "plan.json"
return Plan.model_validate_json(path.read_text())
def save(self, pid: str, plan: Plan) -> Plan:
path = self.project_dir(pid) / "plan.json"
path.write_text(plan.model_dump_json(indent=2))
return plan
没有数据库。项目数据就是JSON文件,资产就是文件系统。简单、可移植、可版本控制。
6.3 任务队列:异步导出
class ExportRunner(ProjectJobRunner):
async def run(self, job_id: str, scene_ids, quality):
# 1. 解析时间轴
plan = resolve_timeline(self.store.load(project_id))
# 2. 序列化为HyperFrames项目
self.bridge.materialize_export_project(plan, project_dir, export_dir)
# 3. 调用HyperFrames CLI渲染
await self.hyperframes.render(export_dir, output_mp4, fps, quality, on_progress)
导出是一个异步任务,通过JobsStore管理状态(queued → running → success/failed)。前端可以轮询进度。
七、HyperFrames:视频渲染引擎
AI Video Studio 本身不处理视频编码,而是委托给 HyperFrames CLI。
HyperFrames 的职责:
- 加载V11 Bridge生成的HTML项目
- 用Headless Browser(Playwright/Puppeteer)渲染每一帧
- 用FFmpeg编码为MP4
这种"Web-to-Video"的架构很巧妙:
- 前端预览和最终渲染,用的是同一套HTML+CSS+GSAP代码
- 你看到的就是你得到的(WYSIWYG)
- 可以充分利用Web生态的动画、字体、布局能力
V11 Bridge 在导出时设置了一个关键环境变量:
env["PRODUCER_ENABLE_STREAMING_ENCODE"] = "false"
这关闭了流式编码,改用"capture-then-encode"路径——先逐帧截图,再编码为视频。更慢但更稳定,适合iframe/screenshot合成场景。
八、设计哲学的五个关键词
1. 本地优先(Local-First)
数据存在本地,不依赖云服务。你可以离线工作,可以用Git管理版本,不用担心隐私泄露。
2. 分镜思维(Scene-Based)
不是"时间轴+轨道"的传统剪辑逻辑,而是"分镜卡片+属性面板"的导演逻辑。每个分镜是一个独立的叙事单元。
3. 人在回路(Human-in-the-Loop)
AI负责"建议",人负责"决策"。脚本拆分有审核门,每个Scene可以独立调整,AI生成的东西都可以覆盖。
4. 可扩展(Pluggable)
Provider注册表让替换AI服务变得简单。今天用Gemini生图,明天可以切到SD,不改业务代码。
5. 成本可控(Cost-Effective)
- Edge TTS:免费
- Gemini Nano Banana:低成本图像生成
- 本地运行:没有订阅费
- 开源:代码可以自己改
九、局限与未来
当前局限
- HyperFrames依赖:视频导出需要HyperFrames CLI,这不是开源组件。如果HyperFrames不公开或收费,导出功能会受限。
- 动画模板有限:目前HTML模板主要是静态布局+简单动画(fade、rise、zoom)。复杂的MG动画需要手动编写HTML/CSS。
- 视频生成未集成:目前只支持图片背景,不支持AI视频(如Runway、可灵)作为背景。
- 桌面版打包:Electron桌面版已包含,但FFmpeg和HyperFrames仍需用户自行安装。
可能的扩展方向
- 更多Provider:接入更多的TTS(如OpenAI TTS、ElevenLabs)、图像(Midjourney API、Leonardo)、视频(Runway、Pika)
- 动画模板市场:让用户提交和分享自定义HTML模板
- 协作功能:基于Git的版本控制 + 多人协作编辑
- 插件系统:允许第三方开发插件扩展功能
十、总结
AI Video Studio 不是又一个"AI一键生成视频"的玩具,而是一个严肃的生产力工具。它的目标用户很明确:知识博主、演讲者、内容创作者——那些需要把"文章"变成"视频"的人。
它的架构设计有几个值得学习的地方:
- 单一数据源(Plan JSON):前后端共享同一个强类型Schema,没有数据同步问题。
- 时间轴自动解析:基于音频时长和文本长度自动计算时间,减少手动调整。
- Web-to-Video管线:用HTML+CSS+GSAP做视频合成,充分利用Web生态。
- Provider注册表:解耦AI服务,让切换和扩展变得容易。
- AI审核门:人在回路中,避免黑盒生成。
如果你也在做AI视频工具,这个项目值得仔细研究。它的代码量不大(前端+后端约1万行左右),但架构清晰,设计用心。
参考
- GitHub: https://github.com/WoyouWoyou/ai-video-studio
- 夸克网盘: https://pan.quark.cn/s/3e62fff831e3(提取码: iycv)
- 移动云盘: https://yun.139.com/shareweb/#/w/i/2v3EhsXDCvfn2(提取码: k75g)
#项目拆解 #AI视频 #开源工具 #视频工作台 #FastAPI #React #HyperFrames #内容创作
讨论回复
加载中...正在加载回复...
推荐
智谱 GLM-5 已上线
我正在智谱大模型开放平台 BigModel.cn 上打造 AI 应用,智谱新一代旗舰模型 GLM-5 已上线,在推理、代码、智能体综合能力达到开源模型 SOTA 水平。