|
|
|
|
|
import type {
|
|
create as createLiteAppFunc,
|
|
Options,
|
|
GradioAppController
|
|
} from "..";
|
|
import { clean_indent } from "./indent";
|
|
|
|
interface GradioComponentOptions {
|
|
info: Options["info"];
|
|
container: Options["container"];
|
|
isEmbed: Options["isEmbed"];
|
|
initialHeight?: Options["initialHeight"];
|
|
eager: Options["eager"];
|
|
themeMode: Options["themeMode"];
|
|
autoScroll: Options["autoScroll"];
|
|
controlPageTitle: Options["controlPageTitle"];
|
|
appMode: Options["appMode"];
|
|
sharedWorkerMode?: Options["sharedWorkerMode"];
|
|
}
|
|
|
|
interface GradioLiteAppOptions {
|
|
files?: Options["files"];
|
|
requirements?: Options["requirements"];
|
|
code?: Options["code"];
|
|
entrypoint?: Options["entrypoint"];
|
|
}
|
|
|
|
function parseRequirementsTxt(content: string): string[] {
|
|
return content
|
|
.split("\n")
|
|
.filter((r) => !r.startsWith("#"))
|
|
.map((r) => r.trim())
|
|
.filter((r) => r !== "");
|
|
}
|
|
|
|
export function bootstrap_custom_element(
|
|
create: typeof createLiteAppFunc
|
|
): void {
|
|
const CUSTOM_ELEMENT_NAME = "gradio-lite";
|
|
|
|
if (customElements.get(CUSTOM_ELEMENT_NAME)) {
|
|
return;
|
|
}
|
|
|
|
class GradioLiteAppElement extends HTMLElement {
|
|
controller: GradioAppController | null = null;
|
|
|
|
connectedCallback(): void {
|
|
|
|
|
|
|
|
window.requestAnimationFrame(() => {
|
|
const gradioComponentOptions = this.parseGradioComponentOptions();
|
|
const gradioLiteAppOptions = this.parseGradioLiteAppOptions();
|
|
|
|
this.innerHTML = "";
|
|
|
|
this.controller = create({
|
|
target: this,
|
|
code: gradioLiteAppOptions.code,
|
|
requirements: gradioLiteAppOptions.requirements,
|
|
files: gradioLiteAppOptions.files,
|
|
entrypoint: gradioLiteAppOptions.entrypoint,
|
|
playground: this.hasAttribute("playground"),
|
|
layout: this.getAttribute("layout"),
|
|
...gradioComponentOptions
|
|
});
|
|
});
|
|
}
|
|
|
|
disconnectedCallback(): void {
|
|
this.controller?.unmount();
|
|
}
|
|
|
|
parseGradioComponentOptions(): GradioComponentOptions {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const info = this.hasAttribute("info");
|
|
const container = this.hasAttribute("container");
|
|
const isEmbed = this.hasAttribute("embed");
|
|
const initialHeight = this.getAttribute("initial-height");
|
|
const eager = this.hasAttribute("eager");
|
|
const themeMode = this.getAttribute("theme");
|
|
const autoScroll = this.hasAttribute("auto-scroll");
|
|
const controlPageTitle = this.hasAttribute("control-page-title");
|
|
const appMode = this.hasAttribute("app-mode");
|
|
const sharedWorkerMode = this.hasAttribute("shared-worker");
|
|
|
|
return {
|
|
info,
|
|
container,
|
|
isEmbed,
|
|
initialHeight: initialHeight ?? undefined,
|
|
eager,
|
|
themeMode:
|
|
themeMode != null && ["light", "dark"].includes(themeMode)
|
|
? (themeMode as GradioComponentOptions["themeMode"])
|
|
: null,
|
|
autoScroll,
|
|
controlPageTitle,
|
|
appMode,
|
|
sharedWorkerMode
|
|
};
|
|
}
|
|
|
|
parseGradioLiteAppOptions(): GradioLiteAppOptions {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const options: GradioLiteAppOptions = {};
|
|
|
|
const fileElements = this.getElementsByTagName("gradio-file");
|
|
for (const fileElement of fileElements) {
|
|
const name = fileElement.getAttribute("name");
|
|
if (name == null) {
|
|
throw new Error("<gradio-file> must have the name attribute.");
|
|
}
|
|
|
|
const entrypoint = fileElement.hasAttribute("entrypoint");
|
|
const url = fileElement.getAttribute("url");
|
|
|
|
options.files ??= {};
|
|
if (url != null) {
|
|
options.files[name] = { url };
|
|
} else {
|
|
let data = fileElement.textContent ?? "";
|
|
if (name.endsWith(".py")) {
|
|
|
|
data = clean_indent(data);
|
|
}
|
|
options.files[name] = { data };
|
|
}
|
|
|
|
if (entrypoint) {
|
|
if (options.entrypoint != null) {
|
|
throw new Error("Multiple entrypoints are not allowed.");
|
|
}
|
|
options.entrypoint = name;
|
|
}
|
|
}
|
|
|
|
if (options.entrypoint == null) {
|
|
|
|
|
|
|
|
const codeElements = this.getElementsByTagName("gradio-code");
|
|
if (codeElements.length === 0) {
|
|
|
|
let code = "";
|
|
this.childNodes.forEach((node) => {
|
|
if (node.nodeType === Node.TEXT_NODE) {
|
|
code += node.textContent;
|
|
}
|
|
});
|
|
options.code = code || undefined;
|
|
} else {
|
|
if (codeElements.length > 1) {
|
|
console.warn(
|
|
"Multiple <gradio-code> elements are found. Only the first one will be used."
|
|
);
|
|
}
|
|
const firstCodeElement = codeElements[0];
|
|
options.code = firstCodeElement?.textContent ?? undefined;
|
|
}
|
|
options.code = options.code && clean_indent(options.code);
|
|
}
|
|
|
|
const requirementsElements = this.getElementsByTagName(
|
|
"gradio-requirements"
|
|
);
|
|
if (requirementsElements.length > 1) {
|
|
console.warn(
|
|
"Multiple <gradio-requirements> elements are found. Only the first one will be used."
|
|
);
|
|
}
|
|
const firstRequirementsElement = requirementsElements[0];
|
|
const requirementsTxt = firstRequirementsElement?.textContent ?? "";
|
|
options.requirements = parseRequirementsTxt(requirementsTxt);
|
|
return options;
|
|
}
|
|
}
|
|
|
|
customElements.define(CUSTOM_ELEMENT_NAME, GradioLiteAppElement);
|
|
}
|
|
|