|
|
|
@ -45,11 +45,16 @@ class TranslationController extends GetxController { |
|
|
|
Timer? _recordTimer; |
|
|
|
//秒 |
|
|
|
int _seconds = 0; |
|
|
|
// 存储相关 |
|
|
|
// 存储相关配置 |
|
|
|
static const String _historyKey = 'translation_history'; |
|
|
|
static const String _sourceLanguageKey = 'translation_source_language'; |
|
|
|
static const String _targetLanguageKey = 'translation_target_language'; |
|
|
|
static const int _maxHistoryItems = 10; |
|
|
|
|
|
|
|
// 【重要改进】区分存储限制和显示限制 |
|
|
|
// 存储限制:大幅增加到1000条,充分利用本地存储能力,几乎无限制存储 |
|
|
|
static const int _maxStorageItems = 1000; |
|
|
|
// 主页面显示限制:只显示最近20条,保证界面性能和用户体验 |
|
|
|
static const int _maxDisplayItems = 20; |
|
|
|
|
|
|
|
RxInt activeSpeaker = 0.obs; // 0=无激活, 1=按钮1, 2=按钮2 |
|
|
|
RxInt lastActiveSpeaker = 0.obs; // 上一次状态 |
|
|
|
@ -559,8 +564,8 @@ class TranslationController extends GetxController { |
|
|
|
String? translationResult; |
|
|
|
|
|
|
|
try { |
|
|
|
var detectedSourceLanguageCode; |
|
|
|
var detectedTargetLanguageCode; |
|
|
|
String detectedSourceLanguageCode; |
|
|
|
String detectedTargetLanguageCode; |
|
|
|
if ((currentMode.value == 'faceToFace' && activeSpeaker.value == 1) || |
|
|
|
(currentMode.value == 'faceToFace' && |
|
|
|
activeSpeaker.value == 0 && |
|
|
|
@ -608,7 +613,12 @@ class TranslationController extends GetxController { |
|
|
|
translationHistory[index].targetLanguageCode = |
|
|
|
detectedTargetLanguageCode; |
|
|
|
translationHistory.refresh(); |
|
|
|
saveTranslationHistory(); |
|
|
|
|
|
|
|
// 【改进】只有在最终结果时才保存,避免中间态时的频繁保存 |
|
|
|
if (isFinal) { |
|
|
|
saveTranslationHistory(); |
|
|
|
} |
|
|
|
|
|
|
|
// 更新后滚动到底部 |
|
|
|
_scrollToBottom(); |
|
|
|
// 播放TTS - 只在最终结果时播放 |
|
|
|
@ -630,7 +640,7 @@ class TranslationController extends GetxController { |
|
|
|
} |
|
|
|
} else { |
|
|
|
Logger.info( |
|
|
|
'未找到匹配的历史项 ${sourceText} ${timestamp.toIso8601String() ?? "无时间戳"}'); |
|
|
|
'未找到匹配的历史项 $sourceText ${timestamp.toIso8601String()}'); |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (e) { |
|
|
|
@ -836,10 +846,13 @@ class TranslationController extends GetxController { |
|
|
|
final List<TranslationItem> allHistory = |
|
|
|
historyList.map((item) => TranslationItem.fromJson(item)).toList(); |
|
|
|
|
|
|
|
// 只保留最新的10条记录 |
|
|
|
if (allHistory.length > _maxHistoryItems) { |
|
|
|
// 【注意】存储中的记录都是完成态记录(isIntermediate = false) |
|
|
|
// 因为保存时已经过滤掉了中间态记录,确保数据质量 |
|
|
|
|
|
|
|
// 主页面只显示最近的20条完成态记录,保证界面性能 |
|
|
|
if (allHistory.length > _maxDisplayItems) { |
|
|
|
translationHistory.value = |
|
|
|
allHistory.sublist(allHistory.length - _maxHistoryItems); |
|
|
|
allHistory.sublist(allHistory.length - _maxDisplayItems); |
|
|
|
} else { |
|
|
|
translationHistory.value = allHistory; |
|
|
|
} |
|
|
|
@ -855,22 +868,76 @@ class TranslationController extends GetxController { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 保存翻译历史 |
|
|
|
// 保存翻译历史 - 回归原始简单实现 |
|
|
|
// 【修复】完全回归原始保存逻辑,只保存当前内存中的完成态记录 |
|
|
|
void saveTranslationHistory() { |
|
|
|
if (translationHistory.length > _maxHistoryItems) { |
|
|
|
translationHistory.removeRange( |
|
|
|
0, translationHistory.length - _maxHistoryItems); |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
// 只保存当前内存中的完成态记录,过滤掉中间态记录 |
|
|
|
final List<TranslationItem> finalRecords = translationHistory |
|
|
|
.where((item) => !item.isIntermediate) |
|
|
|
.toList(); |
|
|
|
|
|
|
|
// 应用存储限制,保留最新的1000条完成态记录 |
|
|
|
List<TranslationItem> historyToSave = finalRecords; |
|
|
|
if (finalRecords.length > _maxStorageItems) { |
|
|
|
historyToSave = finalRecords.sublist(finalRecords.length - _maxStorageItems); |
|
|
|
} |
|
|
|
|
|
|
|
// 保存到本地存储 |
|
|
|
final List<Map<String, dynamic>> historyJson = |
|
|
|
translationHistory.map((item) => item.toJson()).toList(); |
|
|
|
historyToSave.map((item) => item.toJson()).toList(); |
|
|
|
_storage.write(_historyKey, jsonEncode(historyJson)); |
|
|
|
|
|
|
|
Logger.info('翻译历史保存成功: 存储${historyToSave.length}条记录'); |
|
|
|
} catch (e) { |
|
|
|
Logger.error('保存翻译历史失败: ${e.toString()}'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 获取所有完成态历史记录(供历史页面使用) |
|
|
|
// 【修复】简化实现,合并存储和内存中的完成态记录 |
|
|
|
List<TranslationItem> getAllHistory() { |
|
|
|
try { |
|
|
|
final List<TranslationItem> result = <TranslationItem>[]; |
|
|
|
final Set<String> existingIds = <String>{}; |
|
|
|
|
|
|
|
// 添加存储的历史记录(存储中的记录都是完成态) |
|
|
|
final historyJson = _storage.read(_historyKey); |
|
|
|
if (historyJson != null) { |
|
|
|
final List<dynamic> historyList = jsonDecode(historyJson); |
|
|
|
final List<TranslationItem> storedHistory = |
|
|
|
historyList.map((item) => TranslationItem.fromJson(item)).toList(); |
|
|
|
|
|
|
|
for (final item in storedHistory) { |
|
|
|
final id = '${item.sessionId}_${item.timestamp.millisecondsSinceEpoch}'; |
|
|
|
if (!existingIds.contains(id)) { |
|
|
|
existingIds.add(id); |
|
|
|
result.add(item); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 添加当前内存中的完成态记录(排除中间态记录) |
|
|
|
for (final item in translationHistory) { |
|
|
|
if (!item.isIntermediate) { |
|
|
|
final id = '${item.sessionId}_${item.timestamp.millisecondsSinceEpoch}'; |
|
|
|
if (!existingIds.contains(id)) { |
|
|
|
existingIds.add(id); |
|
|
|
result.add(item); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 按时间排序 |
|
|
|
result.sort((a, b) => a.timestamp.compareTo(b.timestamp)); |
|
|
|
return result; |
|
|
|
} catch (e) { |
|
|
|
Logger.error('获取完整历史记录失败: ${e.toString()}'); |
|
|
|
// 发生错误时,返回当前内存中的完成态记录 |
|
|
|
return translationHistory.where((item) => !item.isIntermediate).toList(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 清除翻译历史 |
|
|
|
void clearTranslationHistory() { |
|
|
|
translationHistory.clear(); |
|
|
|
@ -882,11 +949,9 @@ class TranslationController extends GetxController { |
|
|
|
_scrollToBottom(); |
|
|
|
} |
|
|
|
|
|
|
|
/// 处理原生语音交互开始事件 |
|
|
|
void _handleVoiceInteractionStarted() { |
|
|
|
// 收到recognitionStarted事件时,停止当前的AI交互、录音和TTS |
|
|
|
stopAll(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// 翻译项模型 |
|
|
|
|