feat: 修复了插件需要外部Provider的问题;加上了一个简易的车控状态返回

This commit is contained in:
2025-09-18 15:53:39 +08:00
parent 922818f39f
commit b84899ece3
16 changed files with 404 additions and 87 deletions

View File

@@ -5,7 +5,7 @@ import '../models/vehicle_status_info.dart';
typedef CommandCallback = Future<(bool, Map<String, dynamic>? params)> Function(
VehicleCommandType type, Map<String, dynamic>? params);
/// 命令处理器类 - 负责处理来自AI的车辆控制命令
/// 命令处理器类 - 负责处理来自AI的车辆控制命令(使用回调的方式交给App去实现具体的车控逻辑)
class CommandService {
/// 保存主应用注册的回调函数
static CommandCallback? onCommandReceived;

View File

@@ -4,6 +4,7 @@ import '../models/vehicle_cmd.dart';
import '../models/vehicle_cmd_response.dart';
import 'vehicle_state_service.dart';
/// 车辆命令服务 - 负责与后端交互以获取和处理车辆控制命令
class VehicleCommandService {
// final VehicleStateService vehicleStateService = VehicleStateService();

View File

@@ -1,5 +1,6 @@
import 'dart:async';
import 'package:ai_chat_assistant/ai_chat_assistant.dart';
import 'package:ai_chat_assistant/utils/common_util.dart';
import 'package:ai_chat_assistant/utils/tts_util.dart';
import 'package:basic_intl/intl.dart';
@@ -7,11 +8,6 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:uuid/uuid.dart';
import '../enums/vehicle_command_type.dart';
import '../enums/message_service_state.dart';
import '../enums/message_status.dart';
import '../models/chat_message.dart';
import '../models/vehicle_cmd.dart';
import '../services/chat_sse_service.dart';
import '../services/classification_service.dart';
import '../services/control_recognition_service.dart';
@@ -20,48 +16,72 @@ import '../services/control_recognition_service.dart';
import 'command_service.dart';
import 'package:fluttertoast/fluttertoast.dart';
// 用单例的模式创建
class MessageService extends ChangeNotifier {
static const MethodChannel _asrChannel = MethodChannel('com.example.ai_chat_assistant/ali_sdk');
static final MessageService _instance = MessageService._internal();
static MessageService? _instance;
factory MessageService() => _instance;
static MessageService get instance {
return _instance ??= MessageService._internal();
}
// 提供工厂构造函数供 Provider 使用
factory MessageService() => instance;
Completer<String>? _asrCompleter;
MessageService._internal() {
_asrChannel.setMethodCallHandler((call) async {
switch (call.method) {
case "onAsrResult":
replaceMessage(
id: _latestUserMessageId!,
text: call.arguments,
status: MessageStatus.normal);
break;
case "onAsrStop":
int index = findMessageIndexById(_latestUserMessageId!);
if (index == -1) {
return;
}
final message = _messages[index];
if (message.text.isEmpty) {
removeMessageById(_latestUserMessageId!);
return;
}
if (_asrCompleter != null && !_asrCompleter!.isCompleted) {
_asrCompleter!.complete(messages.last.text);
}
break;
}
});
// 注册MethodChannel的handler
_asrChannel.setMethodCallHandler(_handleMethodCall);
}
@override
void dispose() {
// 取消注册MethodChannel的handler避免内存泄漏和意外回调
_asrChannel.setMethodCallHandler(null);
_asrCompleter?.completeError('Disposed');
_asrCompleter = null;
super.dispose();
}
// 提供真正的销毁方法(可选,用于应用退出时)
void destroyInstance() {
_asrChannel.setMethodCallHandler(null);
_asrCompleter?.completeError('Destroyed');
_asrCompleter = null;
super.dispose();
_instance = null;
}
Future<dynamic> _handleMethodCall(MethodCall call) async {
switch (call.method) {
case "onAsrResult":
replaceMessage(
id: _latestUserMessageId!, text: call.arguments, status: MessageStatus.normal);
break;
case "onAsrStop":
int index = findMessageIndexById(_latestUserMessageId!);
if (index == -1) {
return;
}
final message = _messages[index];
if (message.text.isEmpty) {
removeMessageById(_latestUserMessageId!);
return;
}
if (_asrCompleter != null && !_asrCompleter!.isCompleted) {
_asrCompleter!.complete(messages.last.text);
}
break;
}
}
final ChatSseService _chatSseService = ChatSseService();
// final LocalTtsService _ttsService = LocalTtsService();
// final AudioRecorderService _audioService = AudioRecorderService();
// final VoiceRecognitionService _recognitionService = VoiceRecognitionService();
final TextClassificationService _classificationService =
TextClassificationService();
final TextClassificationService _classificationService = TextClassificationService();
final VehicleCommandService _vehicleCommandService = VehicleCommandService();
final List<ChatMessage> _messages = [];
@@ -122,11 +142,7 @@ class MessageService extends ChangeNotifier {
String addMessage(String text, bool isUser, MessageStatus status) {
String uuid = Uuid().v1();
_messages.add(ChatMessage(
id: uuid,
text: text,
isUser: isUser,
timestamp: DateTime.now(),
status: status));
id: uuid, text: text, isUser: isUser, timestamp: DateTime.now(), status: status));
notifyListeners();
return uuid;
}
@@ -226,8 +242,7 @@ class MessageService extends ChangeNotifier {
if (_isReplyAborted) {
return;
}
final vehicleCommandResponse =
await _vehicleCommandService.getCommandFromText(text);
final vehicleCommandResponse = await _vehicleCommandService.getCommandFromText(text);
if (vehicleCommandResponse == null) {
if (_isReplyAborted) {
return;
@@ -235,10 +250,7 @@ class MessageService extends ChangeNotifier {
String msg = isChinese
? "无法识别车辆控制命令,请重试"
: "Cannot recognize the vehicle control command, please try again";
replaceMessage(
id: _latestAssistantMessageId!,
text: msg,
status: MessageStatus.normal);
replaceMessage(id: _latestAssistantMessageId!, text: msg, status: MessageStatus.normal);
} else {
if (_isReplyAborted) {
return;
@@ -259,8 +271,7 @@ class MessageService extends ChangeNotifier {
if (_isReplyAborted) {
return;
}
if (command.type == VehicleCommandType.unknown ||
command.error.isNotEmpty) {
if (command.type == VehicleCommandType.unknown || command.error.isNotEmpty) {
continue;
}
if (command.type == VehicleCommandType.openAC) {
@@ -268,8 +279,8 @@ class MessageService extends ChangeNotifier {
}
bool isSuccess;
if (containOpenAC && command.type == VehicleCommandType.changeACTemp) {
isSuccess = await Future.delayed(const Duration(milliseconds: 2000),
() => processCommand(command, isChinese));
isSuccess = await Future.delayed(
const Duration(milliseconds: 2000), () => processCommand(command, isChinese));
} else {
isSuccess = await processCommand(command, isChinese);
}
@@ -285,8 +296,7 @@ class MessageService extends ChangeNotifier {
if (_isReplyAborted || successCommandList.isEmpty) {
return;
}
String controlResponse =
await _vehicleCommandService.getControlResponse(successCommandList);
String controlResponse = await _vehicleCommandService.getControlResponse(successCommandList);
if (_isReplyAborted || controlResponse.isEmpty) {
return;
}
@@ -297,20 +307,22 @@ class MessageService extends ChangeNotifier {
Future<bool> processCommand(VehicleCommand command, bool isChinese) async {
String msg = "";
MessageStatus status = MessageStatus.normal;
final (isSuccess, result) = await CommandService.executeCommand(
command.type,
params: command.params);
var commandObjc = VehicleCommand(type: command.type, params: command.params);
var client = AIChatAssistantManager.instance.commandClient;
if (client == null) {
msg = isChinese ? "车辆控制服务未初始化" : "Vehicle control service is not initialized";
status = MessageStatus.failure;
addMessage(msg, false, status);
return false;
}
final (isSuccess, result) = await client.executeCommand(commandObjc);
if (command.type == VehicleCommandType.locateCar) {
msg = isChinese
? "很抱歉,定位车辆位置失败"
: "Sorry, locate the vehicle unsuccessfully";
msg = isChinese ? "很抱歉,定位车辆位置失败" : "Sorry, locate the vehicle unsuccessfully";
status = MessageStatus.failure;
if (isSuccess && result != null && result.isNotEmpty) {
String address = result['address'];
if (address.isNotEmpty) {
msg = isChinese
? "已为您找到车辆位置:\"$address\""
: "The vehicle location is \"$address\"";
msg = isChinese ? "已为您找到车辆位置:\"$address\"" : "The vehicle location is \"$address\"";
status = MessageStatus.success;
}
}
@@ -386,8 +398,7 @@ class MessageService extends ChangeNotifier {
status: MessageStatus.completed,
);
} else {
replaceMessage(
id: messageId, text: responseText, status: MessageStatus.thinking);
replaceMessage(id: messageId, text: responseText, status: MessageStatus.thinking);
}
} catch (e) {
abortReply();
@@ -401,8 +412,7 @@ class MessageService extends ChangeNotifier {
if (index == -1 || messages[index].status != MessageStatus.thinking) {
return;
}
replaceMessage(
id: _latestAssistantMessageId!, status: MessageStatus.aborted);
replaceMessage(id: _latestAssistantMessageId!, status: MessageStatus.aborted);
}
void removeMessageById(String id) {