ADFA-5404 | Recover from missing offline language packs - #95
Conversation
…A-5404) Recognize in the host's configured locale, and on error 12/13 retry once with an installed pack for the same language or online while fetching the missing pack, instead of failing the capture with "unknown error 12".
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.
Tip: disable this comment in your organization's Code Review settings.
|
I posted on Slack about strings.xml review |
| // One capture at a time: a second recognizer would race the first for the microphone | ||
| // and for the transcript. A capture stuck past the LLM timeout is treated as over. | ||
| val elapsed = System.currentTimeMillis() - captureStartedAt | ||
| if (recordingState != RecordingState.IDLE && elapsed < STALE_CAPTURE_MS) { |
There was a problem hiding this comment.
F28 (High) — the busy guard expires 42 s before the generation it guards.
STALE_CAPTURE_MS is 90_000 (line 1008), but GENERATION_TIMEOUT_SECONDS is MAX_GENERATION_TOKENS / SLOWEST_TOKENS_PER_SECOND + PROMPT_EVAL_SECONDS = 512 / 5 + 30 = 132 s (lines 989-990). The comment above this line — "A capture stuck past the LLM timeout is treated as over" — is false for every generation that runs between 90 s and 132 s, which is exactly the slow on-device case the timeout was sized for.
On a slow backend:
- t=5 s — recording ends, state is PROCESSING, the backend is still decoding.
- t=90 s — the user taps the mic.
elapsed >= STALE_CAPTURE_MS, so the guard falls through and a second capture starts RECORDING. - t≈137 s — generation chore: bump plugins to Kotlin 2.3.0 and migrate to compilerOptions DSL #1 completes and its
withContext(Dispatchers.Main)block runs. It inserts chore: bump plugins to Kotlin 2.3.0 and migrate to compilerOptions DSL #1's output at the cursor in the middle of the second dictation, thensetState(RecordingState.IDLE)reverts the icon to the mic while feat/ADFA-3603 ndk plugin #2 is still recording — and re-opens the guard for a third concurrent capture.
Derive the constant so the two cannot drift. Both operands are already const, so this stays a compile-time constant:
private const val STALE_CAPTURE_MS =
GENERATION_TIMEOUT_SECONDS * MILLIS_PER_SECOND + STALE_CAPTURE_HEADROOM_MS| val locale = activeLocale | ||
| val requested = languageLabel() | ||
|
|
||
| val installed = usableTag(support.installedOnDeviceLanguages, locale) |
There was a problem hiding this comment.
F30 (Medium) — the installed-pack branch can retry the exact locale that just failed.
usableTag tries an exact match first (line 633), so when the recognizer lists the requested tag in installedOnDeviceLanguages, installed is the tag that just returned ERROR_LANGUAGE_UNAVAILABLE / ERROR_LANGUAGE_NOT_SUPPORTED. restartRecognition(preferOffline = true, locale = fallback) then re-issues the identical request.
A device that reports en-US installed but still errors 13 — a partly-installed or corrupt pack, the common cause of this bug class — fails the retry the same way. languageFallbackSpent is now true, so the capture ends and the online retry that would have worked is never reached.
The toast contradicts itself too: "No offline pack for English (United States) (en-US), so English (United States) is being used instead".
Exclude the failing tag from the installed match. An exact hit then falls through to retryOnline(), while a different-region pack (en-GB for a failed en-US) still short-circuits — that second case is the one this branch is actually for.
Description
Replaces the generic "unknown error 12" with clear, actionable UI messages that display the specific missing Locale. Implements an automatic single online retry when an offline language pack is missing, ensuring the user's dictation session stays alive without being prematurely aborted.
Details
ERROR_LANGUAGE_UNAVAILABLEandERROR_LANGUAGE_NOT_SUPPORTEDinSpeechToTextPlugin.kt.preferOfflineand setEXTRA_LANGUAGEto support a single online retry attempt.strings.xmlto inform the user of the exact failing language and the fallback network attempt.index.htmldocumentation to reflect the new language pack recovery behavior.Prompt EN:
Function that reverses a stringPrompt ES:
Función que reversa un stringdocument_4976756881377724759.mp4
Ticket
ADFA-5404
Parent: ADFA-5402
Observation
The plugin now queries
checkRecognitionSupporton API 33+ devices to find regional fallback packs or trigger downloads, defaulting to a direct network retry on older SDKs.