koishi-plugin-gradio-service
Version:
Provider @gradio/client support for Koishi
1,610 lines (1,600 loc) • 62.9 kB
JavaScript
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 = {