import 'dart:async'; import 'dart:math'; import '../models/pronunciation_item.dart'; /// 语音识别和评分服务 class SpeechRecognitionService { static final SpeechRecognitionService _instance = SpeechRecognitionService._internal(); factory SpeechRecognitionService() => _instance; SpeechRecognitionService._internal(); bool _isListening = false; StreamController? _volumeController; StreamController? _recognitionController; /// 获取音量流 Stream get volumeStream => _volumeController?.stream ?? const Stream.empty(); /// 获取识别结果流 Stream get recognitionStream => _recognitionController?.stream ?? const Stream.empty(); /// 是否正在监听 bool get isListening => _isListening; /// 开始语音识别 Future startListening() async { if (_isListening) return false; try { _isListening = true; _volumeController = StreamController.broadcast(); _recognitionController = StreamController.broadcast(); // TODO: 实现真实的语音识别 // 这里应该调用语音识别API,如Google Speech-to-Text、百度语音识别等 // 模拟音量变化 _simulateVolumeChanges(); return true; } catch (e) { _isListening = false; return false; } } /// 停止语音识别 Future stopListening() async { if (!_isListening) return; _isListening = false; await _volumeController?.close(); await _recognitionController?.close(); _volumeController = null; _recognitionController = null; } /// 分析发音并评分 Future analyzePronunciation( String recordedText, PronunciationItem targetItem, ) async { // TODO: 实现真实的发音分析 // 这里应该调用发音评估API,如科大讯飞语音评测、腾讯云语音评测等 // 模拟分析过程 await Future.delayed(const Duration(milliseconds: 1500)); return _simulateAnalysis(recordedText, targetItem); } /// 模拟音量变化 void _simulateVolumeChanges() { Timer.periodic(const Duration(milliseconds: 100), (timer) { if (!_isListening) { timer.cancel(); return; } // 生成随机音量值 final volume = Random().nextDouble() * 0.8 + 0.1; _volumeController?.add(volume); }); } /// 模拟发音分析 PronunciationResult _simulateAnalysis(String recordedText, PronunciationItem targetItem) { final random = Random(); // 基础分数 double baseScore = 60.0 + random.nextDouble() * 30; // 根据文本相似度调整分数 final similarity = _calculateSimilarity(recordedText.toLowerCase(), targetItem.text.toLowerCase()); final adjustedScore = baseScore + (similarity * 20); // 确保分数在合理范围内 final finalScore = adjustedScore.clamp(0.0, 100.0); return PronunciationResult( score: finalScore, accuracy: _getAccuracyLevel(finalScore), feedback: _generateFeedback(finalScore, targetItem), detailedAnalysis: _generateDetailedAnalysis(finalScore, targetItem), suggestions: _generateSuggestions(finalScore, targetItem), recognizedText: recordedText, ); } /// 计算文本相似度 double _calculateSimilarity(String text1, String text2) { if (text1 == text2) return 1.0; final words1 = text1.split(' '); final words2 = text2.split(' '); int matches = 0; final maxLength = max(words1.length, words2.length); for (int i = 0; i < min(words1.length, words2.length); i++) { if (words1[i] == words2[i]) { matches++; } } return matches / maxLength; } /// 获取准确度等级 AccuracyLevel _getAccuracyLevel(double score) { if (score >= 90) return AccuracyLevel.excellent; if (score >= 80) return AccuracyLevel.good; if (score >= 70) return AccuracyLevel.fair; if (score >= 60) return AccuracyLevel.needsImprovement; return AccuracyLevel.poor; } /// 生成反馈 String _generateFeedback(double score, PronunciationItem item) { if (score >= 90) { return '发音非常标准!语调和节奏都很自然。'; } else if (score >= 80) { return '发音很好,只需要在个别音素上稍作调整。'; } else if (score >= 70) { return '发音基本正确,建议多练习重音和语调。'; } else if (score >= 60) { return '发音需要改进,请注意音素的准确性。'; } else { return '发音需要大幅改进,建议从基础音素开始练习。'; } } /// 生成详细分析 Map _generateDetailedAnalysis(double score, PronunciationItem item) { final random = Random(); final baseVariation = (score - 70) / 30; // 基于总分的变化 return { '音素准确度': (70 + baseVariation * 20 + random.nextDouble() * 10).clamp(0, 100), '语调自然度': (65 + baseVariation * 25 + random.nextDouble() * 15).clamp(0, 100), '语速适中度': (75 + baseVariation * 15 + random.nextDouble() * 10).clamp(0, 100), '重音正确度': (70 + baseVariation * 20 + random.nextDouble() * 10).clamp(0, 100), '流畅度': (60 + baseVariation * 30 + random.nextDouble() * 15).clamp(0, 100), }; } /// 生成改进建议 List _generateSuggestions(double score, PronunciationItem item) { List suggestions = []; if (score < 80) { suggestions.addAll([ '多听标准发音,模仿语调变化', '注意重音位置,突出重读音节', ]); } if (score < 70) { suggestions.addAll([ '放慢语速,确保每个音素清晰', '练习困难音素的发音方法', ]); } if (score < 60) { suggestions.addAll([ '从基础音标开始系统学习', '使用镜子观察口型变化', ]); } // 根据练习类型添加特定建议 switch (item.type) { case PronunciationType.word: suggestions.add('分解单词,逐个音节练习'); break; case PronunciationType.sentence: suggestions.add('注意句子的语调起伏和停顿'); break; case PronunciationType.phrase: suggestions.add('练习短语内部的连读现象'); break; case PronunciationType.phoneme: suggestions.add('重点练习该音素的舌位和口型'); break; } return suggestions; } /// 获取发音提示 List getPronunciationTips(PronunciationItem item) { return item.tips; } /// 播放标准发音 Future playStandardAudio(String audioUrl) async { // TODO: 实现音频播放功能 // 这里应该使用音频播放插件,如audioplayers // 模拟播放时间 await Future.delayed(const Duration(seconds: 2)); } /// 检查麦克风权限 Future checkMicrophonePermission() async { // TODO: 实现权限检查 // 这里应该使用权限插件,如permission_handler // 模拟权限检查 return true; } /// 请求麦克风权限 Future requestMicrophonePermission() async { // TODO: 实现权限请求 // 这里应该使用权限插件,如permission_handler // 模拟权限请求 return true; } } /// 发音分析结果 class PronunciationResult { final double score; final AccuracyLevel accuracy; final String feedback; final Map detailedAnalysis; final List suggestions; final String recognizedText; PronunciationResult({ required this.score, required this.accuracy, required this.feedback, required this.detailedAnalysis, required this.suggestions, required this.recognizedText, }); } /// 准确度等级 enum AccuracyLevel { excellent, good, fair, needsImprovement, poor, } extension AccuracyLevelExtension on AccuracyLevel { String get displayName { switch (this) { case AccuracyLevel.excellent: return '优秀'; case AccuracyLevel.good: return '良好'; case AccuracyLevel.fair: return '一般'; case AccuracyLevel.needsImprovement: return '需要改进'; case AccuracyLevel.poor: return '较差'; } } String get description { switch (this) { case AccuracyLevel.excellent: return '发音非常标准,语调自然'; case AccuracyLevel.good: return '发音准确,略有改进空间'; case AccuracyLevel.fair: return '发音基本正确,需要练习'; case AccuracyLevel.needsImprovement: return '发音有明显问题,需要改进'; case AccuracyLevel.poor: return '发音问题较多,需要系统练习'; } } String get emoji { switch (this) { case AccuracyLevel.excellent: return '🌟'; case AccuracyLevel.good: return '👍'; case AccuracyLevel.fair: return '👌'; case AccuracyLevel.needsImprovement: return '📈'; case AccuracyLevel.poor: return '💪'; } } }