| import type {RgthreeModelInfo} from "typings/rgthree.js"; |
|
|
| export type ModelInfoType = "loras" | "checkpoints"; |
|
|
| type ModelsOptions = { |
| type: ModelInfoType; |
| files?: string[]; |
| }; |
|
|
| type GetModelsOptions = ModelsOptions & { |
| type: ModelInfoType; |
| files?: string[]; |
| format?: null | "details"; |
| }; |
|
|
| type GetModelsInfoOptions = GetModelsOptions & { |
| light?: boolean; |
| }; |
|
|
| type GetModelsResponseDetails = { |
| file: string; |
| modified: number; |
| has_info: boolean; |
| image?: string; |
| }; |
|
|
| class RgthreeApi { |
| private baseUrl!: string; |
| private comfyBaseUrl!: string; |
| getCheckpointsPromise: Promise<string[]> | null = null; |
| getSamplersPromise: Promise<string[]> | null = null; |
| getSchedulersPromise: Promise<string[]> | null = null; |
| getLorasPromise: Promise<GetModelsResponseDetails[]> | null = null; |
| getWorkflowsPromise: Promise<string[]> | null = null; |
|
|
| constructor(baseUrl?: string) { |
| this.setBaseUrl(baseUrl); |
| } |
|
|
| setBaseUrl(baseUrlArg?: string) { |
| let baseUrl = null; |
| if (baseUrlArg) { |
| baseUrl = baseUrlArg; |
| } else if (window.location.pathname.includes("/rgthree/")) { |
| |
| const parts = window.location.pathname.split("/rgthree/")[1]?.split("/"); |
| if (parts && parts.length) { |
| baseUrl = parts.map(() => "../").join("") + "rgthree/api"; |
| } |
| } |
| this.baseUrl = baseUrl || "./rgthree/api"; |
|
|
| |
| |
| |
| const comfyBasePathname = location.pathname.includes("/rgthree/") |
| ? location.pathname.split("rgthree/")[0]! |
| : location.pathname; |
| this.comfyBaseUrl = comfyBasePathname.split("/").slice(0, -1).join("/"); |
| } |
|
|
| apiURL(route: string) { |
| return `${this.baseUrl}${route}`; |
| } |
|
|
| fetchApi(route: string, options?: RequestInit) { |
| return fetch(this.apiURL(route), options); |
| } |
|
|
| async fetchJson(route: string, options?: RequestInit) { |
| const r = await this.fetchApi(route, options); |
| return await r.json(); |
| } |
|
|
| async postJson(route: string, json: any) { |
| const body = new FormData(); |
| body.append("json", JSON.stringify(json)); |
| return await rgthreeApi.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; |
| } |
|
|
| async fetchApiJsonOrNull<T>(route: string, options?: RequestInit) { |
| const response = await this.fetchJson(route, options); |
| if (response.status === 200 && response.data) { |
| return (response.data as T) || null; |
| } |
| return null; |
| } |
|
|
| |
| |
| |
| |
| |
| |
|
|
| async getModelsInfo(options: GetModelsInfoOptions): Promise<RgthreeModelInfo[]> { |
| 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<RgthreeModelInfo[]>(path)) || []; |
| } |
| async getLorasInfo(options: Omit<GetModelsInfoOptions, "type"> = {}) { |
| return this.getModelsInfo({type: "loras", ...options}); |
| } |
| async getCheckpointsInfo(options: Omit<GetModelsInfoOptions, "type"> = {}) { |
| return this.getModelsInfo({type: "checkpoints", ...options}); |
| } |
|
|
| async refreshModelsInfo(options: ModelsOptions) { |
| const params = new URLSearchParams(); |
| if (options.files?.length) { |
| params.set("files", options.files.join(",")); |
| } |
| const path = `/${options.type}/info/refresh?` + params.toString(); |
| const infos = await this.fetchApiJsonOrNull<RgthreeModelInfo[]>(path); |
| return infos; |
| } |
| async refreshLorasInfo(options: Omit<ModelsOptions, "type"> = {}) { |
| return this.refreshModelsInfo({type: "loras", ...options}); |
| } |
| async refreshCheckpointsInfo(options: Omit<ModelsOptions, "type"> = {}) { |
| return this.refreshModelsInfo({type: "checkpoints", ...options}); |
| } |
|
|
| async clearModelsInfo(options: ModelsOptions) { |
| 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<RgthreeModelInfo[]>(path); |
| return; |
| } |
| async clearLorasInfo(options: Omit<ModelsOptions, "type"> = {}) { |
| return this.clearModelsInfo({type: "loras", ...options}); |
| } |
| async clearCheckpointsInfo(options: Omit<ModelsOptions, "type"> = {}) { |
| return this.clearModelsInfo({type: "checkpoints", ...options}); |
| } |
|
|
| |
| |
| |
| async saveModelInfo( |
| type: ModelInfoType, |
| file: string, |
| data: Partial<RgthreeModelInfo>, |
| ): Promise<RgthreeModelInfo | null> { |
| const body = new FormData(); |
| body.append("json", JSON.stringify(data)); |
| return await this.fetchApiJsonOrNull<RgthreeModelInfo>( |
| `/${type}/info?file=${encodeURIComponent(file)}`, |
| {cache: "no-store", method: "POST", body}, |
| ); |
| } |
|
|
| async saveLoraInfo( |
| file: string, |
| data: Partial<RgthreeModelInfo>, |
| ): Promise<RgthreeModelInfo | null> { |
| return this.saveModelInfo("loras", file, data); |
| } |
|
|
| async saveCheckpointsInfo( |
| file: string, |
| data: Partial<RgthreeModelInfo>, |
| ): Promise<RgthreeModelInfo | null> { |
| return this.saveModelInfo("checkpoints", file, data); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| fetchComfyApi(route: string, options?: any): Promise<any> { |
| const url = this.comfyBaseUrl + "/api" + route; |
| options = options || {}; |
| options.headers = options.headers || {}; |
| options.cache = options.cache || "no-cache"; |
| return fetch(url, options); |
| } |
|
|
| |
| |
| |
| print(messageType: string) { |
| this.fetchApi(`/print?type=${messageType}`, {}) |
| } |
| } |
|
|
| export const rgthreeApi = new RgthreeApi(); |
|
|