Flutter语音识别插件vosk_flutter的使用

发布于 1周前 作者 sinazl 来自 Flutter

Flutter语音识别插件vosk_flutter的使用

pub package style: very good analysis vosk_flutter

Flutter插件用于Vosk语音识别。

平台支持

Android iOS MacOS Web Linux Windows

使用

配置

请参考安装页面的说明:

Android

android/app/proguard-rules.pro文件中添加以下规则(如果该文件不存在,则创建它):

-keep class com.sun.jna.* { *; }
-keepclassmembers class * extends com.sun.jna.* { public *; }

如果要使用麦克风输入,请在AndroidManifest.xml中添加麦克风权限:

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

加载模型

pubspec.yaml中添加以下配置:

flutter:
  assets:
    - assets/models/

加载模型:

final vosk = VoskFlutterPlugin.instance();
final enSmallModelPath = await ModelLoader()
    .loadFromAssets('assets/models/vosk-model-small-en-us-0.15.zip');

创建识别器

创建一个识别器实例:

final recognizer = await vosk.createRecognizer(
    model: model,
    sampleRate: sampleRate,
);
final recognizerWithGrammar = await vosk.createRecognizer(
    model: model,
    sampleRate: sampleRate,
    grammar: ['one', 'two', 'three'],
);

识别音频数据

处理音频数据并获取结果:

Uint8List audioBytes = ...; // 音频数据为PCM 16位单声道格式
List<String> results = [];
int chunkSize = 8192;
int pos = 0;

while (pos + chunkSize < audioBytes.length) {
    final resultReady = await recognizer.acceptWaveformBytes(
      Uint8List.fromList(audioBytes.getRange(pos, pos + chunkSize).toList()));
    pos += chunkSize;
    
    if (resultReady) {
      print(await recognizer.getResult());
    } else {
      print(await recognizer.getPartialResult());
    }
}
await recognizer.acceptWaveformBytes(
  Uint8List.fromList(audioBytes.getRange(pos, audioBytes.length).toList()));
print(await recognizer.getFinalResult());

识别麦克风数据

Android

初始化并启动语音服务:

final speechService = await vosk.initSpeechService(recognizer);
speechService.onPartial().forEach((partial) => print(partial));
speechService.onResult().forEach((result) => print(result));
await speechService.start();
Linux & Windows

使用适合的插件获取麦克风输入,并传递给识别器:

// 示例代码省略,具体实现根据所选插件而定

完整示例代码

以下是完整的示例代码,展示了如何使用vosk_flutter插件进行语音识别。

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:record/record.dart';
import 'package:vosk_flutter/vosk_flutter.dart';
import 'package:vosk_flutter_example/test_screen.dart';

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

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: VoskFlutterDemo(),
    );
  }
}

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

  [@override](/user/override)
  State<VoskFlutterDemo> createState() => _VoskFlutterDemoState();
}

class _VoskFlutterDemoState extends State<VoskFlutterDemo> {
  static const _textStyle = TextStyle(fontSize: 30, color: Colors.black);
  static const _modelName = 'vosk-model-small-en-us-0.15';
  static const _sampleRate = 16000;

  final _vosk = VoskFlutterPlugin.instance();
  final _modelLoader = ModelLoader();
  final _recorder = Record();

  String? _fileRecognitionResult;
  String? _error;
  Model? _model;
  Recognizer? _recognizer;
  SpeechService? _speechService;

  bool _recognitionStarted = false;

  [@override](/user/override)
  void initState() {
    super.initState();

    _modelLoader
        .loadModelsList()
        .then((modelsList) =>
            modelsList.firstWhere((model) => model.name == _modelName))
        .then((modelDescription) =>
            _modelLoader.loadFromNetwork(modelDescription.url)) // 加载模型
        .then(
            (modelPath) => _vosk.createModel(modelPath)) // 创建模型对象
        .then((model) => setState(() => _model = model))
        .then((_) => _vosk.createRecognizer(
            model: _model!, sampleRate: _sampleRate)) // 创建识别器
        .then((value) => _recognizer = value)
        .then((recognizer) {
      if (Platform.isAndroid) {
        _vosk
            .initSpeechService(_recognizer!) // 初始化语音服务
            .then((speechService) =>
                setState(() => _speechService = speechService))
            .catchError((e) => setState(() => _error = e.toString()));
      }
    }).catchError((e) {
      setState(() => _error = e.toString());
      return null;
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    if (_error != null) {
      return Scaffold(
          body: Center(child: Text("Error: $_error", style: _textStyle)));
    } else if (_model == null) {
      return const Scaffold(
          body: Center(child: Text("Loading model...", style: _textStyle)));
    } else if (Platform.isAndroid && _speechService == null) {
      return const Scaffold(
        body: Center(
          child: Text("Initializing speech service...", style: _textStyle),
        ),
      );
    } else {
      return Platform.isAndroid ? _androidExample() : _commonExample();
    }
  }

  Widget _androidExample() {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
                onPressed: () async {
                  if (_recognitionStarted) {
                    await _speechService!.stop();
                  } else {
                    await _speechService!.start();
                  }
                  setState(() => _recognitionStarted = !_recognitionStarted);
                },
                child: Text(_recognitionStarted
                    ? "Stop recognition"
                    : "Start recognition")),
            StreamBuilder(
                stream: _speechService!.onPartial(),
                builder: (context, snapshot) => Text(
                    "Partial result: ${snapshot.data.toString()}",
                    style: _textStyle)),
            StreamBuilder(
                stream: _speechService!.onResult(),
                builder: (context, snapshot) => Text(
                    "Result: ${snapshot.data.toString()}",
                    style: _textStyle)),
          ],
        ),
      ),
    );
  }

  Widget _commonExample() {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
                onPressed: () async {
                  if (_recognitionStarted) {
                    await _stopRecording();
                  } else {
                    await _recordAudio();
                  }
                  setState(() => _recognitionStarted = !_recognitionStarted);
                },
                child: Text(
                    _recognitionStarted ? "Stop recording" : "Record audio")),
            Text("Final recognition result: $_fileRecognitionResult",
                style: _textStyle),
          ],
        ),
      ),
    );
  }

  Future<void> _recordAudio() async {
    try {
      await _recorder.start(
          samplingRate: 16000, encoder: AudioEncoder.wav, numChannels: 1);
    } catch (e) {
      _error = e.toString() +
          '\n\n Make sure fmedia(https://stsaz.github.io/fmedia/)'
              ' is installed on Linux';
    }
  }

  Future<void> _stopRecording() async {
    try {
      final filePath = await _recorder.stop();
      if (filePath != null) {
        final bytes = File(filePath).readAsBytesSync();
        _recognizer!.acceptWaveformBytes(bytes);
        _fileRecognitionResult = await _recognizer!.getFinalResult();
      }
    } catch (e) {
      _error = e.toString() +
          '\n\n Make sure fmedia(https://stsaz.github.io/fmedia/)'
              ' is installed on Linux';
    }
  }
}

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

