[update] use aliyun andriod sdk
This commit is contained in:
@@ -3,6 +3,7 @@ import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:ai_chat_assistant/utils/tts_util.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import '../utils/common_util.dart';
|
||||
@@ -16,15 +17,20 @@ class ChatSseService {
|
||||
HttpClient? _currentClient;
|
||||
HttpClientResponse? _currentResponse;
|
||||
bool _isAborted = true;
|
||||
bool isTtsStarted = false;
|
||||
bool _isFirstData = true;
|
||||
bool _isTtsStarted = false;
|
||||
|
||||
String? get conversationId => _cachedConversationId;
|
||||
|
||||
Future<void>? _startTtsFuture;
|
||||
|
||||
void request({
|
||||
required String messageId,
|
||||
required String text,
|
||||
required Function(String, String, String, bool) onStreamResponse,
|
||||
required bool isChinese,
|
||||
required Function(String, String, bool) onStreamResponse,
|
||||
}) async {
|
||||
print("----------------------SSE Start");
|
||||
_isAborted = false;
|
||||
if (_cachedUserId == null) {
|
||||
_cachedUserId = _generateRandomUserId(6);
|
||||
@@ -48,25 +54,17 @@ class ChatSseService {
|
||||
request.add(utf8.encode(json.encode(body)));
|
||||
_currentResponse = await request.close();
|
||||
if (_currentResponse!.statusCode == 200) {
|
||||
bool isFirst = true;
|
||||
_startTtsFuture = startTts(isChinese);
|
||||
await for (final line in _currentResponse!
|
||||
.transform(utf8.decoder)
|
||||
.transform(const LineSplitter())) {
|
||||
if (_isAborted) {
|
||||
break;
|
||||
}
|
||||
if (isFirst) {
|
||||
if (!isTtsStarted) {
|
||||
if (await _channel.invokeMethod<bool>("startTts") == true) {
|
||||
isTtsStarted = true;
|
||||
}
|
||||
}
|
||||
isFirst = false;
|
||||
}
|
||||
if (line.startsWith('data:')) {
|
||||
final jsonStr = line.substring(5).trim();
|
||||
if (jsonStr == '[DONE]' || jsonStr.contains('message_end')) {
|
||||
onStreamResponse(messageId, responseText, tempText, true);
|
||||
onStreamResponse(messageId, responseText, true);
|
||||
break;
|
||||
}
|
||||
try {
|
||||
@@ -81,13 +79,21 @@ class ChatSseService {
|
||||
if (_isAborted) {
|
||||
break;
|
||||
}
|
||||
_channel.invokeMethod("sendTts", {"text": CommonUtil.cleanText(textChunk, true)});
|
||||
tempText += textChunk;
|
||||
int endIndex = _getCompleteTextEndIndex(tempText);
|
||||
String completeText = CommonUtil.cleanText(tempText.substring(0, endIndex).trim(), true);
|
||||
if (completeText.isNotEmpty) {
|
||||
if (_isFirstData && _startTtsFuture != null) {
|
||||
await _startTtsFuture;
|
||||
_isFirstData = false;
|
||||
}
|
||||
print("----------------------Send text: " + completeText);
|
||||
completeText += isChinese ? ',' : ',';
|
||||
TtsUtil.send(completeText);
|
||||
}
|
||||
tempText = tempText.substring(endIndex).trim();
|
||||
responseText += textChunk;
|
||||
// tempText += textChunk;
|
||||
// int endIndex = _getCompleteTextEndIndex(tempText);
|
||||
// final completeText = tempText.substring(0, endIndex).trim();
|
||||
// tempText = tempText.substring(endIndex).trim();
|
||||
onStreamResponse(messageId, responseText, "completeText", false);
|
||||
onStreamResponse(messageId, responseText, false);
|
||||
}
|
||||
} catch (e) {
|
||||
print('解析 SSE 数据出错: $e, 原始数据: $jsonStr');
|
||||
@@ -100,15 +106,22 @@ class ChatSseService {
|
||||
} catch (e) {
|
||||
// todo
|
||||
} finally {
|
||||
isTtsStarted = false;
|
||||
resetRequest();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> startTts(bool isChinese) async {
|
||||
print("----------------------TTS Start");
|
||||
if (!_isTtsStarted) {
|
||||
if (await TtsUtil.start(isChinese) == true) {
|
||||
_isTtsStarted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> abort() async {
|
||||
_isAborted = true;
|
||||
_channel.invokeMethod("stopTts");
|
||||
isTtsStarted = false;
|
||||
TtsUtil.stopTts();
|
||||
resetRequest();
|
||||
}
|
||||
|
||||
@@ -119,11 +132,13 @@ class ChatSseService {
|
||||
_currentClient?.close(force: true);
|
||||
_currentClient = null;
|
||||
_currentResponse = null;
|
||||
_isFirstData = true;
|
||||
_isTtsStarted = false;
|
||||
}
|
||||
|
||||
int _getCompleteTextEndIndex(String buffer) {
|
||||
// 支持句号、问号、感叹号和换行符作为分割依据
|
||||
final sentenceEnders = RegExp(r'[。!?\n]');
|
||||
final sentenceEnders = RegExp(r'[,!?:,。!?:\n]');
|
||||
final matches = sentenceEnders.allMatches(buffer);
|
||||
return matches.isEmpty ? 0 : matches.last.end;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:ai_chat_assistant/utils/common_util.dart';
|
||||
import 'package:ai_chat_assistant/utils/tts_util.dart';
|
||||
import 'package:basic_intl/intl.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
@@ -15,7 +16,6 @@ import '../services/classification_service.dart';
|
||||
import '../services/control_recognition_service.dart';
|
||||
import '../services/audio_recorder_service.dart';
|
||||
import '../services/voice_recognition_service.dart';
|
||||
import '../services/tts_service.dart';
|
||||
import 'command_service.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
|
||||
@@ -213,10 +213,11 @@ class MessageService extends ChangeNotifier {
|
||||
id: _latestAssistantMessageId!,
|
||||
text: vehicleCommandResponse.tips!,
|
||||
status: MessageStatus.executing);
|
||||
// if (!_isReplyAborted) {
|
||||
// _ttsService.pushTextForStreamTTS(vehicleCommandResponse.tips!);
|
||||
// _ttsService.markSSEStreamCompleted();
|
||||
// }
|
||||
if (!_isReplyAborted) {
|
||||
if (await TtsUtil.start(isChinese) == true) {
|
||||
TtsUtil.send(vehicleCommandResponse.tips!);
|
||||
}
|
||||
}
|
||||
bool containOpenAC = false;
|
||||
for (var command in vehicleCommandResponse.commands) {
|
||||
if (_isReplyAborted) {
|
||||
@@ -309,6 +310,7 @@ class MessageService extends ChangeNotifier {
|
||||
_chatSseService.request(
|
||||
messageId: _latestAssistantMessageId!,
|
||||
text: text,
|
||||
isChinese: isChinese,
|
||||
onStreamResponse: handleStreamResponse,
|
||||
);
|
||||
}
|
||||
@@ -325,26 +327,18 @@ class MessageService extends ChangeNotifier {
|
||||
status: MessageStatus.normal);
|
||||
}
|
||||
|
||||
void handleStreamResponse(String messageId, String responseText,
|
||||
String completeText, bool isComplete) {
|
||||
void handleStreamResponse(String messageId, String responseText, bool isComplete) {
|
||||
if (_isReplyAborted) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (isComplete) {
|
||||
// if (completeText.isNotEmpty) {
|
||||
// _ttsService.pushTextForStreamTTS(completeText);
|
||||
// }
|
||||
// _ttsService.markSSEStreamCompleted();
|
||||
replaceMessage(
|
||||
id: messageId,
|
||||
text: responseText,
|
||||
status: MessageStatus.completed,
|
||||
);
|
||||
} else {
|
||||
// if (completeText.isNotEmpty) {
|
||||
// _ttsService.pushTextForStreamTTS(completeText);
|
||||
// }
|
||||
replaceMessage(
|
||||
id: messageId, text: responseText, status: MessageStatus.thinking);
|
||||
}
|
||||
@@ -355,7 +349,6 @@ class MessageService extends ChangeNotifier {
|
||||
|
||||
Future<void> abortReply() async {
|
||||
_isReplyAborted = true;
|
||||
// _ttsService.stop();
|
||||
_chatSseService.abort();
|
||||
int index = findMessageIndexById(_latestAssistantMessageId);
|
||||
if (index == -1 || messages[index].status != MessageStatus.thinking) {
|
||||
|
||||
23
lib/utils/tts_util.dart
Normal file
23
lib/utils/tts_util.dart
Normal file
@@ -0,0 +1,23 @@
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class TtsUtil {
|
||||
static const MethodChannel _channel =
|
||||
MethodChannel('com.example.ai_chat_assistant/tts');
|
||||
|
||||
static Future<T?> execute<T>(String method,
|
||||
[Map<Object, Object>? arguments]) {
|
||||
return _channel.invokeMethod(method, arguments);
|
||||
}
|
||||
|
||||
static Future<bool> start(bool isChinese) async {
|
||||
return await execute('start', {'isChinese': isChinese});
|
||||
}
|
||||
|
||||
static Future<void> send(String text) async {
|
||||
await execute('send', {'text': text});
|
||||
}
|
||||
|
||||
static Future<void> stopTts() async {
|
||||
await execute('stop');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user