SpeechToTextProvider无法实现语音逐字转录至输入框的问题求助
解决SpeechToTextProvider实时转录到输入框的问题
核心问题在于SpeechToTextProvider没有直接暴露onResult回调,但它基于Provider状态管理,每次识别结果更新时会自动通知监听者。我们可以通过监听Provider的状态变化来实现逐字转录,具体修改如下:
步骤1:调整状态监听逻辑
把原来直接在build里赋值speechProvider的方式,改为用Consumer监听SpeechToTextProvider的状态变化,这样每次识别结果更新都会触发回调处理:
@override Widget build(BuildContext context) { return Consumer<SpeechToTextProvider>( builder: (context, speechProvider, child) { // 每次状态变化时处理最新识别结果 _handleSpeechResult(speechProvider); if (speechProvider.isNotAvailable) { return const Center( child: Text('语音识别不可用,无权限或设备不支持'), ); } return MicrophoneWidget( speechProvider.isListening, startListening, stopListening, key: UniqueKey() ); }, ); }
步骤2:实现实时结果处理方法
新增_handleSpeechResult方法替代原resultListener,处理识别结果的实时更新:
void _handleSpeechResult(SpeechToTextProvider speechProvider) { final result = speechProvider.lastResult; if (result == null) return; if (result.finalResult) { // 最终结果确认,更新历史输入记录 widget.setLastInputChange( (widget.key as ValueKey<dynamic>).value, widget.controller.text ); } else { // 实时拼接输入框内容 widget.controller.text = '${widget.lastInputChange} ${result.recognizedWords}'; } }
步骤3:修正startListening方法
去掉无效的onResult参数,开启partialResults以获取实时中间结果:
void startListening() { if (speechProvider.isAvailable && speechProvider.isNotListening) { speechProvider.listen( partialResults: true, // 必须开启才能拿到实时中间识别结果 ); } }
完整修改后的SpeechProvider代码
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:speech_to_text/speech_to_text_provider.dart'; class SpeechProvider extends StatefulWidget { const SpeechProvider({ super.key, required this.controller, required this.lastInputChange, required this.setLastInputChange, }); final TextEditingController controller; final String lastInputChange; final void Function(String, String) setLastInputChange; @override SpeechProviderState createState() => SpeechProviderState(); } class SpeechProviderState extends State<SpeechProvider> { late SpeechToTextProvider speechProvider; void startListening() { if (speechProvider.isAvailable && speechProvider.isNotListening) { speechProvider.listen( partialResults: true, ); } } void stopListening() { if (speechProvider.isListening) { speechProvider.stop(); widget.setLastInputChange( (widget.key as ValueKey<dynamic>).value, widget.controller.text ); } } void _handleSpeechResult(SpeechToTextProvider speechProvider) { final result = speechProvider.lastResult; if (result == null) return; if (result.finalResult) { widget.setLastInputChange( (widget.key as ValueKey<dynamic>).value, widget.controller.text ); } else { widget.controller.text = '${widget.lastInputChange} ${result.recognizedWords}'; } } @override Widget build(BuildContext context) { return Consumer<SpeechToTextProvider>( builder: (context, provider, child) { speechProvider = provider; _handleSpeechResult(provider); if (speechProvider.isNotAvailable) { return const Center( child: Text('语音识别不可用,无权限或设备不支持'), ); } return MicrophoneWidget( speechProvider.isListening, startListening, stopListening, key: UniqueKey() ); }, ); } } class MicrophoneWidget extends StatelessWidget { const MicrophoneWidget(this.isListening, this.startListening, this.stopListening, {super.key}); final bool isListening; final void Function() startListening; final void Function() stopListening; @override Widget build(BuildContext context) { return TapRegion( onTapOutside: (tap) => isListening ? stopListening() : null, child: Padding( padding: const EdgeInsets.all(8.0), child: SizedBox( child: FloatingActionButton( onPressed: isListening ? stopListening : startListening, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(80.0)), ), child: Icon(isListening ? Icons.mic : Icons.mic_off), ), ), ), ); } }
关键说明
partialResults: true是核心:默认关闭状态下只会返回最终识别结果,开启后才能获取实时的中间转录内容。- 利用Consumer监听状态:SpeechToTextProvider内部每次更新识别结果时会调用
notifyListeners(),Consumer会自动触发回调,实现输入框的实时更新。 - 状态同步:通过Consumer获取最新的provider实例,确保每次状态变化都能拿到最新的
lastResult数据。
内容的提问来源于stack exchange,提问作者Giulia Santoiemma
相关产品推荐
相关产品推荐

