1
This commit is contained in:
344
keyBoard/Class/AiTalk/新音频流程说明.md
Normal file
344
keyBoard/Class/AiTalk/新音频流程说明.md
Normal file
@@ -0,0 +1,344 @@
|
||||
# 新音频流程说明
|
||||
|
||||
## 📋 需求概述
|
||||
|
||||
1. **删除 ElevenLabs 接口**:不再使用 `requestElevenLabsSpeechWithText`
|
||||
2. **新的流程**:
|
||||
- 请求 `chat/message` 接口,后端返回 `audioId`
|
||||
- 用户点击语音按钮时,用 `audioId` 请求 `/chat/audio/{audioId}` 获取 MP3 地址
|
||||
- 如果音频还未生成,显示等待效果(3秒后自动停止)
|
||||
|
||||
---
|
||||
|
||||
## 🔄 新的流程图
|
||||
|
||||
```
|
||||
用户说话
|
||||
↓
|
||||
语音识别(Deepgram)
|
||||
↓
|
||||
添加用户消息到聊天列表
|
||||
↓
|
||||
请求 /chat/message 接口
|
||||
↓
|
||||
后端返回:
|
||||
{
|
||||
"code": 0,
|
||||
"message": "ok",
|
||||
"data": {
|
||||
"aiResponse": "AI 回复文本",
|
||||
"audioId": "6e3e90575ce04658ab6c45d77a506100",
|
||||
"llmDuration": 1572
|
||||
}
|
||||
}
|
||||
↓
|
||||
添加 AI 消息到聊天列表(带 audioId)
|
||||
↓
|
||||
用户点击语音按钮
|
||||
↓
|
||||
请求 /chat/audio/{audioId} 接口
|
||||
↓
|
||||
后端返回:
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"url": "http://example.com/audio.mp3"
|
||||
}
|
||||
}
|
||||
↓
|
||||
下载音频文件
|
||||
↓
|
||||
播放音频
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 修改清单
|
||||
|
||||
### 1. AiVM.h/m(网络层)
|
||||
|
||||
#### 新增字段
|
||||
```objective-c
|
||||
@interface KBAiMessageData : NSObject
|
||||
@property(nonatomic, copy, nullable) NSString *aiResponse; // 新增
|
||||
@property(nonatomic, copy, nullable) NSString *audioId; // 新增
|
||||
@property(nonatomic, assign) NSInteger llmDuration; // 新增
|
||||
@end
|
||||
```
|
||||
|
||||
#### 新增接口
|
||||
```objective-c
|
||||
/// 根据 audioId 获取音频 URL
|
||||
- (void)requestAudioWithAudioId:(NSString *)audioId
|
||||
completion:(AiVMAudioURLCompletion)completion;
|
||||
```
|
||||
|
||||
#### 删除接口
|
||||
```objective-c
|
||||
// ❌ 已删除
|
||||
- (void)requestElevenLabsSpeechWithText:...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. KBChatMessage.h/m(消息模型)
|
||||
|
||||
#### 新增字段
|
||||
```objective-c
|
||||
/// 音频 ID - 用于异步加载音频
|
||||
@property (nonatomic, copy, nullable) NSString *audioId;
|
||||
```
|
||||
|
||||
#### 新增构造方法
|
||||
```objective-c
|
||||
/// 创建 AI 消息(带 audioId,异步加载音频)
|
||||
+ (instancetype)assistantMessageWithText:(NSString *)text
|
||||
audioId:(nullable NSString *)audioId;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. KBChatTableView.h/m(聊天视图)
|
||||
|
||||
#### 新增 API
|
||||
```objective-c
|
||||
/// 添加 AI 消息(带 audioId,异步加载音频)
|
||||
- (void)addAssistantMessage:(NSString *)text
|
||||
audioId:(nullable NSString *)audioId;
|
||||
```
|
||||
|
||||
#### 新增功能
|
||||
- **异步加载音频**:点击语音按钮时,如果有 `audioId`,则请求音频 URL
|
||||
- **等待效果**:加载音频时显示播放中状态,3秒后自动停止
|
||||
- **音频缓存**:下载后的音频数据缓存到消息对象,下次点击直接播放
|
||||
|
||||
#### 新增方法
|
||||
```objective-c
|
||||
- (void)loadAndPlayAudioForMessage:(KBChatMessage *)message atIndexPath:(NSIndexPath *)indexPath;
|
||||
- (void)downloadAndPlayAudioFromURL:(NSString *)urlString forMessage:(KBChatMessage *)message atIndexPath:(NSIndexPath *)indexPath;
|
||||
- (void)startWaitingForCell:(NSIndexPath *)indexPath;
|
||||
- (void)stopWaitingForCell:(NSIndexPath *)indexPath;
|
||||
- (void)waitingTimeout;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. KBAiMainVC.m(主控制器)
|
||||
|
||||
#### 删除的代码
|
||||
```objective-c
|
||||
// ❌ 已删除
|
||||
@property(nonatomic, copy) NSString *elevenLabsApiKey;
|
||||
@property(nonatomic, copy) NSString *elevenLabsVoiceId;
|
||||
|
||||
// ❌ 已删除
|
||||
self.elevenLabsVoiceId = @"...";
|
||||
self.elevenLabsApiKey = @"...";
|
||||
|
||||
// ❌ 已删除 ElevenLabs 相关的所有调用
|
||||
```
|
||||
|
||||
#### 修改的流程
|
||||
```objective-c
|
||||
// 原来:
|
||||
// 1. 请求 chat/message
|
||||
// 2. 请求 ElevenLabs TTS
|
||||
// 3. 添加消息(带音频数据)
|
||||
// 4. 播放音频
|
||||
|
||||
// 现在:
|
||||
// 1. 请求 chat/message(返回 audioId)
|
||||
// 2. 添加消息(带 audioId)
|
||||
// 3. 用户点击语音按钮时异步加载音频
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 核心实现
|
||||
|
||||
### 1. 点击语音按钮的处理逻辑
|
||||
|
||||
```objective-c
|
||||
- (void)assistantMessageCell:(KBChatAssistantMessageCell *)cell
|
||||
didTapVoiceButtonForMessage:(KBChatMessage *)message {
|
||||
|
||||
// 如果有 audioData,直接播放
|
||||
if (message.audioData && message.audioData.length > 0) {
|
||||
[self playAudioForMessage:message atIndexPath:indexPath];
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果有 audioId,异步加载音频
|
||||
if (message.audioId.length > 0) {
|
||||
[self loadAndPlayAudioForMessage:message atIndexPath:indexPath];
|
||||
return;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. 异步加载音频
|
||||
|
||||
```objective-c
|
||||
- (void)loadAndPlayAudioForMessage:(KBChatMessage *)message atIndexPath:(NSIndexPath *)indexPath {
|
||||
// 1. 开始等待效果(显示播放中状态)
|
||||
[self startWaitingForCell:indexPath];
|
||||
|
||||
// 2. 请求音频 URL
|
||||
[self.aiVM requestAudioWithAudioId:message.audioId
|
||||
completion:^(NSString *audioURL, NSError *error) {
|
||||
// 3. 停止等待效果
|
||||
[self stopWaitingForCell:indexPath];
|
||||
|
||||
if (error) {
|
||||
NSLog(@"加载音频失败");
|
||||
return;
|
||||
}
|
||||
|
||||
// 4. 下载音频数据
|
||||
[self downloadAndPlayAudioFromURL:audioURL
|
||||
forMessage:message
|
||||
atIndexPath:indexPath];
|
||||
}];
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. 等待效果(3秒超时)
|
||||
|
||||
```objective-c
|
||||
- (void)startWaitingForCell:(NSIndexPath *)indexPath {
|
||||
self.waitingCellIndexPath = indexPath;
|
||||
|
||||
// 更新 Cell 为等待状态(显示播放中图标)
|
||||
KBChatAssistantMessageCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
|
||||
[cell updateVoicePlayingState:YES];
|
||||
|
||||
// 3 秒后自动停止
|
||||
self.waitingTimer = [NSTimer scheduledTimerWithTimeInterval:3.0
|
||||
target:self
|
||||
selector:@selector(waitingTimeout)
|
||||
userInfo:nil
|
||||
repeats:NO];
|
||||
}
|
||||
|
||||
- (void)waitingTimeout {
|
||||
NSLog(@"音频加载超时");
|
||||
[self stopWaitingForCell:self.waitingCellIndexPath];
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. 音频缓存
|
||||
|
||||
```objective-c
|
||||
- (void)downloadAndPlayAudioFromURL:(NSString *)urlString
|
||||
forMessage:(KBChatMessage *)message
|
||||
atIndexPath:(NSIndexPath *)indexPath {
|
||||
// 下载音频
|
||||
NSURLSessionDataTask *task = [session dataTaskWithURL:url
|
||||
completionHandler:^(NSData *data, ...) {
|
||||
// 缓存到消息对象
|
||||
message.audioData = data;
|
||||
|
||||
// 计算时长
|
||||
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithData:data error:nil];
|
||||
message.audioDuration = player.duration;
|
||||
|
||||
// 刷新 Cell
|
||||
[self.tableView reloadRowsAtIndexPaths:@[indexPath] ...];
|
||||
|
||||
// 播放音频
|
||||
[self playAudioForMessage:message atIndexPath:indexPath];
|
||||
}];
|
||||
[task resume];
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 数据结构
|
||||
|
||||
### chat/message 接口返回
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "ok",
|
||||
"data": {
|
||||
"aiResponse": "Ugh, seriously? It's Tiffany...",
|
||||
"audioId": "6e3e90575ce04658ab6c45d77a506100",
|
||||
"llmDuration": 1572
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### /chat/audio/{audioId} 接口返回
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"url": "http://127.0.0.1:4523/m1/7401033-7133645-default/chat/audio/1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ 优势
|
||||
|
||||
1. **后端统一处理 TTS**:不需要前端配置 ElevenLabs API Key
|
||||
2. **异步加载**:不阻塞 UI,用户体验更好
|
||||
3. **音频缓存**:下载后缓存,再次点击直接播放
|
||||
4. **等待效果**:3秒超时保护,避免无限等待
|
||||
5. **降低耦合**:前端不需要关心 TTS 实现细节
|
||||
|
||||
---
|
||||
|
||||
## 🧪 测试清单
|
||||
|
||||
- [ ] 请求 chat/message 接口成功
|
||||
- [ ] 返回的 audioId 正确保存
|
||||
- [ ] 点击语音按钮触发异步加载
|
||||
- [ ] 等待效果正常显示(播放中图标)
|
||||
- [ ] 3秒后自动停止等待
|
||||
- [ ] 音频 URL 请求成功
|
||||
- [ ] 音频下载成功
|
||||
- [ ] 音频播放正常
|
||||
- [ ] 再次点击直接播放(缓存生效)
|
||||
- [ ] 错误处理正常(网络失败、URL 无效等)
|
||||
|
||||
---
|
||||
|
||||
## 🔧 调试建议
|
||||
|
||||
### 1. 查看日志
|
||||
```objective-c
|
||||
NSLog(@"[KBChatTableView] 加载音频失败: %@", error);
|
||||
NSLog(@"[KBChatTableView] 音频 URL: %@", audioURL);
|
||||
NSLog(@"[KBChatTableView] 音频加载超时");
|
||||
```
|
||||
|
||||
### 2. 检查返回数据
|
||||
- 确认 `audioId` 不为空
|
||||
- 确认 `/chat/audio/{audioId}` 返回的 URL 格式正确
|
||||
- 确认 URL 可以正常访问
|
||||
|
||||
### 3. 测试超时
|
||||
- 故意延迟后端响应,测试 3秒超时是否生效
|
||||
|
||||
---
|
||||
|
||||
## 🎉 完成!
|
||||
|
||||
新的音频流程已经完全实现,具备以下特性:
|
||||
|
||||
✅ 后端统一处理 TTS
|
||||
✅ 异步加载音频
|
||||
✅ 等待效果(3秒超时)
|
||||
✅ 音频缓存
|
||||
✅ 错误处理
|
||||
|
||||
运行项目即可测试新流程!
|
||||
Reference in New Issue
Block a user