xray918's picture
Upload folder using huggingface_hub
0ad74ed verified
import {
type ApiData,
type BlobRef,
type Config,
type EndpointInfo,
type JsApiData,
type DataType,
Command,
type Dependency,
type ComponentMeta
} from "../types";
import { FileData } from "../upload";
const is_node =
typeof process !== "undefined" && process.versions && process.versions.node;
export function update_object(
object: { [x: string]: any },
newValue: any,
stack: (string | number)[]
): void {
while (stack.length > 1) {
const key = stack.shift();
if (typeof key === "string" || typeof key === "number") {
object = object[key];
} 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");
}
}
export async function walk_and_store_blobs(
data: DataType,
type: string | undefined = undefined,
path: string[] = [],
root = false,
endpoint_info: EndpointInfo<ApiData | JsApiData> | undefined = undefined
): Promise<BlobRef[]> {
if (Array.isArray(data)) {
let blob_refs: BlobRef[] = [];
await Promise.all(
data.map(async (_, index) => {
let new_path = path.slice();
new_path.push(String(index));
const array_refs = await walk_and_store_blobs(
data[index],
root
? endpoint_info?.parameters[index]?.component || undefined
: type,
new_path,
false,
endpoint_info
);
blob_refs = blob_refs.concat(array_refs);
})
);
return blob_refs;
} else if (
(globalThis.Buffer && data instanceof globalThis.Buffer) ||
data instanceof Blob
) {
return [
{
path: path,
blob: new Blob([data]),
type
}
];
} else if (typeof data === "object" && data !== null) {
let blob_refs: BlobRef[] = [];
for (const key of Object.keys(data) as (keyof typeof data)[]) {
const new_path = [...path, key];
const value = data[key];
blob_refs = blob_refs.concat(
await walk_and_store_blobs(
value,
undefined,
new_path,
false,
endpoint_info
)
);
}
return blob_refs;
}
return [];
}
export function skip_queue(id: number, config: Config): boolean {
let fn_queue = config?.dependencies?.find((dep) => dep.id == id)?.queue;
if (fn_queue != null) {
return !fn_queue;
}
return !config.enable_queue;
}
// todo: add jsdoc for this function
export function post_message<Res = any>(
message: any,
origin: string
): Promise<Res> {
return new Promise((res, _rej) => {
const channel = new MessageChannel();
channel.port1.onmessage = (({ data }) => {
channel.port1.close();
res(data);
}) as (ev: MessageEvent<Res>) => void;
window.parent.postMessage(message, origin, [channel.port2]);
});
}
export function handle_file(
file_or_url: File | string | Blob | Buffer
): FileData | Blob | Command {
if (typeof file_or_url === "string") {
if (
file_or_url.startsWith("http://") ||
file_or_url.startsWith("https://")
) {
return {
path: file_or_url,
url: file_or_url,
orig_name: file_or_url.split("/").pop() ?? "unknown",
meta: { _type: "gradio.FileData" }
};
}
if (is_node) {
// Handle local file paths
return new Command("upload_file", {
path: file_or_url,
name: file_or_url,
orig_path: file_or_url
});
}
} else if (typeof File !== "undefined" && file_or_url instanceof File) {
return new Blob([file_or_url]);
} else if (file_or_url instanceof Buffer) {
return new Blob([file_or_url]);
} else if (file_or_url instanceof Blob) {
return file_or_url;
}
throw new Error(
"Invalid input: must be a URL, File, Blob, or Buffer object."
);
}
/**
* Handles the payload by filtering out state inputs and returning an array of resolved payload values.
* We send null values for state inputs to the server, but we don't want to include them in the resolved payload.
*
* @param resolved_payload - The resolved payload values received from the client or the server
* @param dependency - The dependency object.
* @param components - The array of component metadata.
* @param with_null_state - Optional. Specifies whether to include null values for state inputs. Default is false.
* @returns An array of resolved payload values, filtered based on the dependency and component metadata.
*/
export function handle_payload(
resolved_payload: unknown[],
dependency: Dependency,
components: ComponentMeta[],
type: "input" | "output",
with_null_state = false
): unknown[] {
if (type === "input" && !with_null_state) {
throw new Error("Invalid code path. Cannot skip state inputs for input.");
}
// data comes from the server with null state values so we skip
if (type === "output" && with_null_state) {
return resolved_payload;
}
let updated_payload: unknown[] = [];
let payload_index = 0;
const deps = type === "input" ? dependency.inputs : dependency.outputs;
for (let i = 0; i < deps.length; i++) {
const input_id = deps[i];
const component = components.find((c) => c.id === input_id);
if (component?.type === "state") {
// input + with_null_state needs us to fill state with null values
if (with_null_state) {
if (resolved_payload.length === deps.length) {
const value = resolved_payload[payload_index];
updated_payload.push(value);
payload_index++;
} else {
updated_payload.push(null);
}
} else {
// this is output & !with_null_state, we skip state inputs
// the server payload always comes with null state values so we move along the payload index
payload_index++;
continue;
}
// input & !with_null_state isn't a case we care about, server needs null
continue;
} else {
const value = resolved_payload[payload_index];
updated_payload.push(value);
payload_index++;
}
}
return updated_payload;
}