Flutter连续语音识别插件speech_to_text_continuous的使用

Flutter连续语音识别插件speech_to_text_continuous的使用

插件信息

pub package build status codecov

一个库,用于暴露设备特定的语音识别功能。

此插件包含一组类,使在Flutter中使用底层平台的语音识别功能变得简单。它支持Android、iOS和web。该库的目标用例是命令和短语,而不是连续的语音转换或始终在线监听。

平台支持

支持 Android iOS MacOS Web* Linux Windows
构建
语音
  • 构建: 表示你可以在该平台上构建并运行插件。
  • 语音: 表示大多数语音识别功能都可以工作。对于具有构建但不支持语音的平台,初始化会报告为假。

注意: 仅某些浏览器支持,具体请参见这里

最近更新

6.5.0

  • 新增了initialize选项以改进对一些移动浏览器的支持,SpeechToText.webDoNotAggregate。测试浏览器用户代理以确定是否应使用它。

6.4.0

  • 对新Android设备有更好的支持,现在返回了设备上语音识别支持的语言列表。

注意: 欢迎反馈任何测试设备的信息。

使用

要从麦克风识别文本,请导入该包并调用插件,如下所示:

简单示例

import 'package:speech_to_text/speech_to_text.dart' as stt;

stt.SpeechToText speech = stt.SpeechToText();
bool available = await speech.initialize(onStatus: statusListener, onError: errorListener);
if (available) {
  speech.listen(onResult: resultListener);
} else {
  print("The user has denied the use of speech recognition.");
}
// 一段时间后...
speech.stop();

完整Flutter示例

import 'package:flutter/material.dart';
import 'package:speech_to_text/speech_recognition_result.dart';
import 'package:speech_to_text/speech_to_text.dart';

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

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

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

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

class _MyHomePageState extends State<MyHomePage> {
  SpeechToText _speechToText = SpeechToText();
  bool _speechEnabled = false;
  String _lastWords = '';

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

  /// 这个操作只需要在应用会话期间执行一次
  void _initSpeech() async {
    _speechEnabled = await _speechToText.initialize();
    setState(() {});
  }

  /// 每次开始语音识别会话时
  void _startListening() async {
    await _speechToText.listen(onResult: _onSpeechResult);
    setState(() {});
  }

  /// 手动停止当前活动的语音识别会话
  /// 注意每个平台都有超时,SpeechToText插件也支持在listen方法中设置超时
  void _stopListening() async {
    await _speechToText.stop();
    setState(() {});
  }

