Browse Source

add

newdev_shunjiawei
wolfplus 2 years ago
parent
commit
a35a97b97d
  1. 437
      lib/modules/chat/controllers/chat_controller.dart

437
lib/modules/chat/controllers/chat_controller.dart

@ -34,8 +34,6 @@ class ChatController extends GetxController {
// 用于存储当前正在流式生成的消息 // 用于存储当前正在流式生成的消息
final RxString currentStreamMessage = ''.obs; final RxString currentStreamMessage = ''.obs;
Message? _currentAssistantMessage; Message? _currentAssistantMessage;
String _pendingTtsText = '';
static const int _minTtsLength = 20;
bool _isDisposed = false; bool _isDisposed = false;
// TTS事件订阅 // TTS事件订阅
@ -71,18 +69,6 @@ class ChatController extends GetxController {
isVoiceMode.value = !isVoiceMode.value; isVoiceMode.value = !isVoiceMode.value;
} }
// 辅助方法:管理TTS状态
void _manageTtsState(bool enable) {
if (!enable && isTtsEnabled.value) {
// 需要禁用TTS
_ttsService.endSession(); // 先停止当前播放
isTtsEnabled.value = false;
} else if (enable && !isTtsEnabled.value) {
// 需要启用TTS
isTtsEnabled.value = true;
}
}
// 开始语音输入 // 开始语音输入
void startVoiceInput() { void startVoiceInput() {
// 确保先停止任何可能正在进行的语音识别会话 // 确保先停止任何可能正在进行的语音识别会话
@ -154,38 +140,38 @@ class ChatController extends GetxController {
} }
void stopVoiceInput() { void stopVoiceInput() {
// 确保停止语音识别 // 停止语音识别
if (Get.isRegistered<VoiceInputController>()) { if (Get.isRegistered<VoiceInputController>()) {
try { try {
final voiceController = Get.find<VoiceInputController>(); Get.find<VoiceInputController>().stopRecording();
voiceController.stopRecording(); Get.delete<VoiceInputController>();
} catch (e) { } catch (e) {
debugPrint('Error stopping voice recording: $e'); debugPrint('停止语音输入失败: $e');
} }
} }
// 重置状态
isVoiceInputVisible.value = false; isVoiceInputVisible.value = false;
isVoiceConnecting.value = true; isVoiceConnecting.value = true;
isRecording.value = false; isRecording.value = false;
recordingText.value = ''; recordingText.value = '';
isRecognizing.value = false; isRecognizing.value = false;
// 不再需要恢复TTS状态,因为已启用回声消除 // 清理临时语音消息
// 如果存在临时语音消息但没有实际内容,则移除它
if (_currentVoiceMessage != null && (_currentVoiceMessage!.content == '🎤 ...' || _currentVoiceMessage!.content.startsWith('🎤 '))) { if (_currentVoiceMessage != null && (_currentVoiceMessage!.content == '🎤 ...' || _currentVoiceMessage!.content.startsWith('🎤 '))) {
messages.remove(_currentVoiceMessage); messages.remove(_currentVoiceMessage);
} }
_currentVoiceMessage = null; _currentVoiceMessage = null;
// 当语音面板关闭时,确保ListView滚动回适当位置 // 滚动到底部
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
if (!_isDisposed && scrollController.hasClients && messages.isNotEmpty) { if (!_isDisposed && messages.isNotEmpty) {
// 滚动到底部,确保最新消息可见
_scrollToBottom(animate: true); _scrollToBottom(animate: true);
} }
}); });
// 重置按住说话状态
// 删除语音输入控制器 // 删除语音输入控制器
try { try {
if (Get.isRegistered<VoiceInputController>()) { if (Get.isRegistered<VoiceInputController>()) {
@ -200,7 +186,8 @@ class ChatController extends GetxController {
} }
void handleRecognizing(String text) { void handleRecognizing(String text) {
if (text.isNotEmpty) { if (text.isEmpty) return;
// 更新识别中的文本 // 更新识别中的文本
recordingText.value = text; recordingText.value = text;
@ -208,7 +195,7 @@ class ChatController extends GetxController {
if (_currentVoiceMessage == null) { if (_currentVoiceMessage == null) {
_currentVoiceMessage = Message( _currentVoiceMessage = Message(
role: 'user', role: 'user',
content: '🎤 ' + text, content: '🎤 $text',
timestamp: DateTime.now(), timestamp: DateTime.now(),
); );
messages.add(_currentVoiceMessage!); messages.add(_currentVoiceMessage!);
@ -225,7 +212,7 @@ class ChatController extends GetxController {
if (index != -1) { if (index != -1) {
messages[index] = Message( messages[index] = Message(
role: 'user', role: 'user',
content: '🎤 ' + text, content: '🎤 $text',
timestamp: _currentVoiceMessage!.timestamp, timestamp: _currentVoiceMessage!.timestamp,
); );
@ -234,11 +221,13 @@ class ChatController extends GetxController {
} }
} }
} }
}
void handleVoiceResult(String text) { void handleVoiceResult(String text) {
if (text.isNotEmpty) { if (text.isEmpty) return;
// 如果有临时语音消息,更新它
Message userMessage;
// 处理现有的临时语音消息
if (_currentVoiceMessage != null) { if (_currentVoiceMessage != null) {
final index = messages.indexWhere((msg) => final index = messages.indexWhere((msg) =>
msg.timestamp == _currentVoiceMessage!.timestamp && msg.timestamp == _currentVoiceMessage!.timestamp &&
@ -246,38 +235,30 @@ class ChatController extends GetxController {
if (index != -1) { if (index != -1) {
// 更新消息,移除麦克风图标 // 更新消息,移除麦克风图标
messages[index] = Message( userMessage = Message(
role: 'user', role: 'user',
content: text, content: text,
timestamp: _currentVoiceMessage!.timestamp, timestamp: _currentVoiceMessage!.timestamp,
); );
messages[index] = userMessage;
// 保存聊天历史 } else {
_saveChatHistory(); // 创建新消息
userMessage = Message(
// 滚动到底部 role: 'user',
_scrollToBottom(animate: true); content: text,
timestamp: DateTime.now(),
// 重新启用TTS,以便AI回复时可以播放 );
_manageTtsState(true); messages.add(userMessage);
// 发送给AI处理
_processAIResponse(messages[index]);
// 重置临时语音消息
_currentVoiceMessage = null;
isRecognizing.value = false;
} }
} else { } else {
// 如果没有临时语音消息,创建一个新的用户消息 // 创建新消息
final userMessage = Message( userMessage = Message(
role: 'user', role: 'user',
content: text, content: text,
timestamp: DateTime.now(), timestamp: DateTime.now(),
); );
// 添加到消息列表
messages.add(userMessage); messages.add(userMessage);
}
// 保存聊天历史 // 保存聊天历史
_saveChatHistory(); _saveChatHistory();
@ -285,22 +266,26 @@ class ChatController extends GetxController {
// 滚动到底部 // 滚动到底部
_scrollToBottom(animate: true); _scrollToBottom(animate: true);
// 重新启用TTS,以便AI回复时可以播放 // 重置状态
_manageTtsState(true); _currentVoiceMessage = null;
isRecognizing.value = false;
// 发送给AI处理 // 处理AI响应
_processAIResponse(userMessage); _processAIResponse(userMessage);
} }
}
}
// 处理AI响应 // 处理AI响应
Future<void> _processAIResponse(Message userMessage) async { Future<void> _processAIResponse(Message userMessage) async {
if (_isDisposed) return; if (_isDisposed) return;
// TTS会话状态
bool ttsSessionStarted = false;
const speaker = 'zh_female_shuangkuaisisi_moon_bigtts';
try { try {
isLoading.value = true; isLoading.value = true;
// 创建助手消息
currentStreamMessage.value = ''; currentStreamMessage.value = '';
_currentAssistantMessage = Message( _currentAssistantMessage = Message(
role: 'assistant', role: 'assistant',
@ -308,75 +293,60 @@ class ChatController extends GetxController {
timestamp: DateTime.now(), timestamp: DateTime.now(),
); );
messages.add(_currentAssistantMessage!); messages.add(_currentAssistantMessage!);
_pendingTtsText = '';
// 确保在开始新的合成前停止当前播放 // 准备TTS会话
if (isTtsEnabled.value) { if (isTtsEnabled.value) {
await _ttsService.endSession(); await _ttsService.endSession();
// 添加短暂延迟确保停止完成
await Future.delayed(const Duration(milliseconds: 200)); if (!_ttsService.isConnected.value) {
await _ttsService.connect();
} }
ttsSessionStarted = await _ttsService.startSession(speaker);
}
// 处理AI流式响应
await for (final chunk in _aiService.sendMessageStream( await for (final chunk in _aiService.sendMessageStream(
messages: messages messages: messages.map((m) => {'role': m.role, 'content': m.content}).toList(),
.map((m) => {
'role': m.role,
'content': m.content,
})
.toList(),
systemPrompt: systemPrompt, systemPrompt: systemPrompt,
)) { )) {
if (_isDisposed) break; if (_isDisposed) break;
// 更新UI
currentStreamMessage.value += chunk; currentStreamMessage.value += chunk;
_updateAssistantMessage(currentStreamMessage.value); _updateAssistantMessage(currentStreamMessage.value);
// 累积文本并合成 // 直接将文本片段发送到TTS接口
_pendingTtsText += chunk; if (isTtsEnabled.value && ttsSessionStarted && chunk.isNotEmpty) {
if (!_isDisposed && isTtsEnabled.value) { await _ttsService.speak(chunk, speaker: speaker);
// 检查是否达到最小长度
if (_pendingTtsText.length >= _minTtsLength) {
// 找到最后一个句子结束的位置
int lastSentenceEnd = _findLastSentenceEnd(_pendingTtsText);
if (lastSentenceEnd > 0) {
// 播放到最后一个句子结束的位置
String textToSpeak =
_pendingTtsText.substring(0, lastSentenceEnd + 1);
// 使用新方法替代直接调用speak
_speakText(textToSpeak);
// 保留剩余的文本
_pendingTtsText = _pendingTtsText.substring(lastSentenceEnd + 1);
}
}
} }
} }
// 处理剩余的文本 // 结束TTS会话
if (!_isDisposed && if (isTtsEnabled.value && ttsSessionStarted) {
isTtsEnabled.value && await _ttsService.endSession();
_pendingTtsText.isNotEmpty) {
// 使用新方法替代直接调用speak
_speakText(_pendingTtsText);
} }
_pendingTtsText = '';
// 保存聊天历史
if (!_isDisposed) { if (!_isDisposed) {
await _saveChatHistory(); await _saveChatHistory();
} }
} catch (e) { } catch (e) {
// 错误处理
if (!_isDisposed) { if (!_isDisposed) {
if (_currentAssistantMessage != null) { if (_currentAssistantMessage != null) {
messages.remove(_currentAssistantMessage); messages.remove(_currentAssistantMessage);
} }
Get.snackbar(
'Error', Get.snackbar('Error', 'Failed to get response from AI', snackPosition: SnackPosition.BOTTOM);
'Failed to get response from AI: $e',
snackPosition: SnackPosition.BOTTOM, // 结束TTS会话
); if (isTtsEnabled.value && ttsSessionStarted) {
await _ttsService.endSession();
}
} }
} finally { } finally {
// 重置状态
if (!_isDisposed) { if (!_isDisposed) {
_currentAssistantMessage = null; _currentAssistantMessage = null;
currentStreamMessage.value = ''; currentStreamMessage.value = '';
@ -385,48 +355,36 @@ class ChatController extends GetxController {
} }
} }
// 播放文本并使用WebSocket流式合成 // 播放文本(用于独立播放场景)
Future<void> _speakText(String text) async { Future<void> _speakText(String text) async {
if (text.isEmpty || !isTtsEnabled.value) return; if (text.isEmpty || !isTtsEnabled.value) return;
try { try {
// 如果当前有正在进行的TTS会话,先结束它
if (_isTtsSpeaking) {
await _ttsService.endSession();
}
// 确保连接已建立
if (!_ttsService.isConnected.value) { if (!_ttsService.isConnected.value) {
final connected = await _ttsService.connect(); await _ttsService.connect();
if (!connected) {
print('无法连接到TTS服务');
return;
}
} }
// 开始合成 const speaker = 'zh_female_shuangkuaisisi_moon_bigtts';
await _ttsService.synthesize(text, 'zh_female_1'); // 使用默认说话人
await _ttsService.startSession(speaker);
await _ttsService.speak(text, speaker: speaker);
await _ttsService.endSession();
} catch (e) { } catch (e) {
print('TTS播放出错: $e'); debugPrint('TTS播放出错: $e');
await _ttsService.endSession();
} }
} }
// 确保滚动到底部的方法,使用多种策略确保成功 // 确保滚动到底部
void _ensureScrollToBottom() { void _ensureScrollToBottom() {
// 立即尝试滚动
_scrollToBottom(); _scrollToBottom();
// 延迟100ms后再次尝试滚动(等待视图构建) // 延迟滚动以确保视图已构建
Future.delayed(const Duration(milliseconds: 100), () { Future.delayed(const Duration(milliseconds: 100), () {
if (!_isDisposed) _scrollToBottom(animate: true); if (!_isDisposed) _scrollToBottom(animate: true);
}); });
// 延迟500ms后再次尝试滚动(确保所有元素都已加载) // 帧回调确保在渲染后滚动
Future.delayed(const Duration(milliseconds: 500), () {
if (!_isDisposed) _scrollToBottom(animate: true);
});
// 使用帧回调确保在渲染后滚动
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
if (!_isDisposed) _scrollToBottom(animate: true); if (!_isDisposed) _scrollToBottom(animate: true);
}); });
@ -450,17 +408,17 @@ class ChatController extends GetxController {
messageController = TextEditingController(); messageController = TextEditingController();
scrollController = ScrollController(); scrollController = ScrollController();
// 确保清理任何可能存在的语音输入控制器 // 清理可能存在的语音输入控制器
if (Get.isRegistered<VoiceInputController>()) { if (Get.isRegistered<VoiceInputController>()) {
try { try {
final voiceController = Get.find<VoiceInputController>(); Get.find<VoiceInputController>().stopRecording();
voiceController.stopRecording();
Get.delete<VoiceInputController>(); Get.delete<VoiceInputController>();
} catch (e) { } catch (e) {
debugPrint('Error cleaning up existing VoiceInputController: $e'); debugPrint('清理语音控制器失败: $e');
} }
} }
// 初始化服务和数据
_initTtsService(); _initTtsService();
_initFromArguments(); _initFromArguments();
_initializeController(); _initializeController();
@ -468,18 +426,8 @@ class ChatController extends GetxController {
// 添加滚动监听器 // 添加滚动监听器
scrollController.addListener(_scrollListener); scrollController.addListener(_scrollListener);
// 确保在页面加载完成后滚动到底部 // 确保滚动到底部
_ensureScrollToBottom(); _ensureScrollToBottom();
// 添加帧回调,确保在页面完全渲染后滚动到底部
WidgetsBinding.instance.addPostFrameCallback((_) {
// 延迟执行,确保页面已完全加载
Future.delayed(const Duration(milliseconds: 300), () {
if (!_isDisposed) {
_scrollToBottom(animate: true);
}
});
});
} }
void _initFromArguments() { void _initFromArguments() {
@ -527,21 +475,24 @@ class ChatController extends GetxController {
void _handleTtsEvent(Map<String, dynamic> event) { void _handleTtsEvent(Map<String, dynamic> event) {
if (_isDisposed) return; if (_isDisposed) return;
final String eventType = event['type'] as String? ?? 'unknown'; final String eventType = event['eventType'] as String? ?? 'unknown';
// 根据事件类型更新TTS状态
switch (eventType) { switch (eventType) {
case 'ttsSentenceStart': case 'ttsSentenceStart':
case 'playbackStarted':
case 'synthesisBegin':
_isTtsSpeaking = true; _isTtsSpeaking = true;
break; break;
case 'ttsSentenceEnd': case 'ttsSentenceEnd':
case 'playbackCompleted':
case 'synthesisEnd':
case 'sessionFinished': case 'sessionFinished':
case 'connectionFinished': case 'connectionFinished':
_isTtsSpeaking = false;
break;
case 'connectionFailed': case 'connectionFailed':
case 'sessionFailed': case 'sessionFailed':
case 'playbackError':
_isTtsSpeaking = false; _isTtsSpeaking = false;
print('TTS错误: ${event['message']}');
break; break;
} }
} }
@ -561,44 +512,40 @@ class ChatController extends GetxController {
} }
Future<void> _showWelcomeMessages() async { Future<void> _showWelcomeMessages() async {
if (!agentName.isNotEmpty || !playVoiceOnEnter) return;
try { try {
if (agentName.isNotEmpty && playVoiceOnEnter) { // 生成动态问候语
// 只有 playVoiceOnEnter 为 true 时才生成动态问候语
await _generatePersonalizedGreeting(); await _generatePersonalizedGreeting();
// 保存聊天记录并立即滚动到底部
await _saveChatHistory(); await _saveChatHistory();
_scrollToBottom(animate: true); _scrollToBottom(animate: true);
// 添加一个系统消息,告知用户已启用连续语音对话 // 添加系统消息
final systemMessage = Message( messages.add(Message(
role: 'system', role: 'system',
content: '已为您自动启用连续语音对话模式,您可以直接开始说话', content: '已为您自动启用连续语音对话模式,您可以直接开始说话',
timestamp: DateTime.now(), timestamp: DateTime.now(),
); ));
messages.add(systemMessage);
await _saveChatHistory(); await _saveChatHistory();
// 延迟一小段时间后自动启动语音输入模式 // 启动语音输入
Future.delayed(const Duration(milliseconds: 500), () { Future.delayed(const Duration(milliseconds: 300), () {
if (!_isDisposed) { if (!_isDisposed) {
startVoiceInput(); startVoiceInput();
} }
}); });
}
} catch (e) { } catch (e) {
print('显示欢迎消息失败: $e'); debugPrint('显示欢迎消息失败: $e');
// 如果生成问候语失败,确保至少显示静态欢迎消息
// 播放静态欢迎消息
if (isTtsEnabled.value) { if (isTtsEnabled.value) {
// 使用新方法替代直接调用speak
_speakText(welcomeMessage); _speakText(welcomeMessage);
} }
// 即使问候语生成失败,如果playVoiceOnEnter为true,仍然启动语音输入 // 仍然启动语音输入
if (playVoiceOnEnter) {
Future.delayed(const Duration(milliseconds: 500), () {
if (!_isDisposed) { if (!_isDisposed) {
Future.delayed(const Duration(milliseconds: 300), () {
startVoiceInput(); startVoiceInput();
}
}); });
} }
} }
@ -607,8 +554,8 @@ class ChatController extends GetxController {
Future<void> _generatePersonalizedGreeting() async { Future<void> _generatePersonalizedGreeting() async {
if (_isDisposed) return; if (_isDisposed) return;
String fullGreeting = '';
try { try {
// 创建助手消息
currentStreamMessage.value = ''; currentStreamMessage.value = '';
_currentAssistantMessage = Message( _currentAssistantMessage = Message(
role: 'assistant', role: 'assistant',
@ -617,15 +564,14 @@ class ChatController extends GetxController {
); );
messages.add(_currentAssistantMessage!); messages.add(_currentAssistantMessage!);
// 构建用于生成个性化问候语的消息列表 // 构建问候语请求
final greetingMessages = [ final greetingMessages = [
{'role': 'system', 'content': systemPrompt}, {'role': 'system', 'content': systemPrompt},
{ {'role': 'user', 'content': '请用一句简短的话向我打个招呼,要体现你的特点,不要超过18个字。'},
'role': 'user',
'content': '请根据你的身份和性格,用一句简短的话向我打个招呼,要体现你的特点,不要超过18个字。'
},
]; ];
// 生成问候语
String fullGreeting = '';
await for (final chunk in _aiService.sendMessageStream( await for (final chunk in _aiService.sendMessageStream(
messages: greetingMessages, messages: greetingMessages,
systemPrompt: systemPrompt, systemPrompt: systemPrompt,
@ -638,14 +584,12 @@ class ChatController extends GetxController {
fullGreeting += chunk; fullGreeting += chunk;
} }
// 完整问候语生成完毕后,一次性播放 // 播放问候语
if (!_isDisposed && isTtsEnabled.value && fullGreeting.isNotEmpty) { if (isTtsEnabled.value && fullGreeting.isNotEmpty) {
// 使用新方法替代直接调用speak
await _speakText(fullGreeting); await _speakText(fullGreeting);
} }
} catch (e) { } catch (e) {
print('生成问候语失败: $e'); debugPrint('生成问候语失败: $e');
// 移除未完成的消息
if (_currentAssistantMessage != null) { if (_currentAssistantMessage != null) {
messages.remove(_currentAssistantMessage); messages.remove(_currentAssistantMessage);
} }
@ -661,38 +605,25 @@ class ChatController extends GetxController {
void onClose() { void onClose() {
_isDisposed = true; _isDisposed = true;
// 确保语音输入被停止 // 停止语音输入和TTS
stopVoiceInput(); stopVoiceInput();
_ttsService.endSession();
// 先停止所有正在进行的操作
_ttsService.endSession(); // 使用endSession替代stop
// 取消TTS事件订阅
_ttsEventSubscription?.cancel(); _ttsEventSubscription?.cancel();
// 重置状态
currentStreamMessage.value = ''; currentStreamMessage.value = '';
_currentAssistantMessage = null; _currentAssistantMessage = null;
_pendingTtsText = '';
// 最后再处理控制器的销毁 // 释放控制器
try {
messageController.dispose(); messageController.dispose();
} catch (e) {
debugPrint('Error disposing messageController: $e');
}
try {
scrollController.dispose(); scrollController.dispose();
} catch (e) {
debugPrint('Error disposing scrollController: $e');
}
super.onClose(); super.onClose();
} }
Future<void> _loadChatHistory() async { Future<void> _loadChatHistory() async {
try { try {
final historyJson = _storage.read('${_storagePrefix}${agentId}'); final historyJson = _storage.read('${_storagePrefix}$agentId');
if (historyJson != null) { if (historyJson != null) {
final List<dynamic> historyList = json.decode(historyJson); final List<dynamic> historyList = json.decode(historyJson);
messages.value = historyList.map((item) => Message.fromJson(item)).toList(); messages.value = historyList.map((item) => Message.fromJson(item)).toList();
@ -716,8 +647,8 @@ class ChatController extends GetxController {
Future<void> _saveChatHistory() async { Future<void> _saveChatHistory() async {
try { try {
final historyJson = final historyJson =
json.encode(messages.map((msg) => msg!.toJson()).toList()); json.encode(messages.map((msg) => msg.toJson()).toList());
await _storage.write('${_storagePrefix}${agentId}', historyJson); await _storage.write('${_storagePrefix}$agentId', historyJson);
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
'Error', 'Error',
@ -728,37 +659,34 @@ class ChatController extends GetxController {
} }
void _scrollToBottom({bool animate = false}) { void _scrollToBottom({bool animate = false}) {
if (scrollController.hasClients) { if (!scrollController.hasClients) return;
final position = scrollController.position.maxScrollExtent;
if (animate) { if (animate) {
scrollController.animateTo( scrollController.animateTo(
scrollController.position.maxScrollExtent, position,
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
curve: Curves.easeOut, curve: Curves.easeOut,
); );
} else { } else {
scrollController.jumpTo(scrollController.position.maxScrollExtent); scrollController.jumpTo(position);
}
} else {
// 如果 scrollController 还没有附加到 ListView,延迟执行
Future.delayed(const Duration(milliseconds: 100), () {
if (!_isDisposed) {
_scrollToBottom(animate: animate);
}
});
} }
} }
void _updateAssistantMessage(String content) { void _updateAssistantMessage(String content) {
if (_currentAssistantMessage != null) { if (_currentAssistantMessage == null) return;
final index = messages.indexWhere((msg) => final index = messages.indexWhere((msg) =>
msg.timestamp == _currentAssistantMessage?.timestamp && msg.timestamp == _currentAssistantMessage?.timestamp &&
msg.role == _currentAssistantMessage?.role); msg.role == _currentAssistantMessage?.role);
if (index != -1) { if (index != -1) {
// 使用非空断言,因为我们已经在方法开始时检查了非空
final timestamp = _currentAssistantMessage!.timestamp;
messages[index] = Message( messages[index] = Message(
role: 'assistant', role: 'assistant',
content: content, content: content,
timestamp: _currentAssistantMessage!.timestamp, timestamp: timestamp,
); );
// 只在非初始化阶段滚动 // 只在非初始化阶段滚动
if (!playVoiceOnEnter || content.isNotEmpty) { if (!playVoiceOnEnter || content.isNotEmpty) {
@ -766,7 +694,6 @@ class ChatController extends GetxController {
} }
} }
} }
}
void clearMessage() { void clearMessage() {
if (!_isDisposed && messageController.text.isNotEmpty) { if (!_isDisposed && messageController.text.isNotEmpty) {
@ -780,7 +707,7 @@ class ChatController extends GetxController {
final text = messageController.text.trim(); final text = messageController.text.trim();
if (text.isEmpty) return; if (text.isEmpty) return;
try { // 创建用户消息
final userMessage = Message( final userMessage = Message(
role: 'user', role: 'user',
content: text, content: text,
@ -791,101 +718,14 @@ class ChatController extends GetxController {
await _saveChatHistory(); await _saveChatHistory();
_scrollToBottom(animate: true); _scrollToBottom(animate: true);
isLoading.value = true; // 处理AI响应
try { await _processAIResponse(userMessage);
currentStreamMessage.value = '';
_currentAssistantMessage = Message(
role: 'assistant',
content: '',
timestamp: DateTime.now(),
);
messages.add(_currentAssistantMessage!);
_pendingTtsText = '';
await for (final chunk in _aiService.sendMessageStream(
messages: messages
.map((m) => {
'role': m.role,
'content': m.content,
})
.toList(),
systemPrompt: systemPrompt,
)) {
if (_isDisposed) break;
currentStreamMessage.value += chunk;
_updateAssistantMessage(currentStreamMessage.value);
// 累积文本并合成
_pendingTtsText += chunk;
if (!_isDisposed && isTtsEnabled.value) {
// 检查是否达到最小长度
if (_pendingTtsText.length >= _minTtsLength) {
// 找到最后一个句子结束的位置
int lastSentenceEnd = _findLastSentenceEnd(_pendingTtsText);
if (lastSentenceEnd > 0) {
// 播放到最后一个句子结束的位置
String textToSpeak =
_pendingTtsText.substring(0, lastSentenceEnd + 1);
// 使用新方法替代直接调用speak
_speakText(textToSpeak);
// 保留剩余的文本
_pendingTtsText = _pendingTtsText.substring(lastSentenceEnd + 1);
}
}
}
}
// 处理剩余的文本
if (!_isDisposed && isTtsEnabled.value && _pendingTtsText.isNotEmpty) {
// 使用新方法替代直接调用speak
_speakText(_pendingTtsText);
}
_pendingTtsText = '';
if (!_isDisposed) {
await _saveChatHistory();
}
} catch (e) {
if (!_isDisposed) {
if (_currentAssistantMessage != null) {
messages.remove(_currentAssistantMessage);
}
Get.snackbar(
'Error',
'Failed to get response from AI: $e',
snackPosition: SnackPosition.BOTTOM,
);
}
} finally {
if (!_isDisposed) {
_currentAssistantMessage = null;
currentStreamMessage.value = '';
isLoading.value = false;
}
}
} catch (e) {
print('发送消息失败: $e');
}
}
int _findLastSentenceEnd(String text) {
final sentenceEnds = [
text.lastIndexOf('。'),
text.lastIndexOf('!'),
text.lastIndexOf('?'),
text.lastIndexOf('.'),
text.lastIndexOf('!'),
text.lastIndexOf('?'),
];
return sentenceEnds.reduce((max, pos) => pos > max ? pos : max);
} }
Future<void> clearChat() async { Future<void> clearChat() async {
try { try {
messages.clear(); messages.clear();
await _storage.remove('${_storagePrefix}${agentId}'); await _storage.remove('${_storagePrefix}$agentId');
await _showWelcomeMessages(); await _showWelcomeMessages();
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
@ -900,7 +740,7 @@ class ChatController extends GetxController {
// 切换TTS启用状态 // 切换TTS启用状态
isTtsEnabled.toggle(); isTtsEnabled.toggle();
if (!isTtsEnabled.value) { if (!isTtsEnabled.value) {
_ttsService.endSession(); // 使用endSession替代stop _ttsService.endSession();
} }
} }
@ -909,6 +749,7 @@ class ChatController extends GetxController {
if (_isDisposed) return; if (_isDisposed) return;
try { try {
// 创建助手消息
currentStreamMessage.value = ''; currentStreamMessage.value = '';
_currentAssistantMessage = Message( _currentAssistantMessage = Message(
role: 'assistant', role: 'assistant',
@ -923,6 +764,7 @@ class ChatController extends GetxController {
{'role': 'user', 'content': '请用一句简短的话向我打个招呼,要体现你的特点,不要超过12个字。'}, {'role': 'user', 'content': '请用一句简短的话向我打个招呼,要体现你的特点,不要超过12个字。'},
]; ];
// 生成问候语
String fullGreeting = ''; String fullGreeting = '';
await for (final chunk in _aiService.sendMessageStream( await for (final chunk in _aiService.sendMessageStream(
messages: greetingMessages, messages: greetingMessages,
@ -936,13 +778,12 @@ class ChatController extends GetxController {
fullGreeting += chunk; fullGreeting += chunk;
} }
// 完整问候语生成完毕后,一次性播放 // 播放问候语
if (!_isDisposed && isTtsEnabled.value && fullGreeting.isNotEmpty) { if (isTtsEnabled.value && fullGreeting.isNotEmpty) {
// 使用新方法替代直接调用speak
await _speakText(fullGreeting); await _speakText(fullGreeting);
} }
} catch (e) { } catch (e) {
print('生成问候语失败: $e'); debugPrint('生成问候语失败: $e');
// 移除未完成的消息 // 移除未完成的消息
if (_currentAssistantMessage != null) { if (_currentAssistantMessage != null) {
messages.remove(_currentAssistantMessage); messages.remove(_currentAssistantMessage);

Loading…
Cancel
Save