|
|
|
@ -3,6 +3,7 @@ import 'dart:convert'; |
|
|
|
import 'package:get/get.dart'; |
|
|
|
import 'package:get_storage/get_storage.dart'; |
|
|
|
|
|
|
|
import '../../../core/utils/logger.dart'; |
|
|
|
import '../db/sqflite_api.dart'; |
|
|
|
import '../network/api.dart'; |
|
|
|
import '../../models/user_Info.dart'; |
|
|
|
@ -143,6 +144,11 @@ class MeetingTaskService extends GetxService { |
|
|
|
TranscribeService serviceType, |
|
|
|
) async { |
|
|
|
tasktype.value = 3; |
|
|
|
String oldSummary = ''; |
|
|
|
try { |
|
|
|
final data = await SqfliteApi.getMeetingDetails(id); |
|
|
|
oldSummary = (data['details']?['summary'] ?? '').toString(); |
|
|
|
} catch (_) {} |
|
|
|
await Api.refreshTaskEchomeet({ |
|
|
|
'id': id, |
|
|
|
'templateid': templateid, |
|
|
|
@ -150,9 +156,12 @@ class MeetingTaskService extends GetxService { |
|
|
|
'tolanguage': tolanguage, |
|
|
|
'service_type': serviceType.value, |
|
|
|
}); |
|
|
|
_taskList.removeWhere((i) => i['id'] == id); |
|
|
|
_taskList.add({ |
|
|
|
'id': id, |
|
|
|
'tasktype': 3, |
|
|
|
'oldSummary': oldSummary, |
|
|
|
'pollAttempts': 0, |
|
|
|
}); |
|
|
|
await SqfliteApi.editMeetingTitle( |
|
|
|
id, |
|
|
|
@ -174,12 +183,19 @@ class MeetingTaskService extends GetxService { |
|
|
|
void _executeTask() async { |
|
|
|
if (_isTask) return; |
|
|
|
_isTask = true; |
|
|
|
try { |
|
|
|
while (_taskList.isNotEmpty) { |
|
|
|
await Future.delayed(const Duration(seconds: 5)); |
|
|
|
try { |
|
|
|
await _queryTask(); |
|
|
|
} catch (e, st) { |
|
|
|
Logger.error('MeetingTask polling _queryTask failed: $e\n$st'); |
|
|
|
} |
|
|
|
} |
|
|
|
} finally { |
|
|
|
_isTask = false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
Future<void> removeTask(int id) async { |
|
|
|
_taskList.removeWhere((element) => element['id'] == id); |
|
|
|
@ -204,6 +220,11 @@ class MeetingTaskService extends GetxService { |
|
|
|
'ids': ids, |
|
|
|
}); |
|
|
|
List queryList = response['records'] ?? []; |
|
|
|
Logger.d( |
|
|
|
'MeetingTask', |
|
|
|
'poll: ids=$ids, server returned ${queryList.length} records, ' |
|
|
|
'states=${queryList.map((e) => '${e['id']}:${e['state']}').toList()}', |
|
|
|
); |
|
|
|
for (var element in queryList) { |
|
|
|
int id = element['id']; |
|
|
|
int newTasktype = element['state']; |
|
|
|
@ -211,6 +232,32 @@ class MeetingTaskService extends GetxService { |
|
|
|
(i) => i['id'] == id, |
|
|
|
orElse: () => {}, |
|
|
|
); |
|
|
|
|
|
|
|
// 重新总结的兜底:服务端有时会立刻回 state>=5 但 summary 还是旧的, |
|
|
|
// 等真正的新内容生成后才更新。这里用提交重总结时记录的 oldSummary |
|
|
|
// 做比对,只要服务端返回的 summary 还跟旧的一样,就当作未完成继续轮询, |
|
|
|
// 避免任务被过早移出 _taskList、polling 停掉之后再也拿不到新内容。 |
|
|
|
const int kMaxStaleAttempts = 60; // ~5 分钟(按 5s 间隔) |
|
|
|
if (taskData.isNotEmpty && newTasktype >= 5) { |
|
|
|
final String oldSummary = |
|
|
|
(taskData['oldSummary'] ?? '').toString(); |
|
|
|
final String returnedSummary = |
|
|
|
(element['summary'] ?? '').toString(); |
|
|
|
int attempts = (taskData['pollAttempts'] ?? 0) as int; |
|
|
|
if (oldSummary.isNotEmpty && |
|
|
|
returnedSummary == oldSummary && |
|
|
|
attempts < kMaxStaleAttempts) { |
|
|
|
taskData['pollAttempts'] = attempts + 1; |
|
|
|
Logger.d( |
|
|
|
'MeetingTask', |
|
|
|
're-summary still pending for id=$id ' |
|
|
|
'(server reports state=$newTasktype but summary unchanged, ' |
|
|
|
'attempt=${attempts + 1})', |
|
|
|
); |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (taskData.isNotEmpty) { |
|
|
|
int oldTasktype = taskData['tasktype']; |
|
|
|
if (oldTasktype != newTasktype) { |
|
|
|
@ -233,12 +280,84 @@ class MeetingTaskService extends GetxService { |
|
|
|
} |
|
|
|
if (oldTasktype < 5 && newTasktype >= 5) { |
|
|
|
// 总结完成 |
|
|
|
// 重新总结场景下 translate 也会被服务端按新目标语言重写, |
|
|
|
// 必须把它落进 meetingspeaker 表,否则转写 tab 仍然显示旧语言。 |
|
|
|
final translateField = element['translate']; |
|
|
|
bool translateRefreshed = false; |
|
|
|
Logger.d( |
|
|
|
'MeetingTask', |
|
|
|
'summary complete for id=$id: ' |
|
|
|
'translate ${translateField == null ? 'MISSING' : 'len=${translateField.toString().length}'}, ' |
|
|
|
'available element keys=${element.keys.toList()}', |
|
|
|
); |
|
|
|
if (translateField != null && |
|
|
|
translateField.toString().isNotEmpty) { |
|
|
|
try { |
|
|
|
List<dynamic> decodeList = jsonDecode(translateField); |
|
|
|
List<Map<String, Object?>> speakerList = decodeList |
|
|
|
.map((e) => Map<String, Object?>.from(e)) |
|
|
|
.toList(); |
|
|
|
await SqfliteApi.deleteMeetingSpeaker(id); |
|
|
|
await SqfliteApi.insertMeetingSpeaker(speakerList); |
|
|
|
translateRefreshed = true; |
|
|
|
} catch (e) { |
|
|
|
Logger.error( |
|
|
|
'MeetingTask: failed to refresh meetingspeaker on ' |
|
|
|
'summary complete for id=$id: $e', |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
await SqfliteApi.editMeeting(id, { |
|
|
|
'tasktype': newTasktype, |
|
|
|
'personnel': element['personnel'] ?? '', |
|
|
|
'summary': element['summary'] ?? '', |
|
|
|
'overview': element['overview'] ?? '', |
|
|
|
}); |
|
|
|
|
|
|
|
// 兜底:如果 polling 响应没带 translate(服务端可能在 |
|
|
|
// /echomeet_getrecords 里不返回完整字段),主动去 |
|
|
|
// /echomeet_getallrecords 拉一次,把新翻译同步到本地 DB。 |
|
|
|
if (!translateRefreshed) { |
|
|
|
Logger.d( |
|
|
|
'MeetingTask', |
|
|
|
'translate missing from polling response; ' |
|
|
|
'triggering full sync to fetch new speakers for id=$id', |
|
|
|
); |
|
|
|
try { |
|
|
|
var allResp = await Api.getOperationAllRecord(); |
|
|
|
List allRecords = allResp['records'] ?? []; |
|
|
|
final fullRecord = allRecords.firstWhere( |
|
|
|
(r) => r['id'] == id, |
|
|
|
orElse: () => null, |
|
|
|
); |
|
|
|
if (fullRecord != null && |
|
|
|
fullRecord['translate'] != null && |
|
|
|
fullRecord['translate'].toString().isNotEmpty) { |
|
|
|
List<dynamic> decodeList = |
|
|
|
jsonDecode(fullRecord['translate']); |
|
|
|
List<Map<String, Object?>> speakerList = decodeList |
|
|
|
.map((e) => Map<String, Object?>.from(e)) |
|
|
|
.toList(); |
|
|
|
await SqfliteApi.deleteMeetingSpeaker(id); |
|
|
|
await SqfliteApi.insertMeetingSpeaker(speakerList); |
|
|
|
await SqfliteApi.editMeeting(id, { |
|
|
|
'personnel': fullRecord['personnel'] ?? '', |
|
|
|
'summary': fullRecord['summary'] ?? '', |
|
|
|
'overview': fullRecord['overview'] ?? '', |
|
|
|
}); |
|
|
|
Logger.d( |
|
|
|
'MeetingTask', |
|
|
|
'full sync wrote ${speakerList.length} speaker rows ' |
|
|
|
'for id=$id', |
|
|
|
); |
|
|
|
} |
|
|
|
} catch (e) { |
|
|
|
Logger.error( |
|
|
|
'MeetingTask: fallback full sync failed for id=$id: $e', |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (id == meetingId) { |
|
|
|
personnel = element['personnel'] ?? ''; |
|
|
|
summary = element['summary'] ?? ''; |
|
|
|
|