From e39f42a3df2f2106892a242816fc7d111926ead3 Mon Sep 17 00:00:00 2001 From: Chen Li <422043296@qq.com> Date: Fri, 22 Aug 2025 17:35:02 +0800 Subject: [PATCH] merge commit --- .../ai_chat_assistant/MainActivity.java | 12 ++-- lib/screens/part_screen.dart | 11 +++- lib/services/control_recognition_service.dart | 32 ++++----- lib/services/message_service.dart | 66 +++++++++++-------- lib/utils/tts_util.dart | 8 +-- lib/widgets/floating_icon.dart | 1 + 6 files changed, 71 insertions(+), 59 deletions(-) diff --git a/android/app/src/main/java/com/example/ai_chat_assistant/MainActivity.java b/android/app/src/main/java/com/example/ai_chat_assistant/MainActivity.java index d096418..459ec87 100644 --- a/android/app/src/main/java/com/example/ai_chat_assistant/MainActivity.java +++ b/android/app/src/main/java/com/example/ai_chat_assistant/MainActivity.java @@ -68,7 +68,7 @@ public class MainActivity extends FlutterActivity implements INativeNuiCallback .setMethodCallHandler((call, result) -> { Map args = (Map) call.arguments; switch (call.method) { - case "start": + case "startTts": Object isChinese = args.get("isChinese"); if (isChinese == null || isChinese.toString().isBlank()) { return; @@ -76,17 +76,17 @@ public class MainActivity extends FlutterActivity implements INativeNuiCallback boolean isSuccess = startTts(Boolean.parseBoolean(isChinese.toString())); result.success(isSuccess); break; - case "send": + case "sendTts": Object textArg = args.get("text"); if (textArg == null || textArg.toString().isBlank()) { return; } sendTts(textArg.toString()); break; - case "complete": + case "completeTts": completeTts(); break; - case "stop": + case "stopTts": stopTts(); break; default: @@ -97,10 +97,10 @@ public class MainActivity extends FlutterActivity implements INativeNuiCallback asrMethodChannel = new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), ASR_CHANNEL); asrMethodChannel.setMethodCallHandler((call, result) -> { switch (call.method) { - case "start": + case "startAsr": startAsr(); break; - case "stop": + case "stopAsr": stopAsr(); break; default: diff --git a/lib/screens/part_screen.dart b/lib/screens/part_screen.dart index 40d8b89..981e7cd 100644 --- a/lib/screens/part_screen.dart +++ b/lib/screens/part_screen.dart @@ -18,6 +18,7 @@ class PartScreen extends StatefulWidget { class _PartScreenState extends State { final ScrollController _scrollController = ScrollController(); bool _isInitialized = false; + int _lastMessageCount = 0; @override void initState() { @@ -97,9 +98,13 @@ class _PartScreenState extends State { alignment: Alignment.bottomCenter, child: Consumer( builder: (context, messageService, child) { - WidgetsBinding.instance.addPostFrameCallback((_) { - _scrollToBottom(); - }); + final messageCount = messageService.messages.length; + if (messageCount > _lastMessageCount) { + WidgetsBinding.instance.addPostFrameCallback((_) { + _scrollToBottom(); + }); + } + _lastMessageCount = messageCount; return Container( width: chatWidth, constraints: BoxConstraints( diff --git a/lib/services/control_recognition_service.dart b/lib/services/control_recognition_service.dart index 653ccab..f8a27b1 100644 --- a/lib/services/control_recognition_service.dart +++ b/lib/services/control_recognition_service.dart @@ -9,8 +9,7 @@ class VehicleCommandService { Future getCommandFromText(String text) async { try { - final uri = Uri.parse( - 'http://143.64.185.20:18606/control'); + final uri = Uri.parse('http://143.64.185.20:18606/control'); final response = await http.post( uri, @@ -24,9 +23,9 @@ class VehicleCommandService { final commandList = decoded['commands']; List vehicleCommandList = (commandList as List) .map((item) => VehicleCommand.fromString( - item['command'] as String, - item['params'] as Map?, - item['error'] ?? '')) + item['command'] as String, + item['params'] as Map?, + item['error'] ?? '')) .toList(); return VehicleCommandResponse(tips: tips, commands: vehicleCommandList); } else { @@ -40,30 +39,23 @@ class VehicleCommandService { } } - // 执行车辆控制命令的方法 - Future executeCommand(VehicleCommand command) async { + Future getControlResponse(List successCommandList) async { + String reply = ""; try { - final uri = Uri.parse('http://143.64.185.20:18607/executeCommand'); - + final uri = Uri.parse('http://143.64.185.20:18606/control_resp'); final response = await http.post( uri, headers: {'Content-Type': 'application/json'}, - body: json.encode({ - 'command': command.commandString, // 使用getter转换为字符串 - 'params': command.params, - }), + body: json.encode(successCommandList), ); - if (response.statusCode == 200) { - print('命令执行成功: ${command.commandString}'); - return true; + return response.body; } else { - print('命令执行失败: ${response.statusCode}, ${response.body}'); - return false; + print("请求控制回复失败: ${response.statusCode}"); } } catch (e) { - print('命令执行出错: $e'); - return false; + print('请求控制回复异常: $e'); } + return reply; } } diff --git a/lib/services/message_service.dart b/lib/services/message_service.dart index a4454dd..a31058f 100644 --- a/lib/services/message_service.dart +++ b/lib/services/message_service.dart @@ -33,7 +33,10 @@ class MessageService extends ChangeNotifier { _asrChannel.setMethodCallHandler((call) async { switch (call.method) { case "onAsrResult": - replaceMessage(id: _latestUserMessageId!, text: call.arguments); + replaceMessage( + id: _latestUserMessageId!, + text: call.arguments, + status: MessageStatus.normal); break; case "onAsrStop": int index = findMessageIndexById(_latestUserMessageId!); @@ -45,8 +48,6 @@ class MessageService extends ChangeNotifier { removeMessageById(_latestUserMessageId!); return; } - replaceMessage( - id: _latestUserMessageId!, status: MessageStatus.normal); if (_asrCompleter != null && !_asrCompleter!.isCompleted) { _asrCompleter!.complete(messages.last.text); } @@ -60,7 +61,7 @@ class MessageService extends ChangeNotifier { // final AudioRecorderService _audioService = AudioRecorderService(); // final VoiceRecognitionService _recognitionService = VoiceRecognitionService(); final TextClassificationService _classificationService = - TextClassificationService(); + TextClassificationService(); final VehicleCommandService _vehicleCommandService = VehicleCommandService(); final List _messages = []; @@ -107,9 +108,8 @@ class MessageService extends ChangeNotifier { _latestAssistantMessageId = null; _isReplyAborted = false; changeState(MessageServiceState.recording); - addMessage("", true, MessageStatus.listening); - _latestUserMessageId = messages.last.id; - _asrChannel.invokeMethod("start"); + _latestUserMessageId = addMessage("", true, MessageStatus.listening); + _asrChannel.invokeMethod("startAsr"); } catch (e) { print('录音开始出错: $e'); } @@ -120,14 +120,16 @@ class MessageService extends ChangeNotifier { notifyListeners(); } - void addMessage(String text, bool isUser, MessageStatus status) { + String addMessage(String text, bool isUser, MessageStatus status) { + String uuid = Uuid().v1(); _messages.add(ChatMessage( - id: Uuid().v1(), + id: uuid, text: text, isUser: isUser, timestamp: DateTime.now(), status: status)); notifyListeners(); + return uuid; } Future stopAndProcessVoiceInput() async { @@ -137,7 +139,7 @@ class MessageService extends ChangeNotifier { } try { changeState(MessageServiceState.recognizing); - _asrChannel.invokeMethod("stop"); + _asrChannel.invokeMethod("stopAsr"); _asrCompleter = Completer(); final recognizedText = await _asrCompleter!.future; // final audioData = await _audioService.stopRecording(); @@ -194,8 +196,7 @@ class MessageService extends ChangeNotifier { } Future reply(String text) async { - addMessage("", false, MessageStatus.thinking); - _latestAssistantMessageId = messages.last.id; + _latestAssistantMessageId = addMessage("", false, MessageStatus.thinking); bool isChinese = CommonUtil.containChinese(text); try { if (_isReplyAborted) { @@ -226,7 +227,7 @@ class MessageService extends ChangeNotifier { return; } final vehicleCommandResponse = - await _vehicleCommandService.getCommandFromText(text); + await _vehicleCommandService.getCommandFromText(text); if (vehicleCommandResponse == null) { if (_isReplyAborted) { return; @@ -249,9 +250,11 @@ class MessageService extends ChangeNotifier { if (!_isReplyAborted) { if (await TtsUtil.start(isChinese) == true) { TtsUtil.send(vehicleCommandResponse.tips!); + Future.delayed(const Duration(milliseconds: 300), () => TtsUtil.complete()); } } bool containOpenAC = false; + List successCommandList = []; for (var command in vehicleCommandResponse.commands) { if (_isReplyAborted) { return; @@ -263,11 +266,15 @@ class MessageService extends ChangeNotifier { if (command.type == VehicleCommandType.openAC) { containOpenAC = true; } + bool isSuccess; if (containOpenAC && command.type == VehicleCommandType.changeACTemp) { - await Future.delayed(const Duration(milliseconds: 2000), - () => processCommand(command, isChinese)); + isSuccess = await Future.delayed(const Duration(milliseconds: 2000), + () => processCommand(command, isChinese)); } else { - await processCommand(command, isChinese); + isSuccess = await processCommand(command, isChinese); + } + if (isSuccess) { + successCommandList.add(command.type.name); } } replaceMessage( @@ -275,12 +282,21 @@ class MessageService extends ChangeNotifier { text: vehicleCommandResponse.tips!, status: MessageStatus.normal); notifyListeners(); + if (_isReplyAborted || successCommandList.isEmpty) { + return; + } + String controlResponse = + await _vehicleCommandService.getControlResponse(successCommandList); + if (_isReplyAborted || controlResponse.isEmpty) { + return; + } + addMessage(controlResponse, false, MessageStatus.normal); } } - Future processCommand(VehicleCommand command, bool isChinese) async { - String msg; - MessageStatus status; + Future processCommand(VehicleCommand command, bool isChinese) async { + String msg = ""; + MessageStatus status = MessageStatus.normal; final (isSuccess, result) = await CommandService.executeCommand( command.type, params: command.params); @@ -299,19 +315,17 @@ class MessageService extends ChangeNotifier { } } } else { - if (isSuccess) { - msg = isChinese - ? "为您执行\"${command.type.chinese}\"成功" - : "Execute \"${command.type.english}\" successful"; - status = MessageStatus.success; - } else { + if (!isSuccess) { msg = isChinese ? "很抱歉,\"${command.type.chinese}\"失败" : "Sorry, execute \"${command.type.english}\" unsuccessfully"; status = MessageStatus.failure; } } - addMessage(msg, false, status); + if (msg.isNotEmpty) { + addMessage(msg, false, status); + } + return isSuccess; } Future answerWrongQuestion(bool isChinese) async { diff --git a/lib/utils/tts_util.dart b/lib/utils/tts_util.dart index e8862aa..165577a 100644 --- a/lib/utils/tts_util.dart +++ b/lib/utils/tts_util.dart @@ -10,18 +10,18 @@ class TtsUtil { } static Future start(bool isChinese) async { - return await execute('start', {'isChinese': isChinese}); + return await execute('startTts', {'isChinese': isChinese}); } static Future send(String text) async { - await execute('send', {'text': text}); + await execute('sendTts', {'text': text}); } static Future complete() async { - await execute('complete'); + await execute('completeTts'); } static Future stop() async { - await execute('stop'); + await execute('stopTts'); } } diff --git a/lib/widgets/floating_icon.dart b/lib/widgets/floating_icon.dart index a091b22..ce774cc 100644 --- a/lib/widgets/floating_icon.dart +++ b/lib/widgets/floating_icon.dart @@ -70,6 +70,7 @@ class _FloatingIconState extends State } void _showFullScreen() async { + _hidePartScreen(); await Navigator.of(context).push( MaterialPageRoute( builder: (context) => const FullScreen(),