Browse Source

refactor(usage): 移除成本统计相关功能

移除翻译使用统计中的成本计算、成本配置和阈值预警功能
更新相关视图和控制器以匹配功能变更
newdev_shunjiawei
lxm 11 months ago
parent
commit
eb1c81bb41
  1. 168
      lib/data/services/usage_stats_service.dart
  2. 4
      lib/modules/translation/controllers/translation_controller.dart
  3. 103
      lib/modules/usage/controllers/translation_cost_controller.dart
  4. 26
      lib/modules/usage/controllers/translation_stats_controller.dart
  5. 12
      lib/modules/usage/views/translation_stats_view.dart

168
lib/data/services/usage_stats_service.dart

@ -8,7 +8,6 @@ import '../../core/utils/logger.dart';
class UsageStatsService extends GetxService { class UsageStatsService extends GetxService {
static const String _storageKey = 'usage_stats'; static const String _storageKey = 'usage_stats';
static const String _dailyStatsKey = 'daily_translation_stats'; static const String _dailyStatsKey = 'daily_translation_stats';
static const String _costConfigKey = 'translation_cost_config';
final GetStorage _storage = GetStorage(); final GetStorage _storage = GetStorage();
@ -19,13 +18,6 @@ class UsageStatsService extends GetxService {
final Rx<TranslationUsageStats> todayStats = final Rx<TranslationUsageStats> todayStats =
TranslationUsageStats.empty('').obs; TranslationUsageStats.empty('').obs;
// 成本配置
final RxMap<String, double> costConfig = <String, double>{}.obs;
// 预警阈值
final RxDouble dailyCostThreshold = 10.0.obs; // 日成本预警阈值
final RxDouble monthlyCostThreshold = 300.0.obs; // 月成本预警阈值
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
@ -34,39 +26,8 @@ class UsageStatsService extends GetxService {
/// 初始化服务 /// 初始化服务
void _initializeService() { void _initializeService() {
_loadCostConfig();
_loadTodayStats(); _loadTodayStats();
Logger.info('翻译使用量统计服务初始化完成'); Logger.info('lxm--使用量统计服务初始化完成');
}
/// 加载成本配置
void _loadCostConfig() {
try {
final configData = _storage.read(_costConfigKey);
if (configData != null) {
costConfig.value = Map<String, double>.from(configData);
} else {
// 设置默认成本配置(每千字符的成本,单位:元)
costConfig.value = {
'translation_per_1k_chars': 0.05, // 翻译:每千字符0.05元
'asr_per_minute': 0.02, // ASR:每分钟0.02元
'tts_per_1k_chars': 0.03, // TTS:每千字符0.03元
'ai_summary_per_request': 0.01, // AI摘要:每次请求0.01元
};
_saveCostConfig();
}
} catch (e) {
Logger.error('加载成本配置失败: $e');
}
}
/// 保存成本配置
void _saveCostConfig() {
try {
_storage.write(_costConfigKey, costConfig.value);
} catch (e) {
Logger.error('保存成本配置失败: $e');
}
} }
/// 加载当日统计数据 /// 加载当日统计数据
@ -132,14 +93,12 @@ class UsageStatsService extends GetxService {
languagePair: languagePair, languagePair: languagePair,
translationCount: existing.translationCount + 1, translationCount: existing.translationCount + 1,
sourceCharacters: existing.sourceCharacters + sourceText.length, sourceCharacters: existing.sourceCharacters + sourceText.length,
cost: existing.cost + _calculateTranslationCost(sourceText.length),
); );
} else { } else {
newLanguagePairStats[languagePair] = LanguagePairStats( newLanguagePairStats[languagePair] = LanguagePairStats(
languagePair: languagePair, languagePair: languagePair,
translationCount: 1, translationCount: 1,
sourceCharacters: sourceText.length, sourceCharacters: sourceText.length,
cost: _calculateTranslationCost(sourceText.length),
); );
} }
@ -152,14 +111,12 @@ class UsageStatsService extends GetxService {
apiCalls: existing.apiCalls + 1, apiCalls: existing.apiCalls + 1,
sourceCharacters: existing.sourceCharacters + sourceText.length, sourceCharacters: existing.sourceCharacters + sourceText.length,
ttsCharacters: existing.ttsCharacters + targetText.length, ttsCharacters: existing.ttsCharacters + targetText.length,
cost: existing.cost + _calculateTranslationCost(sourceText.length),
); );
} else { } else {
newModeStats[mode] = TranslationModeStats( newModeStats[mode] = TranslationModeStats(
apiCalls: 1, apiCalls: 1,
sourceCharacters: sourceText.length, sourceCharacters: sourceText.length,
ttsCharacters: targetText.length, ttsCharacters: targetText.length,
cost: _calculateTranslationCost(sourceText.length),
); );
} }
@ -171,17 +128,9 @@ class UsageStatsService extends GetxService {
todayStats.value.ttsTextCharacters + targetText.length, todayStats.value.ttsTextCharacters + targetText.length,
languagePairStats: newLanguagePairStats, languagePairStats: newLanguagePairStats,
modeStats: newModeStats, modeStats: newModeStats,
estimatedCost: _calculateEstimatedCost(todayStats.value.copyWith(
translationApiCalls: todayStats.value.translationApiCalls + 1,
sourceTextCharacters:
todayStats.value.sourceTextCharacters + sourceText.length,
ttsTextCharacters:
todayStats.value.ttsTextCharacters + targetText.length,
)),
); );
_saveTodayStats(); _saveTodayStats();
_checkCostThreshold();
Logger.info( Logger.info(
'记录翻译API调用: 源文本${sourceText.length}字符, 目标文本${targetText.length}字符'); '记录翻译API调用: 源文本${sourceText.length}字符, 目标文本${targetText.length}字符');
@ -190,7 +139,7 @@ class UsageStatsService extends GetxService {
} }
} }
/// 记录ASR API调用 - 优化版(精确计费参数) /// 记录ASR API调用 - 优化版(精确统计参数)
void recordAsrApiCall({ void recordAsrApiCall({
required int effectiveDurationSeconds, // 有效语音时长(VAD检测的实际语音) required int effectiveDurationSeconds, // 有效语音时长(VAD检测的实际语音)
required int totalDurationSeconds, // 总会话时长(包含静音) required int totalDurationSeconds, // 总会话时长(包含静音)
@ -213,12 +162,10 @@ class UsageStatsService extends GetxService {
newModeStats[mode] = existing.copyWith( newModeStats[mode] = existing.copyWith(
effectiveAudioDuration: effectiveAudioDuration:
existing.effectiveAudioDuration + effectiveDurationSeconds, existing.effectiveAudioDuration + effectiveDurationSeconds,
cost: existing.cost + _calculateAsrCost(effectiveDurationSeconds),
); );
} else { } else {
newModeStats[mode] = TranslationModeStats( newModeStats[mode] = TranslationModeStats(
effectiveAudioDuration: effectiveDurationSeconds, effectiveAudioDuration: effectiveDurationSeconds,
cost: _calculateAsrCost(effectiveDurationSeconds),
); );
} }
@ -230,11 +177,6 @@ class UsageStatsService extends GetxService {
totalSessionDuration: totalSessionDuration:
todayStats.value.totalSessionDuration + totalDurationSeconds, todayStats.value.totalSessionDuration + totalDurationSeconds,
modeStats: newModeStats, modeStats: newModeStats,
estimatedCost: _calculateEstimatedCost(todayStats.value.copyWith(
asrApiCalls: todayStats.value.asrApiCalls + 1,
effectiveAudioDuration: todayStats.value.effectiveAudioDuration +
effectiveDurationSeconds,
)),
); );
_saveTodayStats(); _saveTodayStats();
@ -263,10 +205,6 @@ class UsageStatsService extends GetxService {
ttsTextCharacters: todayStats.value.ttsTextCharacters + text.length, ttsTextCharacters: todayStats.value.ttsTextCharacters + text.length,
totalSessionDuration: totalSessionDuration:
todayStats.value.totalSessionDuration + durationSeconds, todayStats.value.totalSessionDuration + durationSeconds,
estimatedCost: _calculateEstimatedCost(todayStats.value.copyWith(
ttsApiCalls: todayStats.value.ttsApiCalls + 1,
ttsTextCharacters: todayStats.value.ttsTextCharacters + text.length,
)),
); );
_saveTodayStats(); _saveTodayStats();
@ -283,9 +221,6 @@ class UsageStatsService extends GetxService {
// 更新当日统计 // 更新当日统计
todayStats.value = todayStats.value.copyWith( todayStats.value = todayStats.value.copyWith(
aiSummaryApiCalls: todayStats.value.aiSummaryApiCalls + 1, aiSummaryApiCalls: todayStats.value.aiSummaryApiCalls + 1,
estimatedCost: _calculateEstimatedCost(todayStats.value.copyWith(
aiSummaryApiCalls: todayStats.value.aiSummaryApiCalls + 1,
)),
); );
_saveTodayStats(); _saveTodayStats();
@ -309,45 +244,6 @@ class UsageStatsService extends GetxService {
Logger.info('开始新的翻译会话'); Logger.info('开始新的翻译会话');
} }
/// 计算预估成本 - 优化版(基于精确计费参数)
double _calculateEstimatedCost(TranslationUsageStats stats) {
double cost = 0.0;
// 翻译成本:基于源文本字符数
cost += (stats.sourceTextCharacters / 1000) *
(costConfig['translation_per_1k_chars'] ?? 0.05);
// ASR成本:基于有效音频时长
cost += (stats.effectiveAudioDuration / 60) *
(costConfig['asr_per_minute'] ?? 0.02);
// TTS成本:基于TTS文本字符数
cost += (stats.ttsTextCharacters / 1000) *
(costConfig['tts_per_1k_chars'] ?? 0.03);
// AI摘要成本(已废弃但保留兼容性)
cost += stats.aiSummaryApiCalls *
(costConfig['ai_summary_per_request'] ?? 0.01);
return cost;
}
/// 计算翻译成本(单次调用)
double _calculateTranslationCost(int sourceCharacters) {
return (sourceCharacters / 1000) *
(costConfig['translation_per_1k_chars'] ?? 0.05);
}
/// 计算ASR成本(单次调用)
double _calculateAsrCost(int durationSeconds) {
return (durationSeconds / 60) * (costConfig['asr_per_minute'] ?? 0.02);
}
/// 计算TTS成本(单次调用)
double _calculateTtsCost(int textCharacters) {
return (textCharacters / 1000) * (costConfig['tts_per_1k_chars'] ?? 0.03);
}
/// 保存当日统计数据 /// 保存当日统计数据
void _saveTodayStats() { void _saveTodayStats() {
try { try {
@ -360,27 +256,6 @@ class UsageStatsService extends GetxService {
} }
} }
/// 检查成本阈值
void _checkCostThreshold() {
final todayCost = todayStats.value.estimatedCost;
if (todayCost >= dailyCostThreshold.value) {
_showCostWarning('今日翻译成本已达到预警阈值:¥${todayCost.toStringAsFixed(2)}');
}
}
/// 显示成本预警
void _showCostWarning(String message) {
Get.snackbar(
'成本预警',
message,
snackPosition: SnackPosition.TOP,
backgroundColor: Get.theme.colorScheme.error.withOpacity(0.1),
colorText: Get.theme.colorScheme.error,
duration: const Duration(seconds: 5),
);
}
/// 获取历史统计数据 /// 获取历史统计数据
Future<List<TranslationUsageStats>> getHistoryStats({ Future<List<TranslationUsageStats>> getHistoryStats({
required DateTime startDate, required DateTime startDate,
@ -434,39 +309,6 @@ class UsageStatsService extends GetxService {
} }
} }
/// 更新成本配置
void updateCostConfig(Map<String, double> newConfig) {
costConfig.value = newConfig;
_saveCostConfig();
// 重新计算当日成本
todayStats.value = todayStats.value.copyWith(
estimatedCost: _calculateEstimatedCost(todayStats.value),
);
_saveTodayStats();
Logger.info('更新成本配置完成');
}
/// 更新预警阈值
void updateThresholds({
double? dailyThreshold,
double? monthlyThreshold,
}) {
if (dailyThreshold != null) {
dailyCostThreshold.value = dailyThreshold;
}
if (monthlyThreshold != null) {
monthlyCostThreshold.value = monthlyThreshold;
}
// 保存阈值配置
_storage.write('daily_cost_threshold', dailyCostThreshold.value);
_storage.write('monthly_cost_threshold', monthlyCostThreshold.value);
Logger.info('更新预警阈值完成');
}
/// 获取月度统计汇总 /// 获取月度统计汇总
Future<TranslationUsageStats> getMonthlyStats(int year, int month) async { Future<TranslationUsageStats> getMonthlyStats(int year, int month) async {
try { try {
@ -492,7 +334,7 @@ class UsageStatsService extends GetxService {
int totalRecordingDuration = 0; int totalRecordingDuration = 0;
int totalTtsPlayDuration = 0; int totalTtsPlayDuration = 0;
int totalSessions = 0; int totalSessions = 0;
double totalCost = 0.0; //double totalCost = 0.0;
final Map<String, int> combinedLanguagePairUsage = {}; final Map<String, int> combinedLanguagePairUsage = {};
final Map<String, int> combinedModeUsage = {}; final Map<String, int> combinedModeUsage = {};
@ -507,7 +349,7 @@ class UsageStatsService extends GetxService {
totalRecordingDuration += stats.audioRecordingDuration; totalRecordingDuration += stats.audioRecordingDuration;
totalTtsPlayDuration += stats.ttsPlaybackDuration; totalTtsPlayDuration += stats.ttsPlaybackDuration;
totalSessions += stats.sessionCount; totalSessions += stats.sessionCount;
totalCost += stats.estimatedCost; // totalCost += stats.estimatedCost;
// 合并语言对使用统计 // 合并语言对使用统计
stats.languagePairUsage.forEach((key, value) { stats.languagePairUsage.forEach((key, value) {
@ -535,7 +377,7 @@ class UsageStatsService extends GetxService {
ttsTextCharacters: totalTargetChars, ttsTextCharacters: totalTargetChars,
totalSessionDuration: totalTtsPlayDuration, totalSessionDuration: totalTtsPlayDuration,
sessionCount: totalSessions, sessionCount: totalSessions,
estimatedCost: totalCost, // estimatedCost: totalCost,
); );
} catch (e) { } catch (e) {
Logger.error('获取月度统计失败: $e'); Logger.error('获取月度统计失败: $e');

4
lib/modules/translation/controllers/translation_controller.dart

@ -48,7 +48,7 @@ class TranslationController extends GetxController with WidgetsBindingObserver {
final BluetoothManager bluetoothManager = Get.find<BluetoothManager>(); final BluetoothManager bluetoothManager = Get.find<BluetoothManager>();
final BleManager bleManager = Get.find<BleManager>(); final BleManager bleManager = Get.find<BleManager>();
final _musiceManager = Get.find<MusicManager>(); final _musiceManager = Get.find<MusicManager>();
late final UsageStatsService _usageService; late final UsageStatsService _usageService; //用量统计服务
late final FloatingWindowManager _floatingWindowManager; late final FloatingWindowManager _floatingWindowManager;
// ==================== 悬浮窗相关 ==================== // ==================== 悬浮窗相关 ====================
@ -431,7 +431,7 @@ class TranslationController extends GetxController with WidgetsBindingObserver {
} }
} }
/// 初始化统计服务 /// 初始化用量统计服务
void _initUsageService() { void _initUsageService() {
try { try {
// 确保统计服务已注册 // 确保统计服务已注册

103
lib/modules/usage/controllers/translation_cost_controller.dart

@ -20,7 +20,6 @@ class TranslationCostController extends GetxController {
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
_loadCurrentConfig();
} }
@override @override
@ -34,74 +33,11 @@ class TranslationCostController extends GetxController {
super.onClose(); super.onClose();
} }
void _loadCurrentConfig() { void _loadCurrentConfig() {}
isLoading.value = true;
try {
costConfig.value = Map<String, double>.from(_usageService.costConfig);
dailyCostThreshold.value = _usageService.dailyCostThreshold.value;
monthlyCostThreshold.value = _usageService.monthlyCostThreshold.value;
translationCostController.text =
(costConfig['translation_per_1k_chars'] ?? 0.05).toString();
asrCostController.text =
(costConfig['asr_per_minute'] ?? 0.02).toString();
ttsCostController.text =
(costConfig['tts_per_1k_chars'] ?? 0.03).toString();
aiSummaryCostController.text =
(costConfig['ai_summary_per_request'] ?? 0.01).toString();
dailyThresholdController.text = dailyCostThreshold.value.toString();
monthlyThresholdController.text = monthlyCostThreshold.value.toString();
Logger.info('成本配置加载完成');
} catch (e) {
Logger.error('加载成本配置失败: $e');
_showErrorSnackbar('加载配置失败');
} finally {
isLoading.value = false;
}
}
Future<void> saveConfig() async { Future<void> saveConfig() async {}
if (isSaving.value) return;
isSaving.value = true;
try {
if (!_validateInputs()) {
return;
}
final newCostConfig = {
'translation_per_1k_chars':
double.parse(translationCostController.text),
'asr_per_minute': double.parse(asrCostController.text),
'tts_per_1k_chars': double.parse(ttsCostController.text),
'ai_summary_per_request': double.parse(aiSummaryCostController.text),
};
final newDailyThreshold = double.parse(dailyThresholdController.text);
final newMonthlyThreshold = double.parse(monthlyThresholdController.text);
_usageService.updateCostConfig(newCostConfig);
_usageService.updateThresholds(
dailyThreshold: newDailyThreshold,
monthlyThreshold: newMonthlyThreshold,
);
costConfig.value = newCostConfig;
dailyCostThreshold.value = newDailyThreshold;
monthlyCostThreshold.value = newMonthlyThreshold;
_showSuccessSnackbar('配置保存成功');
Logger.info('成本配置保存成功');
} catch (e) {
Logger.error('保存成本配置失败: $e');
_showErrorSnackbar('保存配置失败');
} finally {
isSaving.value = false;
}
}
void resetToDefault() { void resetToDefault() {}
translationCostController.text = '0.05';
asrCostController.text = '0.02';
ttsCostController.text = '0.03';
aiSummaryCostController.text = '0.01';
dailyThresholdController.text = '10.0';
monthlyThresholdController.text = '300.0';
_showInfoSnackbar('已重置为默认配置,请点击保存生效');
}
bool _validateInputs() { bool _validateInputs() {
try { try {
@ -134,40 +70,11 @@ class TranslationCostController extends GetxController {
} }
double calculateEstimatedMonthlyCost() { double calculateEstimatedMonthlyCost() {
try { return 0.0;
final dailyStats = _usageService.todayStats.value;
if (dailyStats.estimatedCost == 0) return 0.0;
return dailyStats.estimatedCost * 30;
} catch (e) {
Logger.error('计算预估月成本失败: $e');
return 0.0;
}
} }
List<String> getCostSavingTips() { List<String> getCostSavingTips() {
final tips = <String>[]; return [];
try {
final dailyStats = _usageService.todayStats.value;
if (dailyStats.translationApiCalls > 100) {
tips.add('考虑批量翻译以减少API调用次数');
}
if (dailyStats.ttsApiCalls > 50) {
tips.add('可以关闭自动语音播放以节省TTS成本');
}
if (dailyStats.aiSummaryApiCalls > 10) {
tips.add('AI摘要功能按需使用,避免频繁调用');
}
if (dailyStats.effectiveAudioDuration > 3600) {
tips.add('长时间录音会增加ASR成本,建议分段录音');
}
if (tips.isEmpty) {
tips.add('您的使用习惯很好,继续保持!');
}
} catch (e) {
Logger.error('获取成本节约建议失败: $e');
tips.add('暂无建议');
}
return tips;
} }
void _showSuccessSnackbar(String message) { void _showSuccessSnackbar(String message) {

26
lib/modules/usage/controllers/translation_stats_controller.dart

@ -39,17 +39,11 @@ class TranslationStatsController extends GetxController {
_updateChartData(); _updateChartData();
}); });
ever(_usageService.costConfig, (config) {
costConfig.value = config;
});
ever(_usageService.dailyCostThreshold, (threshold) {
dailyCostThreshold.value = threshold;
});
ever(_usageService.monthlyCostThreshold, (threshold) {
monthlyCostThreshold.value = threshold;
});
loadAllStats(); loadAllStats();
} }
@ -141,7 +135,7 @@ class TranslationStatsController extends GetxController {
int totalRecordingDuration = 0; int totalRecordingDuration = 0;
int totalTtsPlayDuration = 0; int totalTtsPlayDuration = 0;
int totalSessions = 0; int totalSessions = 0;
double totalCost = 0.0;
final Map<String, int> combinedLanguagePairUsage = {}; final Map<String, int> combinedLanguagePairUsage = {};
final Map<String, int> combinedModeUsage = {}; final Map<String, int> combinedModeUsage = {};
@ -156,7 +150,7 @@ class TranslationStatsController extends GetxController {
totalRecordingDuration += stats.effectiveAudioDuration; totalRecordingDuration += stats.effectiveAudioDuration;
totalTtsPlayDuration += stats.totalSessionDuration; totalTtsPlayDuration += stats.totalSessionDuration;
totalSessions += stats.sessionCount; totalSessions += stats.sessionCount;
totalCost += stats.estimatedCost;
stats.languagePairUsage.forEach((key, value) { stats.languagePairUsage.forEach((key, value) {
combinedLanguagePairUsage[key] = combinedLanguagePairUsage[key] =
@ -182,7 +176,7 @@ class TranslationStatsController extends GetxController {
effectiveAudioDuration: totalRecordingDuration, effectiveAudioDuration: totalRecordingDuration,
totalSessionDuration: totalTtsPlayDuration, totalSessionDuration: totalTtsPlayDuration,
sessionCount: totalSessions, sessionCount: totalSessions,
estimatedCost: totalCost, estimatedCost: 0.0,
); );
} }
@ -194,7 +188,7 @@ class TranslationStatsController extends GetxController {
data.add({ data.add({
'label': '今日', 'label': '今日',
'apiCalls': todayStats.value.totalApiCalls, 'apiCalls': todayStats.value.totalApiCalls,
'cost': todayStats.value.estimatedCost, 'cost': 0.0,
'characters': todayStats.value.totalCharacterCount, 'characters': todayStats.value.totalCharacterCount,
}); });
break; break;
@ -202,7 +196,7 @@ class TranslationStatsController extends GetxController {
data.add({ data.add({
'label': '本周', 'label': '本周',
'apiCalls': weekStats.value.totalApiCalls, 'apiCalls': weekStats.value.totalApiCalls,
'cost': weekStats.value.estimatedCost, 'cost': 0.0,
'characters': weekStats.value.totalCharacterCount, 'characters': weekStats.value.totalCharacterCount,
}); });
break; break;
@ -210,7 +204,7 @@ class TranslationStatsController extends GetxController {
data.add({ data.add({
'label': '本月', 'label': '本月',
'apiCalls': monthStats.value.totalApiCalls, 'apiCalls': monthStats.value.totalApiCalls,
'cost': monthStats.value.estimatedCost, 'cost': 0.0,
'characters': monthStats.value.totalCharacterCount, 'characters': monthStats.value.totalCharacterCount,
}); });
break; break;
@ -219,7 +213,7 @@ class TranslationStatsController extends GetxController {
data.add({ data.add({
'label': '${stats.date.month}/${stats.date.day}', 'label': '${stats.date.month}/${stats.date.day}',
'apiCalls': stats.totalApiCalls, 'apiCalls': stats.totalApiCalls,
'cost': stats.estimatedCost, 'cost': 0.0,
'characters': stats.totalCharacterCount, 'characters': stats.totalCharacterCount,
}); });
} }

12
lib/modules/usage/views/translation_stats_view.dart

@ -103,8 +103,6 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
SizedBox(height: 16.h), SizedBox(height: 16.h),
_buildDataVolumeCard(isDarkMode), _buildDataVolumeCard(isDarkMode),
SizedBox(height: 16.h), SizedBox(height: 16.h),
_buildCostCard(isDarkMode),
SizedBox(height: 16.h),
_buildUsageBehaviorCard(isDarkMode), _buildUsageBehaviorCard(isDarkMode),
], ],
), ),
@ -302,15 +300,7 @@ class TranslationStatsView extends GetView<TranslationStatsController> {
isDarkMode, isDarkMode,
), ),
), ),
Expanded(
child: _buildStatItem(
'预估成本',
controller
.formatCost(controller.currentStats.estimatedCost),
Icons.attach_money,
isDarkMode,
),
),
], ],
)), )),
SizedBox(height: 12.h), SizedBox(height: 12.h),

Loading…
Cancel
Save