142 lines
6.2 KiB
TypeScript
142 lines
6.2 KiB
TypeScript
export const API_URL = process.env.NEXT_PUBLIC_API_URL ?? "http://127.0.0.1:8000";
|
|
|
|
export type Subject = { id: number; name: string; slug: string; created_at: string };
|
|
export type Week = { id: number; subject_id: number; number: number; title?: string | null; created_at: string };
|
|
export type Source = {
|
|
id: number;
|
|
week_id: number;
|
|
original_name: string;
|
|
stored_path: string;
|
|
source_type: string;
|
|
status: string;
|
|
file_size?: number | null;
|
|
sha256?: string | null;
|
|
mime_type?: string | null;
|
|
processor?: string | null;
|
|
page_ranges?: string | null;
|
|
processed_at?: string | null;
|
|
document_id?: number | null;
|
|
document_title?: string | null;
|
|
document_markdown_path?: string | null;
|
|
document_created_at?: string | null;
|
|
created_at: string;
|
|
};
|
|
export type Job = { id: number; status: string; message: string; source_id?: number | null; document_id?: number | null; created_at: string; updated_at: string };
|
|
export type DocumentItem = {
|
|
id: number;
|
|
source_id: number;
|
|
title: string;
|
|
markdown_path: string;
|
|
source_original_name?: string | null;
|
|
source_type?: string | null;
|
|
source_status?: string | null;
|
|
source_processor?: string | null;
|
|
source_page_ranges?: string | null;
|
|
created_at: string;
|
|
};
|
|
export type SettingsStatus = { mistral_configured: boolean; deepgram_configured: boolean; data_dir: string; database_path: string };
|
|
|
|
async function parseResponse<T>(response: Response): Promise<T> {
|
|
if (!response.ok) {
|
|
const detail = await response.json().catch(() => null);
|
|
throw new Error(detail?.detail || `Error ${response.status}`);
|
|
}
|
|
return response.json() as Promise<T>;
|
|
}
|
|
|
|
export const api = {
|
|
async health() {
|
|
return parseResponse<{ status: string }>(await fetch(`${API_URL}/health`, { cache: "no-store" }));
|
|
},
|
|
async settings() {
|
|
return parseResponse<SettingsStatus>(await fetch(`${API_URL}/settings/status`, { cache: "no-store" }));
|
|
},
|
|
async subjects() {
|
|
return parseResponse<Subject[]>(await fetch(`${API_URL}/subjects`, { cache: "no-store" }));
|
|
},
|
|
async subject(id: number) {
|
|
return parseResponse<Subject>(await fetch(`${API_URL}/subjects/${id}`, { cache: "no-store" }));
|
|
},
|
|
async createSubject(name: string) {
|
|
return parseResponse<Subject>(await fetch(`${API_URL}/subjects`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ name }),
|
|
}));
|
|
},
|
|
async weeks(subjectId: number) {
|
|
return parseResponse<Week[]>(await fetch(`${API_URL}/subjects/${subjectId}/weeks`, { cache: "no-store" }));
|
|
},
|
|
async week(subjectId: number, weekNumber: number) {
|
|
return parseResponse<Week>(await fetch(`${API_URL}/subjects/${subjectId}/weeks/${weekNumber}`, { cache: "no-store" }));
|
|
},
|
|
async createWeek(subjectId: number, number: number, title: string) {
|
|
return parseResponse<Week>(await fetch(`${API_URL}/subjects/${subjectId}/weeks`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ number, title: title || null }),
|
|
}));
|
|
},
|
|
async updateWeek(subjectId: number, currentNumber: number, number: number, title: string) {
|
|
return parseResponse<Week>(await fetch(`${API_URL}/subjects/${subjectId}/weeks/${currentNumber}`, {
|
|
method: "PUT",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ number, title: title || null }),
|
|
}));
|
|
},
|
|
async sources(subjectId: number, weekNumber: number) {
|
|
return parseResponse<Source[]>(await fetch(`${API_URL}/subjects/${subjectId}/weeks/${weekNumber}/sources`, { cache: "no-store" }));
|
|
},
|
|
async jobs(subjectId: number, weekNumber: number) {
|
|
return parseResponse<Job[]>(await fetch(`${API_URL}/subjects/${subjectId}/weeks/${weekNumber}/jobs`, { cache: "no-store" }));
|
|
},
|
|
async documents(subjectId: number, weekNumber: number) {
|
|
return parseResponse<DocumentItem[]>(await fetch(`${API_URL}/subjects/${subjectId}/weeks/${weekNumber}/documents`, { cache: "no-store" }));
|
|
},
|
|
async deleteSource(sourceId: number) {
|
|
return parseResponse<{ status: string }>(await fetch(`${API_URL}/sources/${sourceId}`, { method: "DELETE" }));
|
|
},
|
|
async deleteDocument(documentId: number) {
|
|
return parseResponse<{ status: string }>(await fetch(`${API_URL}/documents/${documentId}`, { method: "DELETE" }));
|
|
},
|
|
async reprocessSource(sourceId: number, useOcr: boolean, pageRanges?: string) {
|
|
const params = new URLSearchParams({ use_ocr: String(useOcr) });
|
|
if (pageRanges?.trim()) params.set("page_ranges", pageRanges.trim());
|
|
return parseResponse<{ source: Source; job: Job }>(await fetch(`${API_URL}/sources/${sourceId}/reprocess?${params.toString()}`, { method: "POST" }));
|
|
},
|
|
async upload(subjectId: number, weekNumber: number, file: File, useOcr: boolean, pageRanges?: string) {
|
|
const form = new FormData();
|
|
form.append("file", file);
|
|
const params = new URLSearchParams({ use_ocr: String(useOcr) });
|
|
if (pageRanges?.trim()) params.set("page_ranges", pageRanges.trim());
|
|
return parseResponse<{ source: Source; job: Job }>(await fetch(`${API_URL}/subjects/${subjectId}/weeks/${weekNumber}/files?${params.toString()}`, {
|
|
method: "POST",
|
|
body: form,
|
|
}));
|
|
},
|
|
async markdown(documentId: number) {
|
|
const response = await fetch(`${API_URL}/documents/${documentId}/markdown`, { cache: "no-store" });
|
|
if (!response.ok) throw new Error(`Error ${response.status}`);
|
|
return response.text();
|
|
},
|
|
async document(documentId: number) {
|
|
return parseResponse<DocumentItem>(await fetch(`${API_URL}/documents/${documentId}`, { cache: "no-store" }));
|
|
},
|
|
async saveMarkdown(documentId: number, content: string) {
|
|
return parseResponse<DocumentItem>(await fetch(`${API_URL}/documents/${documentId}/markdown`, {
|
|
method: "PUT",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ content }),
|
|
}));
|
|
},
|
|
downloadDocumentUrl(documentId: number) {
|
|
return `${API_URL}/documents/${documentId}/download`;
|
|
},
|
|
exportWeekUrl(subjectId: number, weekNumber: number) {
|
|
return `${API_URL}/subjects/${subjectId}/weeks/${weekNumber}/export`;
|
|
},
|
|
exportWeekZipUrl(subjectId: number, weekNumber: number) {
|
|
return `${API_URL}/subjects/${subjectId}/weeks/${weekNumber}/export.zip`;
|
|
},
|
|
};
|