Spaces:
Sleeping
Sleeping
| // 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(); | |
| } | |