优化
This commit is contained in:
@@ -1,179 +0,0 @@
|
||||
# Technical Design: SiliconFlow Voice Provider
|
||||
|
||||
## Context
|
||||
|
||||
硅基流动(SiliconFlow)是一个提供多种 AI 服务的平台,包括语音合成、语音克隆等功能。本次设计将其作为新的语音供应商集成到现有的多供应商架构中。
|
||||
|
||||
**约束条件**:
|
||||
- 必须兼容现有的 `VoiceCloneProvider` 接口
|
||||
- 不能影响现有的 CosyVoice 供应商功能
|
||||
- 需要适配硅基流动的 API 差异
|
||||
|
||||
**关键 API 差异**:
|
||||
1. **语音克隆**: 硅基流动需要先上传参考音频,返回 `uri` 作为音色 ID
|
||||
2. **TTS 合成**: 使用 `/v1/audio/speech` 端点,返回二进制音频数据
|
||||
3. **认证**: 使用 Bearer Token 格式的 API Key
|
||||
4. **模型**: 使用 `IndexTeam/IndexTTS-2` 模型
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
### Goals
|
||||
- 实现 `SiliconFlowProvider` 完整支持语音克隆和 TTS
|
||||
- 支持硅基流动 `IndexTeam/IndexTTS-2` 模型
|
||||
- 提供完整的配置支持,可独立开关
|
||||
- 处理 API 差异,提供统一的服务接口
|
||||
|
||||
### Non-Goals
|
||||
- 不实现语音转文字(STT)功能(已有其他服务)
|
||||
- 不修改现有的 `VoiceCloneProvider` 接口定义
|
||||
- 不改变前端 API 契约
|
||||
|
||||
## Decisions
|
||||
|
||||
### 1. 实现类结构
|
||||
|
||||
**架构**:
|
||||
```
|
||||
SiliconFlowProvider (implements VoiceCloneProvider)
|
||||
├── SiliconFlowApi (HTTP 客户端)
|
||||
├── SiliconFlowProviderConfig (配置类)
|
||||
└── DTO 类 (请求/响应适配)
|
||||
```
|
||||
|
||||
**Why**:
|
||||
- 遵循现有的 `CosyVoiceProvider` 模式
|
||||
- 分离 API 调用逻辑,便于测试和维护
|
||||
- 专用 DTO 处理硅基流动 API 差异
|
||||
|
||||
### 2. 语音克隆流程适配
|
||||
|
||||
**硅基流动语音克隆 API**:
|
||||
- 端点: `POST /v1/uploads/audio/voice`
|
||||
- 请求参数: `model`, `customName`, `text`, `audio` (base64)
|
||||
- 响应: `{"uri": "speech:customName:xxx:xxx"}`
|
||||
|
||||
**适配策略**:
|
||||
1. 将统一请求的 `audioUrl` 下载并转换为 base64
|
||||
2. 使用 `prefix` 作为 `customName`
|
||||
3. 使用 `audioUrl` 对应的转录文本作为 `text` 参数
|
||||
4. 返回的 `uri` 存储为 `voiceId`
|
||||
|
||||
**代码示例**:
|
||||
```java
|
||||
@Override
|
||||
public VoiceCloneResult cloneVoice(VoiceCloneRequest request) {
|
||||
// 1. 下载音频文件
|
||||
byte[] audioData = downloadAudio(request.getAudioUrl());
|
||||
String base64Audio = Base64.getEncoder().encodeToString(audioData);
|
||||
|
||||
// 2. 构建硅基流动请求
|
||||
SiliconFlowVoiceUploadRequest sfRequest = new SiliconFlowVoiceUploadRequest();
|
||||
sfRequest.setModel("IndexTeam/IndexTTS-2");
|
||||
sfRequest.setCustomName(request.getPrefix());
|
||||
sfRequest.setText(getTranscriptionText(request.getAudioUrl()));
|
||||
sfRequest.setAudio("data:audio/mpeg;base64," + base64Audio);
|
||||
|
||||
// 3. 调用 API
|
||||
SiliconFlowVoiceUploadResponse sfResponse = siliconFlowApi.uploadVoice(sfRequest);
|
||||
|
||||
// 4. 适配返回结果
|
||||
VoiceCloneResult result = new VoiceCloneResult();
|
||||
result.setVoiceId(sfResponse.getUri());
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
### 3. TTS 合成流程适配
|
||||
|
||||
**硅基流动 TTS API**:
|
||||
- 端点: `POST /v1/audio/speech`
|
||||
- 请求参数: `model`, `input`, `voice`, `speed`, `sample_rate`, `response_format`
|
||||
- 响应: 二进制音频数据
|
||||
|
||||
**适配策略**:
|
||||
1. 使用 `voiceId` (uri 格式) 作为 `voice` 参数
|
||||
2. 支持语速调节 (`speed`)
|
||||
3. 将二进制响应转换为 Base64 返回
|
||||
|
||||
### 4. 配置设计
|
||||
|
||||
**配置结构**:
|
||||
```yaml
|
||||
yudao:
|
||||
voice:
|
||||
providers:
|
||||
siliconflow:
|
||||
enabled: false
|
||||
api-key: ${SILICONFLOW_API_KEY}
|
||||
base-url: https://api.siliconflow.cn
|
||||
default-model: IndexTeam/IndexTTS-2
|
||||
audio-format: mp3
|
||||
sample-rate: 24000
|
||||
connect-timeout: 10s
|
||||
read-timeout: 180s
|
||||
```
|
||||
|
||||
**配置类设计**:
|
||||
```java
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SiliconFlowProviderConfig extends VoiceProviderProperties.ProviderConfig {
|
||||
private String baseUrl = "https://api.siliconflow.cn";
|
||||
private String defaultModel = "IndexTeam/IndexTTS-2";
|
||||
private String audioFormat = "mp3";
|
||||
private Integer sampleRate = 24000;
|
||||
private Duration connectTimeout = Duration.ofSeconds(10);
|
||||
private Duration readTimeout = Duration.ofSeconds(180);
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 错误处理策略
|
||||
|
||||
- API 调用失败时记录详细日志
|
||||
- 统一转换为 `VOICE_TTS_FAILED` 业务异常
|
||||
- 不暴露硅基流动技术细节给上层
|
||||
- 支持重试机制(网络错误)
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
| Risk | Mitigation |
|
||||
|------|------------|
|
||||
| 硅基流动 API 变更 | 封装在独立的 API 客户端中,便于更新 |
|
||||
| 语音克隆需要转录文本 | 在创建配音时已有转录流程,复用该文本 |
|
||||
| 音频下载增加延迟 | 可考虑配置是否需要下载,或使用异步处理 |
|
||||
| Base64 编码增加内存占用 | 限制音频文件大小(已有 50MB 限制) |
|
||||
|
||||
## Migration Plan
|
||||
|
||||
### 阶段一:后端实现
|
||||
1. 创建 `SiliconFlowApi` HTTP 客户端
|
||||
2. 创建 `SiliconFlowProviderConfig` 配置类
|
||||
3. 创建硅基流动专用 DTO 类
|
||||
4. 实现 `SiliconFlowProvider`
|
||||
5. 更新 `application.yaml` 配置
|
||||
|
||||
### 阶段二:测试验证
|
||||
1. 单元测试:`SiliconFlowApi` 调用
|
||||
2. 单元测试:`SiliconFlowProvider` 适配逻辑
|
||||
3. 集成测试:语音克隆完整流程
|
||||
4. 集成测试:TTS 合成完整流程
|
||||
|
||||
### 阶段三:前端支持(已有基础)
|
||||
1. 验证 `voiceConfig.js` 已支持 `siliconflow` 类型
|
||||
2. 验证 API 请求已支持 `providerType` 参数
|
||||
|
||||
### 回滚方案
|
||||
- 通过配置 `enabled: false` 禁用硅基流动
|
||||
- 删除 `SiliconFlowProvider` 相关代码
|
||||
- 恢复 `application.yaml` 配置
|
||||
|
||||
## Open Questions
|
||||
|
||||
1. **Q**: 语音克隆时是否必须提供转录文本?
|
||||
**A**: 硅基流动 API 需要 `text` 参数,使用配音创建时的转录文本
|
||||
|
||||
2. **Q**: 是否需要支持硅基流动的其他模型?
|
||||
**A**: 本次仅支持 `IndexTeam/IndexTTS-2`,后续可扩展
|
||||
|
||||
3. **Q**: 音频下载失败如何处理?
|
||||
**A**: 抛出业务异常,提示用户检查音频 URL
|
||||
@@ -1,36 +0,0 @@
|
||||
# Change: Add SiliconFlow Voice Provider
|
||||
|
||||
## Why
|
||||
|
||||
当前语音克隆功能已完成策略模式重构,支持多供应商架构。CosyVoice 供应商已实现并投入使用。为提供更多选择和降低对单一供应商的依赖,需要添加硅基流动(SiliconFlow)作为新的语音供应商,支持 IndexTeam/IndexTTS-2 模型的语音克隆和 TTS 合成。
|
||||
|
||||
## What Changes
|
||||
|
||||
- **ADDED** 新增 `SiliconFlowProvider` 实现类,实现 `VoiceCloneProvider` 接口
|
||||
- **ADDED** 新增 `SiliconFlowProviderConfig` 配置类
|
||||
- **ADDED** 新增 `SiliconFlowApi` API 客户端类
|
||||
- **ADDED** 新增硅基流动专用 DTO 类
|
||||
- **MODIFIED** 更新 `VoiceProviderProperties` 支持硅基流动配置
|
||||
- **MODIFIED** 更新 `application.yaml` 添加硅基流动配置项
|
||||
|
||||
## Impact
|
||||
|
||||
- **Affected specs**:
|
||||
- `voice-clone` - 扩展支持新的语音供应商
|
||||
- **Affected code**:
|
||||
- 新增 `yudao-module-tik/.../voice/client/SiliconFlowProvider.java`
|
||||
- 新增 `yudao-module-tik/.../voice/client/SiliconFlowApi.java`
|
||||
- 新增 `yudao-module-tik/.../voice/config/SiliconFlowProviderConfig.java`
|
||||
- 新增 `yudao-module-tik/.../voice/client/dto/SiliconFlow*.java` (DTO 类)
|
||||
- 更新 `yudao-server/src/main/resources/application.yaml`
|
||||
|
||||
## Dependencies
|
||||
|
||||
- 依赖已完成的多供应商架构重构(`VoiceCloneProvider` 接口和工厂模式)
|
||||
- 硅基流动 API Key 需要在配置中提供
|
||||
|
||||
## Migration
|
||||
|
||||
- 无需数据迁移,新功能为纯新增
|
||||
- 现有 CosyVoice 供应商功能不受影响
|
||||
- 硅基流动默认禁用,需通过配置启用
|
||||
@@ -1,117 +0,0 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: SiliconFlow 语音克隆支持
|
||||
|
||||
系统 MUST 支持使用硅基流动(SiliconFlow)作为语音克隆供应商,允许用户上传参考音频并生成可复用的音色 ID。
|
||||
|
||||
#### Scenario: 成功使用硅基流动克隆音色
|
||||
|
||||
- **GIVEN** 用户已上传参考音频文件并获得文件 URL
|
||||
- **AND** 参考音频已成功转录为文本
|
||||
- **AND** 硅基流动供应商已启用并配置有效的 API Key
|
||||
- **WHEN** 用户通过 API 发起语音克隆请求,指定 `providerType` 为 `siliconflow`
|
||||
- **THEN** 系统应当下载参考音频文件并转换为 base64 格式
|
||||
- **AND** 调用硅基流动 `/v1/uploads/audio/voice` API,使用 `IndexTeam/IndexTTS-2` 模型
|
||||
- **AND** 将返回的 `uri`(格式如 `speech:customName:xxx:xxx`)存储为 `voiceId`
|
||||
- **AND** 返回克隆成功的响应,包含生成的 `voiceId`
|
||||
|
||||
#### Scenario: 硅基流动 API 调用失败
|
||||
|
||||
- **GIVEN** 硅基流动供应商已启用
|
||||
- **WHEN** 调用硅基流动 API 时发生网络错误或认证失败
|
||||
- **THEN** 系统应当记录详细的错误日志
|
||||
- **AND** 返回统一错误码 `VOICE_TTS_FAILED`,不暴露底层技术细节
|
||||
|
||||
#### Scenario: 硅基流动供应商未配置
|
||||
|
||||
- **GIVEN** 硅基流动供应商未启用或 API Key 未配置
|
||||
- **WHEN** 用户尝试使用硅基流动进行语音克隆
|
||||
- **THEN** 系统应当返回友好的错误提示,要求管理员先配置硅基流动
|
||||
|
||||
---
|
||||
|
||||
### Requirement: SiliconFlow 文本转语音支持
|
||||
|
||||
系统 MUST 支持使用硅基流动进行文本转语音合成,允许用户使用已克隆的音色 ID 或系统默认音色合成语音。
|
||||
|
||||
#### Scenario: 使用克隆音色合成语音
|
||||
|
||||
- **GIVEN** 用户已通过硅基流动成功克隆音色,获得 `voiceId`
|
||||
- **AND** 硅基流动供应商已启用
|
||||
- **WHEN** 用户发起 TTS 请求,指定 `providerType` 为 `siliconflow` 和有效的 `voiceId`
|
||||
- **THEN** 系统应当调用硅基流动 `/v1/audio/speech` API
|
||||
- **AND** 使用 `IndexTeam/IndexTTS-2` 模型和指定的 `voiceId`
|
||||
- **AND** 将返回的音频二进制数据转换为 base64 格式
|
||||
- **AND** 返回包含音频数据、格式和采样率的响应
|
||||
|
||||
#### Scenario: 使用默认音色合成语音
|
||||
|
||||
- **GIVEN** 硅基流动供应商已启用
|
||||
- **AND** 用户未指定 `voiceId`
|
||||
- **WHEN** 用户发起 TTS 请求,指定 `providerType` 为 `siliconflow`
|
||||
- **THEN** 系统应当使用硅基流动提供的默认音色进行合成
|
||||
- **AND** 返回合成结果
|
||||
|
||||
#### Scenario: TTS 合成参数支持
|
||||
|
||||
- **GIVEN** 硅基流动供应商已启用
|
||||
- **WHEN** 用户发起 TTS 请求,包含可选参数(语速、采样率、音频格式)
|
||||
- **THEN** 系统应当将这些参数适配为硅基流动 API 格式
|
||||
- **AND** 支持的参数包括:`speed`(0.25-4.0)、`sample_rate`、`response_format`(mp3/wav/pcm)
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 供应商动态切换
|
||||
|
||||
系统 SHALL 支持在请求时动态指定语音供应商,无需重启服务。
|
||||
|
||||
#### Scenario: 通过 providerType 切换供应商
|
||||
|
||||
- **GIVEN** 系统已配置 CosyVoice 和 SiliconFlow 两个供应商
|
||||
- **AND** 默认供应商为 `cosyvoice`
|
||||
- **WHEN** 用户在 API 请求中指定 `providerType` 为 `siliconflow`
|
||||
- **THEN** 系统应当使用 `SiliconFlowProvider` 处理请求
|
||||
- **AND** 不影响其他使用默认供应商的请求
|
||||
|
||||
#### Scenario: 不支持的供应商类型
|
||||
|
||||
- **GIVEN** 系统仅配置了 CosyVoice 和 SiliconFlow 供应商
|
||||
- **WHEN** 用户指定 `providerType` 为不存在的值(如 `other`)
|
||||
- **THEN** 系统应当返回错误提示 "不支持的语音克隆供应商: other"
|
||||
|
||||
---
|
||||
|
||||
### Requirement: SiliconFlow 配置管理
|
||||
|
||||
系统 MUST 支持通过配置文件管理硅基流动供应商的启用状态和连接参数。
|
||||
|
||||
#### Scenario: 配置硅基流动供应商
|
||||
|
||||
- **GIVEN** 管理员希望在系统中启用硅基流动
|
||||
- **WHEN** 管理员在 `application.yaml` 中配置以下参数:
|
||||
```yaml
|
||||
yudao:
|
||||
voice:
|
||||
providers:
|
||||
siliconflow:
|
||||
enabled: true
|
||||
api-key: sk-xxxxx
|
||||
base-url: https://api.siliconflow.cn
|
||||
default-model: IndexTeam/IndexTTS-2
|
||||
```
|
||||
- **THEN** 系统应当在启动时注册 `SiliconFlowProvider`
|
||||
- **AND** 用户可以通过指定 `providerType` 为 `siliconflow` 使用该供应商
|
||||
|
||||
#### Scenario: 禁用硅基流动供应商
|
||||
|
||||
- **GIVEN** 硅基流动供应商已配置
|
||||
- **WHEN** 管理员将 `enabled` 设置为 `false` 或移除配置
|
||||
- **THEN** 系统启动时不应注册 `SiliconFlowProvider`
|
||||
- **AND** 用户请求硅基流动服务时应当返回错误提示
|
||||
|
||||
#### Scenario: 向后兼容旧配置
|
||||
|
||||
- **GIVEN** 系统已从旧版本升级,存在 `yudao.cosyvoice.*` 配置
|
||||
- **WHEN** 系统启动时检测到旧配置
|
||||
- **THEN** 系统应当自动将旧配置迁移到 `yudao.voice.providers.cosyvoice.*` 结构
|
||||
- **AND** 优先使用新配置,旧配置作为 fallback
|
||||
@@ -1,66 +0,0 @@
|
||||
# Implementation Tasks
|
||||
|
||||
## 1. 配置类实现
|
||||
- [ ] 1.1 创建 `SiliconFlowProviderConfig` 配置类
|
||||
- 继承 `VoiceProviderProperties.ProviderConfig`
|
||||
- 添加硅基流动特有配置字段
|
||||
- 添加默认值和配置前缀
|
||||
|
||||
## 2. API 客户端实现
|
||||
- [ ] 2.1 创建 `SiliconFlowApi` HTTP 客户端
|
||||
- 实现 `uploadVoice()` 方法 - 上传参考音频
|
||||
- 实现 `synthesize()` 方法 - 文本转语音
|
||||
- 实现 `transcribe()` 方法 - 语音转文本(可选)
|
||||
- 配置 RestTemplate/ WebClient
|
||||
- 添加请求/响应日志
|
||||
|
||||
## 3. DTO 类实现
|
||||
- [ ] 3.1 创建 `SiliconFlowVoiceUploadRequest` - 上传参考音频请求
|
||||
- [ ] 3.2 创建 `SiliconFlowVoiceUploadResponse` - 上传参考音频响应
|
||||
- [ ] 3.3 创建 `SiliconFlowTtsRequest` - 文本转语音请求
|
||||
- [ ] 3.4 创建 `SiliconFlowTtsResponse` - 文本转语音响应(二进制处理)
|
||||
|
||||
## 4. Provider 实现类
|
||||
- [ ] 4.1 创建 `SiliconFlowProvider` 实现类
|
||||
- 实现 `VoiceCloneProvider` 接口
|
||||
- 实现 `cloneVoice()` 方法
|
||||
- 实现 `synthesize()` 方法
|
||||
- 实现 `supports()` 方法
|
||||
- 实现 `getProviderType()` 方法
|
||||
- 添加 `@Component` 注解注册为 Spring Bean
|
||||
|
||||
## 5. 配置文件更新
|
||||
- [ ] 5.1 更新 `application.yaml`
|
||||
- 添加 `yudao.voice.providers.siliconflow` 配置节
|
||||
- 配置 API Key、base URL、模型等参数
|
||||
- 默认设置为 `enabled: false`
|
||||
|
||||
## 6. 测试与验证
|
||||
- [ ] 6.1 编写单元测试
|
||||
- 测试 `SiliconFlowApi` HTTP 调用
|
||||
- 测试 `SiliconFlowProvider` 适配逻辑
|
||||
- Mock 硅基流动 API 响应
|
||||
- [ ] 6.2 集成测试
|
||||
- 测试语音克隆完整流程
|
||||
- 测试 TTS 合成完整流程
|
||||
- 测试供应商切换功能
|
||||
- [ ] 6.3 验证前端兼容性
|
||||
- 验证 `voiceConfig.js` 支持 `siliconflow` 类型
|
||||
- 验证 API 请求支持 `providerType` 参数
|
||||
|
||||
## 7. 文档与清理
|
||||
- [ ] 7.1 更新相关文档
|
||||
- 添加硅基流动配置说明
|
||||
- 添加硅基流动使用示例
|
||||
- [ ] 7.2 代码审查与清理
|
||||
- 检查代码规范
|
||||
- 移除调试代码
|
||||
- 确保日志级别正确
|
||||
|
||||
---
|
||||
|
||||
**总计**: 20 项任务
|
||||
|
||||
**预计工作量**: 2-3 天
|
||||
|
||||
**依赖**: 多供应商架构重构已完成
|
||||
305
openspec/proposals/points-service-integration.md
Normal file
305
openspec/proposals/points-service-integration.md
Normal file
@@ -0,0 +1,305 @@
|
||||
# AI 服务积分扣减公共服务设计文档
|
||||
|
||||
> 版本: v1.2
|
||||
> 日期: 2025-02-20
|
||||
> 状态: 待确认
|
||||
> 用途: 业务规范文档,供后续开发参考
|
||||
|
||||
---
|
||||
|
||||
# 模块一:公共积分扣减服务
|
||||
|
||||
## 1.1 服务定位
|
||||
|
||||
**积分扣减公共服务** - 位于 `tik` 模块下,供所有 AI 服务复用的基础设施。
|
||||
|
||||
**职责:**
|
||||
- 积分配置查询
|
||||
- 积分预检与扣减
|
||||
- 预扣记录管理
|
||||
- 积分流水记录
|
||||
|
||||
## 1.2 核心能力
|
||||
|
||||
| 能力 | 说明 | 使用场景 |
|
||||
|------|------|---------|
|
||||
| 获取积分配置 | 根据平台+类型获取消耗积分 | 所有业务调用前 |
|
||||
| 预检积分 | 检查余额是否充足,不足抛异常 | 调用前验证 |
|
||||
| 即时扣减 | 直接扣减并记录流水 | 同步调用成功后 |
|
||||
| 创建预扣 | 创建待确认的扣减记录 | 流式/异步任务开始时 |
|
||||
| 确认扣减 | 确认预扣,实际扣减积分 | 流式结束/任务成功时 |
|
||||
| 取消预扣 | 删除预扣记录,不扣费 | 流式出错/任务失败时 |
|
||||
|
||||
## 1.3 数据模型
|
||||
|
||||
### 用户积分(muye_member_user_profile)
|
||||
- `remaining_points` - 剩余积分(扣减来源)
|
||||
- `used_points` - 已用积分
|
||||
|
||||
### 积分记录(muye_point_record)
|
||||
- `point_amount` - 变动数量(负数为扣减)
|
||||
- `biz_type` - 业务类型(dify_chat/voice_tts 等)
|
||||
- `biz_id` - 业务关联ID
|
||||
- `status` - 状态:`pending`(预扣) / `confirmed`(已确认) / `canceled`(已取消)
|
||||
|
||||
### 积分配置(muye_ai_model_config)
|
||||
- `platform` - 平台:dify / tikhub / voice / digital_human
|
||||
- `model_type` - 类型:high/low / tts/clone / latentsync/kling
|
||||
- `consume_points` - 消耗积分
|
||||
- `api_key` - API 密钥(Dify 工作流密钥等)★
|
||||
- `api_url` - API 地址(可选,覆盖默认配置)
|
||||
|
||||
## 1.4 业务规则
|
||||
|
||||
### 积分扣减规则
|
||||
- **原子性**:使用 SQL 条件更新,确保不会超扣
|
||||
- **乐观锁**:`WHERE remaining_points >= points`
|
||||
- **幂等性**:同一预扣记录只能确认/取消一次
|
||||
|
||||
### 预扣过期规则
|
||||
- 预扣记录超过 30 分钟自动清理
|
||||
- 定时任务每 5 分钟执行一次清理
|
||||
|
||||
### 异常处理
|
||||
- 积分不足:抛出 `POINTS_INSUFFICIENT` 异常
|
||||
- 配置不存在:抛出 `POINTS_CONFIG_NOT_FOUND` 异常
|
||||
- 扣减失败:抛出 `POINTS_DEDUCT_FAILED` 异常
|
||||
|
||||
## 1.5 依赖关系
|
||||
|
||||
```
|
||||
业务服务(Dify/TikHub/Voice/DigitalHuman)
|
||||
↓
|
||||
PointsService(公共服务)
|
||||
↓
|
||||
├── AiModelConfigService → 获取积分配置
|
||||
├── MemberUserProfileMapper → 扣减积分
|
||||
└── PointRecordMapper → 记录流水
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# 模块二:Dify 工作流集成
|
||||
|
||||
## 2.1 业务概述
|
||||
|
||||
**Dify 工作流** - AI 对话服务,支持智能体配置和流式响应。
|
||||
|
||||
**设计原则:**
|
||||
- 所有智能体共用一个"文案生成"工作流(同一个 api_key)
|
||||
- 智能体之间只通过 `systemPrompt` 区分
|
||||
- 前端只需传 `agentId`
|
||||
|
||||
**核心流程:**
|
||||
1. 前端传入 `agentId` + `content`
|
||||
2. 后端通过 `agentId` 获取智能体的 `systemPrompt`
|
||||
3. 调用 Dify API(固定工作流),传入 `sysPrompt` 参数
|
||||
4. 流式返回内容
|
||||
5. 流结束或用户停止时扣费
|
||||
|
||||
## 2.2 扣费流程
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Dify 流式扣费流程 │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ 1. 获取智能体配置(systemPrompt) │
|
||||
│ 2. 获取积分配置(platform=dify) │
|
||||
│ 3. 预检积分 → 积分不足则拒绝 │
|
||||
│ 4. 创建预扣记录 │
|
||||
│ 5. 调用 Dify 流式 API(传入 sysPrompt) │
|
||||
│ ├─ 流正常结束 → 确认扣费(全额) │
|
||||
│ ├─ 用户取消 → 确认扣费(按实际消耗或最低消费) │
|
||||
│ └─ 出错 → 取消预扣(不扣费) │
|
||||
│ 6. 记录使用记录 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 2.3 接口定义
|
||||
|
||||
### 阻塞模式
|
||||
- **URL**: `POST /api/tik/dify/chat`
|
||||
- **入参**: agentId, content, conversationId
|
||||
- **出参**: content, conversationId, consumePoints
|
||||
|
||||
### 流式模式
|
||||
- **URL**: `POST /api/tik/dify/chat/stream`
|
||||
- **入参**: agentId, content, conversationId
|
||||
- **出参**: SSE 流(event: message / done)
|
||||
|
||||
**说明:**
|
||||
- `agentId` 用于获取智能体的 `systemPrompt`
|
||||
- 所有智能体共用同一个 Dify 工作流
|
||||
|
||||
## 2.4 配置方案
|
||||
|
||||
**Dify 配置存储在 `muye_ai_model_config` 表:**
|
||||
|
||||
| 字段 | 值 | 说明 |
|
||||
|------|-----|------|
|
||||
| model_name | Dify 文案生成 | 配置名称 |
|
||||
| platform | dify | 平台标识 |
|
||||
| model_type | writing | 类型 |
|
||||
| consume_points | 10 | 消耗积分 |
|
||||
| api_key | app-xxx | Dify 工作流密钥 ★ |
|
||||
| status | 1 | 启用 |
|
||||
|
||||
**配置文件只存公共配置:**
|
||||
|
||||
```yaml
|
||||
yudao:
|
||||
dify:
|
||||
api-url: http://8.155.172.147:8088
|
||||
timeout: 60
|
||||
```
|
||||
|
||||
## 2.5 智能体表(无需修改)
|
||||
|
||||
现有 `muye_ai_agent` 表已有字段:
|
||||
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
| agent_id | 智能体ID |
|
||||
| agent_name | 智能体名称 |
|
||||
| system_prompt | 系统提示词(传递给 Dify 的 sysPrompt 参数) |
|
||||
| status | 状态 |
|
||||
|
||||
**调用流程:**
|
||||
1. 通过 `agentId` 获取智能体的 `systemPrompt`
|
||||
2. 从 `muye_ai_model_config` 获取 `api_key` + `consume_points`(platform=dify)
|
||||
3. 调用 Dify API,传入 `sysPrompt` 参数
|
||||
|
||||
---
|
||||
|
||||
# 模块三:各业务积分扣减集成
|
||||
|
||||
## 3.1 扣费模式总览
|
||||
|
||||
| 业务 | 扣费模式 | 扣费时机 | 失败处理 |
|
||||
|------|---------|---------|---------|
|
||||
| Dify 工作流 | 流式结束扣费 | 流结束/用户停止时 | 不扣费 |
|
||||
| TikHub | 成功后扣费 | API 调用成功后 | 不扣费 |
|
||||
| 语音合成 | 成功后扣费 | TTS 生成成功后 | 不扣费 |
|
||||
| 数字人合成 | 任务完成扣费 | 任务成功完成时 | 不扣费 |
|
||||
|
||||
**统一原则:失败不扣费**
|
||||
|
||||
## 3.2 TikHub 集成
|
||||
|
||||
### 业务场景
|
||||
- 抖音/小红书数据抓取
|
||||
- 用户信息、视频、帖子等
|
||||
|
||||
### 扣费流程
|
||||
```
|
||||
1. 获取积分配置(platform=tikhub, modelType=fetch)
|
||||
2. 预检积分
|
||||
3. 调用 TikHub API
|
||||
4. 成功 → 扣减积分
|
||||
5. 失败 → 不扣费
|
||||
```
|
||||
|
||||
### 积分配置
|
||||
| platform | model_type | consume_points |
|
||||
|----------|------------|----------------|
|
||||
| tikhub | fetch | 5 |
|
||||
|
||||
## 3.3 语音合成集成
|
||||
|
||||
### 业务场景
|
||||
- TTS 语音生成
|
||||
- 音色克隆
|
||||
|
||||
### 扣费流程
|
||||
```
|
||||
1. 获取积分配置(platform=voice, modelType=tts/clone)
|
||||
2. 预检积分
|
||||
3. 执行语音合成
|
||||
4. 成功 → 扣减积分
|
||||
5. 失败 → 不扣费
|
||||
```
|
||||
|
||||
### 积分配置
|
||||
| platform | model_type | consume_points |
|
||||
|----------|------------|----------------|
|
||||
| voice | tts | 2 |
|
||||
| voice | clone | 10 |
|
||||
|
||||
## 3.4 数字人合成集成
|
||||
|
||||
### 业务场景
|
||||
- 口型同步视频生成
|
||||
- 支持 Latentsync / 可灵 两种供应商
|
||||
|
||||
### 扣费流程
|
||||
```
|
||||
1. 获取积分配置(platform=digital_human, modelType=latentsync/kling)
|
||||
2. 预检积分
|
||||
3. 创建预扣记录
|
||||
4. 创建任务并异步处理
|
||||
5. 任务成功 → 确认扣费
|
||||
6. 任务失败/取消 → 取消预扣
|
||||
```
|
||||
|
||||
### 积分配置
|
||||
| platform | model_type | consume_points |
|
||||
|----------|------------|----------------|
|
||||
| digital_human | latentsync | 15 |
|
||||
| digital_human | kling | 20 |
|
||||
|
||||
---
|
||||
|
||||
# 附录
|
||||
|
||||
## A. 业务类型枚举
|
||||
|
||||
| 类型码 | 说明 |
|
||||
|--------|------|
|
||||
| dify_chat | Dify对话 |
|
||||
| ai_chat | AI聊天 |
|
||||
| image_gen | 图像生成 |
|
||||
| tikhub_fetch | TikHub数据抓取 |
|
||||
| voice_tts | 语音合成 |
|
||||
| voice_clone | 音色克隆 |
|
||||
| digital_human | 数字人合成 |
|
||||
| kling_video | 可灵视频 |
|
||||
|
||||
## B. 异常码
|
||||
|
||||
| 错误码 | 说明 |
|
||||
|--------|------|
|
||||
| 1001001 | 积分不足 |
|
||||
| 1001002 | 积分配置不存在 |
|
||||
| 1001003 | 积分扣减失败 |
|
||||
|
||||
## C. 开发计划
|
||||
|
||||
| 步骤 | 内容 |
|
||||
|------|------|
|
||||
| 1 | 数据库:muye_point_record 新增 status 字段 |
|
||||
| 2 | 公共服务:PointsService 接口 + 实现 |
|
||||
| 3 | Dify 集成:配置类 + 客户端 + 服务 + Controller |
|
||||
| 4 | TikHub 集成:添加积分扣减逻辑 |
|
||||
| 5 | 语音合成集成:添加积分扣减逻辑 |
|
||||
| 6 | 数字人集成:添加积分扣减逻辑 |
|
||||
| 7 | 测试验证 |
|
||||
|
||||
**无需修改的表:**
|
||||
- `muye_ai_agent` - 无需改动
|
||||
- `muye_ai_model_config` - 已有 api_key 字段,无需改动
|
||||
|
||||
## D. 成熟度检查
|
||||
|
||||
| 检查项 | 说明 |
|
||||
|--------|------|
|
||||
| 原子扣减 | SQL 条件更新,防止超扣 |
|
||||
| 乐观锁 | WHERE remaining_points >= points |
|
||||
| 预扣机制 | 支持流式/异步场景 |
|
||||
| 过期清理 | 30分钟自动清理预扣 |
|
||||
| 事务隔离 | 核心操作加事务 |
|
||||
| 异常处理 | 统一错误码 |
|
||||
| 配置化 | 积分消耗可配置 |
|
||||
| 业务解耦 | 公共服务复用 |
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user