Flutter语音识别插件vosk_flutter的使用
Flutter语音识别插件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
更多关于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和交互逻辑。
这个示例提供了一个基本的框架,你可以根据实际需求进行扩展和优化。