Files
IPSExtractor/services/desktop_app/src/renderer/lib/apiClient.ts
T

112 lines
3.6 KiB
TypeScript

import type { ExtractionBatch, RowsResponse, SchemaResponse, Task } from "../../shared/types";
export class ApiClient {
constructor(private readonly baseUrl: string) {}
private url(path: string): string {
return `${this.baseUrl.replace(/\/+$/, "")}${path}`;
}
async getJson<T>(path: string): Promise<T> {
const response = await fetch(this.url(path));
return this.handle<T>(response);
}
async postJson<T>(path: string, body: unknown): Promise<T> {
const response = await fetch(this.url(path), {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
return this.handle<T>(response);
}
async postForm<T>(path: string, form: FormData): Promise<T> {
const response = await fetch(this.url(path), {
method: "POST",
body: form,
});
return this.handle<T>(response);
}
async health(): Promise<unknown> {
return this.getJson("/health");
}
async config(): Promise<unknown> {
return this.getJson("/config");
}
async models(): Promise<unknown> {
return this.getJson("/models");
}
async discoverSchema(payload: Record<string, unknown>): Promise<SchemaResponse> {
return this.postJson<SchemaResponse>("/extraction/schemas", payload);
}
async discoverSchemaUpload(form: FormData): Promise<SchemaResponse> {
return this.postForm<SchemaResponse>("/extraction/schemas/upload", form);
}
async estimate(payload: Record<string, unknown>): Promise<unknown> {
return this.postJson("/extraction/estimate", payload);
}
async estimateUpload(form: FormData): Promise<unknown> {
return this.postForm("/extraction/estimate/upload", form);
}
async createBatch(payload: Record<string, unknown>): Promise<ExtractionBatch> {
return this.postJson<ExtractionBatch>("/extraction/batches", payload);
}
async createExtractionTask(payload: Record<string, unknown>): Promise<Task> {
return this.postJson<Task>("/tasks/extraction", payload);
}
async ingestTaskDocument(taskId: string, form: FormData): Promise<Record<string, unknown>> {
return this.postForm<Record<string, unknown>>(`/tasks/${encodeURIComponent(taskId)}/ingest`, form);
}
async ingestTaskDocumentsBulk(taskId: string, form: FormData): Promise<Record<string, unknown>> {
return this.postForm<Record<string, unknown>>(`/tasks/${encodeURIComponent(taskId)}/ingest-many`, form);
}
async tasks(type = "extraction"): Promise<Task[]> {
return this.getJson<Task[]>(`/tasks?type=${encodeURIComponent(type)}`);
}
async task(taskId: string): Promise<Task> {
return this.getJson<Task>(`/tasks/${encodeURIComponent(taskId)}`);
}
async taskRows(taskId: string, limit = 500, offset = 0): Promise<RowsResponse> {
return this.getJson<RowsResponse>(`/tasks/${encodeURIComponent(taskId)}/rows?limit=${limit}&offset=${offset}`);
}
async rows(batchId: string, limit = 500, offset = 0): Promise<RowsResponse> {
return this.getJson<RowsResponse>(`/extraction/batches/${encodeURIComponent(batchId)}/rows?limit=${limit}&offset=${offset}`);
}
private async handle<T>(response: Response): Promise<T> {
const text = await response.text();
let data: unknown = null;
if (text) {
try {
data = JSON.parse(text);
} catch {
data = null;
}
}
if (!response.ok) {
const detail =
typeof (data as { detail?: unknown } | null)?.detail === "string"
? (data as { detail: string }).detail
: text || response.statusText;
throw new Error(detail || `HTTP ${response.status}`);
}
return data as T;
}
}