const API_BASE = process.env.NEXT_PUBLIC_API_BASE ?? "http://localhost:4291" export type JobStatus = | "created" | "downloading" | "downloaded" | "splitting" | "frames_extracted" | "transcribing" | "transcribed" | "failed" export interface KeyFrame { index: number timestamp: number url: string } export interface TranscriptSegment { index: number start: number end: number en: string zh: string } export interface Job { id: string url: string status: JobStatus progress: number message?: string video_url?: string duration?: number width?: number height?: number frames: KeyFrame[] transcript: TranscriptSegment[] error?: string } export async function createJob(tkUrl: string): Promise { const res = await fetch(`${API_BASE}/jobs`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ url: tkUrl }), }) if (!res.ok) throw new Error(`createJob ${res.status}`) return res.json() } export async function uploadJob(file: File): Promise { const fd = new FormData() fd.append("file", file) const res = await fetch(`${API_BASE}/jobs/upload`, { method: "POST", body: fd, }) if (!res.ok) { const text = await res.text().catch(() => "") throw new Error(`uploadJob ${res.status} ${text.slice(0, 200)}`) } return res.json() } export async function getJob(id: string): Promise { const res = await fetch(`${API_BASE}/jobs/${id}`) if (!res.ok) throw new Error(`getJob ${res.status}`) return res.json() } export async function triggerTranscribe(id: string): Promise { const res = await fetch(`${API_BASE}/jobs/${id}/transcribe`, { method: "POST" }) if (!res.ok) throw new Error(`transcribe ${res.status}`) return res.json() } export async function analyzeJob(id: string, frames = 5): Promise { const res = await fetch(`${API_BASE}/jobs/${id}/analyze?frames=${frames}`, { method: "POST" }) if (!res.ok) { const t = await res.text().catch(() => "") throw new Error(`analyze ${res.status} ${t.slice(0, 200)}`) } return res.json() } export async function addManualFrame(id: string, t: number): Promise { const res = await fetch(`${API_BASE}/jobs/${id}/frames?t=${encodeURIComponent(t.toFixed(2))}`, { method: "POST" }) if (!res.ok) { const txt = await res.text().catch(() => "") throw new Error(`addFrame ${res.status} ${txt.slice(0, 200)}`) } return res.json() } export function frameUrl(jobId: string, frameIndex: number): string { return `${API_BASE}/jobs/${jobId}/frames/${frameIndex}.jpg` } export function videoUrl(jobId: string): string { return `${API_BASE}/jobs/${jobId}/video.mp4` }