From 134537fba4e05d15536381698009dadfcf0590aa Mon Sep 17 00:00:00 2001 From: lxm <1274844347@qq.com> Date: Thu, 20 Nov 2025 12:24:52 +0800 Subject: [PATCH] =?UTF-8?q?feat(meeting):=20=E6=B7=BB=E5=8A=A0=E4=BC=9A?= =?UTF-8?q?=E8=AE=AEASR=E4=BB=BB=E5=8A=A1=E4=BD=BF=E7=94=A8=E7=BB=9F?= =?UTF-8?q?=E8=AE=A1=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在MeetingTaskService中添加会议ASR任务的使用统计记录功能,包括任务提交和完成时的数据收集。同时在UsageStatsService中实现相关统计数据的存储和更新逻辑。 --- .../meeting/meeting_task_service.dart | 37 +++++++++++ lib/data/services/usage_stats_service.dart | 65 +++++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/lib/data/services/meeting/meeting_task_service.dart b/lib/data/services/meeting/meeting_task_service.dart index 7ec049fc7..fc6f6b8fc 100644 --- a/lib/data/services/meeting/meeting_task_service.dart +++ b/lib/data/services/meeting/meeting_task_service.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:io'; import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; @@ -9,6 +10,8 @@ import '../../../core/utils/synchrodata.dart'; import '../db/sqflite_api.dart'; import '../deapsound_ai_service.dart'; import 'meeting_upload_service.dart'; +import '../usage_stats_service.dart'; +import '../../models/meeting_usage_stats.dart'; ///会议任务服务类,负责管理会议音频的转写任务处理流程,包括任务提交、状态轮询、结果处理和AI分析等功能。 class MeetingTaskService extends GetxService { @@ -117,6 +120,30 @@ class MeetingTaskService extends GetxService { taskId = await _submitTask(audiourl, isSpeaker, language); } await SqfliteApi.editMeeting(id, {'tasktype': 1, 'taskid': taskId}); + try { + final detail = await SqfliteApi.getMeetingDetails(id); + final seconds = (detail['seconds'] ?? 0) as int; + final filepath = (detail['filepath'] ?? '') as String; + int fileSizeBytes = 0; + if (filepath.isNotEmpty) { + try { + fileSizeBytes = await File(filepath).length(); + } catch (_) {} + } + final record = MeetingAsrRecord( + id: taskId, + meetingId: id, + taskId: taskId, + audioSeconds: seconds, + fileSizeBytes: fileSizeBytes, + language: language, + submitTimestamp: DateTime.now().millisecondsSinceEpoch, + status: asrStatusProcessing, + transcriptBytes: 0, + completeTimestamp: 0, + ); + Get.find().addMeetingAsrRecord(record); + } catch (_) {} _taskList.add({ 'id': id, 'taskid': taskId, @@ -373,6 +400,16 @@ class MeetingTaskService extends GetxService { _storage.write("meeting_task_list", _taskList); _storage.write("meeting_task_finish_list", taskFinishList); } + try { + final details = await SqfliteApi.getMeetingDetails(id); + final tid = (details['taskid'] ?? '') as String; + final transcriptBytes = utf8.encode(text).length; + Get.find().completeMeetingAsrRecord( + id: tid, + transcriptBytes: transcriptBytes, + completeTimestamp: DateTime.now().millisecondsSinceEpoch, + ); + } catch (_) {} // 触发AI分析,分别请求总结和概览 aiServiceMessage(id, text, prompt, outline); diff --git a/lib/data/services/usage_stats_service.dart b/lib/data/services/usage_stats_service.dart index 0f930fab5..f8a2d1be7 100644 --- a/lib/data/services/usage_stats_service.dart +++ b/lib/data/services/usage_stats_service.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; import '../models/translation_usage_stats.dart'; +import '../models/meeting_usage_stats.dart'; import '../../core/utils/logger.dart'; import 'network/api.dart'; import '../models/goods.dart'; @@ -12,6 +13,7 @@ import '../models/user_Info.dart'; class UsageStatsService extends GetxService { static const String _storageKey = 'usage_stats'; static const String _dailyStatsKey = 'daily_translation_stats'; + static const String _meetingDailyKey = 'daily_meeting_asr_stats'; final GetStorage _storage = GetStorage(); @@ -67,6 +69,69 @@ class UsageStatsService extends GetxService { return 'anonymous'; } + MeetingAsrDailyStats _loadMeetingDaily(String dateKey) { + final data = _storage.read('${_meetingDailyKey}_$dateKey'); + if (data != null) { + return MeetingAsrDailyStats.fromJson(Map.from(data)); + } + return MeetingAsrDailyStats( + date: dateKey, userId: getCurrentUserId(), items: []); + } + + void _saveMeetingDaily(MeetingAsrDailyStats stats) { + _storage.write('${_meetingDailyKey}_${stats.date}', stats.toJson()); + } + + String _formatDate(DateTime d) { + final y = d.year; + final m = d.month.toString().padLeft(2, '0'); + final day = d.day.toString().padLeft(2, '0'); + return '$y-$m-$day'; + } + + void addMeetingAsrRecord(MeetingAsrRecord record) { + final dateKey = _formatDate( + DateTime.fromMillisecondsSinceEpoch(record.submitTimestamp)); + final daily = _loadMeetingDaily(dateKey); + final idx = daily.items.indexWhere((e) => e.id == record.id); + if (idx >= 0) { + daily.items[idx] = record; + } else { + daily.items.add(record); + } + _saveMeetingDaily(daily); + } + + void completeMeetingAsrRecord({ + required String id, + required int transcriptBytes, + required int completeTimestamp, + }) { + final now = DateTime.now(); + for (int i = 0; i < 3; i++) { + final dateKey = _formatDate(now.subtract(Duration(days: i))); + final daily = _loadMeetingDaily(dateKey); + final idx = daily.items.indexWhere((e) => e.id == id); + if (idx >= 0) { + final old = daily.items[idx]; + daily.items[idx] = MeetingAsrRecord( + id: old.id, + meetingId: old.meetingId, + taskId: old.taskId, + audioSeconds: old.audioSeconds, + fileSizeBytes: old.fileSizeBytes, + language: old.language, + submitTimestamp: old.submitTimestamp, + status: asrStatusCompleted, + transcriptBytes: transcriptBytes, + completeTimestamp: completeTimestamp, + ); + _saveMeetingDaily(daily); + return; + } + } + } + /// 记录翻译API调用 void recordTranslationApiCall({ required String sourceText,