extract shared whisper transcribe helper, use in file-browser and pi stt routes

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-11 13:17:15 +00:00
co-authored by Claude Opus 4.8
parent e0bfc3d961
commit d723fcb23e
3 changed files with 105 additions and 50 deletions
+8 -35
View File
@@ -7,6 +7,7 @@ import * as errors from '@@/custom-errors';
import { readTtsConfig } from '@@/api/server-settings/tts';
import { readSttConfig } from '@@/api/server-settings/stt';
import { readOcrConfig } from '@@/api/server-settings/ocr';
import { transcribeAudio } from '@@/api/stt/transcribe';
import { getUserSettings } from 'officerdb';
async function getUserTtsVoice(userId: number): Promise<string | null> {
@@ -794,45 +795,17 @@ router.post('/transcribe', async (ctx) => {
const whisperUrl = sttConfig?.url;
if (!whisperUrl) throw errors.BAD_REQUEST('Whisper not configured — set it up in Settings → Speech to Text');
const audioFile = Bun.file(absPath);
// Step 1: Detect language
const detectForm = new FormData();
detectForm.append('file', audioFile);
detectForm.append('temperature', '0.0');
detectForm.append('response_format', 'verbose_json');
detectForm.append('detect_language', 'true');
const detectRes = await fetch(`${whisperUrl}/inference`, { method: 'POST', body: detectForm });
if (!detectRes.ok) throw errors.BAD_REQUEST('Language detection failed');
const detectJson = (await detectRes.json()) as { language?: string };
const detectedLang = detectJson.language ?? 'en';
// Step 2: Check user's spoken languages to decide if translation is needed
let shouldTranslate = false;
const settings = await getUserSettings(user.id);
const spokenLanguages = (settings.languages as { spoken?: string[] })?.spoken ?? [];
if (spokenLanguages.length > 0 && !spokenLanguages.includes(detectedLang)) {
shouldTranslate = true;
let text: string;
try {
const result = await transcribeAudio({ file: Bun.file(absPath), whisperUrl, spokenLanguages });
text = result.text;
} catch (err) {
throw errors.BAD_REQUEST(err instanceof Error ? err.message : 'Transcription failed');
}
// Step 3: Full transcription
const transcribeForm = new FormData();
transcribeForm.append('file', audioFile);
transcribeForm.append('temperature', '0.0');
transcribeForm.append('temperature_inc', '0.2');
transcribeForm.append('response_format', 'text');
transcribeForm.append('language', detectedLang);
if (shouldTranslate) {
transcribeForm.append('translate', 'true');
}
const res = await fetch(`${whisperUrl}/inference`, { method: 'POST', body: transcribeForm });
if (!res.ok) throw errors.BAD_REQUEST('Transcription request failed');
const text = (await res.text()).trim();
await mkdir(dirname(cacheAbs), { recursive: true });
await Bun.write(cacheAbs, text);