Flutter/Dart:任何语言的语音到文本(离线和连续)

Chr*_*ris 9 speech-recognition speech-to-text dart flutter

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

它应包括以下功能:

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

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

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

其他限制:在 iOS 上,默认情况下该插件配置为法语、英语、俄语、西班牙语、意大利语。在 Android 上,无需额外安装,它可能仅适用于默认设备区域设置。

有人测试过这个包并取得了良好的结果吗?或者您还有其他建议吗?

Ser*_*o G 10

在版本上使用 flutterpeer_to_text 库的直接的解决方案,而不是像之前的答案那样5.6.1使用库。bloc

基本上,每当使用状态调用 statusListener 方法时,done我们都会再次调用 Listen 方法。

主程序.dart
import 'package:flutter/material.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';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  MyHomePageState createState() => MyHomePageState();
}

class MyHomePageState extends State<MyHomePage> {
  final SpeechToText _speechToText = SpeechToText();
  bool _speechEnabled = false;
  bool _speechAvailable = false;
  String _lastWords = '';
  String _currentWords = '';
  final String _selectedLocaleId = 'es_MX';

  printLocales() async {
    var locales = await _speechToText.locales();
    for (var local in locales) {
      debugPrint(local.name);
      debugPrint(local.localeId);
    }
  }

  @override
  void initState() {
    super.initState();
    _initSpeech();
  }

  void errorListener(SpeechRecognitionError error) {
    debugPrint(error.errorMsg.toString());
  }

  void statusListener(String status) async {
    debugPrint("status $status");
    if (status == "done" && _speechEnabled) {
      setState(() {
        _lastWords += " $_currentWords";
        _currentWords = "";
        _speechEnabled = false;
      });
      await _startListening();
    }
  }

  /// This has to happen only once per app
  void _initSpeech() async {
    _speechAvailable = await _speechToText.initialize(
        onError: errorListener,
        onStatus: statusListener
    );
    setState(() {});
  }

  /// Each time to start a speech recognition session
  Future _startListening() async {
    debugPrint("=================================================");
    await _stopListening();
    await Future.delayed(const Duration(milliseconds: 50));
    await _speechToText.listen(
        onResult: _onSpeechResult,
        localeId: _selectedLocaleId,
        cancelOnError: false,
        partialResults: true,
        listenMode: ListenMode.dictation
    );
    setState(() {
      _speechEnabled = true;
    });
  }

  /// Manually stop the active speech recognition session
  /// Note that there are also timeouts that each platform enforces
  /// and the SpeechToText plugin supports setting timeouts on the
  /// listen method.
  Future _stopListening() async {
    setState(() {
      _speechEnabled = false;
    });
    await _speechToText.stop();
  }

  /// This is the callback that the SpeechToText plugin calls when
  /// the platform returns recognized words.
  void _onSpeechResult(SpeechRecognitionResult result) {
    setState(() {
      _currentWords = result.recognizedWords;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Speech Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Container(
              padding: const EdgeInsets.all(16),
              child: const Text(
                'Recognized words:',
                style: TextStyle(fontSize: 20.0),
              ),
            ),
            Expanded(
              child: Container(
                padding: const EdgeInsets.all(16),
                child: Text(
                  _lastWords.isNotEmpty
                      ? '$_lastWords $_currentWords'
                      : _speechAvailable
                      ? 'Tap the microphone to start listening...'
                      : 'Speech not available',
                ),
              ),
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed:
        _speechToText.isNotListening ? _startListening : _stopListening,
        tooltip: 'Listen',
        child: Icon(_speechToText.isNotListening ? Icons.mic_off : Icons.mic),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 惊人的!!然后我会更新这里发布的代码 (2认同)

Chr*_*ris 5

我现在使用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());
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

语音识别服务

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();
  }
}
Run Code Online (Sandbox Code Playgroud)