Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
Download interface/frontend/src/api.js from SMSD75/SynthScope: direct link, hf CLI and curl.
- Browser
- Download file 4.78 kB
-
https://huggingface.co/spaces/SMSD75/SynthScope/resolve/main/interface/frontend/src/api.js
- Command line
-
hf download hf://spaces/SMSD75/SynthScope/interface/frontend/src/api.js
-
curl -L -o api.js https://huggingface.co/spaces/SMSD75/SynthScope/resolve/main/interface/frontend/src/api.js
4.78 kB
| // API client for the SynthScope backend. In dev, Vite proxies /api to the FastAPI server. | |
| const BASE = import.meta.env.VITE_API_BASE || ""; | |
| export async function fetchModels() { | |
| const r = await fetch(`${BASE}/api/models`); | |
| if (!r.ok) throw new Error(`models: HTTP ${r.status}`); | |
| return r.json(); | |
| } | |
| export async function predict(file, model) { | |
| const fd = new FormData(); | |
| fd.append("file", file); | |
| fd.append("model", model); | |
| const r = await fetch(`${BASE}/api/predict`, { method: "POST", body: fd }); | |
| const d = await r.json(); | |
| if (!r.ok) throw new Error(d.detail || `HTTP ${r.status}`); | |
| return d; | |
| } | |
| // --- dataset explorer -------------------------------------------------------- | |
| export async function fetchDatasets() { | |
| const r = await fetch(`${BASE}/api/datasets`); | |
| if (!r.ok) throw new Error(`datasets: HTTP ${r.status}`); | |
| return r.json(); | |
| } | |
| export async function sampleDataset(key, split, n, seed) { | |
| const u = `${BASE}/api/datasets/${key}/sample?split=${encodeURIComponent(split)}&n=${n}&seed=${seed}`; | |
| const r = await fetch(u); | |
| const d = await r.json(); | |
| if (!r.ok) throw new Error(d.detail || `HTTP ${r.status}`); | |
| return d; | |
| } | |
| export function datasetMediaUrl(key, rel, thumb) { | |
| return `${BASE}/api/datasets/${key}/media?rel=${encodeURIComponent(rel)}${thumb ? "&thumb=1" : ""}`; | |
| } | |
| export async function predictDataset(dataset, rel, model) { | |
| const fd = new FormData(); | |
| fd.append("dataset", dataset); | |
| fd.append("rel", rel); | |
| fd.append("model", model); | |
| const r = await fetch(`${BASE}/api/predict_dataset`, { method: "POST", body: fd }); | |
| const d = await r.json(); | |
| if (!r.ok) throw new Error(d.detail || `HTTP ${r.status}`); | |
| return d; | |
| } | |
| export async function scoreBatch(dataset, model, rels) { | |
| const r = await fetch(`${BASE}/api/score_batch`, { | |
| method: "POST", | |
| headers: { "Content-Type": "application/json" }, | |
| body: JSON.stringify({ dataset, model, rels }), | |
| }); | |
| const d = await r.json(); | |
| if (!r.ok) throw new Error(d.detail || `HTTP ${r.status}`); | |
| return d; | |
| } | |
| // --- threshold calibration helpers (shared by Detect + Explorer) --- | |
| export const verdictAt = (p, thr) => (p >= thr ? "fake" : "real"); | |
| export function autoCalibrate(scored) { | |
| let best = 0.5, bestAcc = -1; | |
| for (let t = 0; t <= 1.0001; t += 0.01) { | |
| const reals = scored.filter((s) => s.gt === "real"), fakes = scored.filter((s) => s.gt === "fake"); | |
| const tnr = reals.length ? reals.filter((s) => s.p < t).length / reals.length : 0; | |
| const tpr = fakes.length ? fakes.filter((s) => s.p >= t).length / fakes.length : 0; | |
| const acc = (tpr + tnr) / 2; | |
| if (acc > bestAcc) { bestAcc = acc; best = t; } | |
| } | |
| return Math.round(best * 100) / 100; | |
| } | |
| export function targetFprThreshold(scored, fpr) { | |
| const reals = scored.filter((s) => s.gt === "real").map((s) => s.p).sort((a, b) => a - b); | |
| if (!reals.length) return null; | |
| const idx = Math.min(reals.length - 1, Math.max(0, Math.ceil((1 - fpr) * reals.length) - 1)); | |
| return Math.round(reals[idx] * 100) / 100; | |
| } | |
| export function batchStats(scored, thr) { | |
| if (!scored.length) return null; | |
| const reals = scored.filter((s) => s.gt === "real"), fakes = scored.filter((s) => s.gt === "fake"); | |
| return { | |
| n: scored.length, | |
| acc: scored.filter((s) => verdictAt(s.p, thr) === s.gt).length / scored.length, | |
| racc: reals.length ? reals.filter((s) => s.p < thr).length / reals.length : null, | |
| facc: fakes.length ? fakes.filter((s) => s.p >= thr).length / fakes.length : null, | |
| }; | |
| } | |
| // --- SOTA generator vs detector comparison ---------------------------------- | |
| export async function sotaGenerators() { | |
| const r = await fetch(`${BASE}/api/sota/generators`); | |
| if (!r.ok) throw new Error(`generators: HTTP ${r.status}`); | |
| return r.json(); | |
| } | |
| export async function sotaRealImage() { | |
| const r = await fetch(`${BASE}/api/sota/real_image`); | |
| const d = await r.json(); | |
| if (!r.ok) throw new Error(d.detail || `HTTP ${r.status}`); | |
| return d; | |
| } | |
| export async function fetchLeaderboard() { | |
| const r = await fetch(`${BASE}/api/leaderboard`); | |
| if (!r.ok) throw new Error(`leaderboard: HTTP ${r.status}`); | |
| return r.json(); | |
| } | |
| export async function fetchGeneratorBenchmarks() { | |
| const r = await fetch(`${BASE}/api/generator_benchmarks`); | |
| if (!r.ok) throw new Error(`generator benchmarks: HTTP ${r.status}`); | |
| return r.json(); | |
| } | |
| export async function sotaCompare(file, generator, detectors, prompt) { | |
| const fd = new FormData(); | |
| fd.append("file", file); | |
| fd.append("generator", generator); | |
| fd.append("detectors", detectors.join(",")); | |
| fd.append("prompt", prompt); | |
| const r = await fetch(`${BASE}/api/sota/compare`, { method: "POST", body: fd }); | |
| const d = await r.json(); | |
| if (!r.ok) throw new Error(d.detail || `HTTP ${r.status}`); | |
| return d; | |
| } | |