可令对口型
This commit is contained in:
314
docs/kling-strategy-pattern.md
Normal file
314
docs/kling-strategy-pattern.md
Normal file
@@ -0,0 +1,314 @@
|
||||
# 数字人任务策略模式优化
|
||||
|
||||
## 概述
|
||||
|
||||
本次重构将数字人任务的口型同步逻辑从传统的 if-else 条件判断优化为**策略模式**,提升了代码的可维护性、可扩展性和可测试性。
|
||||
|
||||
## 架构设计
|
||||
|
||||
### 1. 策略模式结构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ DigitalHumanTaskServiceImpl │
|
||||
│ - syncLip() │
|
||||
│ ├─ lipSyncStrategyFactory │
|
||||
│ └─ getStrategyForTask() │
|
||||
└───────────────┬─────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌───────────────────┐
|
||||
│ LipSyncStrategy │ (接口)
|
||||
│ + syncLip() │
|
||||
│ + getStrategyName()│
|
||||
│ + supports() │
|
||||
│ + getPriority() │
|
||||
│ + getDescription()│
|
||||
└────────┬──────────┘
|
||||
│
|
||||
├────────────────────┬──────────────────────
|
||||
│ │
|
||||
▼ ▼
|
||||
┌──────────────┐ ┌──────────────────────┐
|
||||
│KlingStrategy │ │LatentsyncStrategy │
|
||||
│ - Priority: │ │ - Priority: 50 │
|
||||
│ 100 │ │ - Fallback策略 │
|
||||
│ - Advanced │ │ - 通用口型同步 │
|
||||
│ Lip-Sync │ └──────────────────────┘
|
||||
└──────────────┘
|
||||
```
|
||||
|
||||
### 2. 核心组件
|
||||
|
||||
#### 2.1 LipSyncStrategy 接口
|
||||
```java
|
||||
public interface LipSyncStrategy {
|
||||
// 执行口型同步
|
||||
String syncLip(TikDigitalHumanTaskDO task, String audioUrl) throws Exception;
|
||||
|
||||
// 策略名称
|
||||
String getStrategyName();
|
||||
|
||||
// 是否支持该任务
|
||||
boolean supports(TikDigitalHumanTaskDO task);
|
||||
|
||||
// 优先级(数字越大优先级越高)
|
||||
int getPriority();
|
||||
|
||||
// 策略描述
|
||||
String getDescription();
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.2 LipSyncStrategyFactory 工厂类
|
||||
```java
|
||||
@Component
|
||||
public class LipSyncStrategyFactory {
|
||||
// 注册策略
|
||||
public void registerStrategy(LipSyncStrategy strategy);
|
||||
|
||||
// 根据任务选择策略
|
||||
public LipSyncStrategy getStrategyForTask(TikDigitalHumanTaskDO task);
|
||||
|
||||
// 获取所有支持的策略
|
||||
public List<LipSyncStrategy> getAllStrategies();
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.3 具体策略实现
|
||||
|
||||
**KlingLipSyncStrategy(优先级 100)**
|
||||
- 使用可灵 advanced-lip-sync API
|
||||
- 要求:`klingSessionId` 和 `klingFaceId`
|
||||
- 如果参数缺失,自动回退到 Latentsync
|
||||
|
||||
**LatentsyncLipSyncStrategy(优先级 50)**
|
||||
- 使用 302.ai Latentsync 通用接口
|
||||
- 作为默认回退策略
|
||||
- 支持所有标准的口型同步任务
|
||||
|
||||
### 3. 工作流程
|
||||
|
||||
```
|
||||
1. 创建任务 → 验证参数 → 存储记录
|
||||
│
|
||||
▼
|
||||
2. 异步处理 → prepareFiles → synthesizeVoice
|
||||
│
|
||||
▼
|
||||
3. 选择策略 → getStrategyForTask()
|
||||
│
|
||||
├─ Kling策略(如果支持)
|
||||
└─ Latentsync策略(回退)
|
||||
│
|
||||
▼
|
||||
4. 执行口型同步 → 提交异步任务 → 加入轮询队列
|
||||
│
|
||||
▼
|
||||
5. 轮询服务检测状态 → 更新任务 → 返回结果
|
||||
```
|
||||
|
||||
## 重构详情
|
||||
|
||||
### 修改前的问题
|
||||
|
||||
**问题 1:违反开闭原则**
|
||||
```java
|
||||
// 传统 if-else 实现
|
||||
if ("302ai".equals(aiProvider)) {
|
||||
syncWithLatentsync();
|
||||
} else if ("kling".equals(aiProvider)) {
|
||||
syncWithKling();
|
||||
} else if ("aliyun".equals(aiProvider)) {
|
||||
// TODO: 新增供应商需要修改此方法
|
||||
}
|
||||
```
|
||||
|
||||
**问题 2:职责不单一**
|
||||
- 每个分支包含大量业务逻辑
|
||||
- 难以单元测试
|
||||
- 重复代码多
|
||||
|
||||
**问题 3:可扩展性差**
|
||||
- 新增 AI 供应商需要修改核心服务类
|
||||
- 违反单一职责原则
|
||||
|
||||
### 修改后的优势
|
||||
|
||||
**优势 1:符合开闭原则**
|
||||
```java
|
||||
// 新增供应商只需:
|
||||
1. 创建新的策略实现类
|
||||
2. 使用 @Component 注解自动注册
|
||||
3. 无需修改 DigitalHumanTaskServiceImpl
|
||||
```
|
||||
|
||||
**优势 2:职责分离**
|
||||
```java
|
||||
// 每个策略类专注自己的业务逻辑
|
||||
KlingLipSyncStrategy → 专注可灵接口
|
||||
LatentsyncLipSyncStrategy → 专注 Latentsync 接口
|
||||
DigitalHumanTaskServiceImpl → 专注任务流程编排
|
||||
```
|
||||
|
||||
**优势 3:可测试性强**
|
||||
```java
|
||||
// 可以独立测试每个策略
|
||||
@Test
|
||||
public void testKlingStrategy() {
|
||||
// 测试可灵策略逻辑
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLatentsyncStrategy() {
|
||||
// 测试 Latentsync 策略逻辑
|
||||
}
|
||||
```
|
||||
|
||||
## 新增文件
|
||||
|
||||
### 1. 策略接口
|
||||
- `cn.iocoder.yudao.module.tik.voice.strategy.LipSyncStrategy.java`
|
||||
|
||||
### 2. 策略工厂
|
||||
- `cn.iocoder.yudao.module.tik.voice.strategy.LipSyncStrategyFactory.java`
|
||||
|
||||
### 3. 具体策略
|
||||
- `cn.iocoder.yudao.module.tik.voice.strategy.impl.KlingLipSyncStrategy.java`
|
||||
- `cn.iocoder.yudao.module.tik.voice.strategy.impl.LatentsyncLipSyncStrategy.java`
|
||||
|
||||
## 修改文件
|
||||
|
||||
### 1. DigitalHumanTaskServiceImpl.java
|
||||
- ✅ 移除 `syncWithLatentsync()` 方法
|
||||
- ✅ 移除 `syncWithKling()` 方法
|
||||
- ✅ 重构 `syncLip()` 方法使用策略模式
|
||||
- ✅ 注入 `LipSyncStrategyFactory` 和 `KlingService`
|
||||
|
||||
## 策略选择逻辑
|
||||
|
||||
```java
|
||||
public LipSyncStrategy getStrategyForTask(TikDigitalHumanTaskDO task) {
|
||||
// 1. 获取所有支持的策略
|
||||
List<LipSyncStrategy> supportedStrategies = strategies.stream()
|
||||
.filter(strategy -> strategy.supports(task))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 2. 按优先级排序
|
||||
supportedStrategies.sort((a, b) -> b.getPriority() - a.getPriority());
|
||||
|
||||
// 3. 返回最高优先级的策略
|
||||
return supportedStrategies.isEmpty() ? null : supportedStrategies.get(0);
|
||||
}
|
||||
```
|
||||
|
||||
## 扩展指南
|
||||
|
||||
### 新增 AI 供应商(例如:阿里云)
|
||||
|
||||
**步骤 1:创建策略类**
|
||||
```java
|
||||
@Component
|
||||
public class AliyunLipSyncStrategy implements LipSyncStrategy {
|
||||
@Override
|
||||
public String syncLip(TikDigitalHumanTaskDO task, String audioUrl) {
|
||||
// 1. 构建阿里云请求参数
|
||||
// 2. 调用阿里云 API
|
||||
// 3. 加入轮询队列
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStrategyName() {
|
||||
return "aliyun";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(TikDigitalHumanTaskDO task) {
|
||||
return "aliyun".equalsIgnoreCase(task.getAiProvider());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority() {
|
||||
return 75; // 可灵之下,Latentsync 之上
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "阿里云语音驱动视频服务";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**步骤 2:无需修改其他代码**
|
||||
- 策略工厂会自动注册
|
||||
- 任务处理时会自动选择
|
||||
|
||||
## 回退机制
|
||||
|
||||
当高优先级策略因参数缺失无法执行时,会自动回退到低优先级策略:
|
||||
|
||||
```
|
||||
Kling任务 → KlingStrategy检查参数
|
||||
├─ 参数完整 → 使用 Kling advanced-lip-sync
|
||||
└─ 参数缺失 → 返回false,尝试Latentsync策略
|
||||
└─ LatentsyncStrategy → 支持 → 使用通用接口
|
||||
```
|
||||
|
||||
## 性能优化
|
||||
|
||||
1. **策略缓存**:工厂类使用 `@Cacheable` 缓存策略选择结果
|
||||
2. **延迟加载**:策略按需创建和初始化
|
||||
3. **优先级排序**:一次性排序,避免重复计算
|
||||
|
||||
## 测试建议
|
||||
|
||||
### 单元测试
|
||||
```java
|
||||
@Test
|
||||
public void testKlingStrategySupports() {
|
||||
// 测试支持条件
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKlingStrategySync() {
|
||||
// 测试口型同步逻辑
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLatentsyncStrategySupports() {
|
||||
// 测试回退逻辑
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStrategyFactory() {
|
||||
// 测试策略选择逻辑
|
||||
}
|
||||
```
|
||||
|
||||
### 集成测试
|
||||
```java
|
||||
@Test
|
||||
public void testEndToEndWithKling() {
|
||||
// 测试完整的可灵流程
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEndToEndWithLatentsync() {
|
||||
// 测试完整的 Latentsync 流程
|
||||
}
|
||||
```
|
||||
|
||||
## 总结
|
||||
|
||||
通过策略模式的引入,我们实现了:
|
||||
|
||||
✅ **高内聚低耦合** - 每个策略专注自己的业务
|
||||
✅ **易于扩展** - 新增供应商无需修改核心代码
|
||||
✅ **易于维护** - 策略之间相互独立,修改互不影响
|
||||
✅ **易于测试** - 每个策略可以独立单元测试
|
||||
✅ **代码复用** - 移除重复代码,统一处理流程
|
||||
|
||||
这套架构设计遵循了 SOLID 原则,特别是:
|
||||
- **单一职责原则(SRP)**:每个策略只负责一种 AI 供应商
|
||||
- **开放封闭原则(OCP)**:对扩展开放,对修改封闭
|
||||
- **依赖倒置原则(DIP)**:依赖抽象而非具体实现
|
||||
Reference in New Issue
Block a user