diff --git a/src/app/api/models/test/ping.js b/src/app/api/models/test/ping.js index 0e915af9..4d22e4f2 100644 --- a/src/app/api/models/test/ping.js +++ b/src/app/api/models/test/ping.js @@ -68,6 +68,35 @@ export async function pingModelByKind(model, kind, baseUrl = `http://127.0.0.1:$ return { ok: true, latencyMs, error: null, status: res.status }; } + if (kind === "stt") { + const form = new FormData(); + const sampleAudio = new File([new Uint8Array([82, 73, 70, 70, 36, 0, 0, 0, 87, 65, 86, 69, 102, 109, 116, 32, 16, 0, 0, 0, 1, 0, 1, 0, 64, 31, 0, 0, 128, 62, 0, 0, 2, 0, 16, 0, 100, 97, 116, 97, 0, 0, 0, 0])], "test.wav", { type: "audio/wav" }); + form.append("file", sampleAudio); + form.append("model", model); + + const res = await fetch(`${baseUrl}/api/v1/audio/transcriptions`, { + method: "POST", + headers: Object.fromEntries(Object.entries(headers).filter(([key]) => key.toLowerCase() !== "content-type")), + body: form, + signal: AbortSignal.timeout(15000), + }); + const latencyMs = Date.now() - start; + const rawText = await res.text().catch(() => ""); + let parsed = null; + try { parsed = rawText ? JSON.parse(rawText) : null; } catch {} + + if (!res.ok) { + const detail = parsed?.error?.message || parsed?.msg || parsed?.message || parsed?.error || rawText; + return { ok: false, latencyMs, error: `HTTP ${res.status}${detail ? `: ${String(detail).slice(0, 240)}` : ""}`, status: res.status }; + } + + const text = typeof parsed?.text === "string" ? parsed.text : ""; + if (!text.trim()) { + return { ok: false, latencyMs, status: res.status, error: "Provider returned no transcription text for this model" }; + } + return { ok: true, latencyMs, error: null, status: res.status }; + } + const res = await fetch(`${baseUrl}/api/v1/chat/completions`, { method: "POST", headers, diff --git a/tests/unit/model-test-routing.test.js b/tests/unit/model-test-routing.test.js index b655fe56..20c87eba 100644 --- a/tests/unit/model-test-routing.test.js +++ b/tests/unit/model-test-routing.test.js @@ -71,4 +71,36 @@ describe("model test route kind routing", () => { }) ); }); + + it("routes stt model tests to /api/v1/audio/transcriptions", async () => { + global.fetch = vi.fn().mockResolvedValue(new Response(JSON.stringify({ + text: "test", + }), { + status: 200, + headers: { "Content-Type": "application/json" }, + })); + + const { POST } = await import("../../src/app/api/models/test/route.js"); + + const req = new Request("http://localhost/api/models/test", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + model: "hf/openai/whisper-small", + kind: "stt", + }), + }); + + const res = await POST(req); + const body = await res.json(); + + expect(body.ok).toBe(true); + expect(global.fetch).toHaveBeenCalledWith( + expect.stringContaining("/api/v1/audio/transcriptions"), + expect.objectContaining({ + method: "POST", + body: expect.any(FormData), + }) + ); + }); });