1
This commit is contained in:
@@ -7,17 +7,22 @@
|
||||
|
||||
#import "KBAiMainVC.h"
|
||||
#import "ConversationOrchestrator.h"
|
||||
#import "AiVM.h"
|
||||
#import "AudioSessionManager.h"
|
||||
#import "DeepgramStreamingManager.h"
|
||||
#import "KBAICommentView.h"
|
||||
#import "KBAiChatView.h"
|
||||
#import "KBAiRecordButton.h"
|
||||
#import "KBHUD.h"
|
||||
#import "LSTPopView.h"
|
||||
#import "VoiceChatStreamingManager.h"
|
||||
#import "KBUserSessionManager.h"
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
@interface KBAiMainVC () <KBAiRecordButtonDelegate,
|
||||
VoiceChatStreamingManagerDelegate,
|
||||
DeepgramStreamingManagerDelegate>
|
||||
DeepgramStreamingManagerDelegate,
|
||||
AVAudioPlayerDelegate>
|
||||
@property(nonatomic, weak) LSTPopView *popView;
|
||||
|
||||
// UI
|
||||
@@ -36,6 +41,9 @@
|
||||
@property(nonatomic, strong) ConversationOrchestrator *orchestrator;
|
||||
@property(nonatomic, strong) VoiceChatStreamingManager *streamingManager;
|
||||
@property(nonatomic, strong) DeepgramStreamingManager *deepgramManager;
|
||||
@property(nonatomic, strong) AiVM *aiVM;
|
||||
@property(nonatomic, strong) AVAudioPlayer *aiAudioPlayer;
|
||||
@property(nonatomic, strong) NSMutableData *voiceChatAudioBuffer;
|
||||
|
||||
// 文本跟踪
|
||||
@property(nonatomic, strong) NSMutableString *assistantVisibleText;
|
||||
@@ -60,7 +68,8 @@
|
||||
[self setupUI];
|
||||
[self setupOrchestrator];
|
||||
[self setupStreamingManager];
|
||||
[self setupDeepgramManager];
|
||||
// 切换到 websocket-api 方案,Deepgram 暂不初始化
|
||||
// [self setupDeepgramManager];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
@@ -145,15 +154,15 @@
|
||||
self.transcriptLabel.font = [UIFont systemFontOfSize:16];
|
||||
self.transcriptLabel.textColor = [UIColor labelColor];
|
||||
self.transcriptLabel.numberOfLines = 0;
|
||||
self.transcriptLabel.textAlignment = NSTextAlignmentLeft;
|
||||
self.transcriptLabel.textAlignment = NSTextAlignmentRight;
|
||||
self.transcriptLabel.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[self.view addSubview:self.transcriptLabel];
|
||||
|
||||
// 聊天视图
|
||||
// self.chatView = [[KBAiChatView alloc] init];
|
||||
// self.chatView.backgroundColor = [UIColor systemBackgroundColor];
|
||||
// self.chatView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
// [self.view addSubview:self.chatView];
|
||||
self.chatView = [[KBAiChatView alloc] init];
|
||||
self.chatView.backgroundColor = [UIColor clearColor];
|
||||
self.chatView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[self.view addSubview:self.chatView];
|
||||
|
||||
// 录音按钮
|
||||
self.recordButton = [[KBAiRecordButton alloc] init];
|
||||
@@ -198,6 +207,12 @@
|
||||
make.top.equalTo(self.statusLabel.mas_bottom).offset(8);
|
||||
make.left.equalTo(self.view).offset(16);
|
||||
make.right.equalTo(self.view).offset(-16);
|
||||
}];
|
||||
|
||||
[self.chatView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.transcriptLabel.mas_bottom).offset(8);
|
||||
make.left.equalTo(self.view).offset(16);
|
||||
make.right.equalTo(self.view).offset(-16);
|
||||
make.bottom.lessThanOrEqualTo(self.recordButton.mas_top).offset(-16);
|
||||
}];
|
||||
|
||||
@@ -325,6 +340,7 @@
|
||||
self.streamingManager.delegate = self;
|
||||
self.streamingManager.serverURL = @"ws://192.168.2.21:7529/api/ws/chat";
|
||||
self.assistantVisibleText = [[NSMutableString alloc] init];
|
||||
self.voiceChatAudioBuffer = [[NSMutableData alloc] init];
|
||||
self.lastRMSLogTime = 0;
|
||||
}
|
||||
|
||||
@@ -346,6 +362,7 @@
|
||||
[self.deepgramManager prepareConnection];
|
||||
|
||||
self.deepgramFullText = [[NSMutableString alloc] init];
|
||||
self.aiVM = [[AiVM alloc] init];
|
||||
}
|
||||
|
||||
#pragma mark - 事件
|
||||
@@ -446,19 +463,20 @@
|
||||
|
||||
self.statusLabel.text = @"正在连接...";
|
||||
self.recordButton.state = KBAiRecordButtonStateRecording;
|
||||
[self.deepgramFullText setString:@""];
|
||||
self.transcriptLabel.text = @"";
|
||||
[self.deepgramManager start];
|
||||
[self.voiceChatAudioBuffer setLength:0];
|
||||
[self.streamingManager startWithToken:token language:@"en" voiceId:nil];
|
||||
}
|
||||
|
||||
- (void)recordButtonDidEndPress:(KBAiRecordButton *)button {
|
||||
NSLog(@"[KBAiMainVC] Record button end press");
|
||||
[self.deepgramManager stopAndFinalize];
|
||||
[self.streamingManager stopAndFinalize];
|
||||
}
|
||||
|
||||
- (void)recordButtonDidCancelPress:(KBAiRecordButton *)button {
|
||||
NSLog(@"[KBAiMainVC] Record button cancel press");
|
||||
[self.deepgramManager cancel];
|
||||
[self.voiceChatAudioBuffer setLength:0];
|
||||
[self.streamingManager cancel];
|
||||
}
|
||||
|
||||
#pragma mark - VoiceChatStreamingManagerDelegate
|
||||
@@ -503,11 +521,15 @@
|
||||
}
|
||||
|
||||
- (void)voiceChatStreamingManagerDidReceiveInterimTranscript:(NSString *)text {
|
||||
self.statusLabel.text = text.length > 0 ? text : @"正在识别...";
|
||||
self.statusLabel.text = @"正在识别...";
|
||||
if (text.length > 0) {
|
||||
self.transcriptLabel.text = text;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)voiceChatStreamingManagerDidReceiveFinalTranscript:(NSString *)text {
|
||||
if (text.length > 0) {
|
||||
self.transcriptLabel.text = @"";
|
||||
[self.chatView addUserMessage:text];
|
||||
}
|
||||
}
|
||||
@@ -516,6 +538,7 @@
|
||||
self.statusLabel.text = @"AI 正在思考...";
|
||||
[self.assistantVisibleText setString:@""];
|
||||
[self.chatView addAssistantMessage:@""];
|
||||
[self.voiceChatAudioBuffer setLength:0];
|
||||
}
|
||||
|
||||
- (void)voiceChatStreamingManagerDidReceiveLLMToken:(NSString *)token {
|
||||
@@ -528,15 +551,29 @@
|
||||
}
|
||||
|
||||
- (void)voiceChatStreamingManagerDidReceiveAudioChunk:(NSData *)audioData {
|
||||
if (audioData.length == 0) {
|
||||
return;
|
||||
}
|
||||
[self.voiceChatAudioBuffer appendData:audioData];
|
||||
}
|
||||
|
||||
- (void)voiceChatStreamingManagerDidCompleteWithTranscript:(NSString *)transcript
|
||||
aiResponse:(NSString *)aiResponse {
|
||||
NSString *finalText = aiResponse.length > 0 ? aiResponse
|
||||
: self.assistantVisibleText;
|
||||
if (aiResponse.length > 0) {
|
||||
[self.assistantVisibleText setString:aiResponse];
|
||||
}
|
||||
if (finalText.length > 0) {
|
||||
[self.chatView updateLastAssistantMessage:finalText];
|
||||
[self.chatView markLastAssistantMessageComplete];
|
||||
} else if (transcript.length > 0) {
|
||||
[self.chatView addAssistantMessage:transcript];
|
||||
[self.chatView markLastAssistantMessageComplete];
|
||||
}
|
||||
if (self.voiceChatAudioBuffer.length > 0) {
|
||||
[self playAiAudioData:self.voiceChatAudioBuffer];
|
||||
[self.voiceChatAudioBuffer setLength:0];
|
||||
}
|
||||
self.recordButton.state = KBAiRecordButtonStateNormal;
|
||||
self.statusLabel.text = @"完成";
|
||||
@@ -591,6 +628,40 @@
|
||||
self.transcriptLabel.text = self.deepgramFullText;
|
||||
self.statusLabel.text = @"识别完成";
|
||||
self.recordButton.state = KBAiRecordButtonStateNormal;
|
||||
|
||||
// NSString *finalText = [self.deepgramFullText copy];
|
||||
// if (finalText.length > 0) {
|
||||
// __weak typeof(self) weakSelf = self;
|
||||
// [KBHUD show];
|
||||
// [self.aiVM syncChatWithTranscript:finalText
|
||||
// completion:^(KBAiSyncResponse *_Nullable response,
|
||||
// NSError *_Nullable error) {
|
||||
// __strong typeof(weakSelf) strongSelf = weakSelf;
|
||||
// if (!strongSelf) {
|
||||
// return;
|
||||
// }
|
||||
// dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// [KBHUD dismiss];
|
||||
// if (error) {
|
||||
// [KBHUD showError:error.localizedDescription ?: @"请求失败"];
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// NSString *aiResponse = response.data.aiResponse ?: @"";
|
||||
// if (aiResponse.length > 0) {
|
||||
// NSLog(@"[KBAiMainVC] /chat/sync aiResponse: %@", aiResponse);
|
||||
// }
|
||||
//
|
||||
// NSData *audioData = response.data.audioData;
|
||||
// if (audioData.length > 0) {
|
||||
// NSLog(@"[KBAiMainVC] /chat/sync audio ready, start play");
|
||||
// [strongSelf playAiAudioData:audioData];
|
||||
// } else {
|
||||
// NSLog(@"[KBAiMainVC] /chat/sync audioData empty");
|
||||
// }
|
||||
// });
|
||||
// }];
|
||||
// }
|
||||
}
|
||||
|
||||
- (void)deepgramStreamingManagerDidFail:(NSError *)error {
|
||||
@@ -598,4 +669,42 @@
|
||||
[self showError:error];
|
||||
}
|
||||
|
||||
#pragma mark - Audio Playback
|
||||
|
||||
- (void)playAiAudioData:(NSData *)audioData {
|
||||
if (audioData.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSError *sessionError = nil;
|
||||
AudioSessionManager *audioSession = [AudioSessionManager sharedManager];
|
||||
if (![audioSession configureForPlayback:&sessionError]) {
|
||||
NSLog(@"[KBAiMainVC] Configure playback failed: %@",
|
||||
sessionError.localizedDescription ?: @"");
|
||||
}
|
||||
if (![audioSession activateSession:&sessionError]) {
|
||||
NSLog(@"[KBAiMainVC] Activate playback session failed: %@",
|
||||
sessionError.localizedDescription ?: @"");
|
||||
}
|
||||
|
||||
NSError *error = nil;
|
||||
self.aiAudioPlayer = [[AVAudioPlayer alloc] initWithData:audioData
|
||||
error:&error];
|
||||
if (error || !self.aiAudioPlayer) {
|
||||
NSLog(@"[KBAiMainVC] Audio player init failed: %@",
|
||||
error.localizedDescription ?: @"");
|
||||
return;
|
||||
}
|
||||
self.aiAudioPlayer.delegate = self;
|
||||
[self.aiAudioPlayer prepareToPlay];
|
||||
[self.aiAudioPlayer play];
|
||||
}
|
||||
|
||||
#pragma mark - AVAudioPlayerDelegate
|
||||
|
||||
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player
|
||||
successfully:(BOOL)flag {
|
||||
[[AudioSessionManager sharedManager] deactivateSession];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user