diff --git a/lib/modules/meeting/controllers/meeting_controller.dart b/lib/modules/meeting/controllers/meeting_controller.dart index f5ead752e..ba3e9494d 100644 --- a/lib/modules/meeting/controllers/meeting_controller.dart +++ b/lib/modules/meeting/controllers/meeting_controller.dart @@ -5,6 +5,7 @@ import '../../../data/services/db/sqflite_api.dart'; import '../views/meeting_home_view.dart'; import '../views/meeting_mine_view.dart'; +// 会议模块控制器 class MeetingController extends GetxController { final GlobalKey scaffoldKey = GlobalKey(); diff --git a/lib/modules/meeting/controllers/meeting_home_controller.dart b/lib/modules/meeting/controllers/meeting_home_controller.dart index 522661d6f..fa2d1bf02 100644 --- a/lib/modules/meeting/controllers/meeting_home_controller.dart +++ b/lib/modules/meeting/controllers/meeting_home_controller.dart @@ -188,8 +188,10 @@ class MeetingHomeController extends GetxController { Directory("${appDir.path}/DestAudio/"), ]; + // 目标目录:LocalAudio final destDir = Directory("${appDir.path}/LocalAudio/"); if (!await destDir.exists()) { + // 检查目标目录是否存在 await destDir.create(recursive: true); } @@ -335,9 +337,14 @@ class MeetingHomeController extends GetxController { EasyLoading.show(status: 'importing'.tr); // 对应中文:正在导入... String fileName = ""; bool isParamProvided = filePath != null; // 更清晰的变量名 + String audioType = 'IMPORT'; // 默认类型为IMPORT if (filePath != null) { // 正确截取文件名(跨平台安全方式) fileName = path.basename(filePath); + // 检查是否来自翻译模块 + if (filePath.contains('/TranslatAudio/')) { + audioType = 'TRANSLAT'; // 设置为翻译音频类型 + } } else { FilePickerResult? result = await FilePicker.platform.pickFiles( withData: false, @@ -368,7 +375,8 @@ class MeetingHomeController extends GetxController { } } - final meetingId = await insertMeetingAudio(fileName, filePath); + final meetingId = + await insertMeetingAudio(fileName, filePath, type: audioType); if (isParamProvided) { Get.toNamed(Routes.meetingDetails, arguments: { @@ -382,13 +390,14 @@ class MeetingHomeController extends GetxController { String fileName, String filePath, { bool isUpload = true, + String type = 'IMPORT', //添加type参数,默认为'IMPORT' }) async { await _audioPlayer.setAudioSource(AudioSource.file(filePath)); int seconds = _audioPlayer.duration?.inSeconds ?? 0; int creationTime = DateTime.now().millisecondsSinceEpoch; Map data = { 'title': fileName, - 'type': 'IMPORT', + 'type': type, // 使用传入的type参数 'seconds': seconds, 'filepath': filePath, 'audiourl': '', diff --git a/lib/modules/meeting/views/template/template_edit_view.dart b/lib/modules/meeting/views/template/template_edit_view.dart index 6c69d3596..27dc4fb5c 100644 --- a/lib/modules/meeting/views/template/template_edit_view.dart +++ b/lib/modules/meeting/views/template/template_edit_view.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; @@ -5,6 +7,7 @@ import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; import '../../../../data/services/db/sqflite_api.dart'; +import '../../../../data/services/deapsound_ai_service.dart'; import '../../../../data/services/network/api.dart'; import '../../controllers/meeting_details_controller.dart'; @@ -27,6 +30,10 @@ class _TemplateEditViewState extends State { bool _isEnable = false; + final _deapsoundAI = DeapsoundAIService(); + StreamSubscription? _aiResponseSubscription; + bool _isLoading = false; + @override void initState() { super.initState(); @@ -42,6 +49,7 @@ class _TemplateEditViewState extends State { _nameController.dispose(); _descController.dispose(); _promptController.dispose(); + _aiResponseSubscription?.cancel(); super.dispose(); } @@ -151,15 +159,42 @@ class _TemplateEditViewState extends State { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Padding( - padding: EdgeInsets.only(left: 10.w), - child: Text( - title, - style: TextStyle( - fontSize: 14.sp, - color: isDarkMode ? Colors.white60 : Colors.black87, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: EdgeInsets.only(left: 10.w), + child: Text( + title, + style: TextStyle( + fontSize: 14.sp, + color: isDarkMode ? Colors.white60 : Colors.black87, + ), + ), ), - ), + if (maxLines > 1) + GestureDetector( + onTap: () { + _generateTemplatePrompt(); + }, + child: Container( + width: 26.w, + height: 26.w, + margin: EdgeInsets.only(right: 10.w), + decoration: BoxDecoration( + color: _isLoading + ? const Color(0xFF4C3F91) + : const Color(0xFF6A5AE0), + borderRadius: BorderRadius.circular(26.r), + ), + child: Icon( + _isLoading ? Icons.pause : Icons.smart_toy, + size: 18.w, + color: Colors.white, + ), + ), + ), + ], ), Container( margin: EdgeInsets.only(top: 10.w, bottom: 20.w), @@ -293,4 +328,37 @@ class _TemplateEditViewState extends State { }); EasyLoading.dismiss(); } + + void _generateTemplatePrompt() { + if (_isLoading || + _nameController.text.isEmpty || + _descController.text.isEmpty) { + return; + } + _promptController.clear(); + setState(() { + _isLoading = true; + }); + final responseStream = _deapsoundAI.sendMessageStream( + messages: [ + {'role': 'system', 'content': '名称:${_nameController.text}'}, + {'role': 'system', 'content': '描述:${_descController.text}'}, + { + 'role': 'user', + 'content': + '请基于以上名称与描述,生成一个高质量会议总结提示词(Prompt),用于指导模型对会议记录进行结构化总结。只返回提示词文本,不要提供示例或额外解释。', + }, + ], + ); + _aiResponseSubscription = responseStream.listen( + (chunk) { + _promptController.text += chunk; + }, + onDone: () { + setState(() { + _isLoading = false; + }); + }, + ); + } } diff --git a/lib/modules/translation/controllers/translation_list_controller.dart b/lib/modules/translation/controllers/translation_list_controller.dart index 2d4bffc19..a908bf6c4 100644 --- a/lib/modules/translation/controllers/translation_list_controller.dart +++ b/lib/modules/translation/controllers/translation_list_controller.dart @@ -164,8 +164,8 @@ class TranslationListController extends GetxController { return; } - // Directory exis - files.value = dir + // 获取音频文件列表并按修改时间降序排序(最新的在最上面) + final audioFiles = dir .listSync() .where((f) => f is File && @@ -176,6 +176,15 @@ class TranslationListController extends GetxController { f.path.endsWith('.mp4') || f.path.endsWith('.mov'))) .toList(); + + // 按文件修改时间降序排序,最新的录音文件在最上面 + audioFiles.sort((a, b) { + final aStat = a.statSync(); + final bStat = b.statSync(); + return bStat.modified.compareTo(aStat.modified); // 降序排序 + }); + + files.value = audioFiles; } catch (e) { print("Error loading files: $e"); files.value = []; // Return empty list on error