merge commit

This commit is contained in:
Chen Li
2025-08-22 17:35:02 +08:00
parent 926f162287
commit e39f42a3df
6 changed files with 71 additions and 59 deletions

View File

@@ -68,7 +68,7 @@ public class MainActivity extends FlutterActivity implements INativeNuiCallback
.setMethodCallHandler((call, result) -> { .setMethodCallHandler((call, result) -> {
Map<String, Object> args = (Map<String, Object>) call.arguments; Map<String, Object> args = (Map<String, Object>) call.arguments;
switch (call.method) { switch (call.method) {
case "start": case "startTts":
Object isChinese = args.get("isChinese"); Object isChinese = args.get("isChinese");
if (isChinese == null || isChinese.toString().isBlank()) { if (isChinese == null || isChinese.toString().isBlank()) {
return; return;
@@ -76,17 +76,17 @@ public class MainActivity extends FlutterActivity implements INativeNuiCallback
boolean isSuccess = startTts(Boolean.parseBoolean(isChinese.toString())); boolean isSuccess = startTts(Boolean.parseBoolean(isChinese.toString()));
result.success(isSuccess); result.success(isSuccess);
break; break;
case "send": case "sendTts":
Object textArg = args.get("text"); Object textArg = args.get("text");
if (textArg == null || textArg.toString().isBlank()) { if (textArg == null || textArg.toString().isBlank()) {
return; return;
} }
sendTts(textArg.toString()); sendTts(textArg.toString());
break; break;
case "complete": case "completeTts":
completeTts(); completeTts();
break; break;
case "stop": case "stopTts":
stopTts(); stopTts();
break; break;
default: default:
@@ -97,10 +97,10 @@ public class MainActivity extends FlutterActivity implements INativeNuiCallback
asrMethodChannel = new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), ASR_CHANNEL); asrMethodChannel = new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), ASR_CHANNEL);
asrMethodChannel.setMethodCallHandler((call, result) -> { asrMethodChannel.setMethodCallHandler((call, result) -> {
switch (call.method) { switch (call.method) {
case "start": case "startAsr":
startAsr(); startAsr();
break; break;
case "stop": case "stopAsr":
stopAsr(); stopAsr();
break; break;
default: default:

View File

@@ -18,6 +18,7 @@ class PartScreen extends StatefulWidget {
class _PartScreenState extends State<PartScreen> { class _PartScreenState extends State<PartScreen> {
final ScrollController _scrollController = ScrollController(); final ScrollController _scrollController = ScrollController();
bool _isInitialized = false; bool _isInitialized = false;
int _lastMessageCount = 0;
@override @override
void initState() { void initState() {
@@ -97,9 +98,13 @@ class _PartScreenState extends State<PartScreen> {
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
child: Consumer<MessageService>( child: Consumer<MessageService>(
builder: (context, messageService, child) { builder: (context, messageService, child) {
final messageCount = messageService.messages.length;
if (messageCount > _lastMessageCount) {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
_scrollToBottom(); _scrollToBottom();
}); });
}
_lastMessageCount = messageCount;
return Container( return Container(
width: chatWidth, width: chatWidth,
constraints: BoxConstraints( constraints: BoxConstraints(

View File

@@ -9,8 +9,7 @@ class VehicleCommandService {
Future<VehicleCommandResponse?> getCommandFromText(String text) async { Future<VehicleCommandResponse?> getCommandFromText(String text) async {
try { try {
final uri = Uri.parse( final uri = Uri.parse('http://143.64.185.20:18606/control');
'http://143.64.185.20:18606/control');
final response = await http.post( final response = await http.post(
uri, uri,
@@ -40,30 +39,23 @@ class VehicleCommandService {
} }
} }
// 执行车辆控制命令的方法 Future<String> getControlResponse(List<String> successCommandList) async {
Future<bool> executeCommand(VehicleCommand command) async { String reply = "";
try { 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( final response = await http.post(
uri, uri,
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
body: json.encode({ body: json.encode(successCommandList),
'command': command.commandString, // 使用getter转换为字符串
'params': command.params,
}),
); );
if (response.statusCode == 200) { if (response.statusCode == 200) {
print('命令执行成功: ${command.commandString}'); return response.body;
return true;
} else { } else {
print('命令执行失败: ${response.statusCode}, ${response.body}'); print("请求控制回复失败: ${response.statusCode}");
return false;
} }
} catch (e) { } catch (e) {
print('命令执行出错: $e'); print('请求控制回复异常: $e');
return false; }
} return reply;
} }
} }

View File

@@ -33,7 +33,10 @@ class MessageService extends ChangeNotifier {
_asrChannel.setMethodCallHandler((call) async { _asrChannel.setMethodCallHandler((call) async {
switch (call.method) { switch (call.method) {
case "onAsrResult": case "onAsrResult":
replaceMessage(id: _latestUserMessageId!, text: call.arguments); replaceMessage(
id: _latestUserMessageId!,
text: call.arguments,
status: MessageStatus.normal);
break; break;
case "onAsrStop": case "onAsrStop":
int index = findMessageIndexById(_latestUserMessageId!); int index = findMessageIndexById(_latestUserMessageId!);
@@ -45,8 +48,6 @@ class MessageService extends ChangeNotifier {
removeMessageById(_latestUserMessageId!); removeMessageById(_latestUserMessageId!);
return; return;
} }
replaceMessage(
id: _latestUserMessageId!, status: MessageStatus.normal);
if (_asrCompleter != null && !_asrCompleter!.isCompleted) { if (_asrCompleter != null && !_asrCompleter!.isCompleted) {
_asrCompleter!.complete(messages.last.text); _asrCompleter!.complete(messages.last.text);
} }
@@ -107,9 +108,8 @@ class MessageService extends ChangeNotifier {
_latestAssistantMessageId = null; _latestAssistantMessageId = null;
_isReplyAborted = false; _isReplyAborted = false;
changeState(MessageServiceState.recording); changeState(MessageServiceState.recording);
addMessage("", true, MessageStatus.listening); _latestUserMessageId = addMessage("", true, MessageStatus.listening);
_latestUserMessageId = messages.last.id; _asrChannel.invokeMethod("startAsr");
_asrChannel.invokeMethod("start");
} catch (e) { } catch (e) {
print('录音开始出错: $e'); print('录音开始出错: $e');
} }
@@ -120,14 +120,16 @@ class MessageService extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
void addMessage(String text, bool isUser, MessageStatus status) { String addMessage(String text, bool isUser, MessageStatus status) {
String uuid = Uuid().v1();
_messages.add(ChatMessage( _messages.add(ChatMessage(
id: Uuid().v1(), id: uuid,
text: text, text: text,
isUser: isUser, isUser: isUser,
timestamp: DateTime.now(), timestamp: DateTime.now(),
status: status)); status: status));
notifyListeners(); notifyListeners();
return uuid;
} }
Future<void> stopAndProcessVoiceInput() async { Future<void> stopAndProcessVoiceInput() async {
@@ -137,7 +139,7 @@ class MessageService extends ChangeNotifier {
} }
try { try {
changeState(MessageServiceState.recognizing); changeState(MessageServiceState.recognizing);
_asrChannel.invokeMethod("stop"); _asrChannel.invokeMethod("stopAsr");
_asrCompleter = Completer<String>(); _asrCompleter = Completer<String>();
final recognizedText = await _asrCompleter!.future; final recognizedText = await _asrCompleter!.future;
// final audioData = await _audioService.stopRecording(); // final audioData = await _audioService.stopRecording();
@@ -194,8 +196,7 @@ class MessageService extends ChangeNotifier {
} }
Future<void> reply(String text) async { Future<void> reply(String text) async {
addMessage("", false, MessageStatus.thinking); _latestAssistantMessageId = addMessage("", false, MessageStatus.thinking);
_latestAssistantMessageId = messages.last.id;
bool isChinese = CommonUtil.containChinese(text); bool isChinese = CommonUtil.containChinese(text);
try { try {
if (_isReplyAborted) { if (_isReplyAborted) {
@@ -249,9 +250,11 @@ class MessageService extends ChangeNotifier {
if (!_isReplyAborted) { if (!_isReplyAborted) {
if (await TtsUtil.start(isChinese) == true) { if (await TtsUtil.start(isChinese) == true) {
TtsUtil.send(vehicleCommandResponse.tips!); TtsUtil.send(vehicleCommandResponse.tips!);
Future.delayed(const Duration(milliseconds: 300), () => TtsUtil.complete());
} }
} }
bool containOpenAC = false; bool containOpenAC = false;
List<String> successCommandList = [];
for (var command in vehicleCommandResponse.commands) { for (var command in vehicleCommandResponse.commands) {
if (_isReplyAborted) { if (_isReplyAborted) {
return; return;
@@ -263,11 +266,15 @@ class MessageService extends ChangeNotifier {
if (command.type == VehicleCommandType.openAC) { if (command.type == VehicleCommandType.openAC) {
containOpenAC = true; containOpenAC = true;
} }
bool isSuccess;
if (containOpenAC && command.type == VehicleCommandType.changeACTemp) { if (containOpenAC && command.type == VehicleCommandType.changeACTemp) {
await Future.delayed(const Duration(milliseconds: 2000), isSuccess = await Future.delayed(const Duration(milliseconds: 2000),
() => processCommand(command, isChinese)); () => processCommand(command, isChinese));
} else { } else {
await processCommand(command, isChinese); isSuccess = await processCommand(command, isChinese);
}
if (isSuccess) {
successCommandList.add(command.type.name);
} }
} }
replaceMessage( replaceMessage(
@@ -275,12 +282,21 @@ class MessageService extends ChangeNotifier {
text: vehicleCommandResponse.tips!, text: vehicleCommandResponse.tips!,
status: MessageStatus.normal); status: MessageStatus.normal);
notifyListeners(); notifyListeners();
if (_isReplyAborted || successCommandList.isEmpty) {
return;
}
String controlResponse =
await _vehicleCommandService.getControlResponse(successCommandList);
if (_isReplyAborted || controlResponse.isEmpty) {
return;
}
addMessage(controlResponse, false, MessageStatus.normal);
} }
} }
Future<void> processCommand(VehicleCommand command, bool isChinese) async { Future<bool> processCommand(VehicleCommand command, bool isChinese) async {
String msg; String msg = "";
MessageStatus status; MessageStatus status = MessageStatus.normal;
final (isSuccess, result) = await CommandService.executeCommand( final (isSuccess, result) = await CommandService.executeCommand(
command.type, command.type,
params: command.params); params: command.params);
@@ -299,20 +315,18 @@ class MessageService extends ChangeNotifier {
} }
} }
} else { } else {
if (isSuccess) { if (!isSuccess) {
msg = isChinese
? "为您执行\"${command.type.chinese}\"成功"
: "Execute \"${command.type.english}\" successful";
status = MessageStatus.success;
} else {
msg = isChinese msg = isChinese
? "很抱歉,\"${command.type.chinese}\"失败" ? "很抱歉,\"${command.type.chinese}\"失败"
: "Sorry, execute \"${command.type.english}\" unsuccessfully"; : "Sorry, execute \"${command.type.english}\" unsuccessfully";
status = MessageStatus.failure; status = MessageStatus.failure;
} }
} }
if (msg.isNotEmpty) {
addMessage(msg, false, status); addMessage(msg, false, status);
} }
return isSuccess;
}
Future<void> answerWrongQuestion(bool isChinese) async { Future<void> answerWrongQuestion(bool isChinese) async {
if (_isReplyAborted) { if (_isReplyAborted) {

View File

@@ -10,18 +10,18 @@ class TtsUtil {
} }
static Future<bool> start(bool isChinese) async { static Future<bool> start(bool isChinese) async {
return await execute('start', {'isChinese': isChinese}); return await execute('startTts', {'isChinese': isChinese});
} }
static Future<void> send(String text) async { static Future<void> send(String text) async {
await execute('send', {'text': text}); await execute('sendTts', {'text': text});
} }
static Future<void> complete() async { static Future<void> complete() async {
await execute('complete'); await execute('completeTts');
} }
static Future<void> stop() async { static Future<void> stop() async {
await execute('stop'); await execute('stopTts');
} }
} }

View File

@@ -70,6 +70,7 @@ class _FloatingIconState extends State<FloatingIcon>
} }
void _showFullScreen() async { void _showFullScreen() async {
_hidePartScreen();
await Navigator.of(context).push( await Navigator.of(context).push(
MaterialPageRoute( MaterialPageRoute(
builder: (context) => const FullScreen(), builder: (context) => const FullScreen(),