feat(import): optional transcription job
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0e090a0e15
commit
7c3f613feb
2 files changed
+139
No files matched your search
@@ -0,0 +1,57 @@
|
||||
import { afterAll, expect, test } from "bun:test";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { importPacktVideo } from "../src/jobs/packt-video";
|
||||
import { segmentsToMarkdown, transcribeCourse } from "../src/jobs/transcribe";
|
||||
import { makeEnv } from "./harness";
|
||||
import { makePacktZip, tmp } from "./fixtures";
|
||||
|
||||
let calls = 0;
|
||||
let auth: string | null = null;
|
||||
const server = Bun.serve({
|
||||
port: 0,
|
||||
async fetch(req) {
|
||||
calls++;
|
||||
auth = req.headers.get("authorization");
|
||||
const form = await req.formData();
|
||||
const f = form.get("file") as File;
|
||||
if (!f || f.size < 100 || form.get("model") !== "whisper-1") return new Response("bad", { status: 400 });
|
||||
return Response.json({ text: "hello world", segments: [{ start: 0, end: 2, text: " hello" }, { start: 35, end: 40, text: " world" }] });
|
||||
},
|
||||
});
|
||||
afterAll(() => server.stop(true));
|
||||
|
||||
test("segments are grouped into timestamped paragraphs", () => {
|
||||
expect(segmentsToMarkdown("T", [{ start: 0, end: 1, text: "a" }, { start: 31, end: 32, text: "b" }, { start: 33, end: 34, text: "c" }], "")).toBe("# T\n\n[0:00] a\n\n[0:31] b c\n");
|
||||
});
|
||||
|
||||
test("skipped when STC_TRANSCRIBE_URL is unset", async () => {
|
||||
const env = await makeEnv();
|
||||
const r = await transcribeCourse(env.deps, { courseId: "x" }, env.jc);
|
||||
expect(r).toMatchObject({ skipped: true, transcribed: 0 });
|
||||
});
|
||||
|
||||
test("transcribes video lessons through a Whisper-compatible endpoint", async () => {
|
||||
const env = await makeEnv({ STC_TRANSCRIBE_URL: `http://127.0.0.1:${server.port}/v1/audio/transcriptions`, STC_TRANSCRIBE_KEY: "k" });
|
||||
const imp = await importPacktVideo(env.deps, { path: await makePacktZip(await tmp()), options: {} }, env.jc);
|
||||
const r = await transcribeCourse(env.deps, { courseId: imp.courseId }, env.jc);
|
||||
expect(r.warnings).toEqual([]);
|
||||
expect(r.transcribed).toBe(3);
|
||||
expect(calls).toBe(3);
|
||||
expect(auth).toBe("Bearer k");
|
||||
const c = env.deps.ctx.courses.get(imp.courseId)!;
|
||||
expect(c.status).toBe("ok");
|
||||
expect(c.manifest!.modules[0]!.lessons[0]!.transcript).toBe("transcripts/m1-l1.md");
|
||||
expect(await env.deps.ctx.courses.readLessonMarkdown(imp.courseId, "m1-l1")).toContain("[0:35] world");
|
||||
expect(JSON.parse(await readFile(join(env.dataDir, "cache/transcripts", imp.courseId, "m1-l1.json"), "utf8")).text).toBe("hello world");
|
||||
// a second run has nothing left to do
|
||||
expect((await transcribeCourse(env.deps, { courseId: imp.courseId }, env.jc)).transcribed).toBe(0);
|
||||
});
|
||||
|
||||
test("an endpoint failure becomes a warning, not a failed job", async () => {
|
||||
const env = await makeEnv({ STC_TRANSCRIBE_URL: `http://127.0.0.1:1/x` });
|
||||
const imp = await importPacktVideo(env.deps, { path: await makePacktZip(await tmp()), options: {} }, env.jc);
|
||||
const r = await transcribeCourse(env.deps, { courseId: imp.courseId }, env.jc);
|
||||
expect(r.transcribed).toBe(0);
|
||||
expect(r.warnings).toHaveLength(3);
|
||||
});
|
||||
Reference in new issue
Block a user