From 3583d608472caddc602dbd3e22e58b98786fa920 Mon Sep 17 00:00:00 2001 From: Lucas Winther Date: Fri, 30 Oct 2026 14:33:08 +0100 Subject: [PATCH] Reject task=translate on the server for models that cannot translate (D-044) The UI already hid it; a direct API call to POST /api/transcribe or the live WebSocket could still get the source language back labelled as a translation. Co-Authored-By: Claude Opus 5.5 --- docs/WorkBreakdown.md | 5 +++-- src/index.ts | 10 +++++++++- src/server/transcribe.ts | 15 ++++++++++++++- tests/transcribe.test.ts | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 4 deletions(-) diff --git a/docs/WorkBreakdown.md b/docs/WorkBreakdown.md index b052419..b35325a 100644 --- a/docs/WorkBreakdown.md +++ b/docs/WorkBreakdown.md @@ -427,8 +427,9 @@ Found while building transcript translation (D-045), 2026-10-29: every row of a padded batch, so translation runs one sentence per call (~4× slower than batch 8 would be). Re-check after the 4.3 upgrade with `bun scripts/bench-translate.ts` ("output identical" across batch sizes). -- [ ] The server API still accepts `task: "translate"` with large-v3-turbo - (only the UI hides it, D-044). +- [x] The server API still accepts `task: "translate"` with large-v3-turbo + (only the UI hides it, D-044). — Fixed: `POST /api/transcribe` and the + live WebSocket answer 400 via `translateNotSupported` (src/server/transcribe.ts). Found in spec 001 workstream 6 (D-046), open: - [ ] Transformers.js 4.2 has no beam search: `num_beams > 1` in a model's diff --git a/src/index.ts b/src/index.ts index df44aa1..fd316d5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,7 +7,13 @@ import { ortAliasPlugin } from "../scripts/ortAlias.ts"; import { injectPrecacheManifest } from "./pwa/precache.ts"; import { auth } from "./server/auth.ts"; import { AUTH_ENABLED } from "./server/flags.ts"; -import { MAX_UPLOAD_BYTES, parseLanguageAndTask, sidecar, transcribe } from "./server/transcribe.ts"; +import { + MAX_UPLOAD_BYTES, + parseLanguageAndTask, + sidecar, + transcribe, + translateNotSupported, +} from "./server/transcribe.ts"; import { liveWebSocket } from "./server/live.ts"; import { getFasterWhisperModel } from "./lib/models.ts"; @@ -140,6 +146,8 @@ async function handleApiRequest(request: Request, server: any): Promise { } }); + test("400 for translate on a model not trained for it; translate still works where it is (D-044)", async () => { + const sidecar = fakeSidecar(); + const handlers = createTranscribeHandlers({ + sidecar, + getSessionUser: sessionFromCookie, + tempDir: await makeTempDir(), + }); + for (const model of [ + "onnx-community/whisper-large-v3-turbo", + "onnx-community/whisper-small.en", + ]) { + const response = await handlers.post( + postRequest(`?model=${model}&task=translate`, pcmBody([0.1]), { cookie: "sid=ok" }), + ); + expect(response.status).toBe(400); + expect(await response.text()).toContain("cannot translate"); + } + expect(sidecar.requests).toHaveLength(0); + + const ok = await handlers.post( + postRequest("?model=onnx-community/whisper-small&task=translate", pcmBody([0.1]), { + cookie: "sid=ok", + }), + ); + expect(ok.status).toBe(200); + }); + + test("translateNotSupported: the shared check for the HTTP and live routes", () => { + expect(translateNotSupported("onnx-community/whisper-large-v3-turbo", "translate")).toContain( + "cannot translate", + ); + expect(translateNotSupported("onnx-community/whisper-large-v3-turbo", "transcribe")).toBeUndefined(); + expect(translateNotSupported("onnx-community/whisper-small", "translate")).toBeUndefined(); + }); + test("503 with the reason when the sidecar is unavailable", async () => { const sidecar = fakeSidecar({ available: false, reason: "faster-whisper is not installed" }); const handlers = createTranscribeHandlers({