Spaces:
Sleeping
Sleeping
File size: 3,341 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 | /**
* upscaleClient.ts — API client for the Quality Enhance (upscaler) feature.
*
* Completely independent of client.ts and the watermark-removal pipeline.
* Do not import from client.ts or share state with watermark-removal hooks.
*
* URL note
* --------
* The backend stores result paths relative to STORAGE_DIR (e.g. "/upscale/{id}/result.jpg").
* The FastAPI StaticFiles mount is at /storage, so the full URL is:
* http://localhost:8000/storage/upscale/{id}/result.jpg
* Use buildUpscaleUrl() to convert a stored relative path to a usable URL.
*/
export const UPSCALE_API_BASE = import.meta.env.VITE_API_BASE ?? "http://localhost:8000";
/**
* Convert a relative result path (e.g. "/upscale/{id}/result.jpg") to the
* full URL served by the FastAPI /storage StaticFiles mount.
*/
export function buildUpscaleUrl(relPath: string): string {
return `${UPSCALE_API_BASE}/storage${relPath}`;
}
// ---------------------------------------------------------------------------
// Upload
// ---------------------------------------------------------------------------
/**
* POST /upscale/upload — submit an image for upscaling.
*
* The backend applies EXIF correction, persists the image, and immediately
* kicks off background upscaling. Returns job_id; poll getUpscaleResult()
* to track progress.
*
* outputScale
* -----------
* "4x" (default) — save the raw Real-ESRGAN 4x output.
* "2x" — generate at 4x internally, then downscale 50% via LANCZOS
* before saving. Produces a more natural-looking result on
* organic textures (grass, foliage, skin) by smoothing the
* model's over-sharpened high-frequency detail.
*/
export async function uploadForUpscale(
file: File,
outputScale: "4x" | "2x" | "1.5x" = "4x",
denoise: boolean = false,
sharpen: boolean = false,
): Promise<{ job_id: string }> {
const formData = new FormData();
formData.append("file", file);
formData.append("output_scale", outputScale);
formData.append("denoise", String(denoise));
formData.append("sharpen", String(sharpen));
const response = await fetch(`${UPSCALE_API_BASE}/upscale/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 }>;
}
// ---------------------------------------------------------------------------
// Result polling
// ---------------------------------------------------------------------------
export interface UpscaleResult {
job_id: string;
status: "pending" | "processing" | "completed" | "failed";
result_image_url: string | null; // relative path, use buildUpscaleUrl() for full URL
error_message: string | null;
}
/**
* GET /upscale/result/{job_id} — poll the current status of an upscale job.
*/
export async function getUpscaleResult(jobId: string): Promise<UpscaleResult> {
const response = await fetch(`${UPSCALE_API_BASE}/upscale/result/${jobId}`);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json() as Promise<UpscaleResult>;
}
|