This commit is contained in:
2026-01-23 21:51:37 +08:00
parent 6ad9783bcb
commit 77fd46aa34
26 changed files with 3681 additions and 199 deletions

View File

@@ -0,0 +1,363 @@
# 新聊天 UI 集成指南
## 📦 已创建的文件
### Model数据模型
- `KBChatMessage.h/m` - 消息模型(支持用户/AI/时间戳三种类型)
### View视图组件
- `KBChatUserMessageCell.h/m` - 用户消息 Cell右侧气泡
- `KBChatAssistantMessageCell.h/m` - AI 消息 Cell左侧气泡 + 语音按钮)
- `KBChatTimeCell.h/m` - 时间戳 Cell居中显示
- `KBChatTableView.h/m` - 聊天列表视图(主容器)
### ViewController测试页面
- `KBChatTestVC.h/m` - 测试页面(可选,用于演示)
### 文档
- `KBChatTableView_Usage.md` - 使用说明
- `集成指南.md` - 本文档
---
## 🎯 核心特性
**三种消息类型**
- 用户消息:右侧浅色气泡
- AI 消息:左侧深色气泡 + 语音播放按钮
- 时间戳居中显示自动插入5 分钟间隔)
**语音播放**
- 点击播放/暂停
- 显示语音时长(如 "6""
- 播放状态图标切换
**打字机效果**
- 支持实时更新 AI 消息文本
- 流式显示
**自动滚动**
- 新消息自动滚动到底部
- 平滑动画
---
## 🔧 集成到 KBAiMainVC
### 步骤 1修改 import
`KBAiMainVC.m` 顶部添加:
```objective-c
#import "KBChatTableView.h"
```
### 步骤 2修改属性声明
将:
```objective-c
@property (nonatomic, strong) KBAiChatView *chatView;
```
改为:
```objective-c
@property (nonatomic, strong) KBChatTableView *chatView;
```
### 步骤 3修改 setupUI 方法
将:
```objective-c
self.chatView = [[KBAiChatView alloc] init];
```
改为:
```objective-c
self.chatView = [[KBChatTableView alloc] init];
```
### 步骤 4修改消息添加逻辑
#### 添加用户消息(保持不变)
```objective-c
[self.chatView addUserMessage:finalText];
```
#### 添加 AI 消息(需要修改)
**原来的代码:**
```objective-c
[self.chatView addAssistantMessage:polishedText];
[self.chatView markLastAssistantMessageComplete];
```
**新的代码:**
```objective-c
// 计算音频时长(如果有音频数据)
NSTimeInterval duration = 0;
if (audioData && audioData.length > 0) {
// 方法 1从 AVAudioPlayer 获取准确时长
NSError *error = nil;
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithData:audioData error:&error];
if (!error && player) {
duration = player.duration;
}
// 方法 2估算时长如果知道采样率
// duration = audioData.length / (sampleRate * channels * bytesPerSample);
}
[self.chatView addAssistantMessage:polishedText
audioDuration:duration
audioData:audioData];
```
### 步骤 5修改打字机效果如果使用
**原来的代码:**
```objective-c
[self.chatView addAssistantMessage:@""];
[self.chatView updateLastAssistantMessage:token];
[self.chatView markLastAssistantMessageComplete];
```
**新的代码:**
```objective-c
// 1. 添加空消息占位
[self.chatView addAssistantMessage:@""
audioDuration:0
audioData:nil];
// 2. 逐步更新
[self.chatView updateLastAssistantMessage:token];
// 3. 完成后标记并添加音频
[self.chatView markLastAssistantMessageComplete];
// 如果有音频,需要更新最后一条消息的音频数据
// 注意:当前实现不支持后续添加音频,建议在完成时重新添加消息
```
---
## 📝 完整示例:修改 deepgramStreamingManagerDidReceiveFinalTranscript
```objective-c
- (void)deepgramStreamingManagerDidReceiveFinalTranscript:(NSString *)text {
if (text.length > 0) {
if (self.deepgramFullText.length > 0) {
[self.deepgramFullText appendString:@" "];
}
[self.deepgramFullText appendString:text];
}
self.transcriptLabel.text = self.deepgramFullText;
self.statusLabel.text = @"识别完成";
self.recordButton.state = KBAiRecordButtonStateNormal;
NSString *finalText = [self.deepgramFullText copy];
if (finalText.length == 0) {
return;
}
// 添加用户消息
[self.chatView addUserMessage:finalText];
if (self.elevenLabsApiKey.length == 0 || self.elevenLabsVoiceId.length == 0) {
[KBHUD showError:@"请先配置 ElevenLabs API Key/VoiceId"];
return;
}
__weak typeof(self) weakSelf = self;
[KBHUD showWithStatus:@"润色中..."];
[self.aiVM requestChatMessageWithContent:finalText
completion:^(KBAiMessageResponse *_Nullable response,
NSError *_Nullable error) {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf) return;
dispatch_async(dispatch_get_main_queue(), ^{
if (error) {
[KBHUD dismiss];
[KBHUD showError:error.localizedDescription ?: @"润色失败"];
return;
}
NSString *polishedText = response.data.content ?: response.data.text ?: response.data.message ?: @"";
if (polishedText.length == 0) {
[KBHUD dismiss];
[KBHUD showError:@"润色结果为空"];
return;
}
[KBHUD showWithStatus:@"生成语音..."];
[strongSelf.aiVM requestElevenLabsSpeechWithText:polishedText
voiceId:strongSelf.elevenLabsVoiceId
apiKey:strongSelf.elevenLabsApiKey
outputFormat:nil
modelId:nil
completion:^(NSData *_Nullable audioData,
NSError *_Nullable ttsError) {
dispatch_async(dispatch_get_main_queue(), ^{
[KBHUD dismiss];
if (ttsError) {
[KBHUD showError:ttsError.localizedDescription ?: @"语音生成失败"];
// 即使语音失败,也添加文本消息
[strongSelf.chatView addAssistantMessage:polishedText
audioDuration:0
audioData:nil];
return;
}
// 计算音频时长
NSTimeInterval duration = 0;
if (audioData && audioData.length > 0) {
NSError *playerError = nil;
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithData:audioData
error:&playerError];
if (!playerError && player) {
duration = player.duration;
}
}
// 添加 AI 消息(带语音)
[strongSelf.chatView addAssistantMessage:polishedText
audioDuration:duration
audioData:audioData];
});
}];
});
}];
}
```
---
## 🧪 测试步骤
### 1. 测试新 UI使用测试页面
在任意地方跳转到测试页面:
```objective-c
KBChatTestVC *testVC = [[KBChatTestVC alloc] init];
[self.navigationController pushViewController:testVC animated:YES];
```
### 2. 集成到 KBAiMainVC
按照上面的步骤修改 `KBAiMainVC.m`
### 3. 验证功能
- ✅ 用户消息显示在右侧
- ✅ AI 消息显示在左侧
- ✅ 时间戳自动插入
- ✅ 语音按钮可点击播放
- ✅ 语音时长正确显示
- ✅ 消息自动滚动到底部
---
## 🎨 自定义样式
### 修改气泡颜色
**用户消息**`KBChatUserMessageCell.m`
```objective-c
self.bubbleView.backgroundColor = [UIColor colorWithRed:0.94 green:0.94 blue:0.94 alpha:1.0];
self.messageLabel.textColor = [UIColor blackColor];
```
**AI 消息**`KBChatAssistantMessageCell.m`
```objective-c
self.bubbleView.backgroundColor = [UIColor colorWithRed:0.2 green:0.2 blue:0.2 alpha:0.7];
self.messageLabel.textColor = [UIColor whiteColor];
```
### 修改时间戳间隔
在 `KBChatTableView.m` 中:
```objective-c
static const NSTimeInterval kTimestampInterval = 5 * 60; // 改为你想要的秒数
```
### 修改气泡圆角
在对应的 Cell 中:
```objective-c
self.bubbleView.layer.cornerRadius = 16; // 改为你想要的值
```
---
## ⚠️ 注意事项
1. **音频格式**:确保 `audioData` 是 AVAudioPlayer 支持的格式MP3、AAC、M4A 等)
2. **音频会话**:播放音频前确保配置了 AVAudioSession已在 `AudioSessionManager` 中处理)
3. **内存管理**:如果消息量很大,考虑:
- 限制消息数量(如只保留最近 100 条)
- 清除旧消息的音频数据
- 实现分页加载
4. **线程安全**:所有 UI 更新必须在主线程执行
5. **音频时长计算**
- 方法 1使用 AVAudioPlayer 获取准确时长(推荐)
- 方法 2根据采样率估算不够准确
---
## 🐛 常见问题
### Q1: 语音按钮不显示?
**A:** 检查 `audioData` 是否为 nil 或长度为 0
### Q2: 点击语音按钮没反应?
**A:** 检查音频数据格式是否正确,查看控制台日志
### Q3: 时间戳不显示?
**A:** 检查消息的 `timestamp` 是否正确设置
### Q4: 消息不自动滚动?
**A:** 确保在主线程调用 `scrollToBottom`
### Q5: 气泡宽度不对?
**A:** 检查 Masonry 约束,确保 `multipliedBy(0.75)` 生效
---
## 📚 相关文件
- 使用说明:`KBChatTableView_Usage.md`
- 测试页面:`KBChatTestVC.h/m`
- 原有实现:`KBAiChatView.h/m`(可保留作为备份)
---
## ✅ 完成清单
- [ ] 创建所有新文件
- [ ] 修改 `KBAiMainVC.m` 的 import
- [ ] 修改属性声明
- [ ] 修改 setupUI 方法
- [ ] 修改消息添加逻辑
- [ ] 测试用户消息显示
- [ ] 测试 AI 消息显示
- [ ] 测试语音播放功能
- [ ] 测试时间戳显示
- [ ] 测试打字机效果
- [ ] 自定义样式(可选)
- [ ] 删除旧的 `KBAiChatView`(可选)
---
## 🎉 完成!
按照以上步骤完成集成后,你将拥有一个功能完整、美观的聊天 UI 界面!