6 changed files with 337 additions and 441 deletions
@ -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<MeetingUploadService>(); |
||||
|
|
||||
|
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<String, String> _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<void> 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<void> 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<String> _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<String> array = path.split('.'); |
||||
|
return array[array.length - 1]; |
||||
|
} |
||||
|
|
||||
|
Future<Map<String, dynamic>> _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<void> _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<void> _addTextList(Map item, List utterances) async { |
||||
|
String text = ''; |
||||
|
String personnel = ''; |
||||
|
List<Map<String, Object?>> 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; |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue