always transcribe in the source language, and let tasks call the API

Three changes that Transcribe Audio needs.

Whisper's translate mode only ever outputs English, so it cannot honour
"translate into <language>" for anything else — it answered Portuguese audio with
a rough English rendering instead of a transcript. The translate decision is gone
and transcription is always faithful to the detected language; spokenLanguages
now only breaks ties on clips Whisper is unsure about.

Script tasks get OFFICER_API_URL / OFFICER_API_HOST / OFFICER_AUTH_TOKEN so they
can call Officer's own endpoints rather than reimplementing server-side work.
Requests go to 127.0.0.1 so nothing depends on DNS or the proxy, but origin
validation matches Host against PUBLIC_URL, hence the separate host variable.

`inline` accepts "ask", which offers both affordances in the runner — Run here
streams into the modal, Run as job queues it. Useful when the same task can take
a second or an hour depending on whether it was pointed at a file or a library.
Existing true/false values behave exactly as before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
brunorezio
2026-07-26 03:03:49 +01:00
co-authored by Claude Opus 5
parent 5f7d574dec
commit 06aac5478f
7 changed files with 82 additions and 40 deletions
+8 -15
View File
@@ -1,13 +1,11 @@
// Whisper transcription with language-aware translation.
// Whisper transcription, always in the audio's own language.
//
// Strategy: detect the audio's language, then transcribe in that language.
// Only ask Whisper to translate (which is English-only) when the detected
// language is NOT one the user speaks — i.e. they wouldn't understand the
// raw transcript anyway.
// Detect the language first, then transcribe in it. Whisper's translate mode is English-only, so it
// cannot honour "translate into <language>" for anything else — rather than silently returning a
// rough English rendering of Portuguese audio, transcription is always faithful to the source.
//
// The detection must win when Whisper is confident. Biasing toward the user's spoken languages
// unconditionally means a user who speaks only English forces `language=en` onto every recording,
// and Whisper answers non-English audio with a rough, unmarked translation instead of a transcript.
// The detection must win when Whisper is confident. `spokenLanguages` only breaks ties on clips
// Whisper is genuinely unsure about, where its low-confidence guess defaults to English.
type TranscribeArgs = {
file: File | Blob;
@@ -18,7 +16,6 @@ type TranscribeArgs = {
export type TranscribeResult = {
text: string;
detectedLanguage: string;
translated: boolean;
};
// Above this probability Whisper's own detection is taken as authoritative. Below it the clip is
@@ -88,21 +85,17 @@ export async function transcribeAudio({
detectedLanguage = LANG_NAME_TO_ISO[raw] ?? raw;
}
// Step 2: translate only when the user doesn't speak the detected language
const translated = spokenLanguages.length > 0 && !spokenLanguages.includes(detectedLanguage);
// Step 3: full transcription
// Step 2: transcribe in the detected language
const transcribeForm = new FormData();
transcribeForm.append('file', file);
transcribeForm.append('temperature', '0.0');
transcribeForm.append('temperature_inc', '0.2');
transcribeForm.append('response_format', 'text');
transcribeForm.append('language', detectedLanguage);
if (translated) transcribeForm.append('translate', 'true');
const res = await fetch(`${base}/inference`, { method: 'POST', body: transcribeForm });
if (!res.ok) throw new Error(`Transcription failed (${res.status})`);
const text = (await res.text()).trim();
return { text, detectedLanguage, translated };
return { text, detectedLanguage };
}