修改TTS前的分句和全屏功能
1、TTS前的分句已经可以正常移除图片url了 2、打开full_screen中的全屏后延迟出现“欢迎语”,避免报错 --------- Issue: 1、分句后的文字提交tts,会出现websocket空闲时间过长,导致语音提前结束的情况
This commit is contained in:
@@ -67,12 +67,12 @@ class _FullScreenState extends State<FullScreen> {
|
|||||||
_scrollToBottom();
|
_scrollToBottom();
|
||||||
});
|
});
|
||||||
if (messageService.messages.isEmpty) {
|
if (messageService.messages.isEmpty) {
|
||||||
// Future.delayed(const Duration(milliseconds: 500), () {
|
Future.delayed(const Duration(milliseconds: 500), () {
|
||||||
String text = Intl.getCurrentLocale().startsWith('zh')
|
String text = Intl.getCurrentLocale().startsWith('zh')
|
||||||
? "您好,我是众众,请问有什么可以帮您?"
|
? "您好,我是众众,请问有什么可以帮您?"
|
||||||
: "Hi, I'm Zhongzhong, may I help you ? ";
|
: "Hi, I'm Zhongzhong, may I help you ? ";
|
||||||
messageService.addMessage(text, false, MessageStatus.normal);
|
messageService.addMessage(text, false, MessageStatus.normal);
|
||||||
// });
|
});
|
||||||
}
|
}
|
||||||
return ChatBox(
|
return ChatBox(
|
||||||
scrollController: _scrollController,
|
scrollController: _scrollController,
|
||||||
|
|||||||
@@ -35,7 +35,59 @@ class ChatSseService {
|
|||||||
print('初始化用户ID: $_cachedUserId');
|
print('初始化用户ID: $_cachedUserId');
|
||||||
}
|
}
|
||||||
String responseText = '';
|
String responseText = '';
|
||||||
String tempText = '';
|
StringBuffer buffer = StringBuffer();
|
||||||
|
// 英文分句符
|
||||||
|
final enEnders = RegExp(r'[.!?]');
|
||||||
|
// 中文分句符
|
||||||
|
final zhEnders = RegExp(r'[。!?]');
|
||||||
|
// 专有名词保护
|
||||||
|
String protectIDUNYX(String text) => text.replaceAll('ID.UNYX', 'ID_UNYX');
|
||||||
|
String restoreIDUNYX(String text) => text.replaceAll('ID_UNYX', 'ID.UNYX');
|
||||||
|
Future<void> processBuffer(bool isChinese) async {
|
||||||
|
String txt = buffer.toString();
|
||||||
|
// 先过滤 markdown 图片语法
|
||||||
|
int imgStart = txt.indexOf('![');
|
||||||
|
while (imgStart != -1) {
|
||||||
|
int imgEnd = txt.indexOf(')', imgStart);
|
||||||
|
if (imgEnd == -1) {
|
||||||
|
// 图片语法未闭合,缓存剩余部分
|
||||||
|
buffer.clear();
|
||||||
|
buffer.write(txt.substring(imgStart));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 移除图片语法
|
||||||
|
txt = txt.substring(0, imgStart) + txt.substring(imgEnd + 1);
|
||||||
|
imgStart = txt.indexOf('![');
|
||||||
|
}
|
||||||
|
// 彻底移除 markdown 有序/无序列表序号(如 1.、2.、-、*、+)
|
||||||
|
txt = txt.replaceAll(RegExp(r'(^|\n)[ \t]*[0-9]+\.[ \t]*'), '\n');
|
||||||
|
txt = txt.replaceAll(RegExp(r'(^|\n)[ \t]*[-\*\+][ \t]+'), '\n');
|
||||||
|
// 分句符
|
||||||
|
RegExp enders = isChinese ? zhEnders : enEnders;
|
||||||
|
int lastEnd = 0;
|
||||||
|
// 本地缓存句子
|
||||||
|
List<String> sentences = [];
|
||||||
|
for (final match in enders.allMatches(txt)) {
|
||||||
|
int endIndex = match.end;
|
||||||
|
String sentence = txt.substring(lastEnd, endIndex).trim();
|
||||||
|
if (sentence.isNotEmpty) {
|
||||||
|
sentences.add(sentence);
|
||||||
|
}
|
||||||
|
lastEnd = endIndex;
|
||||||
|
}
|
||||||
|
// 只在达到完整句子时调用 TtsUtil.send
|
||||||
|
for (final s in sentences) {
|
||||||
|
String ttsStr=CommonUtil.cleanText(s, true);
|
||||||
|
// print("发送数据到TTS: $ttsStr");
|
||||||
|
TtsUtil.send(ttsStr);
|
||||||
|
}
|
||||||
|
// 缓存剩余不完整部分
|
||||||
|
String remain = txt.substring(lastEnd).trim();
|
||||||
|
buffer.clear();
|
||||||
|
if (remain.isNotEmpty) {
|
||||||
|
buffer.write(remain);
|
||||||
|
}
|
||||||
|
}
|
||||||
_currentClient = HttpClient();
|
_currentClient = HttpClient();
|
||||||
try {
|
try {
|
||||||
final chatUri = Uri.parse('http://143.64.185.20:18606/chat');
|
final chatUri = Uri.parse('http://143.64.185.20:18606/chat');
|
||||||
@@ -62,7 +114,7 @@ class ChatSseService {
|
|||||||
if (line.startsWith('data:')) {
|
if (line.startsWith('data:')) {
|
||||||
final jsonStr = line.substring(5).trim();
|
final jsonStr = line.substring(5).trim();
|
||||||
if (jsonStr == '[DONE]' || jsonStr.contains('message_end')) {
|
if (jsonStr == '[DONE]' || jsonStr.contains('message_end')) {
|
||||||
TtsUtil.complete();
|
await processBuffer(isChinese);
|
||||||
onStreamResponse(messageId, responseText, true);
|
onStreamResponse(messageId, responseText, true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -74,27 +126,12 @@ class ChatSseService {
|
|||||||
}
|
}
|
||||||
if (jsonData['event'].toString().contains('message')) {
|
if (jsonData['event'].toString().contains('message')) {
|
||||||
final textChunk =
|
final textChunk =
|
||||||
jsonData.containsKey('answer') ? jsonData['answer'] : '';
|
jsonData.containsKey('answer') ? jsonData['answer'] : '';
|
||||||
if (_isAborted) {
|
if (_isAborted) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tempText += textChunk;
|
buffer.write(textChunk);
|
||||||
if (tempText.contains("ID.")) {
|
await processBuffer(isChinese);
|
||||||
tempText = tempText.replaceAllMapped(
|
|
||||||
RegExp(r'ID\.', caseSensitive: false), (m) => 'ID ');
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
completeText += isChinese ? ',' : ',';
|
|
||||||
print("----------------------Send text: " + completeText);
|
|
||||||
TtsUtil.send(completeText);
|
|
||||||
}
|
|
||||||
tempText = tempText.substring(endIndex).trim();
|
|
||||||
responseText += textChunk;
|
responseText += textChunk;
|
||||||
onStreamResponse(messageId, responseText, false);
|
onStreamResponse(messageId, responseText, false);
|
||||||
}
|
}
|
||||||
@@ -109,7 +146,6 @@ class ChatSseService {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
// todo
|
// todo
|
||||||
} finally {
|
} finally {
|
||||||
print("------------------------------finally");
|
|
||||||
resetRequest();
|
resetRequest();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user