Files
sionrui/openspec/changes/refactor-mix-scene编排/proposal.md
2025-12-22 00:15:02 +08:00

386 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 混剪场景编排功能重新设计提案
## 变更概述
**变更ID** refactor-mix-scene编排
**日期:** 2025-12-21
**优先级:**
## Why (为什么需要这个变更)
当前混剪功能的单一场景模式导致批量生成视频时内容高度相似,无法满足用户对视频多样性的需求。通过引入多候选场景模式,用户可以为每个场景准备多个候选素材,系统在批量混剪时从每个场景的候选中随机选择,从而生成内容差异显著的多个视频。这将显著提升用户体验,满足内容创作者对多样性的追求。
## 问题背景
当前的混剪场景编排功能存在以下限制:
1. **场景素材单一性**:每个场景只能选择一个视频素材,导致批量混剪时视频内容相似度极高
2. **多样性不足**:虽然后端通过随机起点实现差异化,但本质上仍使用相同的素材池
3. **用户需求未满足**:用户希望一次混剪能生成内容差异更大的多个视频
## 解决方案
### 核心设计理念
重新设计场景编排为**"多候选场景模式"**
- 每个场景包含**多个候选视频**(每个场景内视频不重复)
- 批量混剪时,**从每个场景的候选中随机选择一个**视频
- 仍然使用**随机起点**对选中的素材进行二次随机处理
- **两层随机性**(候选选择 + 随机起点)极大增加最终视频的多样性
### 关键特性
1. **场景多候选**:每个场景可以添加多个候选视频素材
2. **防重复机制**:同一场景内的候选视频不能重复
3. **智能填充**
- 一键自动为每个场景添加多个候选
- 支持从素材库快速选择
4. **随机生成**:批量混剪时从每个场景的候选中随机选择
5. **可视化展示**:清晰展示每个场景的候选数量和使用状态
## 技术架构调整
### 前端变更
**文件位置:** `frontend/app/web-gold/src/views/material/Mix.vue`
**主要改动:**
#### 1. 数据结构重构
```javascript
// 原有结构(单一素材)
const scene = {
fileId: 123,
fileUrl: 'xxx.mp4'
}
// 新结构(多候选)
const scene = {
index: 0,
duration: 3,
candidates: [
{fileId: 123, fileUrl: 'xxx1.mp4', fileDuration: 60},
{fileId: 124, fileUrl: 'xxx2.mp4', fileDuration: 45},
{fileId: 125, fileUrl: 'xxx3.mp4', fileDuration: 55}
]
}
```
#### 2. 场景格子 UI 更新
- **候选数量标签**:在场景格子上方显示 `候选 3/10`
- **候选列表预览**:悬停时显示候选素材的缩略图列表
- **状态指示**
- 空场景:虚线边框,提示"点击选择"
- 已填充:实线边框,显示候选数量徽标
- 部分填充:不同颜色标识
- **移除按钮**:每个候选右上角显示删除按钮
#### 3. 交互流程优化
- **点击场景格子** → 打开候选选择弹窗
- **弹窗内容**
- 顶部显示:`场景1 - 已选择 3/10 个候选`
- 主体区域:素材库网格(支持多选)
- 底部操作:`全选` `反选` `确定` `取消`
- **批量操作**
- 支持 Ctrl+Click 多选
- 支持 Shift+Click 范围选择
- 一键全选/清空
#### 4. 一键填充增强(核心优化)
**功能描述:**
一键填充功能从原有的"随机填充空场景"升级为"智能多候选填充",能够自动为每个场景分配多个不重复的候选素材。
**填充策略选择:**
```javascript
// 提供三种填充模式
const FILL_STRATEGIES = {
EMPTY_ONLY: 'empty_only', // 仅填充空场景(默认)
SUPPLEMENT: 'supplement', // 补充不足场景到3个候选
FULL_FILL: 'full_fill' // 全量重新填充所有场景
}
```
**智能分配算法:**
```javascript
/**
* 优化后的一键填充逻辑
* @param strategy 填充策略
* @param targetCount 目标候选数量默认3-5个
*/
const autoFillScenes = (strategy = 'empty_only', targetCount = 3) => {
// 1. 收集所有可用的素材
const availableMaterials = [...groupFiles.value];
// 2. 统计当前已使用的素材(避免重复)
const usedMaterialIds = new Set();
scenes.value.forEach(scene => {
scene.candidates.forEach(candidate => {
usedMaterialIds.add(candidate.fileId);
});
});
// 3. 过滤可用素材(排除已使用的)
const unusedMaterials = availableMaterials.filter(
material => !usedMaterialIds.has(material.id)
);
// 4. 根据策略执行填充
scenes.value.forEach((scene, sceneIndex) => {
const currentCount = scene.candidates.length;
let needFill = false;
let fillCount = targetCount;
// 判断是否需要填充
switch (strategy) {
case 'empty_only':
needFill = currentCount === 0;
break;
case 'supplement':
needFill = currentCount < targetCount;
fillCount = targetCount - currentCount;
break;
case 'full_fill':
needFill = true;
fillCount = targetCount;
break;
}
if (needFill && unusedMaterials.length > 0) {
// 5. 为当前场景随机选择素材(确保不重复)
const selectedMaterials = randomlySelectMaterials(
fillCount,
unusedMaterials,
sceneIndex // 使用场景索引作为随机种子的一部分
);
// 6. 添加到场景候选列表
scene.candidates.push(...selectedMaterials);
// 7. 从可用素材中移除已选择的(避免分配给其他场景)
selectedMaterials.forEach(selected => {
const index = unusedMaterials.findIndex(m => m.id === selected.id);
if (index > -1) {
unusedMaterials.splice(index, 1);
}
});
}
});
// 8. 显示填充结果提示
showFillResultNotification();
}
/**
* 随机选择素材工具函数
* @param count 需要选择的数量
* @param materials 素材池
* @param seed 随机种子(基于场景索引)
* @returns 选中的素材数组
*/
const randomlySelectMaterials = (count, materials, seed) => {
// 使用Fisher-Yates洗牌算法确保随机性
const shuffled = [...materials];
// 基于种子创建确定性随机(同一场景索引结果一致)
const random = createDeterministicRandom(seed);
// 洗牌
for (let i = shuffled.length - 1; i > 0; i--) {
const j = Math.floor(random() * (i + 1));
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
}
// 返回前N个
return shuffled.slice(0, Math.min(count, shuffled.length));
}
```
**防重复机制(优化):**
1. **场景内去重**:确保同一场景内的候选素材不重复(必须)
2. **跨场景复用**(可选):允许同一素材在不同场景中出现
- 优点:提高素材利用率,适合素材库不足的场景
- 缺点:可能降低视频差异性
- 配置项:用户可选择"严格模式"(禁止跨场景重复)或"宽松模式"(允许跨场景重复)
3. **实时更新**:每次填充后立即更新已使用素材列表
4. **视觉反馈**
- 严格模式:已使用素材显示禁用状态
- 宽松模式:已使用素材显示使用次数标记(如"已使用 2 次"
**数量控制逻辑:**
- **默认数量**:每个场景填充 3 个候选
- **自适应调整**:根据素材库总量动态调整
- 素材库 < 10个每个场景 1-2个候选
- 素材库 10-50个每个场景 3-4个候选
- 素材库 > 50个每个场景 4-5个候选
- **上限保护**:单个场景最多 10 个候选
**用户体验优化:**
- **进度提示**:填充过程中显示进度条
- **结果反馈**:填充完成后显示"已为X个场景填充Y个候选"
- **撤销操作**:支持一键撤销最近的填充操作
- **智能建议**:根据素材库情况建议最佳填充策略
**边界情况处理:**
1. **素材库不足场景**
```javascript
// 场景5个场景每个需要3个候选但素材库只有10个素材
// 解决方案:
// 1. 自动切换到"宽松模式",允许跨场景复用
// 2. 调整目标数量:根据素材库/场景数计算最优分配
// 3. 提示用户:"素材库不足,已自动调整为宽松模式"
```
2. **素材库为空**
- 提示"素材库为空,请先上传素材"
- 禁用一键填充按钮
- 提供快速跳转链接到素材上传页
3. **场景数过多**
- 当场景数 × 目标候选数 > 素材库数量时
- 自动建议减少场景数或增加素材库
- 提供"智能合并场景"建议
4. **批量操作确认**
- 全选/清空等操作前显示确认对话框
- 显示影响范围:如"将影响 5 个场景,共 15 个候选"
- 提供预览功能
5. **数据一致性检查**
- 页面刷新后自动恢复场景配置
- 检测并修复损坏的场景数据
- 提示用户进行数据同步
**示例场景:**
```
素材库:[A, B, C, D, E, F, G, H, I, J] (10个素材)
场景数3个场景
目标每个场景3个候选
填充结果:
- 场景1[A, D, G]
- 场景2[B, E, H]
- 场景3[C, F, I]
剩余素材:[J] (未使用,避免浪费)
```
#### 5. 候选管理功能
- **添加候选**:从素材库选择 → 检查重复 → 添加到候选列表
- **移除候选**:点击候选右上角 × → 从列表中移除
- **查看候选详情**:点击场景格子 → 弹窗显示所有候选详情
- **清空场景**:点击"清空"按钮 → 移除所有候选
#### 6. 防重复验证
- **前端实时检查**:选择素材时检查是否已存在于候选列表
- **视觉反馈**:已选择的素材显示禁用状态或"已选择"标记
- **提示信息**:尝试添加重复素材时显示提示"该素材已在候选列表中"
#### 7. 数据提交调整
```javascript
// 修改 handleSubmit 中的数据结构
const submitData = {
title: formData.value.title,
scenes: scenes.value.map(scene => ({
duration: scene.duration,
candidates: scene.candidates
})),
produceCount: formData.value.produceCount,
cropMode: formData.value.cropMode
};
```
### 后端变更
**文件位置:**
- `yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/mix/vo/MixTaskSaveReqVO.java`
- `yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/mix/service/MixTaskServiceImpl.java`
- `yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/media/BatchProduceAlignment.java`
**主要改动:**
1. 修改 API 数据结构:支持场景多候选
2. 更新批量混剪逻辑:从每个场景候选中随机选择素材,然后使用随机起点
3. 实现两层随机算法:第一层从候选中选择,第二层使用随机起点
### 数据库变更
**影响范围:** 无需数据库结构变更
- 前端本地存储场景配置
- 后端通过 JSON 传递候选数据
## 预期效果
### 用户体验提升
1. **多样性提升**:批量混剪的视频内容差异显著增大
2. **操作便捷性**:一键填充和批量选择功能
3. **可视化体验**:清晰的场景候选展示
### 技术收益
1. **代码复用**:保持现有框架结构
2. **性能优化**:随机选择算法高效
3. **向后兼容**:可选模式,不影响现有功能
## 风险评估
### 技术风险
- **中等风险**:需要修改前后端多个文件
- **兼容性**:需要确保现有功能不受影响
### 缓解措施
1. 渐进式迁移:保留现有模式作为备选
2. 充分测试:覆盖各种使用场景
3. 回滚方案:保留现有代码分支
## 实施计划
### 阶段一:数据结构设计
- [ ] 设计新的前后端数据结构
- [ ] 定义 API 接口规范
### 阶段二:前端实现
- [ ] 修改 Mix.vue 组件
- [ ] 更新数据处理逻辑
- [ ] 优化用户界面
### 阶段三:后端实现
- [ ] 更新 VO 对象
- [ ] 修改混剪服务逻辑
- [ ] 调整随机算法
### 阶段四:测试验证
- [ ] 单元测试
- [ ] 集成测试
- [ ] 用户验收测试
## 成功标准
1. **功能完整性**:所有设计功能正常工作
2. **性能指标**:批量混剪性能无明显下降
3. **用户体验**:操作流程顺畅,界面直观
4. **代码质量**:代码结构清晰,有充分注释
## 相关资源
- **前端代码:** `frontend/app/web-gold/src/views/material/Mix.vue`
- **后端 API** `yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/mix/`
- **混剪服务:** `yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/mix/service/MixTaskServiceImpl.java`
- **批量处理:** `yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/media/BatchProduceAlignment.java`
## 决策点
1. **默认候选数量**建议每个场景默认3-5个候选
2. **最大候选限制**建议每个场景最多10个候选
3. **随机算法**基于文件ID和场景索引的确定性随机
4. **UI 展示方式**:采用标签页或下拉列表展示候选
## 后续优化
1. **智能推荐**:基于视频相似度推荐候选
2. **场景模板**:保存和复用场景配置
3. **批量编辑**:支持跨场景批量操作