1 回复

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


当然,以下是一个关于如何在Flutter项目中使用vosk_flutter插件进行语音识别的代码示例。这个插件利用了Vosk语音识别引擎,提供了离线和在线的语音识别功能。

首先,确保你已经在pubspec.yaml文件中添加了vosk_flutter依赖:

dependencies:
  flutter:
    sdk: flutter
  vosk_flutter: ^版本号  # 请替换为最新的版本号

然后,运行flutter pub get来安装依赖。

接下来,我们创建一个简单的Flutter应用,演示如何使用vosk_flutter插件进行语音识别。

1. 导入必要的包

在你的主Dart文件(通常是main.dart)中,导入必要的包:

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

2. 创建语音识别页面

创建一个新的页面或直接在主页面中添加语音识别功能。以下是一个简单的示例:

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Vosk Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: SpeechRecognitionPage(),
    );
  }
}

class SpeechRecognitionPage extends StatefulWidget {
  @override
  _SpeechRecognitionPageState createState() => _SpeechRecognitionPageState();
}

class _SpeechRecognitionPageState extends State<SpeechRecognitionPage> {
  late VoskRecognizer _recognizer;
  late List<String> _results;
  bool _isListening = false;

  @override
  void initState() {
    super.initState();
    _results = [];
    _recognizer = VoskRecognizer();
    _recognizer.setModelPath('path/to/your/model');  // 设置模型路径,这里需要离线模型
    _recognizer.setSampleRate(16000);  // 设置采样率,通常与模型匹配
    _recognizer.init().then((_) {
      print('Recognizer initialized');
    }).catchError((error) {
      print('Failed to initialize recognizer: $error');
    });
  }

  @override
  void dispose() {
    _recognizer.stop().then((_) {
      _recognizer.close();
    });
    super.dispose();
  }

  Future<void> _startListening() async {
    if (!_isListening) {
      setState(() {
        _isListening = true;
      });
      _recognizer.start().then((_) {
        _recognizer.addListener((result) {
          setState(() {
            _results.add(result);
          });
        });
      }).catchError((error) {
        print('Failed to start listening: $error');
      });
    }
  }

  Future<void> _stopListening() async {
    if (_isListening) {
      setState(() {
        _isListening = false;
      });
      _recognizer.stop().then((finalResult) {
        setState(() {
          _results.add(finalResult);
        });
      }).catchError((error) {
        print('Failed to stop listening: $error');
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Vosk Demo'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: _isListening ? _stopListening : _startListening,
              child: Text(_isListening ? 'Stop' : 'Start Listening'),
            ),
            SizedBox(height: 20),
            Expanded(
              child: ListView.builder(
                itemCount: _results.length,
                itemBuilder: (context, index) {
                  return Text(_results[index], style: TextStyle(fontSize: 18));
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

3. 下载并配置模型

注意,上述代码中_recognizer.setModelPath('path/to/your/model');需要指向一个有效的Vosk模型路径。你可以从Vosk模型库下载适合你的语言的模型,并将其放置在设备的适当位置(例如应用的资产文件夹中)。

4. 权限处理

在实际应用中,你还需要处理录音权限。你可以在AndroidManifest.xml中添加必要的权限请求,并在代码中请求这些权限(使用permission_handler插件等)。

注意事项

  • 确保你下载的模型与你的设备架构(如ARM, x86)和采样率匹配。
  • 处理可能的错误和异常情况,如模型加载失败、录音失败等。
  • 根据需要调整UI和交互逻辑。

这个示例提供了一个基本的框架,你可以根据实际需求进行扩展和优化。

回到顶部