Skip to main content
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

PropertyTypeDescription
textStringTranscribed text
confidencedoubleConfidence score (0.0 to 1.0)
durationMsintAudio duration in milliseconds
languageString?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 Format Requirements

Audio must be in the correct format for accurate transcription.
PropertyRequired Value
FormatPCM (raw audio)
Sample Rate16,000 Hz (16kHz)
Channels1 (mono)
Bit Depth16-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 IDSizeLanguagesSpeed
sherpa-onnx-whisper-tiny.en~75MBEnglishFast
sherpa-onnx-whisper-base.en~150MBEnglishMedium
sherpa-onnx-whisper-small.en~250MBEnglishSlower
sherpa-onnx-whisper-tiny~75MBMultilingualFast

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