SMSD75's picture
Update SynthScope Space from the GitHub repository
26a7256 verified
Raw History Blame Contribute Delete
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;
}