16 KiB
16 KiB
Sora-2 角色创建功能开发计划
功能概述
为 Sora-2 视频模型添加角色创建和复用功能,用户可以从已完成的视频任务中提取角色,并在后续视频生成中通过 @username 方式引用该角色。
API 接口说明
1. 创建角色接口
- URL:
POST https://api.tu-zi.com/v1/videos - Content-Type:
multipart/form-data
| 参数 | 类型 | 必需 | 说明 |
|---|---|---|---|
character_from_task |
string | 是 | 源视频任务ID,格式: sora-2:task_xxx |
model |
string | 是 | 固定值: sora-2-character |
character_timestamps |
string | 否 | 时间范围,格式: start,end,差值需在1-3秒内 |
响应示例:
{
"id": "sora-2-character:ch_6944ed3a51888191bd1ac40c763620fb"
}
2. 查询角色接口
- URL:
GET https://api.tu-zi.com/v1/videos/{id} - 认证: Bearer Token
响应示例:
{
"id": "sora-2-character:ch_6944ed3a51888191bd1ac40c763620fb",
"username": "xscjkajd.lunaradian",
"permalink": "https://sora.chatgpt.com/profile/xscjkajd.lunaradian",
"profile_picture_url": "https://filesystem.site/cdn/xxx.jpg"
}
开发任务清单
阶段一:基础架构(预计 2-3 天)
Task 1: 创建角色类型定义
- 文件:
packages/drawnix/src/types/character.types.ts - 内容:
SoraCharacter接口(角色完整信息)CharacterStatus枚举(pending/processing/completed/failed)CreateCharacterParams接口(创建参数)CharacterQueryResponse接口(查询响应)
Task 2: 实现角色 API 服务
- 文件:
packages/drawnix/src/services/character-api-service.ts - 功能:
createCharacter()- 提交角色创建请求queryCharacter()- 查询角色状态createCharacterWithPolling()- 创建并轮询直到完成
- 依赖: Task 1
Task 3: 实现角色存储服务
- 文件:
packages/drawnix/src/services/character-storage-service.ts - 功能:
- IndexedDB 存储(使用 localforage)
saveCharacter()- 保存角色getCharacters()- 获取所有角色getCharacterById()- 按ID获取deleteCharacter()- 删除角色updateCharacter()- 更新角色状态
- 存储键:
sora-characters - 依赖: Task 1
Task 4: 创建角色状态管理 Hook
- 文件:
packages/drawnix/src/hooks/useCharacters.ts - 功能:
- 角色列表状态管理(RxJS BehaviorSubject)
characters- 角色列表pendingCharacters- 处理中的角色createCharacter()- 创建角色(带状态更新)deleteCharacter()- 删除角色refreshCharacters()- 刷新列表
- 依赖: Task 2, Task 3
阶段二:UI 组件(预计 2-3 天)
Task 5: 实现角色创建对话框
- 文件:
packages/drawnix/src/components/character/CharacterCreateDialog.tsx - 功能:
- 显示源视频信息
- 时间范围选择器(滑块或输入框)
- 时间约束验证(1-3秒)
- 提交/取消按钮
- 创建中状态显示
- UI: 使用 TDesign Dialog + Slider/InputNumber
- 依赖: Task 4
Task 6: 在 TaskItem 中添加「提取角色」按钮
- 文件:
packages/drawnix/src/components/task-queue/TaskItem.tsx - 修改:
- 添加「提取角色」按钮(仅对 sora-2 已完成任务显示)
- 添加
onExtractCharacter回调 - 按钮条件判断逻辑
- 依赖: Task 5
Task 7: 实现角色卡片组件
- 文件:
packages/drawnix/src/components/character/CharacterCard.tsx - 功能:
- 显示头像(profile_picture_url)
- 显示 @username
- 复制按钮(复制 @username)
- 删除按钮
- 处理中状态(loading)
- 样式:
character.scss - 依赖: Task 1
Task 8: 实现角色列表/选择器组件
- 文件:
packages/drawnix/src/components/character/CharacterList.tsx - 功能:
- 显示所有已创建的角色
- 支持选择角色(用于插入提示词)
- 空状态提示
- 可选:搜索过滤
- 依赖: Task 4, Task 7
阶段三:提示词集成(预计 1-2 天)
Task 9: 在 PromptInput 中集成 @ 提及功能
- 文件:
packages/drawnix/src/components/ttd-dialog/shared/PromptInput.tsx - 修改:
- 监听
@输入 - 弹出角色选择器(Popup/Dropdown)
- 选择后插入
@username - 支持键盘导航(上下选择,回车确认)
- 监听
- 新文件:
CharacterMentionPopup.tsx - 依赖: Task 4, Task 8
阶段四:状态同步与优化(预计 1 天)
Task 10: 页面刷新恢复
- 从 IndexedDB 恢复角色列表
- 恢复处理中的角色创建任务
- 继续轮询未完成的角色
Task 11: 错误处理与用户反馈
- API 错误提示(网络错误、超时、服务器错误)
- 角色创建失败处理
- 重试机制
文件结构
packages/drawnix/src/
├── types/
│ └── character.types.ts # 角色类型定义
├── services/
│ ├── character-api-service.ts # 角色 API 服务
│ └── character-storage-service.ts # 角色存储服务
├── hooks/
│ └── useCharacters.ts # 角色状态管理 Hook
├── components/
│ ├── character/
│ │ ├── index.ts
│ │ ├── CharacterCreateDialog.tsx
│ │ ├── CharacterCard.tsx
│ │ ├── CharacterList.tsx
│ │ ├── CharacterMentionPopup.tsx
│ │ └── character.scss
│ └── task-queue/
│ └── TaskItem.tsx # 修改:添加提取角色按钮
└── components/ttd-dialog/shared/
└── PromptInput.tsx # 修改:添加 @ 提及功能
数据流
┌─────────────────────────────────────────────────────────────────┐
│ 用户交互流程 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. 用户点击「提取角色」 │
│ │ │
│ ▼ │
│ 2. CharacterCreateDialog 弹出 │
│ │ │
│ ▼ │
│ 3. 用户选择时间范围 → 点击创建 │
│ │ │
│ ▼ │
│ 4. useCharacters.createCharacter() │
│ │ │
│ ├──► characterApiService.createCharacter() │
│ │ │ │
│ │ ▼ │
│ │ POST /v1/videos (character_from_task, model) │
│ │ │ │
│ │ ▼ │
│ │ 返回 character_id │
│ │ │
│ ├──► characterStorageService.saveCharacter(pending) │
│ │ │
│ └──► 开始轮询 queryCharacter() │
│ │ │
│ ▼ │
│ GET /v1/videos/{id} │
│ │ │
│ ▼ │
│ 返回 username, profile_picture_url │
│ │ │
│ ▼ │
│ 5. characterStorageService.updateCharacter(completed) │
│ │ │
│ ▼ │
│ 6. UI 更新显示角色卡片 │
│ │
└─────────────────────────────────────────────────────────────────┘
UI 设计参考
1. 提取角色按钮位置
┌─────────────────────────────────────────────────────────────────┐
│ TaskItem (sora-2 已完成任务) │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 🎬 [prompt text...] │
│ │
│ sora-2 | 10秒 | 1920x1080 | ✅ 已完成 │
│ │
│ [预览图] │
│ │
│ [删除] [下载] [插入] [缓存] [编辑] [👤 提取角色] │
│ │
└─────────────────────────────────────────────────────────────────┘
2. 角色创建对话框
┌─────────────────────────────────────────────────────────────────┐
│ 提取角色 [X] │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 从视频中提取角色,创建后可在后续视频中通过 @username 引用 │
│ │
│ 源视频: 一只白色的猫在花园里玩耍... │
│ 任务ID: sora-2:task_01kbh21pg... │
│ │
│ ───────────────────────────────────────────────────────────── │
│ │
│ 时间范围 (角色在视频中出现的位置) │
│ │
│ 开始时间: [0 ] 秒 结束时间: [3 ] 秒 │
│ │
│ ⓘ 时间范围需在 1-3 秒之间 │
│ │
│ ───────────────────────────────────────────────────────────── │
│ │
│ [取消] [创建角色] │
│ │
└─────────────────────────────────────────────────────────────────┘
3. 角色卡片
┌──────────────────────────────────┐
│ ┌────────┐ │
│ │ 头像 │ @xscjkajd.lunar... │
│ │ 64x64 │ │
│ └────────┘ [📋 复制] [🗑 删除] │
│ │
│ 来源: 白猫视频任务 │
│ 创建于: 2024-01-15 14:30 │
└──────────────────────────────────┘
4. @ 提及弹窗
提示词输入框:
┌─────────────────────────────────────────────────────────────────┐
│ 一只猫在追逐 @| │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ 📷 @xscjkajd.lunaradian │ ← 选中
│ 📷 @abc123.character │
│ ─────────────────────────────── │
│ + 从视频提取新角色... │
└─────────────────────────────────┘
技术要点
1. 模型判断逻辑
// 判断是否可以提取角色
const canExtractCharacter = (task: Task): boolean => {
return (
task.status === TaskStatus.COMPLETED &&
task.type === TaskType.VIDEO &&
task.remoteId?.startsWith('sora-2:') &&
['sora-2', 'sora-2-pro'].includes(task.params.model || '')
);
};
2. 时间范围验证
const validateTimestamps = (start: number, end: number, videoDuration: number): boolean => {
const duration = end - start;
return (
start >= 0 &&
end <= videoDuration &&
duration >= 1 &&
duration <= 3
);
};
3. IndexedDB 存储结构
// 存储键: 'sora-characters'
// 数据结构: SoraCharacter[]
{
id: 'sora-2-character:ch_xxx',
username: 'xscjkajd.lunaradian',
profilePictureUrl: 'https://...',
permalink: 'https://...',
sourceTaskId: 'local-task-uuid',
sourceVideoId: 'sora-2:task_xxx',
characterTimestamps: '0,3',
status: 'completed',
createdAt: 1705312200000,
completedAt: 1705312260000,
}
测试要点
-
API 集成测试
- 角色创建请求格式正确
- 轮询查询正常工作
- 错误响应处理
-
UI 交互测试
- 提取角色按钮仅对符合条件的任务显示
- 时间范围选择器约束正确
- 角色创建状态实时更新
- @ 提及弹窗正确显示和选择
-
数据持久化测试
- 刷新页面后角色列表恢复
- 角色删除后正确移除
- 处理中任务恢复轮询
开发顺序建议
Week 1:
├── Day 1-2: Task 1-3 (类型定义 + API服务 + 存储服务)
├── Day 3: Task 4 (状态管理 Hook)
└── Day 4-5: Task 5-6 (创建对话框 + TaskItem按钮)
Week 2:
├── Day 1-2: Task 7-8 (角色卡片 + 列表组件)
├── Day 3-4: Task 9 (@ 提及功能)
└── Day 5: Task 10-11 (状态同步 + 错误处理)
后续扩展
- 角色库面板 - 独立的角色管理界面
- 角色分组/标签 - 组织和筛选角色
- 角色使用统计 - 追踪角色使用频率
- 批量导出 - 导出角色数据备份
- 角色分享 - 跨设备同步角色(需后端支持)