borderless / assets /gradio_api.js
spagestic's picture
Refactor ZeroGPU handling and update documentation. Reduced default BORDERLESS_GPU_DURATION to 60 seconds in .env.example and README.md. Enhanced error messaging in app.js and gradio_api.js for better user feedback on quota issues. Updated GPU_DURATION logic in config.py to enforce minimum and maximum limits.
fbe6753
Raw
History Blame Contribute Delete
2.81 kB
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] };
}