WhisperBridge provides on-device speech-to-text using Whisper models.
Its API is intentionally small: initialize a model, transcribe a WAV file, and release resources when done.
Platform support#
| Platform | Status |
|---|---|
| Android | supported |
| iOS | supported |
| JVM / Desktop | supported |
| WASM | not implemented |
Public API#
expect object WhisperBridge {
fun getModelPath(modelFileName: String): String
fun initModel(modelPath: String): Boolean
fun transcribeWav(
wavPath: String,
language: String? = null,
initialPrompt: String? = null,
): String
fun transcribeWavSegments(
wavPath: String,
language: String? = null,
initialPrompt: String? = null,
translate: Boolean = false,
diarize: Boolean = false,
): String
fun release()
}getModelPath(modelFileName)#
Returns a platform-usable path for the Whisper model file.
val modelPath = WhisperBridge.getModelPath("ggml-base.en.bin")initModel(modelPath)#
Loads the Whisper model and prepares the transcription context.
val ok = WhisperBridge.initModel(modelPath)
check(ok) { "Failed to initialize Whisper model" }Call this once before transcription.
transcribeWav(wavPath, language, initialPrompt)#
Transcribes a WAV audio file and returns all segments joined into a single flat string.
val text = WhisperBridge.transcribeWav(
wavPath = "/path/to/sample.wav",
language = "en",
initialPrompt = "The following is a technical discussion about Kotlin."
)
println(text)Parameters#
wavPath: path to the WAV file to transcribelanguage: optional language hint such as"en","es", or"fr". Providing it improves predictability and reduces ambiguity when you already know the input language.initialPrompt: optional text to prime the model before transcription begins. Use this to bias the output toward specific vocabulary, domain terms, or formatting conventions. The model treats this as prior context without transcribing it literally.
Return value#
Returns the transcription as a String. If transcription fails, the result may be empty.
transcribeWavSegments(wavPath, language, initialPrompt, translate, diarize)#
Segment-aware transcription. Returns a JSON document that exposes what transcribeWav discards: per-segment text with start/end timestamps (milliseconds), the tinydiarize speaker-turn flag, and the whole-audio detected language code.
JSON shape#
{
"language": "de",
"segments": [
{"text": "Guten Morgen.", "t0": 0, "t1": 1200, "speaker_turn_next": false},
{"text": "Wie geht es Ihnen?", "t0": 1200, "t1": 2800, "speaker_turn_next": true}
]
}| Field | Type | Description |
|---|---|---|
language | String | ISO language code auto-detected by Whisper (e.g. "en", "de") |
segments[].text | String | Transcribed (or translated) text for this segment |
segments[].t0 | Long | Segment start time in milliseconds |
segments[].t1 | Long | Segment end time in milliseconds |
segments[].speaker_turn_next | Boolean | true if a speaker change follows this segment (only meaningful with a -tdrz model) |
Parameters#
wavPath: path to the WAV file to transcribe.language: optional language hint (same astranscribeWav).initialPrompt: optional priming text (same astranscribeWav).translate: passtrueto run Whisper’s built-in ORIGINAL→ENGLISH translation task. Segment text becomes the English translation regardless of the spoken language. Defaultfalse= language-preserving.diarize: passtrueonly with a tinydiarize (…-tdrz) model to enabletdrz_enable— this makesspeaker_turn_nextreturn real speaker-turn boundaries and also injects[SPEAKER_TURN]markers into segment text. Leavefalsefor regular models.
Example#
import com.llamatik.library.platform.WhisperBridge
import kotlinx.serialization.json.*
WhisperBridge.initModel(modelPath)
val json = WhisperBridge.transcribeWavSegments(
wavPath = "/path/to/recording.wav",
language = null, // auto-detect
)
val root = Json.parseToJsonElement(json).jsonObject
val language = root["language"]?.jsonPrimitive?.content
val segments = root["segments"]!!.jsonArray
for (seg in segments) {
val obj = seg.jsonObject
val text = obj["text"]?.jsonPrimitive?.content
val t0 = obj["t0"]?.jsonPrimitive?.long // milliseconds
val t1 = obj["t1"]?.jsonPrimitive?.long
val turn = obj["speaker_turn_next"]?.jsonPrimitive?.boolean
println("[$t0–$t1 ms] $text (turn=$turn)")
}Translation example#
val json = WhisperBridge.transcribeWavSegments(
wavPath = "/path/to/german_audio.wav",
translate = true, // segment text will be English regardless of spoken language
)Diarization example#
// Use a tinydiarize model: e.g. ggml-small.en-tdrz.bin
WhisperBridge.initModel(WhisperBridge.getModelPath("ggml-small.en-tdrz.bin"))
val json = WhisperBridge.transcribeWavSegments(
wavPath = "/path/to/two_speakers.wav",
diarize = true,
)Supported input expectations#
The bridge API is WAV-oriented, so the simplest and most reliable flow is:
- record or load audio
- convert it to WAV if necessary (16 kHz, mono, 16-bit PCM recommended)
- call
transcribeWav(...)ortranscribeWavSegments(...)
If your app records audio in another format, perform a conversion step before calling the bridge.
release()#
Releases native Whisper resources.
WhisperBridge.release()Practical recommendations#
- Keep audio clean and reasonably short when testing.
- Normalize your pipeline around WAV files for fewer surprises.
- Reuse the initialized model when transcribing multiple files.
- Use
transcribeWavwhen you only need the full transcript text. - Use
transcribeWavSegmentswhen you need timestamps, the detected language, or speaker turns. - Pass
diarize = trueonly with a-tdrzmodel — it has no effect (and no error) on regular models, butspeaker_turn_nextwill always befalse. - Release resources when leaving the speech feature or shutting the app down.