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.

197 lines
5.3 KiB

import 'dart:async';
import 'package:get/get.dart';
import 'package:flutter/foundation.dart';
import '../../../data/services/voice_recognition_service.dart';
class VoiceInputController extends GetxController {
// Observable states
final isConnecting = true.obs;
final isMuted = false.obs;
final isRecording = false.obs;
final recognizedText = ''.obs;
// 语音识别服务
late final VoiceRecognitionService _voiceService;
// 连续识别相关
StreamSubscription? _recognitionSubscription;
// Callbacks
final Function(String) onRecordingResult;
final VoidCallback onClosePanel;
final Function(String) onRecognizing;
VoiceInputController({
required this.onRecordingResult,
required this.onClosePanel,
required this.onRecognizing,
});
@override
void onInit() {
super.onInit();
_initializeVoiceService();
}
Future<void> _initializeVoiceService() async {
try {
// 创建语音识别服务实例
_voiceService = VoiceRecognitionService();
// 初始化语音识别服务
await _voiceService.initialize();
// 初始化完成后更新状态
isConnecting.value = false;
// 自动开始连续语音识别
await startContinuousRecognition();
} catch (e) {
print('初始化语音识别服务失败: $e');
Get.snackbar(
'Error',
'初始化语音识别服务失败: $e',
snackPosition: SnackPosition.BOTTOM,
);
}
}
Future<void> startContinuousRecognition() async {
if (isConnecting.value) return;
if (isRecording.value) return; // 已经在录音中
try {
isRecording.value = true;
recognizedText.value = '';
// 开始连续语音识别
final stream = await _voiceService.startContinuousRecognition();
// 订阅识别事件流
_recognitionSubscription = stream.listen((event) {
switch (event.type) {
case RecognitionEventType.intermediateResult:
// 更新中间识别结果
recognizedText.value = event.text;
// 调用识别中回调
onRecognizing(event.text);
break;
case RecognitionEventType.finalResult:
// 更新最终识别结果
if (event.text.isNotEmpty) {
recognizedText.value = event.text;
// 调用最终结果回调,发送识别到的句子
onRecordingResult(event.text);
// 清空识别文本,准备下一句
recognizedText.value = '';
// 不停止录音,继续监听下一句
}
break;
case RecognitionEventType.error:
case RecognitionEventType.canceled:
// 处理错误
print('语音识别错误: ${event.error}');
Get.snackbar(
'Error',
'语音识别错误: ${event.error}',
snackPosition: SnackPosition.BOTTOM,
);
// 尝试重新启动识别
restartRecognition();
break;
case RecognitionEventType.sessionStopped:
// 会话结束,尝试重新启动
isRecording.value = false;
restartRecognition();
break;
default:
break;
}
}, onError: (error) {
print('语音识别流错误: $error');
Get.snackbar(
'Error',
'语音识别流错误: $error',
snackPosition: SnackPosition.BOTTOM,
);
isRecording.value = false;
// 尝试重新启动识别
restartRecognition();
});
} catch (e) {
print('语音识别失败: $e');
Get.snackbar(
'Error',
'启动语音识别失败: $e',
snackPosition: SnackPosition.BOTTOM,
);
isRecording.value = false;
}
}
// 重新启动识别
Future<void> restartRecognition() async {
try {
// 先停止当前识别
await stopRecording();
// 延迟一下再重新启动
await Future.delayed(const Duration(milliseconds: 500));
// 重新启动连续识别
await startContinuousRecognition();
} catch (e) {
print('重新启动语音识别失败: $e');
}
}
Future<void> stopRecording() async {
if (!isRecording.value) return;
try {
// 取消事件订阅
await _recognitionSubscription?.cancel();
_recognitionSubscription = null;
// 停止连续识别
if (_voiceService.isContinuousRecognitionActive()) {
await _voiceService.stopContinuousRecognition();
}
isRecording.value = false;
} catch (e) {
print('停止语音识别失败: $e');
isRecording.value = false;
}
}
void toggleMute() {
// 只切换静音状态,不再影响录音
// 因为已启用回声消除,不需要在录音时停止TTS
isMuted.value = !isMuted.value;
}
// 手动开始录音(用户点击按钮)
void startRecording() {
if (!isRecording.value) {
startContinuousRecognition();
}
}
@override
void onClose() {
// 停止录音
stopRecording();
// 重置状态
isConnecting.value = false;
isMuted.value = false;
isRecording.value = false;
recognizedText.value = '';
super.onClose();
}
}