  /// 当平台返回识别单词时,SpeechToText插件会调用此回调
  void _onSpeechResult(SpeechRecognitionResult result) {
    setState(() {
      _lastWords = result.recognizedWords;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Speech Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Container(
              padding: EdgeInsets.all(16),
              child: Text(
                'Recognized words:',
                style: TextStyle(fontSize: 20.0),
              ),
            ),
            Expanded(
              child: Container(
                padding: EdgeInsets.all(16),
                child: Text(
                  // 如果正在监听语音,则显示识别的单词
                  _speechToText.isListening
                      ? '$_lastWords'
                      // 如果监听未激活但可以启动,请告诉用户如何启动它,否则指示语音尚未准备好或目标设备不支持
                      : _speechEnabled
                          ? '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),
      ),
    );
  }
}

初始化一次

initialize 方法只需要在应用程序会话期间调用一次。之后可以使用 listenstartstopcancel 与插件进行交互。再次调用 initialize 是安全的,但它意味着 onStatusonError 回调在第一次调用 initialize 后无法重置。因此,每个应用程序应该只有一个插件实例。SpeechToTextProvider 是一种创建单个实例并将其轻松重用于多个小部件的方法。

权限

使用此插件的应用程序需要用户的权限。

iOS

将以下键添加到您的 Info.plist 文件中,位于 <project root>/ios/Runner/Info.plist

  • NSSpeechRecognitionUsageDescription - 描述为什么您的应用程序使用语音识别。这在可视化编辑器中称为 Privacy - Speech Recognition Usage Description
  • NSMicrophoneUsageDescription - 描述为什么您的应用程序需要访问麦克风。这在可视化编辑器中称为 Privacy - Microphone Usage Description

Android

在您的 AndroidManifest.xml 文件中添加录音音频权限,位于 <project root>/android/app/src/main/AndroidManifest.xml

  • android.permission.RECORD_AUDIO - 此权限是必需的,因为需要访问麦克风。
  • android.permission.INTERNET - 此权限是必需的,因为语音识别可能使用远程服务。
  • android.permission.BLUETOOTH - 此权限是必需的,因为语音识别可以使用已连接的蓝牙耳机。
  • android.permission.BLUETOOTH_ADMIN - 此权限是必需的,因为语音识别可以使用已连接的蓝牙耳机。
  • android.permission.BLUETOOTH_CONNECT - 此权限是必需的,因为语音识别可以使用已连接的蓝牙耳机。
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.BLUETOOTH"/>
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>

Android SDK 30或更高版本

如果您针对的是Android SDK,即您将targetSDKVersion 设置为30或更高版本,那么您需要在AndroidManifest.xml文件中立即在权限部分之后添加以下内容。请参阅示例应用程序以了解完整的使用情况。

<queries>
    <intent>
        <action android:name="android.speech.RecognitionService" />
    </intent>
</queries>

添加iOS声音(可选)

Android会在语音监听开始或停止时自动播放系统声音,但iOS不会。如果应用程序使用此插件,则可以添加声音文件作为资产,以在iOS上指示监听状态。要在应用程序中启用声音,请将声音文件添加到项目中,并在应用程序的pubspec.yaml文件的assets部分中引用它们。声音文件的位置和文件名必须完全匹配,否则将找不到它们。插件的示例应用程序展示了使用方式。注意这些文件应该非常短,因为它们会延迟语音识别的开始/结束直到声音播放完成。

  assets:
  - assets/sounds/speech_to_text_listening.m4r
  - assets/sounds/speech_to_text_cancel.m4r
  - assets/sounds/speech_to_text_stop.m4r
  • speech_to_text_listening.m4r - 当调用listen方法时播放。
  • speech_to_text_cancel.m4r - 当调用cancel方法时播放。
  • speech_to_text_stop.m4r - 当调用stop方法时播放。

提示

切换识别语言

speech_to_text插件默认使用设备的默认区域设置进行语音识别。但是它还支持使用设备上安装的任何语言。要找到可用的语言并选择特定的语言,请使用这些属性。

SpeechToText实例上有locales属性,提供设备上安装的语言列表作为LocaleName实例。然后listen方法接受一个可选的localeId命名参数,这将是locales返回的任何值的localeId属性。调用看起来像这样:

var locales = await speech.locales();

// 一些UI或其他代码来从列表中选择一个区域
// 导致一个索引,selectedLocale

var selectedLocale = locales[selectedLocale];
speech.listen(
    onResult: resultListener,
    localeId: selectedLocale.localeId,
);

故障排除

iOS模拟器上的语音识别不起作用

如果在模拟器上语音识别不起作用,请转到模拟器中的设置应用: 辅助功能 -> 语音 -> 声音

从那里选择任何语言和任何发言者,它应该下载到设备上。之后,语音识别应该可以在模拟器上工作。

在Android上暂停后语音识别停止

Android语音识别有一个非常短暂的暂停超时。暂停的时间似乎因设备和Android OS版本而异。在我使用的设备中,没有任何设备的暂停时间超过5秒。不幸的是,似乎没有办法改变这种行为。

Android在语音识别开始/停止时发出嘟嘟声

这是Android操作系统的一个特性,目前没有支持的方法可以禁用它。

Android构建

版本5.2.0及以上的插件要求Android构建至少需要compileSdkVersion 31。此属性可以在build.gradle文件中设置。

连续语音识别

已经有许多关于如何使用此插件实现连续语音识别的问题。目前,插件设计用于短期间歇使用,例如当期待一个响应或发出单一语音命令时。问题#63是当前讨论此问题的地方。目前还没有通过Android或iOS语音识别功能实现此目标的方法。

至少有两个独立的使用案例需要连续语音识别:

  1. 语音助手风格,其中识别特定短语触发交互;
  2. 文本输入的口述。

语音助手风格的交互可能更适合通过集成现有设备上的助手功能来处理,而不是建立单独的功能。文本口述是通过键盘对标准文本输入控件可用的,尽管存在其他口述用途目前尚未得到良好支持。

浏览器对语音识别的支持

浏览器对语音识别的支持程度各不相同。这个问题有一些细节。我看到的最佳列表是https://caniuse.com/speech-recognitionhttps://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition。特别是,在问题#239中报告说Brave浏览器和Linux版Firefox不支持语音识别。

从录制的音频进行语音识别

已经有人问过是否可以从录制的音频中识别语音。简短的回答是,这在iOS上可能是可行的,但在Android上似乎不行。这个问题在此处#205有详细说明。

iOS与其他声音插件的交互,监听或初始化时崩溃

在iOS上,语音识别插件可以与其他声音插件交互,如WebRTC、声音播放或录制插件。虽然这个插件努力成为一个好公民并正确共享各种iOS声音资源,但总是有可能出现交互。一个可能有帮助的事情是在另一个声音插件结束之后和开始使用SpeechToText监听之前添加一个小延迟。例如,参见这个问题。

尝试为Android编译时SDK版本错误

Manifest merger failed : uses-sdk:minSdkVersion 16 cannot be smaller than version 21 declared in library [:speech_to_text]

speech_to_text插件要求至少Android SDK 21,因为在Android中的一些语音功能只在该版本中引入。要修复此错误,您需要更改build.gradle文件中的此版本。截至本文撰写时,该文件的相关部分如下所示:

defaultConfig {
    applicationId "com.example.app"
    minSdkVersion 21
    targetSdkVersion 28
    versionCode flutterVersionCode.toInteger()
    versionName flutterVersionName
    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

在Android上录制音频

目前不可能在Android上进行语音识别的同时录制音频。唯一的解决方案是停止录制,同时语音识别器是活跃的,然后在之后重新开始。

尝试为iOS编译时Swift版本错误

/Users/markvandergon/flutter/.pub-cache/hosted/pub.dartlang.org/speech_to_text-1.1.0/ios/Classes/SwiftSpeechToTextPlugin.swift:224:44: error: value of type 'SwiftSpeechToTextPlugin' has no member 'AVAudioSession'
                rememberedAudioCategory = self.AVAudioSession.Category
                                          ~~~~ ^~~~~~~~~~~~~~
    /Users/markvandergon/flutter/.pub-cache/hosted/pub.dartlang.org/speech_to_text-1.1.0/ios/Classes/SwiftSpeechToTextPlugin.swift:227:63: error: type 'Int' has no member 'notifyOthersOnDeactivation'
                try self.audioSession.setActive(true, withFlags: .notifyOthersOnDeactivation)

当Swift语言版本未正确设置时会发生这种情况。参见此线程获取帮助 https://github.com/csdcorp/speech_to_text/issues/45

尝试为iOS编译时Swift不受支持

`speech_to_text` 不指定Swift版本,并且没有任何集成它的目标(`Runner`)设置了 `SWIFT_VERSION` 属性。

这通常发生在仅支持Objective-C的旧项目中。参见此线程获取帮助 https://github.com/csdcorp/speech_to_text/issues/88

Android上的最后一个单词丢失

这里有一个关于此已知问题的讨论 https://github.com/csdcorp/speech_to_text/issues/434,涉及一些Android语音识别。此问题是由Google和其他Android实现者解决的,插件无法改善其识别质量。

在特定的Android设备上不工作

此问题的症状是initialize 方法始终失败。如果使用带有debugLogging: true 标志的initialize 方法打开调试日志记录,您将在Android日志中看到’Speech recognition unavailable’。这里有一个关于此问题的长篇讨论 https://github.com/csdcorp/speech_to_text/issues/36。问题似乎是识别器并非总是在设备上自动启用。两个关键因素帮助解决了这个问题:

  1. 确保Google App是启用状态。
  2. 确保应用程序具有所需的权限。

在Android模拟器上不工作

上述在Android设备上使其工作的提示同样适用于模拟器。一些用户报告在Android模拟器上看到了另一个错误 - SDK gphone x86 (Pixel 3a API 30)。AUDIO_RECORD权限已在清单文件中,也在Android设置中手动设置了Mic权限。当运行示例应用程序时,初始化成功,但开始失败,日志如下:

D/SpeechToTextPlugin(12555): put partial
D/SpeechToTextPlugin(12555): put languageTag
D/SpeechToTextPlugin(12555): Error 9 after start at 35 1000.0 / -100.0
D/SpeechToTextPlugin(12555): Cancel listening

解决方案

通过打开Google,点击麦克风图标并授予其权限,一切都会正常工作。

  1. 前往Google Play
  2. 搜索“Google”
  3. 您应该会找到这个应用: https://play.google.com/store/apps/details?id=com.google.android.googlequicksearchbox。如果“已禁用”,请启用它。

这是帮助的SO帖子: https://stackoverflow.com/questions/28769320/how-to-check-wether-speech-recognition-is-available-or-not

第二步

确保应用程序具有所需的权限。症状是你在开始监听会话时会收到永久性错误通知’error_audio_error’。这里有一个Stack Overflow帖子对此进行了讨论:

You should go to system setting, Apps, Google app, then enable its permission of microphone.

更多关于Flutter连续语音识别插件speech_to_text_continuous的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter连续语音识别插件speech_to_text_continuous的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


speech_to_text_continuous 是一个 Flutter 插件,用于在应用中实现连续语音识别。它基于 Google 的语音识别 API,允许用户持续地说话并将语音转换为文本。以下是如何在 Flutter 项目中使用 speech_to_text_continuous 插件的步骤。

1. 添加依赖

首先,在 pubspec.yaml 文件中添加 speech_to_text_continuous 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  speech_to_text_continuous: ^1.0.0  # 请使用最新版本

然后运行 flutter pub get 来获取依赖。

2. 初始化插件

在应用的入口文件(通常是 main.dart)中初始化插件:

import 'package:flutter/material.dart';
import 'package:speech_to_text_continuous/speech_to_text_continuous.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: SpeechToTextDemo(),
    );
  }
}

class SpeechToTextDemo extends StatefulWidget {
  @override
  _SpeechToTextDemoState createState() => _SpeechToTextDemoState();
}

class _SpeechToTextDemoState extends State<SpeechToTextDemo> {
  final SpeechToTextContinuous _speech = SpeechToTextContinuous();
  String _text = '';

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

