import 'package:get/get.dart'; import '../../../data/services/volcano_ai_service.dart'; import '../controllers/translation_controller.dart'; import '../controllers/translation_history_controller.dart'; import 'package:get_storage/get_storage.dart'; import 'dart:async'; import '../../../core/utils/logger.dart'; class TranslationDetailController extends GetxController { // 依赖注入 final VolcanoAIService _aiService = Get.find(); final GetStorage _storage = GetStorage(); // 存储键前缀 static const String _summaryKeyPrefix = 'translation_summary_'; // 超时设置(秒) static const int _defaultTimeoutDuration = 30; static const int _extendedTimeoutDuration = 60; // 状态变量 final selectedTabIndex = 0.obs; final isGeneratingSummary = false.obs; final summaryResult = ''.obs; final isLoading = true.obs; // 当前会话信息 late final TranslationItem currentItem; late final List sessionItems; late final TranslationHistoryController historyController; @override void onInit() { super.onInit(); // 从路由参数中获取数据 if (Get.arguments != null) { currentItem = Get.arguments['item']; sessionItems = Get.arguments['sessionItems']; historyController = Get.arguments['historyController']; // 异步加载数据,避免阻塞主线程 _asyncInitialize(); } else { Logger.error('TranslationDetailController: 未找到路由参数'); isLoading.value = false; } } // 异步初始化方法 Future _asyncInitialize() async { isLoading.value = true; try { // 使用 Future.microtask 将操作放到后台线程 await Future.microtask(() { // 尝试从存储中加载摘要 loadSavedSummary(); }); } catch (e) { Logger.error('初始化详情控制器失败: $e'); } finally { isLoading.value = false; } } // 加载保存的摘要 void loadSavedSummary() { try { final String? savedSummary = _storage.read(_getSummaryKey()); if (savedSummary != null && savedSummary.isNotEmpty) { summaryResult.value = savedSummary; } } catch (e) { Logger.error('加载摘要失败: $e'); } } // 保存摘要 void saveSummary(String summary) { if (summary.isEmpty) return; try { _storage.write(_getSummaryKey(), summary); } catch (e) { Logger.error('保存摘要失败: $e'); } } // 获取摘要的存储键 String _getSummaryKey() => _summaryKeyPrefix + currentItem.sessionId; // 切换选项卡 void switchTab(int index) => selectedTabIndex.value = index; // 播放翻译项 void playTranslationItem(TranslationItem item) => historyController.playTranslationItem(item); // 播放文本 void playText(String text) => historyController.playText(text); // 获取合并的源文本 String getCombinedSourceText() => sessionItems.map((e) => e.sourceText).join('\n\n'); // 获取合并的翻译文本 String getCombinedTranslatedText() => sessionItems.map((e) => e.translatedText).join('\n\n'); // 使用延长的超时时间重试提取摘要 Future retryExtractSummaryWithExtendedTimeout(String text) async { return _extractSummaryInternal(text, _extendedTimeoutDuration); } // 提取摘要 Future extractSummary(String text) async { return _extractSummaryInternal(text, _defaultTimeoutDuration); } // 内部摘要提取方法,避免代码重复 Future _extractSummaryInternal(String text, int timeoutDuration) async { if (text.isEmpty) { return '无法生成摘要:文本为空'; } isGeneratingSummary.value = true; try { // 构建提示词 final messages = [ {'role': 'user', 'content': '请为以下文本生成一个简洁的摘要,突出重点内容:\n\n$text'}, ]; // 系统提示词 const systemPrompt = ''' 你是一个专业的文本摘要助手,擅长从会议记录、对话和文本中提取关键信息并生成简洁的摘要。 请按照以下格式生成摘要: 1. 首先用1-2句话对整体内容进行简要概括 2. 然后使用项目符号列表(•)列出关键点或重要信息 3. 如果是对话内容,请特别标注出讨论的结论或达成的共识 请遵循以下原则: 1. 保留原文的核心信息和关键点 2. 使用简洁、清晰的语言 3. 保持客观,不添加个人观点 4. 摘要总长度应该是原文的1/3或更短 5. 确保列表中的每个要点都简明扼要,突出重点 '''; String result; try { // 使用超时限制 result = await _aiService.sendMessage( messages: messages, systemPrompt: systemPrompt, ).timeout(Duration(seconds: timeoutDuration), onTimeout: () { throw TimeoutException('请求超时,请稍后重试'); }); } on TimeoutException catch (_) { final timeoutMessage = timeoutDuration == _defaultTimeoutDuration ? '生成摘要超时,请稍后重试' : '生成摘要超时,请检查网络连接后重试'; summaryResult.value = timeoutMessage; return summaryResult.value; } // 更新结果并保存 if (result.isNotEmpty) { summaryResult.value = result; saveSummary(result); } return result; } catch (e) { final errorMessage = '生成摘要失败: ${e.toString()}'; Logger.error(errorMessage); summaryResult.value = errorMessage; return errorMessage; } finally { isGeneratingSummary.value = false; } } @override void onClose() { // 确保资源被正确释放 historyController.translationController.stopAll(); super.onClose(); } }