diff --git a/src/lib/Setting/Pages/OtherBotSettings.svelte b/src/lib/Setting/Pages/OtherBotSettings.svelte index 5cc25c17..6a9154b3 100644 --- a/src/lib/Setting/Pages/OtherBotSettings.svelte +++ b/src/lib/Setting/Pages/OtherBotSettings.svelte @@ -46,6 +46,7 @@ Novel AI Dall-E Stability API + ComfyUI {#if $DataBase.sdProvider === 'webui'} @@ -243,6 +244,28 @@ {/if} {/if} + + {#if $DataBase.sdProvider === 'comfy'} + The first image generated by the prompt will be selected. + {#if !isTauri} + "Please run comfyUI with --enable-cors-header." + {/if} + ComfyUI {language.providerURL} + + Workflow + + + Positive Text Node: ID + + Positive Text Node: Input Field Name + + Negative Text Node: ID + + Positive Text Node: Input Field Name + + Timeout (sec) + + {/if} @@ -370,4 +393,4 @@ {/if} - \ No newline at end of file + diff --git a/src/ts/process/stableDiff.ts b/src/ts/process/stableDiff.ts index aadd9705..fea4138c 100644 --- a/src/ts/process/stableDiff.ts +++ b/src/ts/process/stableDiff.ts @@ -413,6 +413,80 @@ export async function generateAIImage(genPrompt:string, currentChar:character, n return returnSdData + } + if(db.sdProvider === 'comfy'){ + const {workflow, posNodeID, posInputName, negNodeID, negInputName} = db.comfyConfig + const baseUrl = new URL(db.comfyUiUrl) + + const createUrl = (pathname: string, params: Record = {}) => { + const url = new URL(pathname, baseUrl) + url.search = new URLSearchParams(params).toString() + return url.toString() + } + + const fetchWrapper = async (url: string, options = {}) => { + console.log(url) + const response = await globalFetch(url, options) + if (!response.ok) { + console.log(JSON.stringify(response.data)) + throw new Error(JSON.stringify(response.data)) + } + return response.data + } + + try { + const prompt = JSON.parse(workflow) + prompt[posNodeID].inputs[posInputName] = genPrompt + prompt[negNodeID].inputs[negInputName] = neg + + const { prompt_id: id } = await fetchWrapper(createUrl('/prompt'), { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: { 'prompt': prompt } + }) + console.log(`prompt id: ${id}`) + + let item + + const startTime = Date.now() + const timeout = db.comfyConfig.timeout * 1000 + while (!(item = (await (await fetch(createUrl('/history'), { + headers: { 'Content-Type': 'application/json' }, + method: 'GET'})).json())[id])) { + console.log("Checking /history...") + if (Date.now() - startTime >= timeout) { + alertError("Error: Image generation took longer than expected."); + return false + } + await new Promise(r => setTimeout(r, 1000)) + } // Check history until the generation is complete. + const genImgInfo = Object.values(item.outputs).flatMap((output: any) => output.images)[0]; + + const imgResponse = await fetch(createUrl('/view', { + filename: genImgInfo.filename, + subfolder: genImgInfo.subfolder, + type: genImgInfo.type + }), { + headers: { 'Content-Type': 'application/json' }, + method: 'GET'}) + const img64 = Buffer.from(await imgResponse.arrayBuffer()).toString('base64') + + if(returnSdData === 'inlay'){ + return `data:image/png;base64,${img64}` + } + else { + let charemotions = get(CharEmotion) + const img = `data:image/png;base64,${img64}` + const emos:[string, string,number][] = [[img, img, Date.now()]] + charemotions[currentChar.chaId] = emos + CharEmotion.set(charemotions) + } + + return returnSdData + } catch (error) { + alertError(error) + return false + } } return '' -} \ No newline at end of file +} diff --git a/src/ts/storage/database.ts b/src/ts/storage/database.ts index 73e2d7ef..070812ee 100644 --- a/src/ts/storage/database.ts +++ b/src/ts/storage/database.ts @@ -419,6 +419,16 @@ export function setDatabase(data:Database){ data.stabilityModel ??= 'sd3-large' data.stabllityStyle ??= '' data.legacyTranslation ??= false + data.comfyUiUrl ??= 'http://localhost:8188' + data.comfyConfig ??= { + workflow: '', + posNodeID: '', + posInputName: 'text', + negNodeID: '', + negInputName: 'text', + timeout: 30 + } + changeLanguage(data.language) DataBase.set(data) } @@ -695,6 +705,8 @@ export interface Database{ stabilityKey: string stabllityStyle: string legacyTranslation: boolean + comfyConfig: ComfyConfig + comfyUiUrl: string } export interface customscript{ @@ -967,6 +979,16 @@ interface NAIImgConfig{ InfoExtracted:number, RefStrength:number } + +interface ComfyConfig{ + workflow:string, + posNodeID: string, + posInputName:string, + negNodeID: string, + negInputName:string, + timeout: number +} + export type FormatingOrderItem = 'main'|'jailbreak'|'chats'|'lorebook'|'globalNote'|'authorNote'|'lastChat'|'description'|'postEverything'|'personaPrompt' export interface Chat{ @@ -1486,4 +1508,4 @@ export async function importPreset(f:{ pre.name ??= "Imported" db.botPresets.push(pre) setDatabase(db) -} \ No newline at end of file +}