最近,我们为开源浏览器 AI 视频编辑器 Timeline Studio 增加了一套生成插件架构。
目前已经接入三类具有代表性的生成工具:
- Puter.js
- ComfyUI
- Stable Diffusion WebUI / Forge
这次改造并不是简单地在界面上增加几张插件卡片,而是尝试解决一个工程问题:
如何将鉴权方式、任务协议和结果格式各不相同的 AI 生成服务,接入同一套视频素材工作流?
项目地址:
https://github.com/MartinDelophy/ai-video-editor
在线体验:
https://video-editor.ai-creator.top/
一、为什么要设计生成插件系统?
Timeline Studio 是一款本地优先、直接运行在浏览器中的开源 AI 视频编辑器。
项目提供多轨时间线、画中画、字幕、配音、音乐、关键帧、遮罩、滤镜、速度调整和离线视频导出,并通过 WebGPU、WebCodecs、WASM 和 ONNX Runtime Web 实现多项浏览器 AI 能力。
随着图片和视频生成服务不断增加,直接在业务组件中接入供应商会遇到明显的扩展问题。
一种常见写法如下:
javascript
if (provider === "provider-a") {
// Provider A 的鉴权和请求
} else if (provider === "provider-b") {
// Provider B 的轮询和结果解析
} else if (provider === "provider-c") {
// Provider C 的下载与错误处理
}
最初接入一两个服务时,这种方式看起来足够直接。但随着供应商增加,以下逻辑会逐渐混在一起:
- 登录与鉴权
- 连接状态
- 请求参数
- 任务轮询
- 进度解析
- 任务取消
- 错误转换
- 结果下载
- 素材下载
- 多语言文案
最终,一个生成 Hook 或 React 组件可能同时理解所有供应商的接口细节。
插件架构的目标,就是把这些变化频繁的供应商逻辑隔离起来,让编辑器核心只处理稳定的能力和结果。
二、先确定插件边界
Timeline Studio 当前的插件主要面向图片和视频生成。
第一版契约覆盖:
- 文生图
- 图生图
- 文生视频
- 图生视频
- 工作流图片生成
- 工作流视频生成
以下能力暂时不属于这套契约:
- 时间线编辑命令
- 转场和特效
- 任意 React 扩展
- 模型训练
- 内容信息流
- 通用网页嵌入
限制插件范围可以防止第一版接口承担过多职责。
编辑操作需要访问复杂的项目状态和撤销历史,生成插件则只需要接收输入并返回媒体。二者的安全边界和生命周期完全不同,不适合使用同一套契约。
三、插件系统的核心闭环
我们对插件完成状态做了一个明确规定:
插件只有在编辑器取得真实媒体数据并保存到 My assets 后,才能报告完成。
完整流程如下:
text
选择插件
↓
连接服务或完成授权
↓
填写提示词、参数或工作流
↓
提交真实生成任务
↓
同步或轮询任务状态
↓
下载图片或视频
↓
验证媒体类型和数据
↓
提交到 My assets
生成完成后,素材会自动进入 My assets(我的素材),但不会自动插入时间线。
这样设计有两个原因。
第一,远程平台返回的结果 URL 可能带有时效性。只保存 URL 并不能保证用户稍后仍能使用素材。
第二,生成内容是否进入当前作品应由用户决定。插件不应该在没有明确操作的情况下改变时间线结构。
四、Manifest 与 Adapter 分离
插件采用声明信息和传输实现分离的方式组织。
目标目录结构如下:
text
src/plugins/generation/
├── contract.js
├── registry.js
├── host.js
└── providers/
└── example-provider/
├── manifest.js
├── adapter.js
├── Inspector.jsx
├── copy.js
└── index.js
1. Manifest:声明插件能力
Manifest 保存稳定的声明信息:
javascript
export const manifest = {
schemaVersion: 1,
id: "example-provider",
displayName: "Example Provider",
version: "1.0.0",
runtime: "secure-backend",
capabilities: ["text-to-image"],
outputTypes: ["image"],
auth: "backend",
defaultEndpoint: null,
};
字段职责包括:
id:稳定的插件标识;version:适配器行为版本;runtime:插件运行模式;capabilities:支持的生成能力;outputTypes:可返回的媒体类型;auth:使用的鉴权方式。
Manifest 中禁止保存:
- API Key
- Token
- Cookie
- 用户账号
- 工作流密钥
- 任意远程可执行代码
插件卡片的介绍、按钮和表单字段也不直接写在 Manifest 中,而是从独立的多语言文案模块读取。
2. Adapter:隔离供应商接口
Adapter 负责供应商相关的传输逻辑:
javascript
export function createAdapter(services) {
return {
async connect({ config, signal }) {
// 验证端点或完成授权
},
async disconnect() {
// 清理连接状态
},
async generate({ request, signal, onState, onProgress }) {
// 提交任务并返回统一结果
},
async cancel({ job }) {
// 根据供应商能力取消任务
},
normalizeError(error) {
// 转换为编辑器可展示的错误
},
};
}
Adapter 不应该直接修改时间线,也不应该自行维护一套素材库。
它只负责:
- 连接服务;
- 提交请求;
- 读取真实状态;
- 下载生成结果;
- 转换错误;
- 返回标准化数据。
最终素材由共享 Host 验证和提交。
3. Registry:统一发现插件
Registry 是插件的统一注册入口。
编辑器只需要从 Registry 读取可用插件,不必扫描组件,也不必在多个位置维护供应商列表。
新增插件时,开发者注册 Manifest 和 Adapter 即可,不需要在共享 Hook 中增加新的供应商条件分支。
4. Host:统一管理结果
共享 Host 负责供应商不应该自行处理的逻辑:
- 任务互斥
- 取消协调
- 忽略过期回调
- 结果格式归一化
- 图片和视频验证
- My assets 提交
这样可以确保所有插件遵守同一套结果标准。
五、三类插件运行模式
不同服务使用不同的鉴权和部署方式,因此插件需要先选择一种明确的 Runtime。
1. Browser Session
这种模式适合拥有浏览器 SDK、弹窗授权和用户账户体系的服务。
Puter.js 是当前示例。
用户点击连接后打开真实登录窗口,后续生成使用登录用户自己的账户和额度。编辑器不需要保存 API Key,也不能模拟授权成功。
需要注意的是,依赖弹窗的授权必须直接在用户点击事件中同步启动。如果在打开弹窗前执行多个异步检查,浏览器可能将其识别为非用户触发并拦截。
2. Loopback
Loopback 模式用于连接用户电脑上运行的服务,例如:
- ComfyUI
- AUTOMATIC1111
- Stable Diffusion WebUI
- Forge
插件只允许访问本机回环地址:
text
localhost
127.0.0.1
::1
禁止默认连接局域网主机,也不应建议用户:
- 将未认证服务监听到
0.0.0.0; - 对整个局域网开放端口;
- 使用通配符 CORS;
- 关闭必要的访问控制。
显示"已连接"之前,插件必须验证对应服务的健康检查接口和 CORS。
3. Secure Backend
如果供应商需要开发者持有 Secret,则必须通过安全后端调用。
text
Timeline Studio
↓
安全连接后端
↓
云端生成服务
密钥不能存放在:
text
前端源码
浏览器构建文件
localStorage
Manifest
日志
示例配置
Git 仓库
安全后端可以负责创建任务、查询状态、处理回调和签名结果地址。浏览器端 Adapter 只接收完成当前操作所需的受控数据。
六、为什么 ComfyUI 和 WebUI 是两个插件?
ComfyUI 与 Stable Diffusion WebUI / Forge 都能运行图片生成模型,但它们的产品模型不同。
ComfyUI:工作流优先
ComfyUI 插件接收 API Format 工作流,提交真实 Prompt 任务,跟踪执行状态,并下载工作流中声明的全部媒体输出。
它适合:
- 多节点图片工作流
- ControlNet
- 放大和修复
- 图生图
- 视频生成节点
- 自定义节点组合
插件不能假设某个固定节点一定是最终输出,而应根据任务历史和工作流声明收集生成结果。
WebUI / Forge:提示词优先
WebUI 插件直接调用兼容 API,例如:
text
/sdapi/v1/txt2img
/sdapi/v1/img2img
它更适合传统提示词、采样器、尺寸、步数和参考图片等参数驱动的交互。
将二者拆成独立插件,可以避免出现一个同时处理工作流 JSON 和普通提示词表单的超大适配器。
七、不要伪造连接和生成进度
插件系统中很容易出现两类"乐观状态"。
第一类是填写地址后立即显示已连接。
第二类是在供应商没有提供进度时,自行生成一个不断增长的百分比。
Timeline Studio 要求连接状态真实反映服务状态:
text
disconnected
connecting / authorizing
connected
error
任务状态同样需要明确:
text
idle
queued
running
complete
cancelled
error
只有供应商返回具有实际意义的百分比时,界面才能显示数值进度。否则应展示不确定进度状态。
一个任务返回 URL 也不等于完成。插件还需要成功下载并验证媒体数据。
八、处理异步任务中的竞争问题
生成任务通常需要数十秒甚至更长时间,期间用户可能:
- 取消任务;
- 断开连接;
- 切换插件;
- 修改端点并重新连接;
- 启动下一次生成。
这会产生典型的异步竞争问题。
例如,第一次连接请求响应较慢,用户已经修改配置并完成第二次连接。如果第一次响应随后返回,就可能覆盖最新状态。
因此,共享 Host 需要识别当前任务所有权,并忽略来自旧请求的迟到回调。
可以使用递增版本或唯一任务标识:
javascript
const attemptId = ++currentAttempt;
const result = await adapter.connect(config);
if (attemptId !== currentAttempt) {
return;
}
setConnection(result);
生成任务也需要类似处理。取消本地等待并不一定代表远端任务已经停止,因此 Adapter 还必须准确说明取消语义,不能把"停止轮询"描述成"远端任务已取消"。
九、错误信息也属于插件契约
网络请求失败时,浏览器可能只返回:
text
Failed to fetch
这条信息对用户几乎没有帮助。
Adapter 需要把底层错误转换成可操作的提示,例如:
- 本地服务尚未启动;
- 端口或协议配置错误;
- 当前编辑器来源未被 CORS 允许;
- 登录状态已经过期;
- 工作流不是 API Format;
- 服务返回了不支持的媒体格式;
- 结果地址已经过期;
- 当前账户没有生成额度。
供应商特有错误由 Adapter 识别,共享 Host 再将其转换为统一错误结构,最后由多语言界面展示。
十、当前为什么采用源码集成插件?
Timeline Studio 当前的插件是经过代码审查的源码集成连接器,并不是可以下载任意第三方 JavaScript 的开放市场。
开放式插件运行时还需要解决:
- 权限模型
- 沙箱隔离
- 插件签名
- 版本兼容
- 数据访问控制
- 安装与卸载
- 恶意代码检查
- API 生命周期
在这些机制完成前,把源码适配器称为"可任意安装插件"会造成错误预期和安全风险。
因此,当前新增插件的正确方式是:
- 阅读插件开发契约;
- 评估供应商 API 是否满足要求;
- 创建隔离的 Manifest 和 Adapter;
- 补充插件专属界面与多语言文案;
- 验证连接、取消、错误和输出下载;
- 通过 Pull Request 接受代码审查。
十一、如何参与项目?
完整的插件开发规范已经放在仓库中:
本地运行项目:
bash
git clone https://github.com/MartinDelophy/ai-video-editor.git
cd ai-video-editor
npm install
npm run dev
项目使用 MIT License,欢迎参与以下方向:
- 接入新的图片或视频生成服务;
- 完善 ComfyUI 工作流兼容;
- 改进 WebUI / Forge 参数支持;
- 建设安全的云端连接层;
- 优化插件任务状态与错误处理;
- 完善国际化文案;
- 参与 WebGPU、WebCodecs 和浏览器 AI 能力开发。
GitHub:
https://github.com/MartinDelophy/ai-video-editor
在线体验:
https://video-editor.ai-creator.top/
总结
一个可用的 AI 生成插件,不能只是展示一张供应商卡片,也不能只是嵌入一个外部网页。
它至少需要完成:
text
真实连接
+ 真实生成
+ 真实状态
+ 自动下载
+ 媒体验证
+ 素材入库
+ 安全鉴权
Timeline Studio 通过 Manifest、Adapter、Registry 和 Host 分离插件职责,让云端服务、浏览器 SDK 和本地生成工具能够接入同一套素材工作流。
AI 模型还会继续变化,但视频编辑器的核心不应该跟着每个供应商反复重写。
如果你也在关注浏览器 AI、视频编辑或生成服务集成,欢迎体验 Timeline Studio,并在 GitHub 上提交 Issue、建议或 Pull Request。