Transcribe audio data to text using on-device Whisper models via ONNX Runtime.
Basic Usage
// Load STT model first
await RunAnywhere.loadSTTModel('sherpa-onnx-whisper-tiny.en');
// Transcribe audio data (PCM16 at 16kHz mono)
final text = await RunAnywhere.transcribe(audioBytes);
print('Transcription: $text');
With Detailed Result
Get confidence scores and metadata with transcribeWithResult():
final result = await RunAnywhere.transcribeWithResult(audioBytes);
print('Text: ${result.text}');
print('Confidence: ${(result.confidence * 100).toStringAsFixed(1)}%');
print('Duration: ${result.durationMs}ms');
if (result.language != null) {
print('Language: ${result.language}');
}
STTResult
| Property | Type | Description |
|---|
text | String | Transcribed text |
confidence | double | Confidence score (0.0 to 1.0) |
durationMs | int | Audio duration in milliseconds |
language | String? | Detected language code |
Setup
1. Register ONNX Backend
import 'package:runanywhere_onnx/runanywhere_onnx.dart';
await Onnx.register();
2. Add STT Model
Onnx.addModel(
id: 'sherpa-onnx-whisper-tiny.en',
name: 'Whisper Tiny English',
url: 'https://github.com/RunanywhereAI/sherpa-onnx/releases/download/runanywhere-models-v1/sherpa-onnx-whisper-tiny.en.tar.gz',
modality: ModelCategory.speechRecognition,
);
3. Download & Load
// Download
await for (final progress in RunAnywhere.downloadModel('sherpa-onnx-whisper-tiny.en')) {
print('${(progress.percentage * 100).toStringAsFixed(1)}%');
if (progress.state.isCompleted) break;
}
// Load
await RunAnywhere.loadSTTModel('sherpa-onnx-whisper-tiny.en');
Audio must be in the correct format for accurate transcription.
| Property | Required Value |
|---|
| Format | PCM (raw audio) |
| Sample Rate | 16,000 Hz (16kHz) |
| Channels | 1 (mono) |
| Bit Depth | 16-bit |
Recording Audio
Use a package like record to capture audio:
import 'package:record/record.dart';
final recorder = AudioRecorder();
// Start recording with correct format
await recorder.start(
const RecordConfig(
encoder: AudioEncoder.pcm16bits,
sampleRate: 16000,
numChannels: 1,
),
path: tempFilePath,
);
// Stop and get audio
await recorder.stop();
final audioBytes = await File(tempFilePath).readAsBytes();
// Transcribe
final text = await RunAnywhere.transcribe(audioBytes);
Available Models
| Model ID | Size | Languages | Speed |
|---|
sherpa-onnx-whisper-tiny.en | ~75MB | English | Fast |
sherpa-onnx-whisper-base.en | ~150MB | English | Medium |
sherpa-onnx-whisper-small.en | ~250MB | English | Slower |
sherpa-onnx-whisper-tiny | ~75MB | Multilingual | Fast |
Complete Example
class TranscriptionDemo extends StatefulWidget {
@override
_TranscriptionDemoState createState() => _TranscriptionDemoState();
}
class _TranscriptionDemoState extends State<TranscriptionDemo> {
final _recorder = AudioRecorder();
String _transcription = '';
bool _isRecording = false;
bool _isTranscribing = false;
Future<void> _toggleRecording() async {
if (_isRecording) {
// Stop and transcribe
final path = await _recorder.stop();
if (path != null) {
setState(() {
_isRecording = false;
_isTranscribing = true;
});
final audioBytes = await File(path).readAsBytes();
final text = await RunAnywhere.transcribe(audioBytes);
setState(() {
_transcription = text;
_isTranscribing = false;
});
}
} else {
// Start recording
if (await _recorder.hasPermission()) {
final tempDir = await getTemporaryDirectory();
final path = '${tempDir.path}/recording.pcm';
await _recorder.start(
const RecordConfig(
encoder: AudioEncoder.pcm16bits,
sampleRate: 16000,
numChannels: 1,
),
path: path,
);
setState(() => _isRecording = true);
}
}
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text(_transcription),
ElevatedButton(
onPressed: _isTranscribing ? null : _toggleRecording,
child: Text(_isRecording ? 'Stop' : 'Record'),
),
if (_isTranscribing) CircularProgressIndicator(),
],
);
}
}
See Also