forked from 77media/video-flow
469 lines
11 KiB
Markdown
469 lines
11 KiB
Markdown
# video-flow-b AI 剪辑集成技术文档
|
||
|
||
## 📋 项目概述
|
||
|
||
本文档详细记录了将 OpenCut 项目的 AI 智能剪辑功能集成到 video-flow-b 工作流系统中的完整技术方案。该集成实现了从剧本生成的视频片段到最终成片的自动化 AI 剪辑流程。
|
||
|
||
### 🎯 集成目标
|
||
|
||
- **自动化剪辑**: 在 video-flow-b 工作流中实现一键 AI 剪辑功能
|
||
- **无缝集成**: 复用 OpenCut 的核心 AI 剪辑逻辑,无需重复开发
|
||
- **流程优化**: 简化从视频片段到最终成片的处理流程
|
||
- **用户体验**: 提供直观的进度反馈和错误处理机制
|
||
|
||
## 🏗️ 架构设计
|
||
|
||
### 整体架构图
|
||
|
||
```mermaid
|
||
graph TB
|
||
subgraph "video-flow-b 前端层"
|
||
A[work-flow.tsx] --> B[ai-editing-button.tsx]
|
||
B --> C[ai-editing-adapter.ts]
|
||
end
|
||
|
||
subgraph "API 适配层"
|
||
C --> D[/api/export/ai-clips]
|
||
D --> E[export-adapter.ts]
|
||
end
|
||
|
||
subgraph "OpenCut 核心逻辑"
|
||
E --> F[FFmpeg处理]
|
||
F --> G[视频导出]
|
||
G --> H[云存储上传]
|
||
end
|
||
|
||
subgraph "video-flow-b 后端"
|
||
H --> I[任务状态更新]
|
||
I --> J[最终成片展示]
|
||
end
|
||
```
|
||
|
||
### 核心组件关系
|
||
|
||
```mermaid
|
||
classDiagram
|
||
class WorkFlowPage {
|
||
+handleAIEditingComplete()
|
||
+handleAIEditingError()
|
||
+showGotoCutButton: boolean
|
||
}
|
||
|
||
class AIEditingButton {
|
||
+onClick()
|
||
+showProgress()
|
||
+handleComplete()
|
||
}
|
||
|
||
class AIEditingAdapter {
|
||
+executeAIEditing()
|
||
+convertVideoFlowData()
|
||
+callExportAPI()
|
||
}
|
||
|
||
class ExportAdapter {
|
||
+POST()
|
||
+processFFmpeg()
|
||
+uploadToCloud()
|
||
}
|
||
|
||
WorkFlowPage --> AIEditingButton
|
||
AIEditingButton --> AIEditingAdapter
|
||
AIEditingAdapter --> ExportAdapter
|
||
```
|
||
|
||
## 📁 文件结构
|
||
|
||
```
|
||
video-flow-b/
|
||
├── components/pages/work-flow/
|
||
│ ├── ai-editing-adapter.ts # AI剪辑逻辑适配器
|
||
│ ├── ai-editing-button.tsx # AI剪辑按钮组件
|
||
│ └── work-flow.tsx # 主工作流页面(已修改)
|
||
├── app/api/export/
|
||
│ ├── ai-clips/route.ts # AI剪辑导出API路由
|
||
│ └── download/[exportId]/route.ts # 视频下载API路由
|
||
├── api/
|
||
│ └── export-adapter.ts # 导出API适配器
|
||
└── docs/
|
||
└── AI-EDITING-INTEGRATION.md # 本技术文档
|
||
```
|
||
|
||
## 🔧 核心组件详解
|
||
|
||
### 1. AI 剪辑适配器 (`ai-editing-adapter.ts`)
|
||
|
||
**职责**: 将 video-flow-b 的数据结构转换为 OpenCut 兼容格式,并管理整个 AI 剪辑流程。
|
||
|
||
**核心功能**:
|
||
|
||
```typescript
|
||
class AIEditingAdapter {
|
||
// 执行完整的AI剪辑流程
|
||
async executeAIEditing(): Promise<string>;
|
||
|
||
// 数据格式转换
|
||
private convertVideoFlowToAIClips(): AIClipData[];
|
||
|
||
// 调用导出API
|
||
private callExportAPI(): Promise<string>;
|
||
|
||
// 进度回调管理
|
||
private onProgress?: (progress: number, message: string) => void;
|
||
}
|
||
```
|
||
|
||
**数据转换逻辑**:
|
||
|
||
```typescript
|
||
// video-flow-b格式 -> OpenCut AI剪辑格式
|
||
{
|
||
videos: VideoFlowVideoData[]
|
||
}
|
||
↓
|
||
{
|
||
clips: AIClipData[],
|
||
totalDuration: number,
|
||
options: ExportOptions
|
||
}
|
||
```
|
||
|
||
### 2. AI 剪辑按钮组件 (`ai-editing-button.tsx`)
|
||
|
||
**职责**: 提供用户交互界面,显示剪辑进度和状态反馈。
|
||
|
||
**功能特性**:
|
||
|
||
- ✨ 美观的玻璃态设计
|
||
- 📊 实时进度显示
|
||
- 🔄 状态管理(待机/处理中/完成/错误)
|
||
- 🎭 流畅的动画效果
|
||
- 📱 响应式设计
|
||
|
||
**使用示例**:
|
||
|
||
```tsx
|
||
<AIEditingIconButton
|
||
projectId={episodeId}
|
||
taskObject={taskObject}
|
||
onComplete={handleAIEditingComplete}
|
||
onError={handleAIEditingError}
|
||
/>
|
||
```
|
||
|
||
### 3. 导出 API 适配器 (`export-adapter.ts`)
|
||
|
||
**职责**: 复用 OpenCut 的 FFmpeg 处理逻辑,提供流式进度反馈。
|
||
|
||
**核心流程**:
|
||
|
||
1. **数据验证**: 检查输入的视频片段数据
|
||
2. **FFmpeg 处理**: 执行视频剪辑和合成
|
||
3. **进度推送**: 通过 Server-Sent Events 推送实时进度
|
||
4. **云存储上传**: 将处理完成的视频上传到云存储
|
||
5. **URL 返回**: 返回最终的视频访问链接
|
||
|
||
## 🚀 完整工作流程
|
||
|
||
### 1. 触发条件
|
||
|
||
```typescript
|
||
// 当video-flow-b工作流进入video阶段且有视频片段时
|
||
if (taskObject.currentStage === "video" && taskObject.videos.data.length > 0) {
|
||
// 显示AI剪辑按钮
|
||
showAIEditingButton = true;
|
||
}
|
||
```
|
||
|
||
### 2. AI 剪辑执行流程
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant U as 用户
|
||
participant B as AI剪辑按钮
|
||
participant A as AI适配器
|
||
participant API as 导出API
|
||
participant F as FFmpeg
|
||
participant C as 云存储
|
||
participant W as WorkFlow页面
|
||
|
||
U->>B: 点击AI剪辑按钮
|
||
B->>A: executeAIEditing()
|
||
A->>A: convertVideoFlowToAIClips()
|
||
A->>API: POST /api/export/ai-clips
|
||
API->>F: 启动FFmpeg处理
|
||
|
||
loop 进度更新
|
||
F->>API: 处理进度
|
||
API->>A: Server-Sent Events
|
||
A->>B: onProgress回调
|
||
B->>U: 更新进度UI
|
||
end
|
||
|
||
F->>C: 上传处理完成的视频
|
||
C->>API: 返回视频URL
|
||
API->>A: 完成通知
|
||
A->>B: onComplete回调
|
||
B->>W: handleAIEditingComplete()
|
||
W->>W: 更新任务状态到final_video
|
||
```
|
||
|
||
### 3. 数据流转换
|
||
|
||
**输入数据结构**:
|
||
|
||
```typescript
|
||
// video-flow-b视频数据
|
||
interface VideoFlowVideoData {
|
||
id: string;
|
||
url: string;
|
||
scene_id: string;
|
||
duration?: number;
|
||
// ... 其他字段
|
||
}
|
||
```
|
||
|
||
**转换后数据结构**:
|
||
|
||
```typescript
|
||
// OpenCut AI剪辑格式
|
||
interface AIClipData {
|
||
sequence_clip_id: string;
|
||
source_clip_id: string;
|
||
video_url: string;
|
||
source_in_timecode: string;
|
||
source_out_timecode: string;
|
||
sequence_start_timecode: string;
|
||
clip_duration_in_sequence: string;
|
||
corresponding_script_scene_id?: string;
|
||
}
|
||
```
|
||
|
||
## 🔌 API 接口文档
|
||
|
||
### POST /api/export/ai-clips
|
||
|
||
**描述**: AI 剪辑导出接口,复用 OpenCut 的核心导出逻辑
|
||
|
||
**请求体**:
|
||
|
||
```typescript
|
||
{
|
||
clips: AIClipData[];
|
||
subtitles?: string;
|
||
totalDuration: number;
|
||
options: {
|
||
quality: 'low' | 'standard' | 'high';
|
||
format: 'mp4' | 'webm' | 'mov';
|
||
fps?: number;
|
||
};
|
||
}
|
||
```
|
||
|
||
**响应格式**: Server-Sent Events 流式响应
|
||
|
||
```typescript
|
||
// 进度更新
|
||
data: {"type": "progress", "progress": 45, "message": "处理视频片段 2/5"}
|
||
|
||
// 完成通知
|
||
data: {"type": "completed", "downloadUrl": "https://example.com/video.mp4"}
|
||
```
|
||
|
||
### GET /api/export/download/[exportId]
|
||
|
||
**描述**: 导出视频下载接口
|
||
|
||
**参数**:
|
||
|
||
- `exportId`: 导出任务 ID
|
||
|
||
**响应**:
|
||
|
||
- 成功: 返回视频文件流
|
||
- 失败: 返回错误 JSON
|
||
|
||
## 🎨 UI/UX 设计
|
||
|
||
### 按钮状态设计
|
||
|
||
```typescript
|
||
enum AIEditingState {
|
||
IDLE = "idle", // 待机状态 - 显示剪刀图标
|
||
PROCESSING = "processing", // 处理中 - 显示进度环
|
||
COMPLETED = "completed", // 完成 - 显示对勾图标
|
||
ERROR = "error", // 错误 - 显示错误图标
|
||
}
|
||
```
|
||
|
||
### 进度显示设计
|
||
|
||
```typescript
|
||
// 进度阶段划分
|
||
const PROGRESS_STAGES = {
|
||
DATA_CONVERSION: { start: 0, end: 20, message: "数据转换中..." },
|
||
VIDEO_PROCESSING: { start: 20, end: 80, message: "AI剪辑处理中..." },
|
||
UPLOAD_COMPLETE: { start: 80, end: 100, message: "上传完成!" },
|
||
};
|
||
```
|
||
|
||
### 视觉效果
|
||
|
||
- **玻璃态设计**: 使用`backdrop-blur-lg`实现磨砂玻璃效果
|
||
- **动画效果**: 使用 Framer Motion 实现流畅的状态转换
|
||
- **进度指示**: 圆形进度条配合百分比显示
|
||
- **状态反馈**: 不同状态使用不同的颜色和图标
|
||
|
||
## 🔧 配置与部署
|
||
|
||
### 环境依赖
|
||
|
||
```json
|
||
{
|
||
"dependencies": {
|
||
"framer-motion": "^10.x.x",
|
||
"lucide-react": "^0.x.x",
|
||
"antd": "^5.x.x"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 环境变量
|
||
|
||
```bash
|
||
# 云存储配置(继承自OpenCut项目)
|
||
QINIU_ACCESS_KEY=your_access_key
|
||
QINIU_SECRET_KEY=your_secret_key
|
||
QINIU_BUCKET=your_bucket_name
|
||
QINIU_DOMAIN=your_domain
|
||
|
||
# FFmpeg配置
|
||
FFMPEG_PATH=/usr/local/bin/ffmpeg
|
||
```
|
||
|
||
### 部署检查清单
|
||
|
||
- [ ] 确保 FFmpeg 已正确安装
|
||
- [ ] 验证云存储配置
|
||
- [ ] 检查 API 路由是否正确注册
|
||
- [ ] 测试流式响应功能
|
||
- [ ] 验证错误处理机制
|
||
|
||
## 🧪 测试策略
|
||
|
||
### 单元测试
|
||
|
||
```typescript
|
||
describe("AIEditingAdapter", () => {
|
||
test("应该正确转换video-flow-b数据格式", () => {
|
||
const adapter = new AIEditingAdapter(mockTaskObject);
|
||
const result = adapter.convertVideoFlowToAIClips();
|
||
expect(result).toHaveLength(mockTaskObject.videos.data.length);
|
||
});
|
||
|
||
test("应该正确处理进度回调", () => {
|
||
const onProgress = jest.fn();
|
||
const adapter = new AIEditingAdapter(mockTaskObject, { onProgress });
|
||
adapter.executeAIEditing();
|
||
expect(onProgress).toHaveBeenCalled();
|
||
});
|
||
});
|
||
```
|
||
|
||
### 集成测试
|
||
|
||
```typescript
|
||
describe("AI剪辑集成测试", () => {
|
||
test("完整的AI剪辑流程", async () => {
|
||
// 1. 准备测试数据
|
||
const mockTaskObject = createMockTaskObject();
|
||
|
||
// 2. 执行AI剪辑
|
||
const result = await executeAIEditing(mockTaskObject);
|
||
|
||
// 3. 验证结果
|
||
expect(result).toContain("http");
|
||
expect(result).toMatch(/\.mp4$/);
|
||
});
|
||
});
|
||
```
|
||
|
||
### 性能测试
|
||
|
||
- **响应时间**: API 响应时间应在 5 秒内
|
||
- **内存使用**: 处理过程中内存使用应保持在合理范围
|
||
- **并发处理**: 支持多个 AI 剪辑任务并发执行
|
||
|
||
## 🐛 故障排除
|
||
|
||
### 常见问题
|
||
|
||
1. **FFmpeg 未找到**
|
||
|
||
```bash
|
||
错误: FFmpeg executable not found
|
||
解决: 确保FFmpeg已安装并在PATH中
|
||
```
|
||
|
||
2. **视频格式不支持**
|
||
|
||
```bash
|
||
错误: Unsupported video format
|
||
解决: 检查输入视频格式,确保为支持的格式
|
||
```
|
||
|
||
3. **云存储上传失败**
|
||
```bash
|
||
错误: Upload failed
|
||
解决: 检查云存储配置和网络连接
|
||
```
|
||
|
||
### 日志分析
|
||
|
||
```typescript
|
||
// 启用详细日志
|
||
console.log("🎬 AI剪辑开始:", { projectId, clipCount });
|
||
console.log("📊 数据转换完成:", convertedData);
|
||
console.log("🚀 API调用中:", apiEndpoint);
|
||
console.log("✅ 处理完成:", finalVideoUrl);
|
||
```
|
||
|
||
## 🔮 未来优化方向
|
||
|
||
### 性能优化
|
||
|
||
1. **并行处理**: 支持多个视频片段并行处理
|
||
2. **缓存机制**: 实现处理结果缓存,避免重复计算
|
||
3. **压缩优化**: 优化视频压缩算法,减小文件大小
|
||
|
||
### 功能增强
|
||
|
||
1. **自定义剪辑规则**: 允许用户自定义 AI 剪辑参数
|
||
2. **批量处理**: 支持批量项目的 AI 剪辑处理
|
||
3. **预览功能**: 在正式导出前提供剪辑预览
|
||
|
||
### 用户体验
|
||
|
||
1. **进度细化**: 提供更详细的处理进度信息
|
||
2. **错误恢复**: 实现处理失败后的自动重试机制
|
||
3. **通知系统**: 添加处理完成的通知功能
|
||
|
||
## 📚 参考资料
|
||
|
||
- [OpenCut 项目文档](../apps/web/README.md)
|
||
- [video-flow-b 项目文档](./README.md)
|
||
- [FFmpeg 官方文档](https://ffmpeg.org/documentation.html)
|
||
- [Next.js API Routes 文档](https://nextjs.org/docs/api-routes/introduction)
|
||
- [Server-Sent Events 规范](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events)
|
||
|
||
## 📞 技术支持
|
||
|
||
如有技术问题,请联系开发团队或在项目仓库中创建 Issue。
|
||
|
||
---
|
||
|
||
**文档版本**: v1.0.0
|
||
**最后更新**: 2025-01-08
|
||
**维护者**: 资深全栈开发工程师
|
||
**审核者**: 项目技术负责人
|