Spaces:
Sleeping
Sleeping
File size: 4,540 Bytes
a3953cb | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | export const API_BASE = import.meta.env.VITE_API_BASE ?? "http://localhost:8000";
// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------
export interface StepSummary {
step_number: number;
status: "pending" | "processing" | "completed" | "failed";
original_image_url: string | null;
result_image_url: string | null;
error_message: string | null;
}
// ---------------------------------------------------------------------------
// Upload
// ---------------------------------------------------------------------------
/**
* Upload an image file to the backend.
* POSTs as multipart/form-data; backend applies EXIF rotation, saves step 0,
* and returns the job_id.
*/
export async function uploadImage(file: File): Promise<{ job_id: string }> {
const formData = new FormData();
formData.append("file", file);
const response = await fetch(`${API_BASE}/upload`, {
method: "POST",
body: formData,
});
if (!response.ok) {
let detail = `HTTP ${response.status}`;
try {
const json = await response.json();
if (json?.detail) detail = json.detail;
} catch { /* ignore */ }
throw new Error(detail);
}
return response.json() as Promise<{ job_id: string }>;
}
// ---------------------------------------------------------------------------
// Generate
// ---------------------------------------------------------------------------
/**
* POST /generate — send the mask JSON to the backend and start inpainting.
*
* The backend creates a new step (truncating any forward history if needed),
* starts inference in a BackgroundTask, and returns immediately.
*/
export async function generateMask(
jobId: string,
maskJson: object,
maskSource: "manual" | "ocr" | "mixed" = "manual",
): Promise<{ job_id: string; step_number: number; status: string }> {
const response = await fetch(`${API_BASE}/generate`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
job_id: jobId,
mask_source: maskSource,
mask_json: maskJson,
}),
});
if (!response.ok) {
let detail = `HTTP ${response.status}`;
try {
const json = await response.json();
if (json?.detail) detail = json.detail;
} catch { /* ignore */ }
throw new Error(detail);
}
return response.json() as Promise<{ job_id: string; step_number: number; status: string }>;
}
// ---------------------------------------------------------------------------
// Result polling
// ---------------------------------------------------------------------------
/**
* GET /result/{job_id} — poll current job state.
*
* Returns top-level `status` / `error_message` for the current step
* (backward-compatible with the polling hook), plus the full `steps[]` array
* and `current_step` for the multi-step history navigator.
*/
export async function getJobResult(jobId: string): Promise<{
job_id: string;
current_step: number;
status: "pending" | "processing" | "completed" | "failed";
result_image_url: string | null;
original_image_url: string | null;
error_message: string | null;
steps: StepSummary[];
}> {
const response = await fetch(`${API_BASE}/result/${jobId}`);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
}
// ---------------------------------------------------------------------------
// Step navigation
// ---------------------------------------------------------------------------
/**
* POST /jobs/{job_id}/goto-step — set job.current_step to stepNumber.
*
* Only completed steps may be navigated to. Truncation of forward history
* happens lazily on the next POST /generate call.
*/
export async function goToStep(
jobId: string,
stepNumber: number,
): Promise<{ job_id: string; current_step: number }> {
const response = await fetch(`${API_BASE}/jobs/${jobId}/goto-step`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ step_number: stepNumber }),
});
if (!response.ok) {
let detail = `HTTP ${response.status}`;
try {
const json = await response.json();
if (json?.detail) detail = json.detail;
} catch { /* ignore */ }
throw new Error(detail);
}
return response.json() as Promise<{ job_id: string; current_step: number }>;
}
|