UNPKG

koishi-plugin-gradio-service

Version:
1,610 lines (1,600 loc) 62.9 kB
var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); // src/constants.ts var HOST_URL = `host`; var API_URL = `predict/`; var SSE_URL_V0 = `queue/join`; var SSE_DATA_URL_V0 = `queue/data`; var SSE_URL = `queue/data`; var SSE_DATA_URL = `queue/join`; var UPLOAD_URL = `upload`; var LOGIN_URL = `login`; var CONFIG_URL = `config`; var API_INFO_URL = `info`; var RUNTIME_URL = `runtime`; var SLEEPTIME_URL = `sleeptime`; var HEARTBEAT_URL = `heartbeat`; var COMPONENT_SERVER_URL = `component_server`; var RESET_URL = `reset`; var CANCEL_URL = `cancel`; var RAW_API_INFO_URL = `info?serialize=False`; var SPACE_FETCHER_URL = "https://gradio-space-api-fetcher-v2.hf.space/api"; var SPACE_URL = "https://hf.space/{}"; var QUEUE_FULL_MSG = "This application is currently busy. Please try again. "; var BROKEN_CONNECTION_MSG = "Connection errored out. "; var CONFIG_ERROR_MSG = "Could not resolve app config. "; var SPACE_STATUS_ERROR_MSG = "Could not get space status. "; var API_INFO_ERROR_MSG = "Could not get API info. "; var SPACE_METADATA_ERROR_MSG = "Space metadata could not be loaded. "; var INVALID_URL_MSG = "Invalid URL. A full URL path is required."; var UNAUTHORIZED_MSG = "Not authorized to access this space. "; var INVALID_CREDENTIALS_MSG = "Invalid credentials. Could not login. "; var MISSING_CREDENTIALS_MSG = "Login credentials are required to access this space."; var NODEJS_FS_ERROR_MSG = "File system access is only available in Node.js environments"; var ROOT_URL_ERROR_MSG = "Root URL not found in client config"; var FILE_PROCESSING_ERROR_MSG = "Error uploading file"; // src/helpers/init_helpers.ts async function getJwt(ctx, space, token, cookies) { try { const r = await ctx.http.get( `${ctx.gradio.config.baseURL}/api/spaces/${space}/jwt`, { headers: { Authorization: `Bearer ${token}`, ...cookies ? { Cookie: cookies } : {} } } ); const jwt = r?.token; return jwt || false; } catch (e) { ctx.logger.error(`get jwt with error %s`, JSON.stringify(e.response)); return false; } } __name(getJwt, "getJwt"); function determineProtocol(endpoint) { if (endpoint.startsWith("http")) { const { protocol, host, pathname } = new URL(endpoint); if (host.endsWith("hf.space")) { return { ws_protocol: "wss", host, http_protocol: protocol }; } return { ws_protocol: protocol === "https:" ? "wss" : "ws", http_protocol: protocol, host: host + (pathname !== "/" ? pathname : "") }; } else if (endpoint.startsWith("file:")) { return { ws_protocol: "ws", http_protocol: "http:", host: "lite.local" // Special fake hostname only used for this case. This matches the hostname allowed in `is_self_host()` in `js/wasm/network/host.ts`. }; } return { ws_protocol: "wss", http_protocol: "https:", host: endpoint }; } __name(determineProtocol, "determineProtocol"); var parseAndSetCookies = /* @__PURE__ */ __name((cookieHeader) => { const cookies = []; const parts = cookieHeader.split(/,(?=\s*[^\s=;]+=[^\s=;]+)/); parts.forEach((cookie) => { const [name, value] = cookie.split(";")[0].split("="); if (name && value) { cookies.push(`${name.trim()}=${value.trim()}`); } }); return cookies; }, "parseAndSetCookies"); async function getCookieHeader(httpProtocol, host, auth, ctx, hfToken) { const formData = new FormData(); formData.append("username", auth?.[0]); formData.append("password", auth?.[1]); const headers = {}; if (hfToken) { headers.Authorization = `Bearer ${hfToken}`; } const res = await ctx.http.post(`${httpProtocol}//${host}/${LOGIN_URL}`, { headers, method: "POST", body: formData, credentials: "include" }); if (res.status === 200) { return res.headers.get("set-cookie"); } else if (res.status === 401) { throw new Error(INVALID_CREDENTIALS_MSG); } else { throw new Error(SPACE_METADATA_ERROR_MSG); } } __name(getCookieHeader, "getCookieHeader"); async function resolveConfig(endpoint) { const headers = this.options.hf_token ? { Authorization: `Bearer ${this.options.hf_token}` } : {}; headers["Content-Type"] = "application/json"; if (endpoint) { const configUrl = joinUrls(endpoint, CONFIG_URL); const response = await this.ctx.http(configUrl, { headers, method: "GET" }); if (response?.status === 401 && !this.options.auth) { throw new Error(MISSING_CREDENTIALS_MSG); } else if (response?.status === 401 && this.options.auth) { throw new Error(INVALID_CREDENTIALS_MSG); } if (response?.status === 200) { const config = await response.data; config.path = config.path ?? ""; config.root = endpoint; config.dependencies?.forEach((dep, i) => { if (dep.id === void 0) { dep.id = i; } }); return config; } else if (response?.status === 401) { throw new Error(UNAUTHORIZED_MSG); } throw new Error(CONFIG_ERROR_MSG); } throw new Error(CONFIG_ERROR_MSG); } __name(resolveConfig, "resolveConfig"); async function resolveCookies() { const { http_protocol, host } = await processEndpoint( this.ctx, this.appReference, this.options.hf_token ); try { if (this.options.auth) { const cookie_header = await getCookieHeader( http_protocol, host, this.options.auth, this.ctx, this.options.hf_token ); if (cookie_header) this.setCookies(cookie_header); } } catch (e) { throw Error(e.message); } } __name(resolveCookies, "resolveCookies"); function mapNamesToIds(fns) { const apis = {}; fns.forEach(({ api_name, id }) => { if (api_name) apis[api_name] = id; }); return apis; } __name(mapNamesToIds, "mapNamesToIds"); function resolveRoot(baseUrl, rootPath, prioritizeBase) { if (rootPath.startsWith("http://") || rootPath.startsWith("https://")) { return prioritizeBase ? baseUrl : rootPath; } return baseUrl + rootPath; } __name(resolveRoot, "resolveRoot"); // src/helpers/api_info.ts var RE_SPACE_NAME = /^[a-zA-Z0-9_\-\.]+\/[a-zA-Z0-9_\-\.]+$/; var RE_SPACE_DOMAIN = /.*hf\.space\/{0,1}.*$/; async function processEndpoint(ctx, appReference, hfToken) { const headers = {}; if (hfToken) { headers.Authorization = `Bearer ${hfToken}`; } const _appReference = appReference.trim().replace(/\/$/, ""); if (RE_SPACE_NAME.test(_appReference)) { try { const baseURL = ctx.gradio?.config?.baseURL ?? "https://huggingface.co"; const res = await ctx.http.get( `${baseURL}/api/spaces/${_appReference}/${HOST_URL}`, { headers } ); const _host = res.host; return { space_id: appReference, ...determineProtocol(_host) }; } catch (e) { throw new Error(SPACE_METADATA_ERROR_MSG); } } if (RE_SPACE_DOMAIN.test(_appReference)) { const { ws_protocol, http_protocol, host } = determineProtocol(_appReference); return { space_id: host.split("/")[0].replace(".hf.space", ""), ws_protocol, http_protocol, host }; } return { space_id: false, ...determineProtocol(appReference) }; } __name(processEndpoint, "processEndpoint"); var joinUrls = /* @__PURE__ */ __name((...urls) => { try { return urls.reduce((baseUrl, part) => { baseUrl = baseUrl.replace(/\/+$/, ""); part = part.replace(/^\/+/, ""); return new URL(part, baseUrl + "/").toString(); }); } catch (e) { throw new Error(INVALID_URL_MSG); } }, "joinUrls"); function transformAPIInfo(apiInfo, config, apiMap) { const transformedInfo = { named_endpoints: {}, unnamed_endpoints: {} }; Object.keys(apiInfo).forEach((category) => { if (category === "named_endpoints" || category === "unnamed_endpoints") { transformedInfo[category] = {}; Object.entries(apiInfo[category]).forEach( ([endpoint, { parameters, returns }]) => { const dependencyIndex = config.dependencies.find( (dep) => dep.api_name === endpoint || dep.api_name === endpoint.replace("/", "") )?.id || apiMap[endpoint.replace("/", "")] || -1; const dependencyTypes = dependencyIndex !== -1 ? config.dependencies.find( (dep) => dep.id === dependencyIndex )?.types : { generator: false, cancel: false }; if (dependencyIndex !== -1 && config.dependencies.find( (dep) => dep.id === dependencyIndex )?.inputs?.length !== parameters.length) { const components = config.dependencies.find((dep) => dep.id === dependencyIndex).inputs.map( (input) => config.components.find( (c) => c.id === input )?.type ); try { components.forEach((comp, idx) => { if (comp === "state") { const newParam = { component: "state", example: null, parameter_default: null, parameter_has_default: true, parameter_name: null, hidden: true // eslint-disable-next-line @typescript-eslint/no-explicit-any }; parameters.splice(idx, 0, newParam); } }); } catch (e) { console.error(e); } } const transformType = /* @__PURE__ */ __name((data, component, serializer, signatureType) => ({ ...data, description: getDescription(data?.type, serializer), type: getType( data?.type, component, serializer, signatureType ) || "", enum: data?.type?.enum || void 0 }), "transformType"); transformedInfo[category][endpoint] = { parameters: parameters.map( (p) => transformType( p, p?.component, p?.serializer, "parameter" ) ), returns: returns.map( (r) => transformType( r, r?.component, r?.serializer, "return" ) ), type: dependencyTypes }; } ); } }); return transformedInfo; } __name(transformAPIInfo, "transformAPIInfo"); function getType(type, component, serializer, signatureType) { switch (type?.type) { case "string": return "string"; case "boolean": return "boolean"; case "number": return "number"; } if (serializer === "JSONSerializable" || serializer === "StringSerializable") { return "any"; } else if (serializer === "ListStringSerializable") { return "string[]"; } else if (component === "Image") { return signatureType === "parameter" ? "Blob | File | Buffer" : "string"; } else if (serializer === "FileSerializable") { if (type?.type === "array") { return signatureType === "parameter" ? "(Blob | File | Buffer)[]" : `{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}[]`; } return signatureType === "parameter" ? "Blob | File | Buffer" : `{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}`; } else if (serializer === "GallerySerializable") { return signatureType === "parameter" ? "[(Blob | File | Buffer), (string | null)][]" : `[{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}, (string | null))][]`; } } __name(getType, "getType"); function getDescription(type, serializer) { if (serializer === "GallerySerializable") { return "array of [file, label] tuples"; } else if (serializer === "ListStringSerializable") { return "array of strings"; } else if (serializer === "FileSerializable") { return "array of files or single file"; } return type?.description; } __name(getDescription, "getDescription"); function handleMessage(data, lastStatus) { const queue = true; switch (data.msg) { case "send_data": return { type: "data" }; case "send_hash": return { type: "hash" }; case "queue_full": return { type: "update", status: { queue, message: QUEUE_FULL_MSG, stage: "error", code: data.code, success: data.success } }; case "heartbeat": return { type: "heartbeat" }; case "unexpected_error": return { type: "unexpected_error", status: { queue, message: data.message, stage: "error", success: false } }; case "estimation": return { type: "update", status: { queue, stage: lastStatus || "pending", code: data.code, size: data.queue_size, position: data.rank, eta: data.rank_eta, success: data.success } }; case "progress": return { type: "update", status: { queue, stage: "pending", code: data.code, progress_data: data.progress_data, success: data.success } }; case "log": return { type: "log", data }; case "process_generating": return { type: "generating", status: { queue, message: !data.success ? data.output.error : null, stage: data.success ? "generating" : "error", code: data.code, progress_data: data.progress_data, eta: data.average_duration }, data: data.success ? data.output : null }; case "process_completed": if ("error" in data.output) { return { type: "update", status: { queue, message: data.output.error, visible: data.output.visible, duration: data.output.duration, stage: "error", code: data.code, success: data.success } }; } return { type: "complete", status: { queue, message: !data.success ? data.output.error : void 0, stage: data.success ? "complete" : "error", code: data.code, progress_data: data.progress_data, changed_state_ids: data.success ? data.output.changed_state_ids : void 0 }, data: data.success ? data.output : null }; case "process_starts": return { type: "update", status: { queue, stage: "pending", code: data.code, size: data.rank, position: 0, success: data.success, eta: data.eta } }; } return { type: "none", status: { stage: "error", queue } }; } __name(handleMessage, "handleMessage"); var mapDataToParams = /* @__PURE__ */ __name((data = [], endpointInfo) => { const parameters = endpointInfo ? endpointInfo.parameters : []; if (Array.isArray(data)) { if (data.length > parameters.length) { console.warn("Too many arguments provided for the endpoint."); } return data; } const resolvedData = []; const providedKeys = Object.keys(data); parameters.forEach((param, index) => { if (data.hasOwnProperty(param.parameter_name)) { resolvedData[index] = data[param.parameter_name]; } else if (param.parameter_has_default) { resolvedData[index] = param.parameter_default; } else { throw new Error( `No value provided for required parameter: ${param.parameter_name}` ); } }); providedKeys.forEach((key) => { if (!parameters.some((param) => param.parameter_name === key)) { throw new Error( `Parameter \`${key}\` is not a valid keyword argument. Please refer to the API for usage.` ); } }); resolvedData.forEach((value, idx) => { if (value === void 0 && !parameters[idx].parameter_has_default) { throw new Error( `No value provided for required parameter: ${parameters[idx].parameter_name}` ); } }); return resolvedData; }, "mapDataToParams"); // src/utils/view_api.ts import semiver from "semiver"; async function viewApi() { if (this.apiInfo) return this.apiInfo; const { hf_token } = this.options; const { config } = this; const headers = { "Content-Type": "application/json" }; if (hf_token) { headers.Authorization = `Bearer ${hf_token}`; } if (!config) { return; } try { let response; let apiInfo; if (semiver(config?.version || "2.0.0", "3.30") < 0) { response = await this.ctx.http(SPACE_FETCHER_URL, { method: "POST", data: JSON.stringify({ serialize: false, config: JSON.stringify(config) }), headers }); } else { const url = joinUrls(config.root, this.apiPrefix, API_INFO_URL); response = await this.ctx.http(url, { method: "GET", headers }); } if (response.status !== 200) { throw new Error(BROKEN_CONNECTION_MSG); } apiInfo = response.data; if ("api" in apiInfo) { apiInfo = apiInfo.api; } if (apiInfo.named_endpoints["/predict"] && !apiInfo.unnamed_endpoints["0"]) { apiInfo.unnamed_endpoints[0] = apiInfo.named_endpoints["/predict"]; } return transformAPIInfo(apiInfo, config, this.apiMap); } catch (e) { throw new Error("Could not get API info. " + e.message); } } __name(viewApi, "viewApi"); // src/types.ts var Command = class { static { __name(this, "Command"); } type; command; meta; fileData; constructor(command, meta) { this.type = "command"; this.command = command; this.meta = meta; } }; // src/helpers/data.ts function updateObject(object, newValue, stack) { while (stack.length > 1) { const key2 = stack.shift(); if (typeof key2 === "string" || typeof key2 === "number") { object = object[key2]; } else { throw new Error("Invalid key type"); } } const key = stack.shift(); if (typeof key === "string" || typeof key === "number") { object[key] = newValue; } else { throw new Error("Invalid key type"); } } __name(updateObject, "updateObject"); async function walkAndStoreBlobs(data, type = void 0, path = [], root = false, endpointInfo = void 0) { if (Array.isArray(data)) { let blobRefs = []; await Promise.all( data.map(async (_, index) => { const newPath = path.slice(); newPath.push(String(index)); const arrayRefs = await walkAndStoreBlobs( data[index], root ? endpointInfo?.parameters[index]?.component || void 0 : type, newPath, false, endpointInfo ); blobRefs = blobRefs.concat(arrayRefs); }) ); return blobRefs; } else if (globalThis.Buffer && data instanceof globalThis.Buffer || data instanceof Blob) { return [ { path, blob: new Blob([data]), type } ]; } else if (typeof data === "object" && data !== null) { let blobRefs = []; for (const key of Object.keys(data)) { const newPath = [...path, key]; const value = data[key]; blobRefs = blobRefs.concat( await walkAndStoreBlobs( value, void 0, newPath, false, endpointInfo ) ); } return blobRefs; } return []; } __name(walkAndStoreBlobs, "walkAndStoreBlobs"); function skipQueue(id, config) { const fnQueue = config?.dependencies?.find((dep) => dep.id === id)?.queue; if (fnQueue != null) { return !fnQueue; } return !config.enable_queue; } __name(skipQueue, "skipQueue"); function postMessage(message, origin) { return new Promise((resolve, reject) => { const channel = new MessageChannel(); channel.port1.onmessage = ({ data }) => { channel.port1.close(); resolve(data); }; window.parent.postMessage(message, origin, [channel.port2]); }); } __name(postMessage, "postMessage"); function handleFile(file) { if (typeof file === "string") { if (file.startsWith("http://") || file.startsWith("https://")) { return { path: file, url: file, orig_name: file.split("/").pop() ?? "unknown", meta: { _type: "gradio.FileData" } }; } return new Command("upload_file", { path: file, name: file, orig_path: file }); } else if (typeof File !== "undefined" && file instanceof File) { return new Blob([file]); } else if (file instanceof Buffer) { return new Blob([file]); } else if (file instanceof Blob) { return file; } throw new Error( "Invalid input: must be a URL, File, Blob, or Buffer object." ); } __name(handleFile, "handleFile"); function handlePayload(resolvedPayload, dependency, components, type, withNullState = false) { if (type === "input" && !withNullState) { throw new Error( "Invalid code path. Cannot skip state inputs for input." ); } if (type === "output" && withNullState) { return resolvedPayload; } const updatedPayload = []; let payloadIndex = 0; const deps = type === "input" ? dependency.inputs : dependency.outputs; for (let i = 0; i < deps.length; i++) { const inputId = deps[i]; const component = components.find((c) => c.id === inputId); if (component?.type === "state") { if (withNullState) { if (resolvedPayload.length === deps.length) { const value = resolvedPayload[payloadIndex]; updatedPayload.push(value); payloadIndex++; } else { updatedPayload.push(null); } } else { payloadIndex++; continue; } continue; } else { const value = resolvedPayload[payloadIndex]; updatedPayload.push(value); payloadIndex++; } } return updatedPayload; } __name(handlePayload, "handlePayload"); // src/utils/stream.ts async function openStream() { const { eventCallbacks, unclosedEvents, pendingStreamMessages, streamStatus, config, jwt } = this; if (!config) { throw new Error("Could not resolve app config"); } const that = this; streamStatus.open = true; let stream = null; const params = new URLSearchParams({ session_hash: this.session_hash }).toString(); const url = new URL(`${config.root}${this.apiPrefix}/${SSE_URL}?${params}`); if (this.config.space_id && this.options.hf_token && typeof this.jwt !== "string") { this.jwt = await getJwt( this.ctx, this.config.space_id, this.options.hf_token ); } if (jwt) { url.searchParams.set("__sign", jwt); } stream = this.stream(url); if (!stream) { console.warn("Cannot connect to SSE endpoint: " + url.toString()); return; } stream.onmessage = async function(event) { const _data = JSON.parse(event.data); if (_data.msg === "close_stream") { closeStream(streamStatus, that.abortController); return; } const eventId = _data.event_id; if (!eventId) { await Promise.all( Object.keys(eventCallbacks).map( (eventId2) => eventCallbacks[eventId2](_data) ) ); } else if (eventCallbacks[eventId] && config) { if (_data.msg === "process_completed" && ["sse", "sse_v1", "sse_v2", "sse_v2.1", "sse_v3"].includes( config.protocol )) { unclosedEvents.delete(eventId); } const fn = eventCallbacks[eventId]; fn(_data); } else { if (!pendingStreamMessages[eventId]) { pendingStreamMessages[eventId] = []; } pendingStreamMessages[eventId].push(_data); } }; stream.onerror = async function() { await Promise.all( Object.keys(eventCallbacks).map( (eventId) => eventCallbacks[eventId]({ msg: "unexpected_error", message: BROKEN_CONNECTION_MSG }) ) ); }; } __name(openStream, "openStream"); function closeStream(streamStatus, abortController) { if (streamStatus) { streamStatus.open = false; abortController?.abort(); } } __name(closeStream, "closeStream"); function applyDiffStream(pendingDiffStreams, eventId, data) { const isFirstGeneration = !pendingDiffStreams[eventId]; if (isFirstGeneration) { pendingDiffStreams[eventId] = []; data.data.forEach((value, i) => { pendingDiffStreams[eventId][i] = value; }); } else { data.data.forEach((value, i) => { const newData = applyDiff(pendingDiffStreams[eventId][i], value); pendingDiffStreams[eventId][i] = newData; data.data[i] = newData; }); } } __name(applyDiffStream, "applyDiffStream"); function applyDiff(obj, diff) { diff.forEach(([action, path, value]) => { obj = applyEdit(obj, path, action, value); }); return obj; } __name(applyDiff, "applyDiff"); function applyEdit(target, path, action, value) { if (path.length === 0) { if (action === "replace") { return value; } else if (action === "append") { return target + value; } throw new Error(`Unsupported action: ${action}`); } let current = target; for (let i = 0; i < path.length - 1; i++) { current = current[path[i]]; } const lastPath = path[path.length - 1]; switch (action) { case "replace": current[lastPath] = value; break; case "append": current[lastPath] += value; break; case "add": if (Array.isArray(current)) { current.splice(Number(lastPath), 0, value); } else { current[lastPath] = value; } break; case "delete": if (Array.isArray(current)) { current.splice(Number(lastPath), 1); } else { delete current[lastPath]; } break; default: throw new Error(`Unknown action: ${action}`); } return target; } __name(applyEdit, "applyEdit"); function readableStream(ctx, input, init = {}) { const instance = { close: /* @__PURE__ */ __name(() => { }, "close"), onerror: null, onmessage: null, onopen: null, readyState: 0, url: input.toString(), withCredentials: false, CONNECTING: 0, OPEN: 1, CLOSED: 2, addEventListener: /* @__PURE__ */ __name(() => { throw new Error("Method not implemented."); }, "addEventListener"), dispatchEvent: /* @__PURE__ */ __name(() => { throw new Error("Method not implemented."); }, "dispatchEvent"), removeEventListener: /* @__PURE__ */ __name(() => { throw new Error("Method not implemented."); }, "removeEventListener") }; if (init.headers instanceof Headers) { init.headers = Object.fromEntries(init.headers.entries()); } ctx.http(input, { method: init?.method || "GET", headers: init?.headers || {}, data: init?.body || void 0, signal: init?.signal || void 0, responseType: "event-stream" }).then(async (res) => { instance.readyState = instance.OPEN; try { for await (const chunk of res.data) { instance.onmessage && instance.onmessage(chunk); } instance.readyState = instance.CLOSED; } catch (e) { instance.onerror && instance.onerror(e); instance.readyState = instance.CLOSED; } }).catch((e) => { ctx.logger.error(e); instance.onerror && instance.onerror(e); instance.readyState = instance.CLOSED; }); return instance; } __name(readableStream, "readableStream"); // src/utils/post_data.ts async function postData(url, body, additionalHeaders) { const headers = { "Content-Type": "application/json" }; if (this.options.hf_token) { headers.Authorization = `Bearer ${this.options.hf_token}`; } let response; try { response = await this.ctx.http(url, { method: "POST", data: JSON.stringify(body), headers: { ...headers, ...additionalHeaders } }); } catch (e) { return [{ error: BROKEN_CONNECTION_MSG }, 500]; } let output; let status; try { output = response.data; status = response.status; } catch (e) { output = { error: `Could not parse server response: ${e}` }; status = 500; } return [output, status]; } __name(postData, "postData"); // src/utils/submit.ts import semiver2 from "semiver"; function submit(endpoint, data = {}, eventData, triggerId, allEvents) { try { let fireEvent = function(event) { if (allEvents || eventsToPublish[event.type]) { pushEvent(event); } }, close = function() { done = true; while (resolvers.length > 0) resolvers.shift()({ value: void 0, done: true }); }, push = function(data2) { if (done) return; if (resolvers.length > 0) { ; resolvers.shift()(data2); } else { values.push(data2); } }, pushError = function(error) { push(thenableReject(error)); close(); }, pushEvent = function(event) { push({ value: event, done: false }); }, next = function() { if (values.length > 0) return Promise.resolve(values.shift()); if (done) return Promise.resolve({ value: void 0, done: true }); return new Promise((resolve) => resolvers.push(resolve)); }; __name(fireEvent, "fireEvent"); __name(close, "close"); __name(push, "push"); __name(pushError, "pushError"); __name(pushEvent, "pushEvent"); __name(next, "next"); let done = false; const values = []; const resolvers = []; const { hf_token } = this.options; const { appReference, config, session_hash, apiInfo, apiMap, streamStatus, pendingStreamMessages, pendingDiffStreams, eventCallbacks, unclosedEvents, options } = this; const that = this; if (!apiInfo) throw new Error("No API found"); if (!config) throw new Error("Could not resolve app config"); const { fn_index, endpoint_info, dependency } = getEndPointInfo( apiInfo, endpoint, apiMap, config ); const resolvedData = mapDataToParams(data, endpoint_info); let websocket; let stream; const protocol = config.protocol ?? "ws"; const _endpoint = typeof endpoint === "number" ? "/predict" : endpoint; let payload; let eventId = null; let complete = false; const lastStatus = {}; const urlParams = typeof window !== "undefined" && typeof document !== "undefined" ? new URLSearchParams(window.location.search).toString() : ""; const eventsToPublish = options?.events?.reduce( (acc, event) => { acc[event] = true; return acc; }, {} ) || {}; async function cancel() { const _status = { stage: "complete", queue: false, time: /* @__PURE__ */ new Date() }; complete = _status; fireEvent({ ..._status, type: "status", endpoint: _endpoint, fn_index }); let resetRequest = {}; let cancelRequest = {}; if (protocol === "ws") { if (websocket && websocket.readyState === 0) { websocket.addEventListener("open", () => { websocket.close(); }); } else { websocket.close(); } resetRequest = { fn_index, session_hash }; } else { closeStream(streamStatus, that.abortController); close(); resetRequest = { event_id: eventId }; cancelRequest = { event_id: eventId, session_hash, fn_index }; } try { if (!config) { throw new Error("Could not resolve app config"); } if ("event_id" in cancelRequest) { await that.ctx.http.post( `${config.root}${that.apiPrefix}/${CANCEL_URL}`, JSON.stringify(cancelRequest), { headers: { "Content-Type": "application/json" }, method: "POST" } ); } await that.ctx.http.post( `${config.root}${that.apiPrefix}/${RESET_URL}`, JSON.stringify(resetRequest), { headers: { "Content-Type": "application/json" }, method: "POST" } ); } catch (e) { that.ctx.logger.warn( "The `/reset` endpoint could not be called. Subsequent endpoint results may be unreliable." ); } } __name(cancel, "cancel"); this.handleBlob(config.root, resolvedData, endpoint_info).then( async (_payload) => { const inputData = handlePayload( _payload, dependency, config.components, "input", true ); payload = { data: inputData || [], event_data: eventData, fn_index, trigger_id: triggerId }; if (skipQueue(fn_index, config)) { fireEvent({ type: "status", endpoint: _endpoint, stage: "pending", queue: false, fn_index, time: /* @__PURE__ */ new Date() }); this.postData( `${config.root}${that.apiPrefix}/run${_endpoint.startsWith("/") ? _endpoint : `/${_endpoint}`}${urlParams ? "?" + urlParams : ""}`, { ...payload, session_hash } ).then(([output, statusCode]) => { const data2 = output.data; if (statusCode === 200) { fireEvent({ type: "data", endpoint: _endpoint, fn_index, data: handlePayload( data2, dependency, config.components, "output", options.with_null_state ), time: /* @__PURE__ */ new Date(), event_data: eventData, trigger_id: triggerId }); fireEvent({ type: "status", endpoint: _endpoint, fn_index, stage: "complete", eta: output.average_duration, queue: false, time: /* @__PURE__ */ new Date() }); } else { fireEvent({ type: "status", stage: "error", endpoint: _endpoint, fn_index, message: output.error, queue: false, time: /* @__PURE__ */ new Date() }); } }).catch((e) => { fireEvent({ type: "status", stage: "error", message: e.message, endpoint: _endpoint, fn_index, queue: false, time: /* @__PURE__ */ new Date() }); }); } else if (protocol === "ws") { const { ws_protocol, host } = await processEndpoint( this.ctx, appReference, hf_token ); fireEvent({ type: "status", stage: "pending", queue: true, endpoint: _endpoint, fn_index, time: /* @__PURE__ */ new Date() }); const url = new URL( `${ws_protocol}://${resolveRoot( host, config.path, true )}/queue/join${urlParams ? "?" + urlParams : ""}` ); if (this.jwt) { url.searchParams.set("__sign", this.jwt); } websocket = this.ctx.http.ws(url); websocket.onclose = (evt) => { if (!evt.wasClean) { fireEvent({ type: "status", stage: "error", broken: true, message: BROKEN_CONNECTION_MSG, queue: true, endpoint: _endpoint, fn_index, time: /* @__PURE__ */ new Date() }); } }; websocket.onmessage = function(event) { const _data = JSON.parse(event.data); const { type, status, data: data2 } = handleMessage( _data, lastStatus[fn_index] ); if (type === "update" && status && !complete) { fireEvent({ type: "status", endpoint: _endpoint, fn_index, time: /* @__PURE__ */ new Date(), ...status }); if (status.stage === "error") { websocket.close(); } } else if (type === "hash") { websocket.send( JSON.stringify({ fn_index, session_hash }) ); return; } else if (type === "data") { websocket.send( JSON.stringify({ ...payload, session_hash }) ); } else if (type === "complete") { complete = status; } else if (type === "log") { fireEvent({ type: "log", log: data2.log, level: data2.level, endpoint: _endpoint, duration: data2.duration, visible: data2.visible, fn_index }); } else if (type === "generating") { fireEvent({ type: "status", time: /* @__PURE__ */ new Date(), ...status, stage: status?.stage, queue: true, endpoint: _endpoint, fn_index }); } if (data2) { fireEvent({ type: "data", time: /* @__PURE__ */ new Date(), data: handlePayload( data2.data, dependency, config.components, "output", options.with_null_state ), endpoint: _endpoint, fn_index, event_data: eventData, trigger_id: triggerId }); if (complete) { fireEvent({ type: "status", time: /* @__PURE__ */ new Date(), ...complete, stage: status?.stage, queue: true, endpoint: _endpoint, fn_index }); websocket.close(); } } }; if (semiver2(config.version || "2.0.0", "3.6") < 0) { addEventListener( "open", () => websocket.send( JSON.stringify({ hash: session_hash }) ) ); } } else if (protocol === "sse") { fireEvent({ type: "status", stage: "pending", queue: true, endpoint: _endpoint, fn_index, time: /* @__PURE__ */ new Date() }); const params = new URLSearchParams({ fn_index: fn_index.toString(), session_hash }).toString(); const url = new URL( `${config.root}${that.apiPrefix}/${SSE_URL}?${urlParams ? urlParams + "&" : ""}${params}` ); if (this.jwt) { url.searchParams.set("__sign", this.jwt); } stream = this.stream(url); if (!stream) { return Promise.reject( new Error( "Cannot connect to SSE endpoint: " + url.toString() ) ); } stream.onmessage = async function(event) { const _data = JSON.parse(event.data); const { type, status, data: data2 } = handleMessage( _data, lastStatus[fn_index] ); if (type === "update" && status && !complete) { fireEvent({ type: "status", endpoint: _endpoint, fn_index, time: /* @__PURE__ */ new Date(), ...status }); if (status.stage === "error") { stream?.close(); close(); } } else if (type === "data") { eventId = _data.event_id; const [, status2] = await that.postData( `${config.root}${that.apiPrefix}/queue/data`, { ...payload, session_hash, event_id: eventId } ); if (status2 !== 200) { fireEvent({ type: "status", stage: "error", message: BROKEN_CONNECTION_MSG, queue: true, endpoint: _endpoint, fn_index, time: /* @__PURE__ */ new Date() }); stream?.close(); close(); } } else if (type === "complete") { complete = status; } else if (type === "log") { fireEvent({ type: "log", log: data2.log, level: data2.level, endpoint: _endpoint, duration: data2.duration, visible: data2.visible, fn_index }); } else if (type === "generating") { fireEvent({ type: "status", time: /* @__PURE__ */ new Date(), ...status, stage: status?.stage, queue: true, endpoint: _endpoint, fn_index }); } if (data2) { fireEvent({ type: "data", time: /* @__PURE__ */ new Date(), data: handlePayload( data2.data, dependency, config.components, "output", options.with_null_state ), endpoint: _endpoint, fn_index, event_data: eventData, trigger_id: triggerId }); if (complete) { fireEvent({ type: "status", time: /* @__PURE__ */ new Date(), ...complete, stage: status?.stage, queue: true, endpoint: _endpoint, fn_index }); stream?.close(); close(); } } }; } else if (protocol === "sse_v1" || protocol === "sse_v2" || protocol === "sse_v2.1" || protocol === "sse_v3") { fireEvent({ type: "status", stage: "pending", queue: true, endpoint: _endpoint, fn_index, time: /* @__PURE__ */ new Date() }); const postDataPromise = that.postData( `${config.root}${that.apiPrefix}/${SSE_DATA_URL}?${urlParams}`, { ...payload, session_hash } ); postDataPromise.then(async ([response, status]) => { if (status === 503) { fireEvent({ type: "status", stage: "error", message: QUEUE_FULL_MSG, queue: true, endpoint: _endpoint, fn_index, time: /* @__PURE__ */ new Date() }); } else if (status !== 200) { fireEvent({ type: "status", stage: "error", message: BROKEN_CONNECTION_MSG, queue: true, endpoint: _endpoint, fn_index, time: /* @__PURE__ */ new Date() }); } else { eventId = response.event_id; const callback = /* @__PURE__ */ __name(async function(_data) { try { const { type, status: status2, data: data2 } = handleMessage( _data, lastStatus[fn_index] ); if (type === "heartbeat") { return; } if (type === "update" && status2 && !complete) { fireEvent({ type: "status", endpoint: _endpoint, fn_index, time: /* @__PURE__ */ new Date(), ...status2 }); } else if (type === "complete") { complete = status2; } else if (type === "unexpected_error") { that.ctx.logger.error( "Unexpected error", status2?.message ); fireEvent({ type: "status", stage: "error", message: status2?.message || "An Unexpected Error Occurred!", queue: true, endpoint: _endpoint, fn_index, time: /* @__PURE__ */ new Date() }); } else if (type === "log") { fireEvent({ type: "log", log: data2.log, level: data2.level, endpoint: _endpoint, duration: data2.duration, visible: data2.visible, fn_index }); return; } else if (type === "generating") { fireEvent({ type: "status", time: /* @__PURE__ */ new Date(), ...status2, stage: status2?.stage, queue: true, endpoint: _endpoint, fn_index }); if (data2 && [ "sse_v2", "sse_v2.1", "sse_v3" ].includes(protocol)) { applyDiffStream( pendingDiffStreams, eventId, data2 ); } } if (data2) { fireEvent({ type: "data", time: /* @__PURE__ */ new Date(), data: handlePayload( data2.data, dependency, config.components, "output", options.with_null_state ), endpoint: _endpoint, fn_index }); if (complete) { fireEvent({ type: "status", time: /* @__PURE__ */ new Date(), ...complete, stage: status2?.stage, queue: true, endpoint: _endpoint, fn_index }); close(); } } if (status2?.stage === "complete" || status2?.stage === "error") { if (eventCallbacks[eventId]) { delete eventCallbacks[eventId]; } if (eventId in pendingDiffStreams) { delete pendingDiffStreams[eventId]; } } } catch (e) { that.ctx.logger.error( "Unexpected client exception", e ); fireEvent({ type: "status", stage: "error", message: "An Unexpected Error Occurred!", queue: true, endpoint: _endpoint, fn_index, time: /* @__PURE__ */ new Date() }); if ([ "sse_v2", "sse_v2.1", "sse_v3" ].includes(protocol)) { closeStream( streamStatus, that.abortController ); streamStatus.open = false; close(); } } }, "callback"); if (eventId in pendingStreamMessages) { pendingStreamMessages[eventId].forEach( (msg) => callback(msg) ); delete pendingStreamMessages[eventId]; } eventCallbacks[eventId] = callback; unclosedEvents.add(eventId); if (!streamStatus.open) { await this.openStream(); } } }); } } ); const iterator = {