Jacobina / static /js /api.js
marinarosa's picture
initial commit
be82719
Raw
History Blame Contribute Delete
3.35 kB
// Gradio Server-mode API client: POST /gradio_api/call/<name> {"data": [...]}
// returns {event_id}; GET /gradio_api/call/<name>/<event_id> streams SSE
// events ("generating" per chunk, "complete" at the end).
async function beginCall(name, data) {
const res = await fetch(`./gradio_api/call/${name}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ data }),
});
if (!res.ok) throw new Error(`API ${name}: HTTP ${res.status}`);
const { event_id } = await res.json();
return event_id;
}
// Parse an SSE byte stream and invoke onEvent(type, payload) per event.
async function readSSE(name, eventId, onEvent) {
const res = await fetch(`./gradio_api/call/${name}/${eventId}`);
if (!res.ok) throw new Error(`API ${name}: HTTP ${res.status} on stream`);
const reader = res.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
for (;;) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
let sep;
while ((sep = buffer.indexOf('\n\n')) !== -1) {
const block = buffer.slice(0, sep);
buffer = buffer.slice(sep + 2);
let type = 'message';
let dataLine = '';
for (const line of block.split('\n')) {
if (line.startsWith('event:')) type = line.slice(6).trim();
else if (line.startsWith('data:')) dataLine += line.slice(5).trim();
}
if (!dataLine) continue;
let payload = null;
try { payload = JSON.parse(dataLine); } catch { /* keep null */ }
onEvent(type, payload);
}
}
}
function unwrap(payload) {
// Endpoints return a single dict; gradio wraps outputs in a list.
return Array.isArray(payload) ? payload[0] : payload;
}
// One-shot call: resolves with the final (complete) output dict.
export async function call(name, data = []) {
const eventId = await beginCall(name, data);
let result = null;
let errored = null;
await readSSE(name, eventId, (type, payload) => {
if (type === 'error') errored = payload || 'server error';
else result = unwrap(payload);
});
if (errored) throw new Error(typeof errored === 'string' ? errored : JSON.stringify(errored));
return result;
}
// Streaming call: onChunk(dict) per "generating" event; resolves with the
// final dict. Our streaming endpoints tag payloads {type: progress|final}.
export async function stream(name, data, onChunk) {
const eventId = await beginCall(name, data);
let result = null;
let errored = null;
await readSSE(name, eventId, (type, payload) => {
if (type === 'error') { errored = payload || 'server error'; return; }
const value = unwrap(payload);
if (value == null) return;
if (type === 'generating') onChunk(value);
else result = value;
});
if (errored) throw new Error(typeof errored === 'string' ? errored : JSON.stringify(errored));
return result;
}
export async function getJSON(url) {
const res = await fetch(url);
if (!res.ok) throw new Error(`GET ${url}: HTTP ${res.status}`);
return res.json();
}
export async function uploadFile(url, file) {
const form = new FormData();
form.append('file', file);
const res = await fetch(url, { method: 'POST', body: form });
if (!res.ok) throw new Error(`upload: HTTP ${res.status}`);
return res.json();
}