diff --git a/lib/core/bindings/initial_binding.dart b/lib/core/bindings/initial_binding.dart index 231096b83..d9fc3e47a 100644 --- a/lib/core/bindings/initial_binding.dart +++ b/lib/core/bindings/initial_binding.dart @@ -2,6 +2,7 @@ import 'package:deep_voice/data/services/location_manager.dart'; import 'package:deep_voice/data/services/music_manager.dart'; import 'package:deep_voice/data/services/navigation_manager.dart'; import 'package:get/get.dart'; +import '../../data/services/meeting/meeting_task_service.dart'; import '../../data/services/meeting/meeting_upload_service.dart'; import '../../data/services/speech_factory.dart'; import '../../data/services/volcano_translation_service.dart'; @@ -51,6 +52,9 @@ class InitialBinding extends Bindings { Get.lazyPut(() => VersionUpdateService(), fenix: true); + // 会议助手任务服务 + Get.lazyPut(() => MeetingTaskService(), fenix: true); + // 会议助手音频上传 Get.lazyPut(() => MeetingUploadService(), fenix: true); diff --git a/lib/data/services/meeting/meeting_task_service.dart b/lib/data/services/meeting/meeting_task_service.dart new file mode 100644 index 000000000..aac40b62e --- /dev/null +++ b/lib/data/services/meeting/meeting_task_service.dart @@ -0,0 +1,302 @@ +import 'dart:convert'; + +import 'package:get/get.dart'; +import 'package:get_storage/get_storage.dart'; +import 'package:http/http.dart' as http; + +import '../../../core/utils/logger.dart'; +import '../../../core/utils/synchrodata.dart'; +import '../../models/appconfig.dart'; +import '../db/sqflite_api.dart'; +import '../deapsound_ai_service.dart'; +import 'meeting_upload_service.dart'; + +class MeetingTaskService extends GetxService { + final GetStorage _storage = GetStorage(); + + MeetingUploadService get _uploadService => Get.find(); + + RxList taskList = [].obs; + + bool _isTask = false; + int _handled = 0; + + String _systemPrompt = ''; + String _userId = ''; + + final String _appid = '2316081933'; + final String _token = 'mcJTh6OelBqU_L78lgGd77Nyrc_-5-En'; + final String _cluster = 'volc_auc_common_flash'; + final String _serviceUrl = 'https://openspeech.bytedance.com/api/v1/auc'; + Map _headers = {}; + + RxList textList = [].obs; + String allText = ''; + + @override + void onInit() { + super.onInit(); + _headers = { + 'Authorization': 'Bearer; $_token', + 'Content-Type': 'application/json', + }; + _getAgent(); + _getTaskList(); + } + + void _getAgent() async { + Map userInfo = _storage.read("user_info"); + _userId = userInfo['user']['uid']; + _systemPrompt = AppConfig.agentsystemPrompt("meet_assistant") ?? ''; + } + + void _getTaskList() { + taskList.value = _storage.read("meeting_task_list") ?? []; + _executeTask(); + } + + Future addTask(int id, String audiourl, String taskid) async { + if (audiourl.isEmpty) { + Map uploadData = _uploadService.uploadList.firstWhere( + (element) => element['id'] == id, + orElse: () => {}, + ); + if (uploadData.isNotEmpty) { + if (uploadData['audiourl'].isEmpty) { + uploadData['isTask'] = true; + } else { + await addTaskList(id, uploadData['audiourl'], taskid); + } + } + } else { + await addTaskList(id, audiourl, taskid); + } + } + + Future addTaskList(int id, String audiourl, String taskId) async { + if (taskId.isEmpty) { + taskId = await _submitTask(audiourl); + } + await SqfliteApi.editMeeting(id, {'tasktype': 1, 'taskid': taskId}); + taskList.add({ + 'id': id, + 'taskid': taskId, + 'tasktype': 1, + }); + _storage.write("meeting_task_list", taskList); + _executeTask(); + } + + void _executeTask() async { + if (_isTask) return; + _isTask = true; + _handled = 0; + while (_handled < taskList.length) { + await Future.delayed(const Duration(seconds: 2)); + + int completed = 0; + for (var element in taskList) { + if (element['tasktype'] == 1) { + await _fileRecognize(element); + } else { + completed++; + } + } + _handled = completed; + } + _isTask = false; + } + + void removeTask(int id, {bool isDeleteTask = false}) { + Map taskData = taskList.firstWhere( + (element) => element['id'] == id, + orElse: () => {}, + ); + if (taskData.isNotEmpty) { + if (isDeleteTask || taskData['tasktype'] >= 3) { + taskList.remove(taskData); + _storage.write("meeting_task_list", taskList); + if (taskList.isEmpty) { + _handled = 0; + } + } + } + } + + Future _submitTask(String audiourl) async { + String format = _getFileType(audiourl); + + final requestBody = jsonEncode({ + "app": { + "appid": _appid, + "token": _token, + "cluster": _cluster, + }, + "user": { + "uid": _userId, + }, + "audio": { + "format": format, + "url": audiourl, + }, + "additions": { + "with_speaker_info": "True", + } + }); + + try { + final response = await http.post( + Uri.parse('$_serviceUrl/submit'), + headers: _headers, + body: requestBody, + ); + + if (response.statusCode != 200) { + throw Exception('Submit failed with status: ${response.statusCode}'); + } + + final respDic = jsonDecode(response.body); + final taskId = respDic['resp']['id'] as String; + Logger.debug('taskId: $taskId'); + return taskId; + } catch (e) { + Logger.error('Submit error: ${e.toString()}'); + rethrow; + } + } + + String _getFileType(String path) { + List array = path.split('.'); + return array[array.length - 1]; + } + + Future> _queryTask(String taskId) async { + final queryBody = jsonEncode({ + "appid": _appid, + "token": _token, + "id": taskId, + "cluster": _cluster, + }); + + try { + final response = await http.post( + Uri.parse('$_serviceUrl/query'), + headers: _headers, + body: queryBody, + ); + + if (response.statusCode != 200) { + throw Exception('Query failed with status: ${response.statusCode}'); + } + + final respDic = jsonDecode(response.body); + return respDic; + } catch (e) { + Logger.error('Query error: ${e.toString()}'); + rethrow; + } + } + + Future _fileRecognize(Map item) async { + try { + var respDic = await _queryTask(item['taskid']); + var code = respDic['resp']['code'] as int; + + if (code == 1000) { + await _addTextList(item, respDic['resp']['utterances']); + return; + } else if (code < 2000) { + Logger.debug("FileRecognize failed"); + return; + } + } catch (e) { + Logger.error('Error occurred: ${e.toString()}'); + } + } + + Future _addTextList(Map item, List utterances) async { + String text = ''; + String personnel = ''; + List> list = []; + for (var element in utterances) { + String speaker = ''; + if (element['additions'].isNotEmpty) { + speaker = 'Speaker ${element['additions']['speaker']}'; + text += '[$speaker]: '; + if (!personnel.contains(speaker)) { + personnel += '[$speaker] '; + } + } + list.add({ + 'meetingid': item['id'], + 'content': element['text'], + 'starttime': element['start_time'], + 'endtime': element['end_time'], + 'speaker': speaker, + }); + text += '${element['text']}\n'; + } + var result = await SqfliteApi.insertMeetingSpeaker(list); + if (result != null) { + await SqfliteApi.editMeeting( + item['id'], + {'tasktype': 2, 'personnel': personnel}, + ); + List speakerList = await SqfliteApi.getMeetingSpeaker(item['id']); + textList.value = List.from(speakerList); + Synchrodata.saveOperationRecord('update', { + 'original': jsonEncode(textList), + 'id': item['id'], + }); + item['tasktype'] = 2; + } + allText = text; + _aiServiceMessage(item); + } + + void _aiServiceMessage(Map item) { + int awaitQuantity = 0; + String summaryText = ''; + String overviewText = ''; + DeapsoundAIService().sendMessage( + messages: [ + { + 'role': 'system', + 'content': + '您将扮演一名会议总结专家,拥有超强的信息归纳与细分能力。不仅能高效处理各类通用场景会议,精准提炼会议核心内容,为后续思维导图生成奠定坚实基础。若涉及人员,人员名称保留[]。并根据内容只输出对应语言。', + }, + {'role': 'user', 'content': allText}, + ], + ).then((value) { + awaitQuantity++; + summaryText = value; + if (awaitQuantity >= 2) { + _aiServiceValue(item, summaryText, overviewText); + } + }); + DeapsoundAIService().sendMessage( + messages: [ + { + 'role': 'system', + 'content': '您将扮演一名会议事件归纳专家,能准确抓住会议中事件的关键点,并每个事件只需一句话精简总结。', + }, + {'role': 'user', 'content': allText}, + ], + ).then((value) { + awaitQuantity++; + overviewText = value; + if (awaitQuantity >= 2) { + _aiServiceValue(item, summaryText, overviewText); + } + }); + } + + void _aiServiceValue(Map item, String summaryText, String overviewText) { + SqfliteApi.editMeeting(item['id'], { + 'tasktype': 3, + 'summary': summaryText, + 'overview': overviewText, + }); + item['tasktype'] = 3; + } +} diff --git a/lib/data/services/meeting/meeting_upload_service.dart b/lib/data/services/meeting/meeting_upload_service.dart index 85ac61dac..f22fd6759 100644 --- a/lib/data/services/meeting/meeting_upload_service.dart +++ b/lib/data/services/meeting/meeting_upload_service.dart @@ -4,8 +4,11 @@ import 'package:get_storage/get_storage.dart'; import '../../../core/utils/logger.dart'; import '../../../core/utils/upload_oss.dart'; import '../db/sqflite_api.dart'; +import 'meeting_task_service.dart'; class MeetingUploadService extends GetxService { + final _taskService = Get.find(); + final GetStorage _storage = GetStorage(); RxInt meetingId = 0.obs; @@ -22,7 +25,7 @@ class MeetingUploadService extends GetxService { } void _getUploadList() { - uploadList.value = _storage.read("upload_list") ?? []; + uploadList.value = _storage.read("meeting_upload_list") ?? []; _executeUpload(); } @@ -32,8 +35,9 @@ class MeetingUploadService extends GetxService { 'filepath': filePath, 'rootdir': rootDir, 'audiourl': '', + 'isTask': false, }); - _storage.write("upload_list", uploadList); + _storage.write("meeting_upload_list", uploadList); _executeUpload(); } @@ -58,9 +62,12 @@ class MeetingUploadService extends GetxService { element['id'], {'audiourl': audiourl}, ); + if (element['isTask']) { + await _taskService.addTaskList(element['id'], audiourl, ''); + } element['audiourl'] = audiourl; uploadProgress.value = 0.0; - _storage.write("upload_list", uploadList); + _storage.write("meeting_upload_list", uploadList); } catch (e) { Logger.error('Upload failed: $e'); } @@ -78,7 +85,7 @@ class MeetingUploadService extends GetxService { if (uploadData.isNotEmpty) { if (isDeleteTask || uploadData['audiourl'].isNotEmpty) { uploadList.remove(uploadData); - _storage.write("upload_list", uploadList); + _storage.write("meeting_upload_list", uploadList); if (uploadList.isEmpty) { _handled = 0; } diff --git a/lib/modules/meeting/controllers/meeting_controller.dart b/lib/modules/meeting/controllers/meeting_controller.dart index 363383c13..6f07ab900 100644 --- a/lib/modules/meeting/controllers/meeting_controller.dart +++ b/lib/modules/meeting/controllers/meeting_controller.dart @@ -1,11 +1,9 @@ -import 'dart:convert'; import 'dart:io'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:get/get.dart'; -import 'package:http/http.dart' as http; import 'package:just_audio/just_audio.dart'; import 'package:path/path.dart' as path; import 'package:path_provider/path_provider.dart'; @@ -19,11 +17,13 @@ import '../../../core/utils/permission_util.dart'; import 'package:share_plus/share_plus.dart'; +import '../../../data/services/meeting/meeting_task_service.dart'; import '../../../data/services/meeting/meeting_upload_service.dart'; import '../../../routes/app_routes.dart'; class MeetingController extends GetxController { final meetingUploadService = Get.find(); + final meetingTaskService = Get.find(); final ScrollController listController = ScrollController(); final AudioPlayer _audioPlayer = AudioPlayer(); @@ -40,27 +40,15 @@ class MeetingController extends GetxController { TextEditingController titleController = TextEditingController(); // 录音标题 String titleCSuffix = ""; // 录音标题后缀 RxList dataList = [].obs; + // 蓝牙服务 final bleManager = Get.find(); - List dataListTask = []; - bool isDisposed = false; - String filePath = ''; - - final String _appid = '2316081933'; - final String _token = 'mcJTh6OelBqU_L78lgGd77Nyrc_-5-En'; - final String _cluster = 'volc_auc_common_flash'; - final String _serviceUrl = 'https://openspeech.bytedance.com/api/v1/auc'; - Map _headers = {}; @override void onInit() { super.onInit(); listController.addListener(_onScroll); _requestStoragePermission(); - _headers = { - 'Authorization': 'Bearer; $_token', - 'Content-Type': 'application/json', - }; _initGetDataList(); addMeetingAudio(); final Map args = Get.arguments ?? {}; @@ -79,7 +67,6 @@ class MeetingController extends GetxController { listController.dispose(); titleController.dispose(); _audioPlayer.dispose(); - isDisposed = true; super.onClose(); } @@ -107,7 +94,6 @@ class MeetingController extends GetxController { void _getDataList() async { List list = await SqfliteApi.getMeetingList((page - 1) * 10 + addQuantity); dataList.addAll(list); - queryDataListTask(list); addQuantity = 0; if (list.length < 10) { isGetMore = false; @@ -401,6 +387,7 @@ class MeetingController extends GetxController { SqfliteApi.deleteMeeting(id); _deleteFile(filepath); meetingUploadService.removeUpload(id, isDeleteTask: true); + meetingTaskService.removeTask(id, isDeleteTask: true); addQuantity--; } @@ -412,107 +399,4 @@ class MeetingController extends GetxController { await file.delete(); } } - - // 查询转写状态 - void queryDataListTask(List list, {bool isAdd = true}) { - for (var element in List.from(list)) { - if (element['tasktype'] == 1) { - if (isAdd) { - dataListTask.add(element); - } - final taskId = element['taskid']; - _fileRecognize(element['id'], taskId); - } - } - } - - Future _fileRecognize(int id, String taskId) async { - try { - final startTime = DateTime.now().millisecondsSinceEpoch; - - if (isDisposed) return; - var respDic = await _queryTask(taskId); - var code = respDic['resp']['code'] as int; - - if (code == 1000) { - await SqfliteApi.editMeetingTitle(id, {'tasktype': 2}); - int index = dataList.indexWhere((item) => item['id'] == id); - if (index != -1) { - final dataMap = Map.from(dataList[index]); - dataMap['tasktype'] = 2; - dataList[index] = dataMap; - int taskIndex = dataListTask.indexWhere((item) => item['id'] == id); - if (taskIndex != -1) { - dataListTask.removeAt(taskIndex); - } - } - return; - } else if (code < 2000) { - Logger.debug("FileRecognize failed"); - return; - } - - while (!isDisposed) { - await Future.delayed(const Duration(seconds: 2)); - - if (isDisposed) return; - - respDic = await _queryTask(taskId); - code = respDic['resp']['code'] as int; - - if (code == 1000) { - await SqfliteApi.editMeetingTitle(id, {'tasktype': 2}); - int index = dataList.indexWhere((item) => item['id'] == id); - if (index != -1) { - final dataMap = Map.from(dataList[index]); - dataMap['tasktype'] = 2; - dataList[index] = dataMap; - int taskIndex = dataListTask.indexWhere((item) => item['id'] == id); - if (taskIndex != -1) { - dataListTask.removeAt(taskIndex); - } - } - return; - } else if (code < 2000) { - Logger.debug("FileRecognize failed"); - return; - } - - final currentTime = DateTime.now().millisecondsSinceEpoch; - if (currentTime - startTime > 300 * 1000) { - Logger.debug('wait time exceeds 300s'); - return; - } - } - } catch (e) { - Logger.error('Error occurred: ${e.toString()}'); - } - } - - Future> _queryTask(String taskId) async { - final queryBody = jsonEncode({ - "appid": _appid, - "token": _token, - "id": taskId, - "cluster": _cluster, - }); - - try { - final response = await http.post( - Uri.parse('$_serviceUrl/query'), - headers: _headers, - body: queryBody, - ); - - if (response.statusCode != 200) { - throw Exception('Query failed with status: ${response.statusCode}'); - } - - final respDic = jsonDecode(response.body); - return respDic; - } catch (e) { - Logger.error('Query error: ${e.toString()}'); - rethrow; - } - } } diff --git a/lib/modules/meeting/controllers/meeting_details_controller.dart b/lib/modules/meeting/controllers/meeting_details_controller.dart index 90c08b4d9..3b731eff6 100644 --- a/lib/modules/meeting/controllers/meeting_details_controller.dart +++ b/lib/modules/meeting/controllers/meeting_details_controller.dart @@ -9,20 +9,14 @@ import 'package:flutter/services.dart' show rootBundle; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; -import 'package:get_storage/get_storage.dart'; -import 'package:http/http.dart' as http; import 'package:path_provider/path_provider.dart'; -import '../../../core/utils/logger.dart'; import '../../../core/utils/synchrodata.dart'; -import '../../../core/utils/upload_oss.dart'; -import '../../../data/models/appconfig.dart'; import '../../../data/services/db/sqflite_api.dart'; -import '../../../data/services/deapsound_ai_service.dart'; +import '../../../data/services/meeting/meeting_task_service.dart'; import '../../../data/services/meeting/meeting_upload_service.dart'; import '../model/meeting_details_model.dart'; import '../model/meeting_model.dart'; -import 'meeting_controller.dart'; class MeetingDetailsController extends GetxController with GetTickerProviderStateMixin { @@ -32,9 +26,13 @@ class MeetingDetailsController extends GetxController late AnimationController lottieController; final _meetingUploadService = Get.find(); - final _meetingController = Get.find(); + final _meetingTaskService = Get.find(); final PlayerController playerController = PlayerController(); + + StreamSubscription? _currentDurationSubscription; + StreamSubscription? _playerStateSubscription; + RxBool isTop = false.obs; RxInt durationMax = 0.obs; RxDouble dragOffset = 210.w.obs; @@ -66,17 +64,6 @@ class MeetingDetailsController extends GetxController RxBool isDownload = false.obs; RxDouble downloadProgress = 0.0.obs; - String _systemPrompt = ''; - String _userId = ''; - - bool _isDisposed = false; - - final String _appid = '2316081933'; - final String _token = 'mcJTh6OelBqU_L78lgGd77Nyrc_-5-En'; - final String _cluster = 'volc_auc_common_flash'; - final String _serviceUrl = 'https://openspeech.bytedance.com/api/v1/auc'; - Map _headers = {}; - @override void onInit() { super.onInit(); @@ -91,66 +78,23 @@ class MeetingDetailsController extends GetxController ..duration = const Duration(seconds: 2); final Map args = Get.arguments ?? {}; id = args['id']; - _headers = { - 'Authorization': 'Bearer; $_token', - 'Content-Type': 'application/json', - }; - _getAgent(); _getDataDetails(); _loadJS(); } @override void onClose() { + _currentDurationSubscription?.cancel(); + _playerStateSubscription?.cancel(); tabController.dispose(); playerController.dispose(); - _isDisposed = true; lottieController.dispose(); super.onClose(); } void popInvokedWithResult(didPop, result) async { - if (meetingData.value.tasktype != meetingDetails.value.tasktype) { - await SqfliteApi.editMeetingTitle( - id, {'tasktype': meetingDetails.value.tasktype}); - int index = - _meetingController.dataList.indexWhere((item) => item['id'] == id); - if (index != -1) { - final dataMap = - Map.from(_meetingController.dataList[index]); - dataMap['tasktype'] = meetingDetails.value.tasktype; - if (dataMap['taskid'].isEmpty) { - dataMap['taskid'] = meetingDetails.value.taskid; - } - _meetingController.dataList[index] = dataMap; - int taskIndex = _meetingController.dataListTask - .indexWhere((item) => item['id'] == id); - if (taskIndex != -1) { - if (meetingDetails.value.tasktype == 1) { - _meetingController.dataListTask[taskIndex] = dataMap; - } else { - _meetingController.dataListTask.removeAt(taskIndex); - } - } else { - if (meetingDetails.value.tasktype == 1) { - _meetingController.dataListTask.add(dataMap); - } - } - } - } - _meetingController.isDisposed = false; - _meetingController.queryDataListTask( - _meetingController.dataListTask, - isAdd: false, - ); _meetingUploadService.removeUpload(id); - } - - void _getAgent() async { - final GetStorage storage = GetStorage(); - Map userInfo = storage.read("user_info"); - _userId = userInfo['user']['uid']; - _systemPrompt = AppConfig.agentsystemPrompt("meet_assistant") ?? ''; + _meetingTaskService.removeTask(id); } void _getDataDetails() async { @@ -168,10 +112,6 @@ class MeetingDetailsController extends GetxController List speakerList = await SqfliteApi.getMeetingSpeaker(id); textList.value = List.from(speakerList); } - if (meetingDetails.value.tasktype == 1 || - meetingDetails.value.tasktype == 2) { - summaryCreate(); - } isLoading.value = false; } @@ -183,7 +123,8 @@ class MeetingDetailsController extends GetxController ); durationMax.value = await playerController.getDuration(DurationType.max); playerController.setFinishMode(finishMode: FinishMode.pause); - playerController.onCurrentDurationChanged.listen((int position) { + _currentDurationSubscription = + playerController.onCurrentDurationChanged.listen((int position) { currentDuration.value = position; if (speakerAllEndtime.value > 0) { if (position >= speakerAllEndtime.value) { @@ -193,9 +134,9 @@ class MeetingDetailsController extends GetxController } } }); - playerController.onPlayerStateChanged.listen((PlayerState playerState) { + _playerStateSubscription = + playerController.onPlayerStateChanged.listen((PlayerState playerState) { isPlay.value = playerState.isPlaying; - if (_isDisposed) return; if (playerState.isPlaying) { lottieController.repeat(); } else { @@ -283,253 +224,12 @@ class MeetingDetailsController extends GetxController } void summaryCreate() async { - if (meetingDetails.value.tasktype <= 1) { - await _audioSpeaker(); - } - if (allText.isEmpty) { - String text = ''; - for (var element in textList) { - if (element['speaker'].isNotEmpty) { - text += '[${element['speaker']}]: '; - } - text += '${element['content']}\n'; - } - allText = text; - } - if (allText.isEmpty) return; - _aiServiceMessage(); - } - - void _aiServiceMessage() { - int awaitQuantity = 0; - int verifyQuantity = 0; - String summaryText = meetingDetails.value.summary; - String overviewText = meetingDetails.value.overview; - if (summaryText.isEmpty) { - verifyQuantity++; - DeapsoundAIService().sendMessage( - messages: [ - { - 'role': 'system', - 'content': - '您将扮演一名会议总结专家,拥有超强的信息归纳与细分能力。不仅能高效处理各类通用场景会议,精准提炼会议核心内容,为后续思维导图生成奠定坚实基础。若涉及人员,人员名称保留[]。并根据内容只输出对应语言。', - }, - {'role': 'user', 'content': allText}, - ], - ).then((value) { - awaitQuantity++; - summaryText = value; - if (awaitQuantity >= verifyQuantity) { - _aiServiceValue(summaryText, overviewText); - } - }); - } - if (overviewText.isEmpty) { - verifyQuantity++; - DeapsoundAIService().sendMessage( - messages: [ - { - 'role': 'system', - 'content': '您将扮演一名会议事件归纳专家,能准确抓住会议中事件的关键点,并每个事件只需一句话精简总结。', - }, - {'role': 'user', 'content': allText}, - ], - ).then((value) { - awaitQuantity++; - overviewText = value; - if (awaitQuantity >= verifyQuantity) { - _aiServiceValue(summaryText, overviewText); - } - }); - } - } - - void _aiServiceValue(String summaryText, String overviewText) { - SqfliteApi.editMeeting(id, { - 'tasktype': 3, - 'summary': summaryText, - 'overview': overviewText, - }); - meetingDetails.value.tasktype = 3; - meetingDetails.value.summary = summaryText; - meetingDetails.value.overview = overviewText; - meetingDetails.refresh(); - } - - Future _audioSpeaker() async { EasyLoading.show(); String audiourl = meetingData.value.audiourl; - if (audiourl.isEmpty) { - audiourl = await UploadOss.upload( - filepath: meetingData.value.filepath, - rootDir: 'audio', - ); - meetingData.value.audiourl = audiourl; - } String taskId = meetingDetails.value.taskid; - if (taskId.isEmpty) { - taskId = await _submitTask(audiourl); - await SqfliteApi.editMeeting(id, {'tasktype': 1, 'taskid': taskId}); - meetingDetails.value.taskid = taskId; - meetingDetails.value.tasktype = 1; - meetingDetails.refresh(); - } + await _meetingTaskService.addTask(id, audiourl, taskId); + meetingDetails.value.tasktype = 1; + meetingDetails.refresh(); EasyLoading.dismiss(); - await _fileRecognize(taskId); - } - - Future _submitTask(String audiourl) async { - String format = _getFileType(audiourl); - - final requestBody = jsonEncode({ - "app": { - "appid": _appid, - "token": _token, - "cluster": _cluster, - }, - "user": { - "uid": _userId, - }, - "audio": { - "format": format, - "url": audiourl, - }, - "additions": { - "with_speaker_info": "True", - } - }); - - try { - final response = await http.post( - Uri.parse('$_serviceUrl/submit'), - headers: _headers, - body: requestBody, - ); - - if (response.statusCode != 200) { - throw Exception('Submit failed with status: ${response.statusCode}'); - } - - final respDic = jsonDecode(response.body); - final taskId = respDic['resp']['id'] as String; - Logger.debug('taskId: $taskId'); - return taskId; - } catch (e) { - Logger.error('Submit error: ${e.toString()}'); - rethrow; - } - } - - String _getFileType(String path) { - List array = path.split('.'); - return array[array.length - 1]; - } - - Future> _queryTask(String taskId) async { - final queryBody = jsonEncode({ - "appid": _appid, - "token": _token, - "id": taskId, - "cluster": _cluster, - }); - - try { - final response = await http.post( - Uri.parse('$_serviceUrl/query'), - headers: _headers, - body: queryBody, - ); - - if (response.statusCode != 200) { - throw Exception('Query failed with status: ${response.statusCode}'); - } - - final respDic = jsonDecode(response.body); - return respDic; - } catch (e) { - Logger.error('Query error: ${e.toString()}'); - rethrow; - } - } - - Future _fileRecognize(String taskId) async { - try { - final startTime = DateTime.now().millisecondsSinceEpoch; - - if (_isDisposed) return; - var respDic = await _queryTask(taskId); - var code = respDic['resp']['code'] as int; - - if (code == 1000) { - await _addTextList(respDic['resp']['utterances']); - return; - } else if (code < 2000) { - Logger.debug("FileRecognize failed"); - return; - } - - while (!_isDisposed) { - await Future.delayed(const Duration(seconds: 2)); - - if (_isDisposed) return; - - respDic = await _queryTask(taskId); - code = respDic['resp']['code'] as int; - - if (code == 1000) { - await _addTextList(respDic['resp']['utterances']); - return; - } else if (code < 2000) { - Logger.debug("FileRecognize failed"); - return; - } - - final currentTime = DateTime.now().millisecondsSinceEpoch; - if (currentTime - startTime > 300 * 1000) { - Logger.debug('wait time exceeds 300s'); - return; - } - } - } catch (e) { - Logger.error('Error occurred: ${e.toString()}'); - } - } - - Future _addTextList(List utterances) async { - String text = ''; - String personnel = ''; - List> list = []; - for (var element in utterances) { - String speaker = ''; - if (element['additions'].isNotEmpty) { - speaker = 'Speaker ${element['additions']['speaker']}'; - text += '[$speaker]: '; - if (!personnel.contains(speaker)) { - personnel += '[$speaker] '; - } - } - list.add({ - 'meetingid': id, - 'content': element['text'], - 'starttime': element['start_time'], - 'endtime': element['end_time'], - 'speaker': speaker, - }); - text += '${element['text']}\n'; - } - var result = await SqfliteApi.insertMeetingSpeaker(list); - if (result != null) { - await SqfliteApi.editMeeting(id, {'tasktype': 2, 'personnel': personnel}); - List speakerList = await SqfliteApi.getMeetingSpeaker(id); - textList.value = List.from(speakerList); - Synchrodata.saveOperationRecord('update', { - 'original': jsonEncode(textList), - 'id': id, - }); - meetingDetails.value.tasktype = 2; - meetingDetails.value.personnel = personnel; - meetingDetails.refresh(); - } - allText = text; } } diff --git a/lib/modules/meeting/views/meeting_view.dart b/lib/modules/meeting/views/meeting_view.dart index a45184d51..338b06993 100644 --- a/lib/modules/meeting/views/meeting_view.dart +++ b/lib/modules/meeting/views/meeting_view.dart @@ -472,7 +472,6 @@ class MeetingView extends GetView { Widget _item(BuildContext context, bool isDarkMode, MeetingModel data) { return GestureDetector( onTap: () { - controller.isDisposed = true; Get.toNamed(Routes.meetingDetails, arguments: { 'id': data.id, });