function unwrapStreamData(data) { if (Array.isArray(data)) { return data.length === 1 ? data[0] : data; } return data; } export async function gradioStream(apiName, payload = {}, onChunk) { const route = apiName.replace(/^\//, ""); const start = await fetch(`/gradio_api/call/v2/${route}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), credentials: "include", }); if (!start.ok) { throw new Error(`Gradio API failed to start (${start.status})`); } const { event_id: eventId } = await start.json(); if (!eventId) { throw new Error("Gradio API did not return an event id"); } const stream = await fetch(`/gradio_api/call/${route}/${eventId}`, { credentials: "include", }); if (!stream.ok) { throw new Error(`Gradio API stream failed (${stream.status})`); } const reader = stream.body.getReader(); const decoder = new TextDecoder(); let buffer = ""; let lastData = null; let errorMessage = null; let currentEvent = null; const processLine = (line) => { if (line.startsWith("event: ")) { currentEvent = line.slice(7).trim(); if (currentEvent === "error") { errorMessage = "Gradio API returned an error"; } return; } if (!line.startsWith("data: ")) { return; } try { const parsed = JSON.parse(line.slice(6)); lastData = parsed; if (currentEvent === "error") { errorMessage = typeof parsed === "string" ? parsed : parsed?.error || JSON.stringify(parsed); return; } const chunk = unwrapStreamData(parsed); if (chunk !== null && chunk !== undefined) { onChunk(chunk); } } catch { // Ignore malformed SSE chunks and keep the last valid payload. } }; while (true) { const { done, value } = await reader.read(); if (done) { break; } buffer += decoder.decode(value, { stream: true }); const lines = buffer.split("\n"); buffer = lines.pop() || ""; for (const line of lines) { if (line.trim() === "") { currentEvent = null; continue; } processLine(line); } } if (buffer.trim()) { for (const line of buffer.split("\n")) { if (line.trim() === "") { currentEvent = null; continue; } processLine(line); } } if (errorMessage) { throw new Error(errorMessage); } if (lastData === null) { throw new Error("Gradio API returned no data"); } return { data: lastData }; } export async function gradioPredict(apiName, payload = {}) { let resultData = null; await gradioStream(apiName, payload, (chunk) => { resultData = chunk; }); return { data: [resultData] }; }