【问题标题】:Flutter/Dart: speech to text (offline and continuous) for any languageFlutter/Dart:任何语言的语音到文本(离线和连续)
【发布时间】:2019-09-23 10:56:25
【问题描述】:

我可以使用任何软件包来创建可以将语音转文本的应用程序吗?

它应该包括以下功能:

  • 离线语音转文字
  • 连续聆听(10-30 分钟)
  • 识别器适用于 Android/IOS 支持的所有语言

到目前为止,我发现了这个https://pub.dev/packages/speech_recognition,但它说:

iOS API 发送中间结果,在我的 Android 设备上,只有 最终转录已收到

其他限制:在 iOS 上,默认情况下插件配置为 法语、英语、俄语、西班牙语、意大利语。在 Android 上,没有 额外的安装,它可能只适用于默认 设备语言环境。

有人测试过这个包,结果很好?或者您有什么其他建议?

【问题讨论】:

    标签: flutter dart speech-recognition speech-to-text


    【解决方案1】:

    我现在使用https://pub.dev/packages/speech_to_text。它得到了积极的维护,而且效果很好。我认为可以编写一些自定义代码来让它连续监听。

    编辑:

    根据要求,请参阅下面的连续收听逻辑。我仅将其用作概念证明,因此我不建议将其用于生产应用程序。据我所知,Android API 不支持开箱即用的连续监听。

    语音识别块

    import 'package:bloc/bloc.dart';
    import 'package:meta/meta.dart';
    import 'package:template_mobile/core/sevices/speech_recognition_service.dart';
    import 'package:template_mobile/core/state/event/speech_recognition_event.dart';
    import 'package:template_mobile/core/state/state/speech_recognition_state.dart';
    
    class SpeechRecognitionBloc
        extends Bloc<SpeechRecognitionEvent, SpeechRecognitionState> {
      final SpeechRecognitionService speechRecognitionService;
    
      SpeechRecognitionBloc({
        @required this.speechRecognitionService,
      }) : assert(speechRecognitionService != null) {
        speechRecognitionService.errors.stream.listen((errorResult) {
          add(SpeechRecognitionErrorEvent(
            error: "${errorResult.errorMsg} - ${errorResult.permanent}",
          ));
        });
    
        speechRecognitionService.statuses.stream.listen((status) {
          if (state is SpeechRecognitionRecognizedState) {
            var currentState = state as SpeechRecognitionRecognizedState;
            if (currentState.finalResult) {
              add(SpeechRecognitionStatusChangedEvent());
            }
          }
        });
    
        speechRecognitionService.words.stream.listen((speechResult) {
          add(SpeechRecognitionRecognizedEvent(
            words: speechResult.recognizedWords,
            finalResult: speechResult.finalResult,
          ));
        });
      }
    
      @override
      SpeechRecognitionState get initialState =>
          SpeechRecognitionUninitializedState();
    
      @override
      Stream<SpeechRecognitionState> mapEventToState(
          SpeechRecognitionEvent event) async* {
        if (event is SpeechRecognitionInitEvent) {
          var hasSpeech = await speechRecognitionService.initSpeech();
          if (hasSpeech) {
            yield SpeechRecognitionAvailableState();
          } else {
            yield SpeechRecognitionUnavailableState();
          }
        }
    
        if (event is SpeechRecognitionStartPressEvent) {
          yield SpeechRecognitionStartPressedState();
          add(SpeechRecognitionStartEvent());
        }
    
        if (event is SpeechRecognitionStartEvent) {
          speechRecognitionService.startListening();
          yield SpeechRecognitionStartedState();
        }
    
        if (event is SpeechRecognitionStopPressEvent) {
          yield SpeechRecognitionStopPressedState();
          add(SpeechRecognitionStopEvent());
        }
    
        if (event is SpeechRecognitionStopEvent) {
          speechRecognitionService.stopListening();
          yield SpeechRecognitionStopedState();
        }
    
        if (event is SpeechRecognitionCancelEvent) {
          speechRecognitionService.cancelListening();
          yield SpeechRecognitionCanceledState();
        }
    
        if (event is SpeechRecognitionRecognizedEvent) {
          yield SpeechRecognitionRecognizedState(
              words: event.words, finalResult: event.finalResult);
          if (event.finalResult == true &&
              speechRecognitionService.statuses.value == 'notListening') {
            await Future.delayed(Duration(milliseconds: 50));
            add(SpeechRecognitionStatusChangedEvent());
          }
        }
    
        if (event is SpeechRecognitionErrorEvent) {
          yield SpeechRecognitionErrorState(error: event.error);
          // Just for UI updates for the state to propagates
          await Future.delayed(Duration(milliseconds: 50));
          add(SpeechRecognitionInitEvent());
          await Future.delayed(Duration(milliseconds: 50));
          add(SpeechRecognitionStartPressEvent());
        }
    
        if (event is SpeechRecognitionStatusChangedEvent) {
          yield SpeechRecognitionStatusState();
          add(SpeechRecognitionStartPressEvent());
        }
      }
    }
    

    语音识别服务

    import 'dart:async';
    
    import 'package:rxdart/rxdart.dart';
    import 'package:speech_to_text/speech_recognition_error.dart';
    import 'package:speech_to_text/speech_recognition_result.dart';
    import 'package:speech_to_text/speech_to_text.dart';
    
    class SpeechRecognitionService {
      final SpeechToText speech = SpeechToText();
    
      var errors = StreamController<SpeechRecognitionError>();
      var statuses = BehaviorSubject<String>();
      var words = StreamController<SpeechRecognitionResult>();
    
      var _localeId = '';
    
      Future<bool> initSpeech() async {
        bool hasSpeech = await speech.initialize(
          onError: errorListener,
          onStatus: statusListener,
        );
    
        if (hasSpeech) {
          var systemLocale = await speech.systemLocale();
          _localeId = systemLocale.localeId;
        }
    
        return hasSpeech;
      }
    
      void startListening() {
        speech.stop();
        speech.listen(
            onResult: resultListener,
            listenFor: Duration(minutes: 1),
            localeId: _localeId,
            onSoundLevelChange: null,
            cancelOnError: true,
            partialResults: true);
      }
    
      void errorListener(SpeechRecognitionError error) {
        errors.add(error);
      }
    
      void statusListener(String status) {
        statuses.add(status);
      }
    
      void resultListener(SpeechRecognitionResult result) {
        words.add(result);
      }
    
      void stopListening() {
        speech.stop();
      }
    
      void cancelListening() {
        speech.cancel();
      }
    }
    

    【讨论】:

    • 你能让它连续收听吗?
    • 是的,有点。在每个结果/错误之后,我都能顺利地重新开始演讲。当然不理想,但据我了解Android API不支持持续识别。
    • 能否请您上传您的代码作为要点或其他内容,以便我使用它?
    • @SIMMORSAL 我用请求的代码更新了答案。
    • 谢谢。快速提问,这段代码是否会在每次激活和停用时播放默认语音?
    【解决方案2】:

    https://pub.dev/packages/speech_recognition 是最好的选择。 它基于SpeechRecognizer 并提供离线语音到文本。

    无法连续收听。即使是付费的在线Cloud Speech-to-Text API 也不允许这样做,因为它很危险(滥用等)。

    在 iOS 上,默认情况下插件配置为法语、英语、俄语、西班牙语、意大利语,但您可以将缺少的语言添加到 swift 源文件中。

    所以最终你不会找到更好的语音识别插件,即使它并不完美。

    【讨论】:

      【解决方案3】:

      如果您愿意编写自定义平台特定代码https://flutter.dev/docs/development/platform-integration/platform-channels,对于Android,您可以使用https://github.com/alphacep/vosk-android-demo 来获得您想要的。

      另一种方法是按照How Can I Implement Google Voice Typing In My Application? 中的建议构建您自己的键盘输入法以使用语音输入。

      【讨论】:

        猜你喜欢
        • 2022-10-03
        • 1970-01-01
        • 1970-01-01
        • 2018-10-23
        • 2021-02-26
        • 2017-12-29
        • 1970-01-01
        • 2019-06-07
        • 2019-03-25
        相关资源
        最近更新 更多