更新
This commit is contained in:
@@ -33,9 +33,10 @@ backend/
|
||||
│ │ ├── materials/ # 素材管理(router/schemas/service)
|
||||
│ │ ├── publish/ # 多平台发布
|
||||
│ │ ├── auth/ # 认证与会话
|
||||
│ │ ├── ai/ # AI 功能(标题标签生成等)
|
||||
│ │ ├── ai/ # AI 功能(标题标签生成、多语言翻译)
|
||||
│ │ ├── assets/ # 静态资源(字体/样式/BGM)
|
||||
│ │ ├── ref_audios/ # 声音克隆参考音频(router/schemas/service)
|
||||
│ │ ├── generated_audios/ # 预生成配音管理(router/schemas/service)
|
||||
│ │ ├── login_helper/ # 扫码登录辅助
|
||||
│ │ ├── tools/ # 工具接口(router/schemas/service)
|
||||
│ │ └── admin/ # 管理员功能
|
||||
|
||||
@@ -19,12 +19,13 @@ backend/
|
||||
│ │ ├── materials/ # 素材管理(router/schemas/service)
|
||||
│ │ ├── publish/ # 多平台发布
|
||||
│ │ ├── auth/ # 认证与会话
|
||||
│ │ ├── ai/ # AI 功能(标题标签生成)
|
||||
│ │ ├── assets/ # 静态资源(字体/样式/BGM)
|
||||
│ │ ├── ref_audios/ # 声音克隆参考音频(router/schemas/service)
|
||||
│ │ ├── login_helper/ # 扫码登录辅助
|
||||
│ │ ├── tools/ # 工具接口(router/schemas/service)
|
||||
│ │ └── admin/ # 管理员功能
|
||||
│ │ ├── ai/ # AI 功能(标题标签生成、多语言翻译)
|
||||
│ │ ├── assets/ # 静态资源(字体/样式/BGM)
|
||||
│ │ ├── ref_audios/ # 声音克隆参考音频(router/schemas/service)
|
||||
│ │ ├── generated_audios/ # 预生成配音管理(router/schemas/service)
|
||||
│ │ ├── login_helper/ # 扫码登录辅助
|
||||
│ │ ├── tools/ # 工具接口(router/schemas/service)
|
||||
│ │ └── admin/ # 管理员功能
|
||||
│ ├── repositories/ # Supabase 数据访问
|
||||
│ ├── services/ # 外部服务集成 (TTS/Remotion/Storage/Uploader 等)
|
||||
│ └── tests/ # 单元测试与集成测试
|
||||
@@ -83,11 +84,19 @@ backend/
|
||||
|
||||
7. **AI 功能 (AI)**
|
||||
* `POST /api/ai/generate-meta`: AI 生成标题和标签
|
||||
* `POST /api/ai/translate`: AI 多语言翻译(支持 9 种目标语言)
|
||||
|
||||
8. **工具 (Tools)**
|
||||
8. **预生成配音 (Generated Audios)**
|
||||
* `POST /api/generated-audios/generate`: 异步生成配音(返回 task_id)
|
||||
* `GET /api/generated-audios/tasks/{task_id}`: 轮询生成进度
|
||||
* `GET /api/generated-audios`: 列出用户所有配音
|
||||
* `DELETE /api/generated-audios/{audio_id}`: 删除配音
|
||||
* `PUT /api/generated-audios/{audio_id}`: 重命名配音
|
||||
|
||||
9. **工具 (Tools)**
|
||||
* `POST /api/tools/extract-script`: 从视频链接提取文案
|
||||
|
||||
9. **健康检查**
|
||||
10. **健康检查**
|
||||
* `GET /api/lipsync/health`: LatentSync 服务健康状态
|
||||
* `GET /api/voiceclone/health`: Qwen3-TTS 服务健康状态
|
||||
|
||||
@@ -113,6 +122,9 @@ backend/
|
||||
- `tts_mode`: TTS 模式 (`edgetts` / `voiceclone`)
|
||||
- `voice`: EdgeTTS 音色 ID(edgetts 模式)
|
||||
- `ref_audio_id` / `ref_text`: 参考音频 ID 与文本(voiceclone 模式)
|
||||
- `generated_audio_id`: 预生成配音 ID(存在时跳过内联 TTS,使用已生成的配音文件)
|
||||
- `custom_assignments`: 自定义素材分配数组(每项含 `material_path` / `start` / `end` / `source_start`),存在时跳过 Whisper 均分
|
||||
- `language`: TTS 语言(默认自动检测,声音克隆时透传给 Qwen3-TTS)
|
||||
- `title`: 片头标题文字
|
||||
- `subtitle_style_id`: 字幕样式 ID
|
||||
- `title_style_id`: 标题样式 ID
|
||||
|
||||
@@ -165,6 +165,8 @@ playwright install chromium
|
||||
CREATE POLICY "Allow public read" ON storage.objects FOR SELECT TO anon USING (bucket_id = 'materials' OR bucket_id = 'outputs');
|
||||
EOF
|
||||
```
|
||||
|
||||
> **注意**:后端启动时会自动创建额外的存储桶(`ref-audios`、`generated-audios`),无需手动创建。
|
||||
|
||||
---
|
||||
|
||||
@@ -570,6 +572,7 @@ pm2 logs vigent2-qwen-tts
|
||||
| `next` | React 框架 |
|
||||
| `swr` | 数据请求与缓存 |
|
||||
| `tailwindcss` | CSS 样式 |
|
||||
| `wavesurfer.js` | 音频波形(时间轴编辑器) |
|
||||
|
||||
### LatentSync 关键依赖
|
||||
|
||||
|
||||
546
Docs/DevLogs/Day23.md
Normal file
546
Docs/DevLogs/Day23.md
Normal file
@@ -0,0 +1,546 @@
|
||||
## 🎙️ 配音前置重构 — 第一阶段 (Day 23)
|
||||
|
||||
### 概述
|
||||
|
||||
将配音从视频生成流程中独立出来,实现"先生成配音 → 选中配音 → 再选素材 → 生成视频"的新工作流。用户可以独立管理配音(生成/试听/改名/删除/选择),并在选中配音后看到时长信息,为第二阶段的素材时间轴编排奠定数据基础。
|
||||
|
||||
**旧流程**: 文案 + 选素材 → 一键生成(内联 TTS → Whisper → 均分 → LipSync → 合成)
|
||||
**新流程**: 文案 → 配音方式 → **生成配音** → 选中配音 → 选素材 → 背景音乐 → 生成视频
|
||||
|
||||
---
|
||||
|
||||
### 一、后端:新增 `generated_audios` 模块
|
||||
|
||||
#### 模块结构
|
||||
|
||||
```
|
||||
backend/app/modules/generated_audios/
|
||||
├── __init__.py
|
||||
├── router.py # 5 个 API 端点
|
||||
├── schemas.py # 请求/响应模型
|
||||
└── service.py # 生成/列表/删除/改名
|
||||
```
|
||||
|
||||
#### API 端点
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| POST | `/api/generated-audios/generate` | 异步生成配音(返回 task_id) |
|
||||
| GET | `/api/generated-audios/tasks/{task_id}` | 轮询生成进度 |
|
||||
| GET | `/api/generated-audios` | 列出用户所有配音 |
|
||||
| DELETE | `/api/generated-audios/{audio_id}` | 删除配音 |
|
||||
| PUT | `/api/generated-audios/{audio_id}` | 改名 |
|
||||
|
||||
#### 存储方案
|
||||
|
||||
- Supabase 存储桶:`generated-audios`(启动时自动创建)
|
||||
- 音频文件:`{user_id}/{timestamp}_audio.wav`
|
||||
- 元数据文件:`{user_id}/{timestamp}_audio.json`(含 display_name、text、tts_mode、duration_sec 等)
|
||||
|
||||
#### 生成流程
|
||||
|
||||
复用现有 `TTSService` / `voice_clone_service` / `task_store`:
|
||||
|
||||
```
|
||||
POST /generate → 创建 task → BackgroundTask:
|
||||
1. edgetts → TTSService.generate_audio()
|
||||
voiceclone → 下载 ref_audio → voice_clone_service.generate_audio()
|
||||
2. ffprobe 获取时长
|
||||
3. 上传 .wav + .json 到 generated-audios 桶
|
||||
4. 更新 task(status=completed, output={audio_id, duration_sec, ...})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 二、后端:修改视频生成 workflow
|
||||
|
||||
#### `GenerateRequest` 新增字段
|
||||
|
||||
```python
|
||||
generated_audio_id: Optional[str] = None # 预生成配音 ID(存在时跳过内联 TTS)
|
||||
```
|
||||
|
||||
#### `workflow.py` TTS 阶段新增分支
|
||||
|
||||
```python
|
||||
if req.generated_audio_id:
|
||||
# 下载预生成配音 + 从元数据读取 language
|
||||
elif req.tts_mode == "voiceclone":
|
||||
# 原有声音克隆逻辑
|
||||
else:
|
||||
# 原有 EdgeTTS 逻辑
|
||||
```
|
||||
|
||||
向后兼容:不传 `generated_audio_id` 时,原有内联 TTS 流程不受影响。
|
||||
|
||||
---
|
||||
|
||||
### 三、前端:新增配音列表 hook + 面板
|
||||
|
||||
#### `useGeneratedAudios.ts`
|
||||
|
||||
- 状态:`generatedAudios[]`、`selectedAudio`、`isGeneratingAudio`、`audioTask`
|
||||
- 方法:`fetchGeneratedAudios()`、`generateAudio()`、`deleteAudio()`、`renameAudio()`、`selectAudio()`
|
||||
- 轮询:生成后 1s 轮询 task 状态,完成后自动刷新列表并选中最新配音
|
||||
- 独立于视频生成的 TaskContext(不互相干扰)
|
||||
|
||||
#### `GeneratedAudiosPanel.tsx`
|
||||
|
||||
- 每条配音:播放/暂停、名称、时长、重命名、删除
|
||||
- 选中态:`border-purple-500 bg-purple-500/20`
|
||||
- 内嵌进度条(生成中显示)
|
||||
- 底部显示选中配音的原始文案(截断)
|
||||
- 播放逻辑自包含于面板内(`new Audio()` + play/pause toggle)
|
||||
|
||||
---
|
||||
|
||||
### 四、前端:UI 面板重排序
|
||||
|
||||
**旧顺序**: MaterialSelector → ScriptEditor → TitleSubtitle → VoiceSelector → BgmPanel → GenerateActionBar
|
||||
|
||||
**新顺序**:
|
||||
1. ScriptEditor(文案编辑)
|
||||
2. TitleSubtitlePanel(标题与字幕样式)
|
||||
3. VoiceSelector(配音方式)
|
||||
4. **GeneratedAudiosPanel**(配音列表)← 新增
|
||||
5. MaterialSelector(视频素材)← 后移,需选中配音才解锁
|
||||
6. BgmPanel(背景音乐)
|
||||
7. GenerateActionBar(生成视频)
|
||||
|
||||
#### 素材区门控
|
||||
|
||||
未选中配音时,素材区显示半透明遮罩 + "请先生成并选中配音"提示。素材上传/预览/改名/删除始终可用,仅选择勾选被遮罩。
|
||||
|
||||
#### 时长信息
|
||||
|
||||
选中配音后,MaterialSelector 顶部显示:
|
||||
```
|
||||
当前配音: 45.2 秒 | 已选 3 个素材(自动均分每段 ~15.1 秒)
|
||||
```
|
||||
|
||||
#### 生成按钮条件更新
|
||||
|
||||
```typescript
|
||||
// 旧条件
|
||||
disabled={isGenerating || selectedMaterials.length === 0 || (ttsMode === "voiceclone" && !selectedRefAudio)}
|
||||
// 新条件
|
||||
disabled={isGenerating || selectedMaterials.length === 0 || !selectedAudio}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 五、持久化
|
||||
|
||||
`useHomePersistence` 新增 `selectedAudioId` 的 localStorage 读写,刷新页面后恢复选中的配音。
|
||||
|
||||
---
|
||||
|
||||
### 涉及文件汇总
|
||||
|
||||
#### 后端新增
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `backend/app/modules/generated_audios/__init__.py` | 模块标记 |
|
||||
| `backend/app/modules/generated_audios/router.py` | 5 个 API 端点 |
|
||||
| `backend/app/modules/generated_audios/service.py` | 生成/列表/删除/改名 |
|
||||
| `backend/app/modules/generated_audios/schemas.py` | 请求/响应模型 |
|
||||
|
||||
#### 后端修改
|
||||
|
||||
| 文件 | 变更 |
|
||||
|------|------|
|
||||
| `backend/app/main.py` | 注册 generated_audios 路由 |
|
||||
| `backend/app/services/storage.py` | 新增 `BUCKET_GENERATED_AUDIOS`,启动时自动创建桶 |
|
||||
| `backend/app/modules/videos/schemas.py` | `GenerateRequest` 新增 `generated_audio_id` 字段 |
|
||||
| `backend/app/modules/videos/workflow.py` | TTS 阶段新增预生成音频分支 |
|
||||
|
||||
#### 前端新增
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `frontend/src/features/home/model/useGeneratedAudios.ts` | 配音列表 hook |
|
||||
| `frontend/src/features/home/ui/GeneratedAudiosPanel.tsx` | 配音列表面板 |
|
||||
|
||||
#### 前端修改
|
||||
|
||||
| 文件 | 变更 |
|
||||
|------|------|
|
||||
| `frontend/src/features/home/ui/HomePage.tsx` | 面板重排序 + 素材区门控 + 插入 GeneratedAudiosPanel |
|
||||
| `frontend/src/features/home/ui/MaterialSelector.tsx` | 新增 `selectedAudioDuration` prop + 时长信息显示 |
|
||||
| `frontend/src/features/home/ui/GenerateActionBar.tsx` | 禁用条件改为 `!selectedAudio` |
|
||||
| `frontend/src/features/home/model/useHomeController.ts` | 集成 useGeneratedAudios、新增 handleGenerateAudio、修改 handleGenerate 使用 generated_audio_id |
|
||||
| `frontend/src/features/home/model/useHomePersistence.ts` | 新增 selectedAudioId 持久化 |
|
||||
|
||||
---
|
||||
|
||||
## 🎞️ 素材时间轴编排 — 第二阶段 (Day 23)
|
||||
|
||||
### 概述
|
||||
|
||||
在第一阶段"配音前置"基础上,新增**时间轴编辑器**,用户可以:
|
||||
1. 在音频波形上查看各素材块的时长分配
|
||||
2. 拖拽分割线调整每段素材的时长(无缝铺满,调整一段自动压缩/扩展相邻段)
|
||||
3. 为每段素材设置**源视频截取起点**(从视频任意位置开始,而非始终从头)
|
||||
|
||||
**旧行为**: 多素材时自动均分(`_split_equal`),无法控制每段时长和源视频起始点
|
||||
**新行为**: 时间轴编辑器可视化分配 + 拖拽调整 + ClipTrimmer 截取设置
|
||||
|
||||
---
|
||||
|
||||
### 一、后端改动
|
||||
|
||||
#### 1.1 新增 `CustomAssignment` 模型
|
||||
|
||||
```python
|
||||
# backend/app/modules/videos/schemas.py
|
||||
class CustomAssignment(BaseModel):
|
||||
material_path: str
|
||||
start: float # 音频时间轴起点
|
||||
end: float # 音频时间轴终点
|
||||
source_start: float = 0.0 # 源视频截取起点
|
||||
```
|
||||
|
||||
`GenerateRequest` 新增 `custom_assignments: Optional[List[CustomAssignment]] = None`。存在时跳过 Whisper 均分,直接使用用户定义的分配。
|
||||
|
||||
#### 1.2 `prepare_segment` 支持 `source_start`
|
||||
|
||||
```python
|
||||
def prepare_segment(self, video_path, target_duration, output_path,
|
||||
target_resolution=None, source_start: float = 0.0):
|
||||
```
|
||||
|
||||
关键逻辑:
|
||||
- `source_start > 0` 时使用 `-ss` 快速 seek,并强制重编码(避免 stream copy 关键帧不精确)
|
||||
- 当需要循环且有 `source_start` 时,先裁剪出 `source_start` 到视频结尾的片段,再循环裁剪后的文件(避免 `stream_loop` 从视频 0s 开始循环)
|
||||
- 裁剪临时文件在 `finally` 中自动清理
|
||||
|
||||
#### 1.3 `workflow.py` 支持 `custom_assignments`
|
||||
|
||||
- **多素材模式**: `custom_assignments` 存在时,直接使用用户分配(仍运行 Whisper 生成字幕),每个 `prepare_segment` 调用传入 `source_start`
|
||||
- **单素材模式**: `custom_assignments` 有 1 条且 `source_start > 0` 时,先截取片段再传入 LatentSync
|
||||
- **向后兼容**: `custom_assignments` 为 `None` 时完全走旧路径
|
||||
|
||||
---
|
||||
|
||||
### 二、前端新增组件
|
||||
|
||||
#### 2.1 `useTimelineEditor.ts` — 时间轴段管理 hook
|
||||
|
||||
```typescript
|
||||
interface TimelineSegment {
|
||||
id: string; // React key
|
||||
materialId: string; // 素材 ID
|
||||
materialName: string; // 显示名
|
||||
start: number; // 音频时间轴开始秒数
|
||||
end: number; // 音频时间轴结束秒数
|
||||
sourceStart: number; // 源视频截取起点(默认 0)
|
||||
sourceEnd: number; // 源视频截取终点(0 = 到结尾)
|
||||
color: string; // 色块颜色
|
||||
}
|
||||
```
|
||||
|
||||
核心方法:
|
||||
- `initSegments()`: selectedMaterials 变化时按数量均分 audioDuration
|
||||
- `resizeSegment(id, newEnd)`: 拖拽右边界,约束每段最小 1s
|
||||
- `setSourceRange(id, sourceStart, sourceEnd)`: 设置截取范围
|
||||
- `toCustomAssignments()`: 转为后端 `CustomAssignment[]` 格式
|
||||
|
||||
#### 2.2 `TimelineEditor.tsx` — 波形 + 色块时间轴
|
||||
|
||||
- **wavesurfer.js** 渲染音频波形(仅展示,不播放)
|
||||
- 色块层按比例排列,显示素材名 + 时长 + 截取标记
|
||||
- 色块间分割线可拖拽(`onPointerDown/Move/Up` 实现连续像素拖拽)
|
||||
- 点击色块打开 ClipTrimmer
|
||||
|
||||
#### 2.3 `ClipTrimmer.tsx` — 素材截取模态框
|
||||
|
||||
- HTML5 `<video>` 实时预览,拖拽滑块时 `video.currentTime` 跟随
|
||||
- 双端 Range Slider(起点/终点),互锁约束 ≥ 0.5s
|
||||
- 显示截取时长 vs 分配时长对比(循环补足/截断提示)
|
||||
- `loadedmetadata` 获取源视频时长
|
||||
|
||||
---
|
||||
|
||||
### 三、前端整合改动
|
||||
|
||||
#### 3.1 `useHomeController.ts`
|
||||
|
||||
- 集成 `useTimelineEditor` hook
|
||||
- 新增 `clipTrimmerOpen` / `clipTrimmerSegmentId` 状态
|
||||
- `handleGenerate` 多素材时始终发送 `custom_assignments`;单素材 + `sourceStart > 0` 时也发送
|
||||
- 移除不再使用的 `reorderMaterials` 导出
|
||||
|
||||
#### 3.2 `HomePage.tsx`
|
||||
|
||||
- 在 MaterialSelector 和 BgmPanel 之间插入 TimelineEditor(仅当有配音且已选素材时显示)
|
||||
- 底部新增 ClipTrimmer 模态框
|
||||
- 移除 `reorderMaterials` 和 `selectedAudioDuration` prop 传递
|
||||
|
||||
#### 3.3 `MaterialSelector.tsx`
|
||||
|
||||
- 移除配音时长信息栏(功能迁至 TimelineEditor)
|
||||
- 移除拖拽排序区(SortableChip + @dnd-kit 相关代码)
|
||||
- 移除 `onReorderMaterials` / `selectedAudioDuration` prop
|
||||
|
||||
---
|
||||
|
||||
### 四、审查修复的 Bug
|
||||
|
||||
| # | 严重程度 | 问题 | 修复 |
|
||||
|---|---------|------|------|
|
||||
| 1 | **中** | `prepare_segment` 使用 `source_start > 0` + stream copy 时 seek 不精确 | 添加 `source_start > 0` 到重编码条件 |
|
||||
| 2 | **高** | `stream_loop + source_start` 循环时从视频 0s 开始而非从 source_start 循环 | 改为两步:先裁剪片段再循环裁剪后的文件 |
|
||||
| 3 | **低** | `useHomeController` 导出已废弃的 `reorderMaterials` | 移除 |
|
||||
|
||||
---
|
||||
|
||||
### 涉及文件汇总
|
||||
|
||||
#### 后端修改
|
||||
|
||||
| 文件 | 变更 |
|
||||
|------|------|
|
||||
| `backend/app/modules/videos/schemas.py` | 新增 `CustomAssignment` model,`GenerateRequest` 新增 `custom_assignments` 字段 |
|
||||
| `backend/app/services/video_service.py` | `prepare_segment` 新增 `source_start` 参数,循环+截取两步处理 |
|
||||
| `backend/app/modules/videos/workflow.py` | 多素材/单素材流水线支持 `custom_assignments`,传递 `source_start` |
|
||||
|
||||
#### 前端新增
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `frontend/src/features/home/model/useTimelineEditor.ts` | 时间轴段管理 hook |
|
||||
| `frontend/src/features/home/ui/TimelineEditor.tsx` | 波形 + 色块时间轴组件 |
|
||||
| `frontend/src/features/home/ui/ClipTrimmer.tsx` | 素材截取模态框 |
|
||||
|
||||
#### 前端修改
|
||||
|
||||
| 文件 | 变更 |
|
||||
|------|------|
|
||||
| `frontend/src/features/home/ui/HomePage.tsx` | 插入 TimelineEditor + ClipTrimmer |
|
||||
| `frontend/src/features/home/ui/MaterialSelector.tsx` | 移除时长信息 + 拖拽排序区 + 相关 prop |
|
||||
| `frontend/src/features/home/model/useHomeController.ts` | 集成 useTimelineEditor,handleGenerate 发送 custom_assignments |
|
||||
| `frontend/package.json` | 新增 `wavesurfer.js` 依赖 |
|
||||
|
||||
---
|
||||
|
||||
## 🎨 UI 体验优化 + TTS 稳定性修复 — 第三阶段 (Day 23)
|
||||
|
||||
### 概述
|
||||
|
||||
根据用户反馈,修复 6 项 UI 体验问题,同时修复 Qwen3-TTS 声音克隆服务的 SoX 路径问题和显存缓存管理。
|
||||
|
||||
---
|
||||
|
||||
### 一、Qwen3-TTS 稳定性修复
|
||||
|
||||
#### 1.1 SoX PATH 修复
|
||||
|
||||
**问题**: PM2 启动 qwen-tts 时,`sox` 工具安装在 conda env 的 bin 目录中,系统 PATH 找不到,导致音频编解码走 fallback 路径(CPU 密集型),日志中出现 `SoX could not be found!` 警告。
|
||||
|
||||
**修复**: `run_qwen_tts.sh` 中 export conda env bin 到 PATH:
|
||||
|
||||
```bash
|
||||
export PATH="/home/rongye/ProgramFiles/miniconda3/envs/qwen-tts/bin:$PATH"
|
||||
```
|
||||
|
||||
#### 1.2 CUDA 缓存清理
|
||||
|
||||
**修复**: `qwen_tts_server.py` 每次生成完成后(无论成功或失败)调用 `torch.cuda.empty_cache()`,防止显存碎片累积。使用 `asyncio.to_thread()` 在线程池中运行推理,避免阻塞事件循环导致健康检查超时。
|
||||
|
||||
---
|
||||
|
||||
### 二、配音列表按钮布局统一 (反馈 #1 + #6)
|
||||
|
||||
**问题**: `GeneratedAudiosPanel` 的试听按钮位于左侧(独立于 Edit/Delete),与 `RefAudioPanel` 的布局不一致。底部文案摘要区域不需要展示。
|
||||
|
||||
**修复**:
|
||||
- Play/Edit/Delete 按钮统一放在右侧同组,hover 显示,顺序为 试听→重命名→删除
|
||||
- 移除选中配音的文案摘要区域
|
||||
- 布局与 RefAudioPanel 一致:左侧名称+时长,右侧操作按钮组
|
||||
|
||||
---
|
||||
|
||||
### 三、视频素材区域移除配音依赖遮罩 (反馈 #2)
|
||||
|
||||
**问题**: MaterialSelector 被 `!selectedAudio` 遮罩覆盖,必须先选配音才能操作素材。
|
||||
|
||||
**修复**: 移除 `HomePage.tsx` 中 MaterialSelector 外层的 disabled overlay `<div>`。素材随时可上传/预览/管理,仅 TimelineEditor 需要选中配音才显示(已有独立条件 `selectedAudio && selectedMaterials.length > 0`)。
|
||||
|
||||
---
|
||||
|
||||
### 四、时间轴拖拽排序 (反馈 #3)
|
||||
|
||||
**问题**: TimelineEditor 不支持调换素材顺序。
|
||||
|
||||
**修复**:
|
||||
- `useTimelineEditor` 已有 `reorderSegments()` 方法(交换两个段的素材信息但保留时间范围)
|
||||
- 通过 `useHomeController` 暴露 `reorderSegments`,传入 `TimelineEditor`
|
||||
- 色块支持 HTML5 Drag & Drop:`draggable` + `onDragStart/Over/Drop/End`
|
||||
- 拖拽时:源色块半透明(`opacity-50`),目标色块高亮 ring(`ring-2 ring-purple-400 scale-[1.02]`)
|
||||
- 光标样式:`cursor-grab` / `active:cursor-grabbing`
|
||||
|
||||
---
|
||||
|
||||
### 五、截取设置双手柄 Range Slider (反馈 #4)
|
||||
|
||||
**问题**: ClipTrimmer 使用两个独立的 `<input type="range">` 滑块,起点和终点分开操作,体验不直观。
|
||||
|
||||
**修复**: 改为自定义双手柄 range slider:
|
||||
- 单条轨道,紫色圆形手柄(起点)+ 粉色圆形手柄(终点)
|
||||
- 轨道底色 `bg-white/10`,选中范围用素材对应颜色高亮
|
||||
- Pointer Events 实现拖拽:`onPointerDown` 捕获手柄 → `onPointerMove` 更新位置 → `onPointerUp` 释放
|
||||
- 手柄互锁约束:起点不超过终点 - 0.5s,终点不低于起点 + 0.5s
|
||||
- 底部显示起点(紫色)和终点(粉色)时间标签
|
||||
|
||||
---
|
||||
|
||||
### 六、截取设置视频预览 (反馈 #5)
|
||||
|
||||
**问题**: ClipTrimmer 的视频只能静态查看,无法播放预览截取范围。
|
||||
|
||||
**修复**:
|
||||
- 视频区域点击可播放/暂停(Play/Pause 图标覆盖层)
|
||||
- 播放范围:从 sourceStart 播放到 sourceEnd 自动停止
|
||||
- 播放结束后回到起点
|
||||
- 拖拽手柄时 `video.currentTime` 实时跟随(seek 到当前位置查看画面)
|
||||
- 播放进度条(白色竖线)叠加在 range slider 轨道上
|
||||
- `preload="auto"` 预加载视频,确保拖拽时快速 seek
|
||||
|
||||
---
|
||||
|
||||
### 涉及文件汇总
|
||||
|
||||
#### 后端修改
|
||||
|
||||
| 文件 | 变更 |
|
||||
|------|------|
|
||||
| `run_qwen_tts.sh` | export conda env bin 到 PATH,修复 SoX 找不到问题 |
|
||||
| `models/Qwen3-TTS/qwen_tts_server.py` | 每次生成后 `torch.cuda.empty_cache()`,asyncio.to_thread 避免阻塞 |
|
||||
|
||||
#### 前端修改
|
||||
|
||||
| 文件 | 变更 |
|
||||
|------|------|
|
||||
| `frontend/src/features/home/ui/GeneratedAudiosPanel.tsx` | 按钮布局统一(Play/Edit/Delete 右侧同组),移除文案摘要 |
|
||||
| `frontend/src/features/home/ui/HomePage.tsx` | 移除 MaterialSelector 配音遮罩,传入 onReorderSegment |
|
||||
| `frontend/src/features/home/ui/TimelineEditor.tsx` | 新增 HTML5 Drag & Drop 排序,新增 onReorderSegment prop |
|
||||
| `frontend/src/features/home/ui/ClipTrimmer.tsx` | 双手柄 range slider + 视频播放预览 + 播放进度指示 |
|
||||
| `frontend/src/features/home/model/useHomeController.ts` | 暴露 reorderSegments 方法 |
|
||||
|
||||
---
|
||||
|
||||
## 📝 历史文案保存 + 时间轴拖拽修复 — 第四阶段 (Day 23)
|
||||
|
||||
### 概述
|
||||
|
||||
新增文案手动保存与加载功能,修复时间轴拖拽排序后素材时长不跟随的 Bug,统一按钮视觉规范。
|
||||
|
||||
---
|
||||
|
||||
### 一、历史文案保存与加载
|
||||
|
||||
#### 功能
|
||||
|
||||
用户可手动保存当前文案到历史列表,随时从历史中加载恢复。只有手动保存的文案才出现在历史列表中,与自动保存(`useHomePersistence`)完全独立。
|
||||
|
||||
#### UI 布局
|
||||
|
||||
```
|
||||
按钮栏: [历史文案▼] [文案提取助手] [AI多语言▼] [AI生成标题标签]
|
||||
底部栏: 128 字 [保存文案]
|
||||
```
|
||||
|
||||
- **历史文案下拉**: 展示已保存列表(名称 + 日期 + 删除按钮),点击条目加载文案,空列表显示"暂无保存的文案"
|
||||
- **保存文案按钮**: 文案为空时 disabled,点击后 `toast.success("文案已保存")`
|
||||
- **预计时长已移除**: 底部栏只保留字数 + 保存按钮
|
||||
|
||||
#### 实现
|
||||
|
||||
##### `useSavedScripts.ts`(新建)
|
||||
|
||||
```typescript
|
||||
interface SavedScript { id: string; name: string; content: string; savedAt: number }
|
||||
```
|
||||
|
||||
- localStorage key: `vigent_{storageKey}_savedScripts`
|
||||
- `saveScript(content)`: 取前 15 字符自动命名,新条目插入列表头部,**直接写入 localStorage**
|
||||
- `deleteScript(id)`: 删除指定条目,直接写入 localStorage
|
||||
- `useEffect([lsKey])`: lsKey 变化时(guest → userId)重新从 localStorage 读取
|
||||
- **不使用自动持久化 effect**,避免 storageKey 切换时空数组覆盖已有数据
|
||||
|
||||
##### 数据流
|
||||
|
||||
```
|
||||
ScriptEditor (UI)
|
||||
↑ savedScripts / onSaveScript / onLoadScript / onDeleteScript (纯 props + callbacks)
|
||||
│
|
||||
useHomeController
|
||||
├── useSavedScripts(storageKey) → { savedScripts, saveScript, deleteScript }
|
||||
└── handleSaveScript() → saveScript(text) + toast
|
||||
│
|
||||
HomePage
|
||||
└── 传递 props 到 ScriptEditor
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 二、时间轴拖拽排序 Bug 修复
|
||||
|
||||
#### 问题
|
||||
|
||||
拖拽调换素材顺序后,各素材的时长没有跟随素材移动,而是留在原槽位。例如:素材1(3s) + 素材2(8s+4s循环),拖拽后变成素材2(3s) + 素材1(8s+4s循环),时长分配没变。
|
||||
|
||||
#### 根因
|
||||
|
||||
`reorderSegments` 使用**属性交换**方式:逐个拷贝 `materialId`、`sourceStart`、`sourceEnd` 等属性在两个槽位间交换,然后调用 `recalcPositions` 重算位置。
|
||||
|
||||
#### 修复
|
||||
|
||||
改为**数组移动**(splice):将整个 segment 对象从旧位置取出,插入到新位置。segment 对象携带全部属性(materialId、sourceStart、sourceEnd、color 等)作为一个整体移动,再由 `recalcPositions` 重算位置。
|
||||
|
||||
```typescript
|
||||
// 修复前:属性交换
|
||||
const fromMat = { materialId: next[fromIdx].materialId, ... };
|
||||
const toMat = { materialId: next[toIdx].materialId, ... };
|
||||
next[fromIdx] = { ...next[fromIdx], ...toMat };
|
||||
next[toIdx] = { ...next[toIdx], ...fromMat };
|
||||
|
||||
// 修复后:数组移动
|
||||
const [moved] = next.splice(fromIdx, 1);
|
||||
next.splice(toIdx, 0, moved);
|
||||
```
|
||||
|
||||
附带优势:3+ 素材拖拽行为从"交换"变为"插入",更符合用户直觉。
|
||||
|
||||
---
|
||||
|
||||
### 三、按钮视觉统一
|
||||
|
||||
#### 问题
|
||||
|
||||
历史文案、文案提取助手、AI多语言、AI生成标题标签 4 个按钮高度不一致,AI 按钮的文本被 `<span>` 嵌套包裹导致内部布局差异。
|
||||
|
||||
#### 修复
|
||||
|
||||
- 4 个按钮统一为 `h-7 px-2.5 text-xs rounded inline-flex items-center gap-1`(固定高度 28px)
|
||||
- 移除 AI多语言 / AI生成标题标签 按钮内多余的 `<span>` 嵌套,改为 `<>...</>` fragment
|
||||
|
||||
---
|
||||
|
||||
### 涉及文件汇总
|
||||
|
||||
#### 前端新增
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `frontend/src/features/home/model/useSavedScripts.ts` | 历史文案 hook(localStorage 持久化) |
|
||||
|
||||
#### 前端修改
|
||||
|
||||
| 文件 | 变更 |
|
||||
|------|------|
|
||||
| `frontend/src/features/home/ui/ScriptEditor.tsx` | 历史文案下拉 + 保存按钮 + 移除预计时长 + 按钮高度统一 |
|
||||
| `frontend/src/features/home/model/useHomeController.ts` | 集成 useSavedScripts,新增 handleSaveScript |
|
||||
| `frontend/src/features/home/ui/HomePage.tsx` | 传递 savedScripts / handleSaveScript / deleteSavedScript 到 ScriptEditor |
|
||||
| `frontend/src/features/home/model/useTimelineEditor.ts` | reorderSegments 从属性交换改为数组移动(splice) |
|
||||
@@ -19,9 +19,12 @@ frontend/src/
|
||||
│ │ │ ├── useHomePersistence.ts # 持久化管理
|
||||
│ │ │ ├── useBgm.ts
|
||||
│ │ │ ├── useGeneratedVideos.ts
|
||||
│ │ │ ├── useGeneratedAudios.ts
|
||||
│ │ │ ├── useMaterials.ts
|
||||
│ │ │ ├── useMediaPlayers.ts
|
||||
│ │ │ ├── useRefAudios.ts
|
||||
│ │ │ ├── useSavedScripts.ts
|
||||
│ │ │ ├── useTimelineEditor.ts
|
||||
│ │ │ └── useTitleSubtitleStyles.ts
|
||||
│ │ └── ui/ # UI 组件(纯 props + 回调)
|
||||
│ │ ├── HomePage.tsx
|
||||
@@ -35,6 +38,9 @@ frontend/src/
|
||||
│ │ ├── FloatingStylePreview.tsx
|
||||
│ │ ├── VoiceSelector.tsx
|
||||
│ │ ├── RefAudioPanel.tsx
|
||||
│ │ ├── GeneratedAudiosPanel.tsx
|
||||
│ │ ├── TimelineEditor.tsx
|
||||
│ │ ├── ClipTrimmer.tsx
|
||||
│ │ ├── BgmPanel.tsx
|
||||
│ │ ├── GenerateActionBar.tsx
|
||||
│ │ ├── PreviewPanel.tsx
|
||||
@@ -301,6 +307,15 @@ import { formatDate } from '@/shared/lib/media';
|
||||
- 标题字号 / 字幕字号
|
||||
- 背景音乐选择 / 音量 / 开关状态
|
||||
- 素材选择 / 历史作品选择
|
||||
- 选中配音 ID (`selectedAudioId`)
|
||||
- 时间轴段信息 (`useTimelineEditor` 的 localStorage)
|
||||
|
||||
### 历史文案(独立持久化)
|
||||
|
||||
`useSavedScripts` hook 独立管理历史文案的 localStorage 持久化:
|
||||
- key: `vigent_{storageKey}_savedScripts`
|
||||
- 仅在用户手动保存/删除时写入 localStorage,不使用自动持久化 effect
|
||||
- 与 `useHomePersistence` 完全独立,互不影响
|
||||
|
||||
### 实施规范
|
||||
- 使用 `storageKey = userId || 'guest'`,按用户隔离。
|
||||
|
||||
@@ -17,7 +17,9 @@ ViGent2 的前端界面,采用 Next.js 16 + TailwindCSS 构建。
|
||||
- **作品预览**: 生成完成后直接播放下载(作品预览 + 历史作品)。
|
||||
- **预览优化**: 预览视频 `metadata` 预取,首帧加载更快。
|
||||
- **本地保存**: 文案/标题/偏好由 `useHomePersistence` 统一持久化,刷新后恢复 (Day 14/17)。
|
||||
- **历史文案**: 手动保存/加载/删除历史文案,独立 localStorage 持久化 (Day 23)。
|
||||
- **选择持久化**: 首页/发布页作品选择均使用稳定 `id` 持久化,刷新保持用户选择;新视频生成后自动选中最新 (Day 21)。
|
||||
- **AI 多语言翻译**: 支持 9 种目标语言翻译文案 + 还原原文 (Day 22)。
|
||||
|
||||
### 2. 全自动发布 (`/publish`) [Day 7 新增]
|
||||
- **多平台管理**: 统一管理抖音、微信视频号、B站、小红书账号状态。
|
||||
@@ -35,8 +37,17 @@ ViGent2 的前端界面,采用 Next.js 16 + TailwindCSS 构建。
|
||||
- **TTS 模式选择**: EdgeTTS (预设音色) / 声音克隆 (自定义音色) 切换。
|
||||
- **参考音频管理**: 上传/列表/删除参考音频 (3-20秒 WAV)。
|
||||
- **一键克隆**: 选择参考音频后自动调用 Qwen3-TTS 服务。
|
||||
- **多语言支持**: EdgeTTS 10 语言声音列表,声音克隆 language 透传 (Day 22)。
|
||||
|
||||
### 4. 字幕与标题 [Day 13 新增]
|
||||
### 4. 配音前置 + 时间轴编排 [Day 23 新增]
|
||||
- **配音独立生成**: 先生成配音 → 选中配音 → 再选素材 → 生成视频。
|
||||
- **配音管理面板**: 生成/试听/改名/删除/选中,异步生成 + 进度轮询。
|
||||
- **时间轴编辑器**: wavesurfer.js 音频波形 + 色块可视化素材分配,拖拽分割线调整各段时长。
|
||||
- **素材截取设置**: ClipTrimmer 双手柄 range slider + HTML5 视频预览播放。
|
||||
- **拖拽排序**: 时间轴色块支持 HTML5 Drag & Drop 调换素材顺序。
|
||||
- **自定义分配**: 后端 `custom_assignments` 支持用户定义的素材分配方案。
|
||||
|
||||
### 5. 字幕与标题 [Day 13 新增]
|
||||
- **片头标题**: 可选输入,限制 15 字,视频开头显示 3 秒淡入淡出标题。
|
||||
- **标题同步**: 首页片头标题修改会同步到发布信息标题。
|
||||
- **逐字高亮字幕**: 卡拉OK效果,默认开启,可关闭。
|
||||
@@ -45,16 +56,16 @@ ViGent2 的前端界面,采用 Next.js 16 + TailwindCSS 构建。
|
||||
- **默认样式**: 标题 90px 站酷快乐体;字幕 60px 经典黄字 + DingTalkJinBuTi (Day 17)。
|
||||
- **样式持久化**: 标题/字幕样式与字号刷新保留 (Day 17)。
|
||||
|
||||
### 5. 背景音乐 [Day 16 新增]
|
||||
### 6. 背景音乐 [Day 16 新增]
|
||||
- **试听预览**: 点击试听即选中,音量滑块实时生效。
|
||||
- **混音控制**: 仅影响 BGM,配音保持原音量。
|
||||
|
||||
### 6. 账户设置 [Day 15 新增]
|
||||
### 7. 账户设置 [Day 15 新增]
|
||||
- **手机号登录**: 11位中国手机号验证登录。
|
||||
- **账户下拉菜单**: 显示有效期 + 修改密码 + 安全退出。
|
||||
- **修改密码**: 弹窗输入当前密码与新密码,修改后强制重新登录。
|
||||
|
||||
### 7. 文案提取助手 (`ScriptExtractionModal`) [Day 15 新增]
|
||||
### 8. 文案提取助手 (`ScriptExtractionModal`) [Day 15 新增]
|
||||
- **多源提取**: 支持文件拖拽上传与 URL 粘贴 (B站/抖音/TikTok)。
|
||||
- **AI 洗稿**: 集成 GLM-4.7-Flash,自动改写为口播文案。
|
||||
- **一键填入**: 提取结果直接填充至视频生成输入框。
|
||||
@@ -66,6 +77,7 @@ ViGent2 的前端界面,采用 Next.js 16 + TailwindCSS 构建。
|
||||
- **样式**: TailwindCSS
|
||||
- **图标**: Lucide React
|
||||
- **组件**: 自定义现代化组件 (Glassmorphism 风格)
|
||||
- **音频波形**: wavesurfer.js (时间轴编辑器)
|
||||
- **API**: Axios 实例 `@/shared/api/axios` (对接后端 FastAPI :8006)
|
||||
|
||||
## 🚀 开发指南
|
||||
|
||||
@@ -298,12 +298,20 @@ Response: audio/wav 文件
|
||||
SoX could not be found!
|
||||
```
|
||||
|
||||
**解决**: 通过 conda 安装 sox:
|
||||
**解决**:
|
||||
|
||||
1. 通过 conda 安装 sox:
|
||||
|
||||
```bash
|
||||
conda install -y -c conda-forge sox
|
||||
```
|
||||
|
||||
2. 确保启动脚本 `run_qwen_tts.sh` 中已 export conda env bin 到 PATH(PM2 启动时系统 PATH 不含 conda 环境目录):
|
||||
|
||||
```bash
|
||||
export PATH="/home/rongye/ProgramFiles/miniconda3/envs/qwen-tts/bin:$PATH"
|
||||
```
|
||||
|
||||
### CUDA 内存不足
|
||||
|
||||
Qwen3-TTS 1.7B 通常需要 8-10GB VRAM。如果遇到 OOM:
|
||||
@@ -371,6 +379,7 @@ FOR INSERT TO anon WITH CHECK (bucket_id = 'ref-audios');
|
||||
|
||||
| 日期 | 版本 | 说明 |
|
||||
|------|------|------|
|
||||
| 2026-02-09 | 1.2.0 | 修复 SoX PATH 问题(run_qwen_tts.sh export conda bin),每次生成后 empty_cache() |
|
||||
| 2026-01-30 | 1.1.0 | 明确默认模型升级为 1.7B-Base,替换旧版 0.6B 路径 |
|
||||
|
||||
---
|
||||
|
||||
@@ -15,9 +15,13 @@
|
||||
原有流程:
|
||||
文本 → EdgeTTS → 音频 → LatentSync → FFmpeg合成 → 最终视频
|
||||
|
||||
新流程:
|
||||
文本 → EdgeTTS → 音频 ─┬→ LatentSync → 唇形视频 ─┐
|
||||
└→ faster-whisper → 字幕JSON ─┴→ Remotion合成 → 最终视频
|
||||
新流程 (单素材):
|
||||
文本 → EdgeTTS/Qwen3-TTS/预生成配音 → 音频 ─┬→ LatentSync → 唇形视频 ─┐
|
||||
└→ faster-whisper → 字幕JSON ─┴→ Remotion合成 → 最终视频
|
||||
|
||||
新流程 (多素材):
|
||||
音频 → 多素材按 custom_assignments 拼接 → LatentSync (单次推理) → 唇形视频 ─┐
|
||||
音频 → faster-whisper → 字幕JSON ─────────────────────────────────────────────┴→ Remotion合成 → 最终视频
|
||||
```
|
||||
|
||||
## 系统要求
|
||||
@@ -140,7 +144,7 @@ remotion/
|
||||
| 阶段 | 进度 | 说明 |
|
||||
|------|------|------|
|
||||
| 下载素材 | 0% → 5% | 从 Supabase 下载输入视频 |
|
||||
| TTS 语音生成 | 5% → 25% | EdgeTTS 或 Qwen3-TTS 生成音频 |
|
||||
| TTS 语音生成 | 5% → 25% | EdgeTTS / Qwen3-TTS / 预生成配音下载 |
|
||||
| 唇形同步 | 25% → 80% | LatentSync 推理 |
|
||||
| 字幕对齐 | 80% → 85% | faster-whisper 生成字级别时间戳 |
|
||||
| Remotion 渲染 | 85% → 95% | 合成字幕和标题 |
|
||||
@@ -282,4 +286,5 @@ WhisperService(device="cuda:0") # 或 "cuda:1"
|
||||
| 日期 | 版本 | 说明 |
|
||||
|------|------|------|
|
||||
| 2026-01-29 | 1.0.0 | 初始版本,使用 faster-whisper + Remotion 实现逐字高亮字幕和片头标题 |
|
||||
| 2026-02-10 | 1.1.0 | 更新架构图:多素材 concat-then-infer、预生成配音选项 |
|
||||
| 2026-01-30 | 1.0.1 | 字幕高亮样式与标题动画优化,视觉表现更清晰 |
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# ViGent2 开发任务清单 (Task Log)
|
||||
|
||||
**项目**: ViGent2 数字人口播视频生成系统
|
||||
**进度**: 100% (Day 21 - 缺陷修复与持久化回归治理)
|
||||
**更新时间**: 2026-02-08
|
||||
**进度**: 100% (Day 23 - 配音前置重构 + 素材时间轴编排 + UI 体验优化)
|
||||
**更新时间**: 2026-02-10
|
||||
|
||||
---
|
||||
|
||||
@@ -10,7 +10,46 @@
|
||||
|
||||
> 这里记录了每一天的核心开发内容与 milestone。
|
||||
|
||||
### Day 21: 缺陷修复 + 浮动预览 + 发布重构 + 架构优化 + 多素材生成 (Current)
|
||||
### Day 23: 配音前置重构 + 素材时间轴编排 + UI 体验优化 + 历史文案 (Current)
|
||||
|
||||
#### 第一阶段:配音前置
|
||||
- [x] **配音生成独立化**: 新增 `generated_audios` 后端模块(router/schemas/service),5 个 API 端点,复用现有 TTSService / voice_clone_service / task_store。
|
||||
- [x] **配音管理面板**: 前端新增 `useGeneratedAudios` hook + `GeneratedAudiosPanel` 组件,支持生成/试听/改名/删除/选中。
|
||||
- [x] **UI 面板重排序**: 文案 → 标题字幕 → 配音方式 → 配音列表 → 素材选择 → BGM → 生成视频。
|
||||
- [x] **素材区门控**: 未选中配音时素材区显示遮罩,选中后显示配音时长 + 素材均分信息。
|
||||
- [x] **视频生成对接**: workflow.py 新增预生成音频分支(`generated_audio_id`),跳过内联 TTS,向后兼容。
|
||||
- [x] **持久化**: selectedAudioId 加入 useHomePersistence,刷新页面恢复选中配音。
|
||||
|
||||
#### 第二阶段:素材时间轴编排
|
||||
- [x] **时间轴编辑器**: 新增 `TimelineEditor` 组件,wavesurfer.js 音频波形 + 色块可视化素材分配,拖拽分割线调整各段时长。
|
||||
- [x] **素材截取设置**: 新增 `ClipTrimmer` 模态框,HTML5 视频预览 + 双端滑块设置源视频截取起点/终点。
|
||||
- [x] **后端自定义分配**: 新增 `CustomAssignment` 模型,`prepare_segment` 支持 `source_start`,workflow 多素材/单素材流水线支持 `custom_assignments`。
|
||||
- [x] **循环截取修复**: `stream_loop + source_start` 改为两步处理(先裁剪再循环),确保从截取起点循环而非从视频 0s 开始。
|
||||
- [x] **MaterialSelector 精简**: 移除旧的时长信息栏和拖拽排序区(功能迁移到 TimelineEditor)。
|
||||
|
||||
#### 第三阶段:UI 体验优化 + TTS 稳定性
|
||||
- [x] **TTS SoX PATH 修复**: `run_qwen_tts.sh` export conda env bin 到 PATH,修复 `SoX could not be found!` 警告。
|
||||
- [x] **TTS 显存管理**: 每次生成后 `torch.cuda.empty_cache()`,asyncio.to_thread 避免阻塞事件循环。
|
||||
- [x] **配音列表按钮统一**: Play/Edit/Delete 按钮右侧同组 hover 显示,与 RefAudioPanel 一致,移除文案摘要。
|
||||
- [x] **素材区解除配音门控**: 移除 MaterialSelector 的 selectedAudio 遮罩,素材随时可上传管理。
|
||||
- [x] **时间轴拖拽排序**: TimelineEditor 色块支持 HTML5 Drag & Drop 调换素材顺序。
|
||||
- [x] **截取设置 Range Slider**: ClipTrimmer 改为单轨道双手柄(紫色起点+粉色终点),替换两个独立滑块。
|
||||
- [x] **截取设置视频预览**: 视频区域可播放/暂停,从 sourceStart 到 sourceEnd 自动停止,拖拽手柄时实时 seek。
|
||||
|
||||
#### 第四阶段:历史文案 + Bug 修复
|
||||
- [x] **历史文案保存与加载**: 新增 `useSavedScripts` hook,手动保存/加载/删除历史文案,独立 localStorage 持久化。
|
||||
- [x] **时间轴拖拽修复**: `reorderSegments` 从属性交换改为数组移动(splice),修复拖拽后时长不跟随素材的 Bug。
|
||||
- [x] **按钮视觉统一**: 文案编辑区 4 个按钮统一为固定高度 `h-7`,移除多余 `<span>` 嵌套。
|
||||
- [x] **底部栏调整**: "保存文案"按钮移至底部右侧,移除预计时长显示。
|
||||
|
||||
### Day 22: 多素材优化 + AI 翻译 + TTS 多语言
|
||||
- [x] **多素材 Bug 修复**: 6 个高优 Bug(边界溢出、单段 fallback、除零、duration 校验、Whisper 兜底、空列表检查)。
|
||||
- [x] **架构重构**: 多素材从"逐段 LatentSync"重构为"先拼接再推理",推理次数 N→1。
|
||||
- [x] **前端优化**: payload 安全、进度消息、上传自动选中、Material 接口统一、拖拽修复、素材上限 4 个。
|
||||
- [x] **AI 多语言翻译**: 新增 `/api/ai/translate` 接口,前端 9 种语言翻译 + 还原原文。
|
||||
- [x] **TTS 多语言**: EdgeTTS 10 语言声音列表、翻译自动切换声音、声音克隆 language 透传、textLang 持久化。
|
||||
|
||||
### Day 21: 缺陷修复 + 浮动预览 + 发布重构 + 架构优化 + 多素材生成
|
||||
- [x] **Remotion 崩溃容错**: 渲染进程 SIGABRT 退出时检查输出文件,避免误判失败导致标题/字幕丢失。
|
||||
- [x] **首页作品选择持久化**: 修复 `fetchGeneratedVideos` 无条件覆盖恢复值的问题,新增 `preferVideoId` 参数控制选中逻辑。
|
||||
- [x] **发布页作品选择持久化**: 根因为签名 URL 不稳定,全面改用 `video.id` 替代 `path` 进行选择/持久化/比较。
|
||||
@@ -129,6 +168,7 @@
|
||||
## 🛤️ 后续规划 (Roadmap)
|
||||
|
||||
### 🔴 优先待办
|
||||
- [x] ~~**配音前置重构 — 第二阶段**: 素材片段截取 + 语音时间轴编排~~ ✅ Day 23 已完成
|
||||
- [ ] **批量生成架构**: 支持 Excel 导入,批量生产视频。
|
||||
- [ ] **定时任务后台化**: 迁移前端触发的定时发布到后端 APScheduler。
|
||||
- [ ] **发布任务恢复机制**: 发布任务化 + 状态持久化 + 前端断点恢复,解决刷新后状态丢失。
|
||||
@@ -146,7 +186,7 @@
|
||||
| **核心 API** | 100% | ✅ 稳定 |
|
||||
| **Web UI** | 100% | ✅ 稳定 (移动端适配) |
|
||||
| **唇形同步** | 100% | ✅ LatentSync 1.6 |
|
||||
| **TTS 配音** | 100% | ✅ EdgeTTS + Qwen3 |
|
||||
| **TTS 配音** | 100% | ✅ EdgeTTS + Qwen3 + 配音前置 + 时间轴编排 |
|
||||
| **自动发布** | 100% | ✅ 抖音/微信视频号/B站/小红书 |
|
||||
| **用户认证** | 100% | ✅ 手机号 + JWT |
|
||||
| **部署运维** | 100% | ✅ PM2 + Watchdog |
|
||||
|
||||
Reference in New Issue
Block a user