Snapshot of ~1 year of accumulated work prior to restructuring: smart loaders merge, checkpoint loader/saver, live preview, model storage auto-registration, LTX2 power lora loader, and misc web UI. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
139 lines
4.0 KiB
JavaScript
139 lines
4.0 KiB
JavaScript
class MxdApi {
|
|
constructor(baseUrl) {
|
|
this.getLorasPromise = null;
|
|
this.filenamesPromises = {};
|
|
this.setBaseUrl(baseUrl);
|
|
}
|
|
|
|
setBaseUrl(baseUrlArg) {
|
|
let baseUrl = null;
|
|
if (baseUrlArg) {
|
|
baseUrl = baseUrlArg;
|
|
} else if (window.location.pathname.includes("/loraloader-mxd/")) {
|
|
const parts = window.location.pathname.split("/loraloader-mxd/")[1]?.split("/");
|
|
if (parts && parts.length) {
|
|
baseUrl = parts.map(() => "../").join("") + "loraloader-mxd/api";
|
|
}
|
|
}
|
|
this.baseUrl = baseUrl || "./loraloader-mxd/api";
|
|
const comfyBasePathname = location.pathname.includes("/loraloader-mxd/")
|
|
? location.pathname.split("loraloader-mxd/")[0]
|
|
: location.pathname;
|
|
this.comfyBaseUrl = comfyBasePathname.split("/").slice(0, -1).join("/");
|
|
}
|
|
|
|
apiURL(route) {
|
|
return `${this.baseUrl}${route}`;
|
|
}
|
|
|
|
fetchApi(route, options) {
|
|
return fetch(this.apiURL(route), options);
|
|
}
|
|
|
|
async fetchJson(route, options) {
|
|
const r = await this.fetchApi(route, options);
|
|
return await r.json();
|
|
}
|
|
|
|
async postJson(route, json) {
|
|
const body = new FormData();
|
|
body.append("json", JSON.stringify(json));
|
|
return await this.fetchJson(route, { method: "POST", body });
|
|
}
|
|
|
|
getLoras(force = false) {
|
|
if (!this.getLorasPromise || force) {
|
|
this.getLorasPromise = this.fetchJson("/loras?format=details", { cache: "no-store" });
|
|
}
|
|
return this.getLorasPromise;
|
|
}
|
|
|
|
getFilenames(type, force = false) {
|
|
if (!this.filenamesPromises[type] || force) {
|
|
this.filenamesPromises[type] = this.fetchJson(`/${type}`, { cache: "no-store" });
|
|
}
|
|
return this.filenamesPromises[type];
|
|
}
|
|
|
|
async getUnetModelList(force = false) {
|
|
const [standard, gguf] = await Promise.all([
|
|
this.getFilenames("diffusion_models", force),
|
|
this.getFilenames("unet_gguf", force),
|
|
]);
|
|
return [...new Set([...standard, ...gguf])].sort();
|
|
}
|
|
|
|
async getClipModelList(force = false) {
|
|
const [standard, gguf] = await Promise.all([
|
|
this.getFilenames("text_encoders", force),
|
|
this.getFilenames("clip_gguf", force),
|
|
]);
|
|
return [...new Set([...standard, ...gguf])].sort();
|
|
}
|
|
|
|
getCheckpointList(force = false) {
|
|
return this.getFilenames("checkpoints", force);
|
|
}
|
|
|
|
async fetchApiJsonOrNull(route, options) {
|
|
const response = await this.fetchJson(route, options);
|
|
if (response.status === 200 && response.data) {
|
|
return response.data || null;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
async getModelsInfo(options) {
|
|
const params = new URLSearchParams();
|
|
if (options.files?.length) {
|
|
params.set("files", options.files.join(","));
|
|
}
|
|
if (options.light) {
|
|
params.set("light", "1");
|
|
}
|
|
if (options.format) {
|
|
params.set("format", options.format);
|
|
}
|
|
const path = `/${options.type}/info?` + params.toString();
|
|
return (await this.fetchApiJsonOrNull(path)) || [];
|
|
}
|
|
|
|
async refreshModelsInfo(options) {
|
|
const params = new URLSearchParams();
|
|
if (options.files?.length) {
|
|
params.set("files", options.files.join(","));
|
|
}
|
|
const path = `/${options.type}/info/refresh?` + params.toString();
|
|
return await this.fetchApiJsonOrNull(path);
|
|
}
|
|
|
|
async clearModelsInfo(options) {
|
|
const params = new URLSearchParams();
|
|
if (options.files?.length) {
|
|
params.set("files", options.files.join(","));
|
|
}
|
|
const path = `/${options.type}/info/clear?` + params.toString();
|
|
await this.fetchApiJsonOrNull(path);
|
|
}
|
|
|
|
async saveModelInfo(type, file, data) {
|
|
const body = new FormData();
|
|
body.append("json", JSON.stringify(data));
|
|
return await this.fetchApiJsonOrNull(`/${type}/info?file=${encodeURIComponent(file)}`, {
|
|
cache: "no-store",
|
|
method: "POST",
|
|
body,
|
|
});
|
|
}
|
|
|
|
fetchComfyApi(route, options) {
|
|
const url = this.comfyBaseUrl + "/api" + route;
|
|
const opts = options || {};
|
|
opts.headers = opts.headers || {};
|
|
opts.cache = opts.cache || "no-cache";
|
|
return fetch(url, opts);
|
|
}
|
|
}
|
|
|
|
export const mxdApi = new MxdApi();
|