  void _initializeSpeech() async {
    bool available = await _speech.initialize();
    if (available) {
      setState(() {});
    } else {
      print("语音识别不可用");
    }
  }

  void _startListening() async {
    _speech.listen(
      onResult: (result) {
        setState(() {
          _text = result.recognizedWords;
        });
      },
    );
  }

  void _stopListening() {
    _speech.stop();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('连续语音识别'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(_text),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _startListening,
              child: Text('开始识别'),
            ),
            ElevatedButton(
              onPressed: _stopListening,
              child: Text('停止识别'),
            ),
          ],
        ),
      ),
    );
  }
}

3. 配置权限

为了使用语音识别功能,需要在 AndroidManifest.xmlInfo.plist 文件中添加相应的权限。

Android

android/app/src/main/AndroidManifest.xml 中添加以下权限:

<uses-permission android:name="android.permission.RECORD_AUDIO"/>

iOS

ios/Runner/Info.plist 中添加以下键值对:

<key>NSMicrophoneUsageDescription</key>
<string>需要访问麦克风以进行语音识别</string>
<key>NSSpeechRecognitionUsageDescription</key>
<string>需要访问语音识别以进行语音转文本</string>

4. 运行应用

完成上述步骤后,运行应用。你应该能够看到一个简单的界面,点击“开始识别”按钮后,应用会开始监听语音并将其转换为文本显示在屏幕上。点击“停止识别”按钮可以停止监听。

5. 处理结果

onResult 回调函数会在每次识别到语音时被调用。你可以在这里处理识别到的文本,例如将其显示在界面上或保存到数据库中。

6. 其他功能

speech_to_text_continuous 插件还支持其他功能,例如:

  • 部分结果: 可以通过 partialResults: true 参数获取部分识别结果。
  • 语言设置: 可以通过 localeId 参数设置识别的语言。

例如:

_speech.listen(
  onResult: (result) {
    setState(() {
      _text = result.recognizedWords;
    });
  },
  partialResults: true,
  localeId: 'zh-CN',
);
回到顶部