Browse Source

修改按住说话

weicu
tanlongsheng 1 year ago
parent
commit
abd84c36f9
  1. 99
      lib/modules/chat/controllers/chat_controller.dart
  2. 209
      lib/modules/chat/views/chat_view.dart

99
lib/modules/chat/controllers/chat_controller.dart

@ -86,10 +86,16 @@ class ChatController extends GetxController {
// 记录最后一次活动时间
DateTime _lastActivityTime = DateTime.now();
// 音乐播放
final player = AudioPlayer();
final RxString audiourl = ''.obs;
final RxBool isPlay = false.obs;
// 按住说话、文字输入切换
final RxBool isTextInput = false.obs;
final RxBool isHoldSpeak = false.obs;
String finalResult = '';
@override
Future<void> onInit() async {
super.onInit();
@ -570,6 +576,53 @@ class ChatController extends GetxController {
}
}
// 按下开始说话
void talkLongPress() async {
if (isHoldSpeak.value) return;
_voiceInteractionService.pauseVoiceInteraction();
try {
final recognitionStream = await _asrService.startContinuousRecognition();
isHoldSpeak.value = true;
recognizedText.value = '';
finalResult = '';
// 监听识别事件
_recognitionSubscription = recognitionStream.listen(
_handleRecognitionEvent,
onError: _handleRecognitionError,
);
} catch (e) {
Logger.error('启动语音识别失败', e);
isHoldSpeak.value = false;
}
}
// 松开停止说话
void talkLongPressUp() async {
if (!isHoldSpeak.value) return;
try {
await _asrService.stopContinuousRecognition();
_recognitionSubscription?.cancel();
_recognitionSubscription = null;
final intermediateIndex =
messages.indexWhere((m) => m.isIntermediate && m.role == 'user');
if (intermediateIndex >= 0) {
messages.removeAt(intermediateIndex);
}
sendMessage(finalResult);
recognizedText.value = '';
finalResult = '';
isHoldSpeak.value = false;
} catch (e) {
Logger.error('停止语音识别失败', e);
}
}
// 开始语音识别
Future<void> startVoiceRecognition() async {
if (isVoiceRecognitionActive.value) return;
@ -682,7 +735,7 @@ class ChatController extends GetxController {
if (intermediateIndex >= 0) {
// 更新已有的中间状态消息
messages[intermediateIndex] = messages[intermediateIndex].copyWith(
content: text,
content: isVoiceRecognitionActive.value ? text : finalResult + text,
);
messages.refresh();
} else {
@ -703,26 +756,44 @@ class ChatController extends GetxController {
if (text.isEmpty) return;
Logger.info('处理语音识别最终结果: $text');
recognizedText.value = text;
// 更新活动时间
_updateActivityTime();
// 查找并移除用户的中间状态消息
final intermediateIndex =
messages.indexWhere((m) => m.isIntermediate && m.role == 'user');
if (intermediateIndex >= 0) {
messages.removeAt(intermediateIndex);
}
if (isVoiceRecognitionActive.value) {
// 一直语音说话
// 发送识别到的文本
sendMessage(text);
recognizedText.value = text;
// 查找并移除用户的中间状态消息
final intermediateIndex =
messages.indexWhere((m) => m.isIntermediate && m.role == 'user');
if (intermediateIndex >= 0) {
messages.removeAt(intermediateIndex);
}
// 发送识别到的文本
sendMessage(text);
// 重置识别文本,但不关闭语音识别框
recognizedText.value = '';
// 重置语音检测状态
isSpeechDetected.value = false;
} else {
// 按住说话
// 重置识别文本,但不关闭语音识别框
recognizedText.value = '';
finalResult += text;
recognizedText.value = finalResult;
// 重置语音检测状态
isSpeechDetected.value = false;
final intermediateIndex =
messages.indexWhere((m) => m.isIntermediate && m.role == 'user');
if (intermediateIndex >= 0) {
// 更新已有的中间状态消息
messages[intermediateIndex] = messages[intermediateIndex].copyWith(
content: finalResult,
);
messages.refresh();
}
}
}
// 处理语音识别事件错误

209
lib/modules/chat/views/chat_view.dart

@ -113,6 +113,13 @@ class ChatView extends GetView<ChatController> {
],
),
actions: [
IconButton(
icon: Icon(
Icons.phone,
color: isDarkMode ? Colors.white : Colors.black87,
),
onPressed: controller.startVoiceRecognition,
),
// TTS开关
Obx(() => IconButton(
icon: Icon(
@ -389,120 +396,122 @@ class ChatView extends GetView<ChatController> {
Widget _buildTextInputPanel(
bool isDarkMode, TextEditingController textController) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h),
height: 48.w,
margin: EdgeInsets.only(left: 16.w, right: 16.w, top: 10.w, bottom: 20.w),
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
color: isDarkMode ? AppColors.cardBackground : Colors.white,
color: controller.isHoldSpeak.value
? AppColors.primary
: isDarkMode
? AppColors.cardBackground
: Colors.white,
borderRadius: BorderRadius.circular(12.w),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 3,
offset: Offset(0, -1),
offset: const Offset(0, -1),
),
],
),
child: SafeArea(
child: Row(
children: [
// 语音识别按钮
Container(
width: 40.w,
height: 40.w,
decoration: BoxDecoration(
color: isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.grey[100],
shape: BoxShape.circle,
),
child: IconButton(
icon: Icon(
Icons.mic_none,
color: isDarkMode ? Colors.white : Colors.grey[700],
size: 20.r,
),
padding: EdgeInsets.zero,
onPressed: controller.startVoiceRecognition,
),
child: Row(
children: [
Expanded(
child: Obx(
() => controller.isTextInput.value
? Center(
child: TextField(
controller: textController,
style: TextStyle(
fontSize: 15.sp,
color: isDarkMode ? Colors.white : Colors.black87,
),
textInputAction: TextInputAction.send,
decoration: InputDecoration(
hintText: 'inputMessage'.tr, // 输入消息...
hintStyle: TextStyle(color: Colors.grey[500]),
filled: false,
border: InputBorder.none,
focusedBorder: InputBorder.none,
contentPadding: EdgeInsets.only(left: 10.w),
),
onSubmitted: (value) {
if (value.trim().isNotEmpty) {
controller.sendMessage(value);
textController.clear();
controller.inputText.value = ''; // 清空输入框
}
},
),
)
: Listener(
onPointerDown: (event) {
controller.talkLongPress();
},
onPointerUp: (event) {
controller.talkLongPressUp();
},
child: Container(
padding: EdgeInsets.only(
left: controller.isHoldSpeak.value ? 0 : 46.w),
color: Colors.transparent,
child: controller.isHoldSpeak.value
? Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(40, (int index) {
return Container(
width: 3.w,
height: 10.w,
margin:
EdgeInsets.symmetric(horizontal: 2.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(3.r),
),
);
}),
)
: Center(
child: Text(
'按住说话',
style: TextStyle(
fontSize: 16.sp,
color: isDarkMode
? Colors.white
: Colors.black87,
),
),
),
),
),
),
SizedBox(width: 8.w),
// 输入框
Expanded(
child: TextField(
controller: textController,
decoration: InputDecoration(
hintText: 'inputMessage'.tr, // 输入消息...
hintStyle: TextStyle(
color: isDarkMode ? Colors.grey[500] : Colors.grey[500]),
filled: true,
fillColor: isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.grey[100],
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.r),
borderSide: BorderSide.none,
),
contentPadding: EdgeInsets.symmetric(
horizontal: 16.w,
vertical: 10.h,
),
if (!controller.isHoldSpeak.value)
GestureDetector(
onTap: () {
controller.isTextInput.value = !controller.isTextInput.value;
},
child: Container(
width: 30.w,
height: 30.w,
margin: EdgeInsets.all(8.w),
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30.r),
border: Border.all(
color: isDarkMode ? Colors.white : Colors.black87,
width: 2,
),
),
maxLines: null,
textInputAction: TextInputAction.newline,
style: TextStyle(
fontSize: 15.sp,
color: isDarkMode ? Colors.white : Colors.black87,
child: Obx(
() => Icon(
controller.isTextInput.value ? Icons.mic : Icons.keyboard,
size: 20.w,
),
),
onChanged: (value) => controller.inputText.value = value,
onSubmitted: (value) {
if (value.trim().isNotEmpty) {
controller.sendMessage(value);
textController.clear();
controller.inputText.value = ''; // 清空输入框
}
},
),
),
SizedBox(width: 8.w),
// 发送按钮
Obx(() {
final hasText = controller.inputText.value.isNotEmpty;
return Container(
width: 40.w,
height: 40.w,
decoration: BoxDecoration(
color: hasText
? AppColors.primary
: isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.grey[200],
shape: BoxShape.circle,
),
child: IconButton(
icon: Icon(
Icons.send,
color: hasText
? Colors.white
: isDarkMode
? Colors.white.withOpacity(0.5)
: Colors.grey[400],
size: 18.r,
),
padding: EdgeInsets.zero,
onPressed: hasText
? () {
controller.sendMessage(controller.inputText.value);
textController.clear();
controller.inputText.value = ''; // 清空输入框
}
: null,
),
);
}),
],
),
],
),
);
}

Loading…
Cancel
Save