You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
331 lines
9.2 KiB
331 lines
9.2 KiB
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>();
|
|
|
|
List _taskList = [];
|
|
RxList taskFinishList = [].obs;
|
|
|
|
bool _isTask = false;
|
|
|
|
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 = {};
|
|
|
|
int meetingId = 0;
|
|
RxInt tasktype = 1.obs;
|
|
List textList = [];
|
|
String summary = '';
|
|
String overview = '';
|
|
|
|
@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 = _storage.read("meeting_task_list") ?? [];
|
|
taskFinishList.value = _storage.read("meeting_task_finish_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,
|
|
});
|
|
taskFinishList.add({
|
|
'id': id,
|
|
'tasktype': 1,
|
|
});
|
|
_storage.write("meeting_task_list", _taskList);
|
|
_storage.write("meeting_task_finish_list", taskFinishList);
|
|
_executeTask();
|
|
}
|
|
|
|
void _executeTask() async {
|
|
if (_isTask) return;
|
|
_isTask = true;
|
|
while (_taskList.isNotEmpty) {
|
|
await Future.delayed(const Duration(seconds: 2));
|
|
|
|
for (var element in List.from(_taskList)) {
|
|
await _fileRecognize(element);
|
|
}
|
|
}
|
|
_isTask = false;
|
|
}
|
|
|
|
void removeTask(int id, {bool isDeleteTask = false}) {
|
|
Map taskFinishData = taskFinishList.firstWhere(
|
|
(element) => element['id'] == id,
|
|
orElse: () => {},
|
|
);
|
|
if (taskFinishData.isNotEmpty) {
|
|
if (isDeleteTask || taskFinishData['tasktype'] >= 3) {
|
|
taskFinishList.remove(taskFinishData);
|
|
_storage.write("meeting_task_finish_list", taskFinishList);
|
|
}
|
|
}
|
|
if (isDeleteTask) {
|
|
_taskList.removeWhere((element) => element['id'] == id);
|
|
_storage.write("meeting_task_list", _taskList);
|
|
}
|
|
}
|
|
|
|
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['id'], respDic['resp']['utterances']);
|
|
return;
|
|
} else if (code < 2000) {
|
|
Logger.debug("FileRecognize failed");
|
|
return;
|
|
}
|
|
} catch (e) {
|
|
Logger.error('Error occurred: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
Future<void> _addTextList(int id, 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': 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);
|
|
List newSpeakerList = List.from(speakerList);
|
|
Synchrodata.saveOperationRecord('update', {
|
|
'original': jsonEncode(newSpeakerList),
|
|
'id': id,
|
|
});
|
|
if (id == meetingId) {
|
|
textList = newSpeakerList;
|
|
tasktype.value = 2;
|
|
}
|
|
_taskList.removeWhere((element) => element['id'] == id);
|
|
Map taskFinishData = taskFinishList.firstWhere(
|
|
(element) => element['id'] == id,
|
|
orElse: () => {},
|
|
);
|
|
if (taskFinishData.isNotEmpty) {
|
|
taskFinishData['tasktype'] = 2;
|
|
taskFinishList.refresh();
|
|
}
|
|
_storage.write("meeting_task_list", _taskList);
|
|
_storage.write("meeting_task_finish_list", taskFinishList);
|
|
}
|
|
aiServiceMessage(id, text);
|
|
}
|
|
|
|
void aiServiceMessage(int id, String text) {
|
|
int awaitQuantity = 0;
|
|
String summaryText = '';
|
|
String overviewText = '';
|
|
DeapsoundAIService().sendMessage(
|
|
messages: [
|
|
{
|
|
'role': 'system',
|
|
'content':
|
|
'您将扮演一名会议总结专家,拥有超强的信息归纳与细分能力。不仅能高效处理各类通用场景会议,精准提炼会议核心内容,为后续思维导图生成奠定坚实基础。若涉及人员,人员名称保留[]。并根据内容只输出对应语言。',
|
|
},
|
|
{'role': 'user', 'content': text},
|
|
],
|
|
).then((value) {
|
|
awaitQuantity++;
|
|
summaryText = value;
|
|
if (awaitQuantity >= 2) {
|
|
_aiServiceValue(id, summaryText, overviewText);
|
|
}
|
|
});
|
|
DeapsoundAIService().sendMessage(
|
|
messages: [
|
|
{
|
|
'role': 'system',
|
|
'content': '您将扮演一名会议事件归纳专家,能准确抓住会议中事件的关键点,并每个事件只需一句话精简总结。',
|
|
},
|
|
{'role': 'user', 'content': text},
|
|
],
|
|
).then((value) {
|
|
awaitQuantity++;
|
|
overviewText = value;
|
|
if (awaitQuantity >= 2) {
|
|
_aiServiceValue(id, summaryText, overviewText);
|
|
}
|
|
});
|
|
}
|
|
|
|
void _aiServiceValue(int id, String summaryText, String overviewText) {
|
|
SqfliteApi.editMeeting(id, {
|
|
'tasktype': 3,
|
|
'summary': summaryText,
|
|
'overview': overviewText,
|
|
});
|
|
if (id == meetingId) {
|
|
summary = summaryText;
|
|
overview = overviewText;
|
|
tasktype.value = 3;
|
|
}
|
|
Map taskFinishData = taskFinishList.firstWhere(
|
|
(element) => element['id'] == id,
|
|
orElse: () => {},
|
|
);
|
|
if (taskFinishData.isNotEmpty) {
|
|
taskFinishData['tasktype'] = 3;
|
|
taskFinishList.refresh();
|
|
}
|
|
_storage.write("meeting_task_finish_list", taskFinishList);
|
|
}
|
|
}
|
|
|