flutter_gemma_speech library
On-device speech-to-text and text-to-speech for flutter_gemma, via the
LiteRT C API + dart:ffi.
Opt-in. Add to pubspec.yaml and pass instances to
FlutterGemma.initialize(sttBackends: [LiteRtSttBackend()], ttsBackends: [LiteRtTtsBackend()]).
import 'package:flutter_gemma/flutter_gemma.dart';
import 'package:flutter_gemma_speech/flutter_gemma_speech.dart';
await FlutterGemma.initialize(
sttBackends: [LiteRtSttBackend()],
ttsBackends: [LiteRtTtsBackend()],
);
Classes
- LiteRtSttBackend
-
Web stub for LiteRtSttBackend — the STT web arm is a follow-on (see the
design spec's "Out of scope"). Registers cleanly so
initializedoesn't break on web, but building a model throws. - LiteRtTtsBackend
-
Web stub for LiteRtTtsBackend —
flutter_gemma_speechhas no web TTS arm (native-only). Registers cleanly soinitializedoesn't break on web, but building a model throws. - VoiceErrorEvent
- Non-fatal, per-turn error. RESERVED in v1 (never emitted): fatal errors in runTurn surface as Dart stream errors. Exists so future full-duplex mode can report a per-turn failure without tearing down the stream (§4.1 E1).
- VoiceEvent
- One event in a voice turn. Sealed — the vocabulary is designed to cover the streaming/barge-in endgame; later phases emit MORE of these events, never new subtypes. (Design spec §4.1.)
- VoiceReplyAudioEvent
- Synthesized reply audio: 16-bit LE mono PCM at sampleRate.
- VoiceReplyTextEvent
- A chunk of the LLM's streamed text reply (token granularity in v1).
- VoiceResponder
- The LLM step of a voice turn: stream the reply's tokens for a user utterance, plus a portable stop for barge-in. Injecting this (not a concrete type) keeps VoiceSession engine-agnostic and usable with a chat, an agent, or a custom (remote / one-shot) responder. (Design spec §4.2.)
- VoiceSession
-
On-device voice turn: PCM in → VoiceEvents out. Pure orchestration — owns
NO microphone, NO player, and none of the injected components' lifecycles
(the caller creates + closes recognizer / chat / synthesizer). See the
design spec (
2026-07-29-voice-loop-design.md) for the full contract. - VoiceTranscriptEvent
- Recognized user speech. v1 emits exactly one with isFinal = true.
- VoiceTurnCompleteEvent
- Terminal in v1: the turn finished normally.
- VoiceTurnInterruptedEvent
-
Terminal: the turn was cut short by VoiceSession.interrupt (barge-in).
Carries what was produced so the caller can reconcile app state and (for
fromChat) chat history from the caller-owned
chat.fullHistory— there is deliberately nohistoryRecordedflag (§12 B2).
Constants
-
languageIds
→ const Map<
String, int> -
Language id map from the model config (
talker_config.codec_language_id). Ported fromtext_to_speech_lm/python/qwen3_tts_pipeline.py LANGUAGE_IDS.
Properties
-
qwen3SupportedLanguages
→ List<
String> -
The full set of
languagevalues Qwen3-TTS accepts: languageIds's keys (alphabetical) plus'auto'(automatic language detection — no language-id control token is emitted; seeQwen3Prompt.build's'auto'branch).'auto'is appended last since it isn't a language, it's a detection mode.final
Functions
-
assertQwen3LanguageSupported(
String language) → void -
Throws ArgumentError if
language(case-insensitive) is not in qwen3SupportedLanguages. Factored out as a standalone pure function (rather than inlined at the call site) so it is unit-testable without spawning aTtsWorker— which needs the ~1.9 GB Qwen3-TTS model bundle on disk to construct at all. -
normalizeQwen3Language(
String language) → String -
Canonicalizes an already-assertQwen3LanguageSupported-validated
languageto the lowercase form every downstream consumer expects.