This commit is contained in:
2026-01-21 17:25:38 +08:00
parent d1d47336c2
commit 36c0b0b210
10 changed files with 1877 additions and 10 deletions

View File

@@ -11,8 +11,11 @@
#import "KBAiChatView.h"
#import "KBAiRecordButton.h"
#import "LSTPopView.h"
#import "VoiceChatStreamingManager.h"
#import "KBUserSessionManager.h"
@interface KBAiMainVC () <KBAiRecordButtonDelegate>
@interface KBAiMainVC () <KBAiRecordButtonDelegate,
VoiceChatStreamingManagerDelegate>
@property(nonatomic, weak) LSTPopView *popView;
// UI
@@ -28,6 +31,13 @@
//
@property(nonatomic, strong) ConversationOrchestrator *orchestrator;
@property(nonatomic, strong) VoiceChatStreamingManager *streamingManager;
//
@property(nonatomic, strong) NSMutableString *assistantVisibleText;
//
@property(nonatomic, assign) NSTimeInterval lastRMSLogTime;
@end
@@ -44,6 +54,7 @@
[self setupUI];
[self setupOrchestrator];
[self setupStreamingManager];
}
- (void)viewWillAppear:(BOOL)animated {
@@ -56,6 +67,7 @@
//
[self.orchestrator stop];
[self.streamingManager disconnect];
}
- (void)viewDidLayoutSubviews {
@@ -184,11 +196,15 @@
- (void)setupOrchestrator {
self.orchestrator = [[ConversationOrchestrator alloc] init];
// TODO:
// self.orchestrator.asrServerURL = @"wss://your-asr-server.com/ws/asr";
// self.orchestrator.llmServerURL =
// @"https://your-llm-server.com/api/chat/stream";
// self.orchestrator.ttsServerURL = @"https://your-tts-server.com/api/tts";
//
// 1. ASR WebSocket
self.orchestrator.asrServerURL = @"ws://192.168.2.21:7529/ws/asr";
// 2. LLM HTTP Stream
self.orchestrator.llmServerURL = @"http://192.168.2.21:7529/api/chat/stream";
// 3. TTS HTTP
self.orchestrator.ttsServerURL = @"http://192.168.2.21:7529/api/tts/stream";
__weak typeof(self) weakSelf = self;
@@ -278,6 +294,16 @@
};
}
#pragma mark - Streaming Manager
- (void)setupStreamingManager {
self.streamingManager = [[VoiceChatStreamingManager alloc] init];
self.streamingManager.delegate = self;
self.streamingManager.serverURL = @"ws://192.168.2.21:7529/api/ws/chat";
self.assistantVisibleText = [[NSMutableString alloc] init];
self.lastRMSLogTime = 0;
}
#pragma mark -
- (void)showComment {
CGFloat customViewHeight = KB_SCREEN_HEIGHT * (0.8);
@@ -367,16 +393,112 @@
#pragma mark - KBAiRecordButtonDelegate
- (void)recordButtonDidBeginPress:(KBAiRecordButton *)button {
[self.orchestrator userDidPressRecord];
NSLog(@"[KBAiMainVC] Record button began press");
NSString *token = [[KBUserSessionManager shared] accessToken] ?: @"";
if (token.length == 0) {
[[KBUserSessionManager shared] goLoginVC];
return;
}
self.statusLabel.text = @"正在连接...";
self.recordButton.state = KBAiRecordButtonStateRecording;
[self.streamingManager startWithToken:token language:@"en" voiceId:nil];
}
- (void)recordButtonDidEndPress:(KBAiRecordButton *)button {
[self.orchestrator userDidReleaseRecord];
NSLog(@"[KBAiMainVC] Record button end press");
[self.streamingManager stopAndFinalize];
}
- (void)recordButtonDidCancelPress:(KBAiRecordButton *)button {
// releaseASR
[self.orchestrator userDidReleaseRecord];
NSLog(@"[KBAiMainVC] Record button cancel press");
[self.streamingManager cancel];
}
#pragma mark - VoiceChatStreamingManagerDelegate
- (void)voiceChatStreamingManagerDidConnect {
self.statusLabel.text = @"已连接,准备中...";
}
- (void)voiceChatStreamingManagerDidDisconnect:(NSError *_Nullable)error {
self.recordButton.state = KBAiRecordButtonStateNormal;
if (error) {
[self showError:error];
}
}
- (void)voiceChatStreamingManagerDidStartSession:(NSString *)sessionId {
self.statusLabel.text = @"正在聆听...";
self.recordButton.state = KBAiRecordButtonStateRecording;
}
- (void)voiceChatStreamingManagerDidStartTurn:(NSInteger)turnIndex {
self.statusLabel.text = @"正在聆听...";
self.recordButton.state = KBAiRecordButtonStateRecording;
}
- (void)voiceChatStreamingManagerDidReceiveEagerEndOfTurnWithTranscript:(NSString *)text
confidence:(double)confidence {
self.statusLabel.text = @"准备响应...";
}
- (void)voiceChatStreamingManagerDidResumeTurn {
self.statusLabel.text = @"正在聆听...";
}
- (void)voiceChatStreamingManagerDidUpdateRMS:(float)rms {
[self.recordButton updateVolumeRMS:rms];
NSTimeInterval now = [[NSDate date] timeIntervalSince1970];
if (now - self.lastRMSLogTime >= 1.0) {
self.lastRMSLogTime = now;
NSLog(@"[KBAiMainVC] RMS: %.3f", rms);
}
}
- (void)voiceChatStreamingManagerDidReceiveInterimTranscript:(NSString *)text {
self.statusLabel.text = text.length > 0 ? text : @"正在识别...";
}
- (void)voiceChatStreamingManagerDidReceiveFinalTranscript:(NSString *)text {
if (text.length > 0) {
[self.chatView addUserMessage:text];
}
}
- (void)voiceChatStreamingManagerDidReceiveLLMStart {
self.statusLabel.text = @"AI 正在思考...";
[self.assistantVisibleText setString:@""];
[self.chatView addAssistantMessage:@""];
}
- (void)voiceChatStreamingManagerDidReceiveLLMToken:(NSString *)token {
if (token.length == 0) {
return;
}
[self.assistantVisibleText appendString:token];
[self.chatView updateLastAssistantMessage:self.assistantVisibleText];
}
- (void)voiceChatStreamingManagerDidReceiveAudioChunk:(NSData *)audioData {
}
- (void)voiceChatStreamingManagerDidCompleteWithTranscript:(NSString *)transcript
aiResponse:(NSString *)aiResponse {
NSString *finalText = aiResponse.length > 0 ? aiResponse
: self.assistantVisibleText;
if (finalText.length > 0) {
[self.chatView updateLastAssistantMessage:finalText];
[self.chatView markLastAssistantMessageComplete];
}
self.recordButton.state = KBAiRecordButtonStateNormal;
self.statusLabel.text = @"完成";
}
- (void)voiceChatStreamingManagerDidFail:(NSError *)error {
self.recordButton.state = KBAiRecordButtonStateNormal;
[self showError:error];
}
@end