diff --git a/package.json b/package.json index 52302fc..3748016 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "stablestudio-plugin-webui": "yarn workspace @stability/stablestudio-plugin-webui", "stablestudio-ui": "yarn workspace @stability/stablestudio-ui", "dev:use-example-plugin": "cross-env VITE_USE_EXAMPLE_PLUGIN=true yarn dev", + "dev:use-webui-plugin": "cross-env VITE_USE_WEBUI_PLUGIN=true yarn dev", "dev": "yarn workspaces foreach --all --interlaced --verbose --parallel --jobs unlimited run dev", "build": "yarn workspaces foreach --all --interlaced --verbose --jobs unlimited run build", "clean": "yarn workspaces foreach --all --interlaced --verbose --parallel --jobs unlimited run clean && rimraf node_modules" diff --git a/packages/stablestudio-plugin-webui/README.md b/packages/stablestudio-plugin-webui/README.md new file mode 100644 index 0000000..ac676fc --- /dev/null +++ b/packages/stablestudio-plugin-webui/README.md @@ -0,0 +1,23 @@ +This is a basic implement for stable-diffusion-webui plugin. + +# How to use +1. On stable-diffusion-webui side, edit webui-user.bat and +`set COMMANDLINE_ARGS=--nowebui --cors-allow-origins=http://localhost:3000` +Then start your webui. +2. Once you see **INFO: Uvicorn running on http://127.0.0.1:7861**, means you started webui on api mode successfully. +you can open http://127.0.0.1:7861/docs to double check. +3. On StableStudio side, run `yarn dev:use-webui-plugin` +4. once the server started, click settings to check this plugin loaded successfully or not. ![webui-plugin](docs/images/webui-plugin.png) +![overall](docs/images/overall.png) +5. click **Dream**, your webui server should start to process your request from StableStudio. + +Still, currently this plugin is a basic implement for webui, and only support a few of features: +- [x] txt2img +- [x] basic features (prompt, negative prompt, steps, batch_size, image size) +- [x] features provided by StableStudio +- [ ] model select +- [ ] sampler select +- [ ] img2img +- [ ] load existing images +- [ ] upscale +- [ ] many other features from webui... \ No newline at end of file diff --git a/packages/stablestudio-plugin-webui/docs/images/overall.png b/packages/stablestudio-plugin-webui/docs/images/overall.png new file mode 100644 index 0000000..ad8c0f9 Binary files /dev/null and b/packages/stablestudio-plugin-webui/docs/images/overall.png differ diff --git a/packages/stablestudio-plugin-webui/docs/images/webui-plugin.png b/packages/stablestudio-plugin-webui/docs/images/webui-plugin.png new file mode 100644 index 0000000..2b296eb Binary files /dev/null and b/packages/stablestudio-plugin-webui/docs/images/webui-plugin.png differ diff --git a/packages/stablestudio-plugin-webui/src/index.ts b/packages/stablestudio-plugin-webui/src/index.ts index 536a2bc..bf98461 100644 --- a/packages/stablestudio-plugin-webui/src/index.ts +++ b/packages/stablestudio-plugin-webui/src/index.ts @@ -1,3 +1,115 @@ import * as StableStudio from "@stability/stablestudio-plugin"; -export const createPlugin = StableStudio.createPlugin(() => ({})); +function base64ToBlob(base64: string, contentType = '', sliceSize = 512): Promise { + return fetch(`data:${contentType};base64,${base64}`).then(res => res.blob()); +} +const getStableDiffusionDefaultCount = () => 4; +export const createPlugin = StableStudio.createPlugin<{ + imagesGeneratedSoFar: number; + settings: { + exampleSetting: StableStudio.PluginSettingString; + }; +}>(({ set, get }) => ({ + imagesGeneratedSoFar: 0, + + manifest: { + name: "stable diffusion webui Plugin", + author: "Terry Jia", + link: "https://github.com/jtydhr88", + icon: `${window.location.origin}/DummyImage.png`, + version: "0.0.1", + license: "MIT", + description: "An plugin for Stable Diffusion webui", + }, + + createStableDiffusionImages: async (options) => { + console.log(options); + + const url = 'http://127.0.0.1:7861/sdapi/v1/txt2img'; + + const input = { + ...options?.input, + }; + + const prompts = input.prompts; + + const prompt = prompts?.at(0)?.text??""; + const negativePrompt = prompts?.at(1)?.text??""; + let seed = options?.input?.seed??-1; + + if (seed === 0) { + seed = -1; + } + + const data = { + "seed": seed, + "prompt": prompt, + "negative_prompt": negativePrompt, + "steps": options?.input?.steps??20, + "batch_size": options?.count ?? getStableDiffusionDefaultCount(), + "width": options?.input?.width??512, + "height": options?.input?.height??512, + }; + + const response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), + }); + + const responseData = await response.json(); + + const images = []; + + const createdAt = new Date(); + + for (let i = 0; i < responseData.images.length; i++) { + const blob = await base64ToBlob(responseData.images[i], 'image/jpeg'); + + const image = { + id: `${Math.random() * 10000000}`, + createdAt, + blob + } + + images.push(image) + } + + set(({ imagesGeneratedSoFar }) => ({ + imagesGeneratedSoFar: imagesGeneratedSoFar + 1, + })); + + return { + id: `${Math.random() * 10000000}`, + images: images + }; + }, + + getStatus: () => { + const { imagesGeneratedSoFar } = get(); + return { + indicator: "success", + text: + imagesGeneratedSoFar > 0 + ? `${imagesGeneratedSoFar} images generated` + : "Ready", + }; + }, + + settings: { + exampleSetting: { + type: "string" as const, + default: "Hello, World!", + placeholder: "Example setting", + }, + }, + + setSetting: (key, value) => + set(({ settings }) => ({ + settings: { + [key]: { ...settings[key], value: value as string }, + }, + })), +})); diff --git a/packages/stablestudio-ui/src/Environment/index.tsx b/packages/stablestudio-ui/src/Environment/index.tsx index e9842cc..5401368 100644 --- a/packages/stablestudio-ui/src/Environment/index.tsx +++ b/packages/stablestudio-ui/src/Environment/index.tsx @@ -8,6 +8,7 @@ declare global { interface ImportMetaEnv { readonly VITE_GIT_HASH: string; readonly VITE_USE_EXAMPLE_PLUGIN: string; + readonly VITE_USE_WEBUI_PLUGIN: string; } } @@ -20,6 +21,7 @@ export namespace Environment { const variables = { VITE_GIT_HASH: import.meta.env.VITE_GIT_HASH, VITE_USE_EXAMPLE_PLUGIN: import.meta.env.VITE_USE_EXAMPLE_PLUGIN ?? "false", + VITE_USE_WEBUI_PLUGIN: import.meta.env.VITE_USE_WEBUI_PLUGIN ?? "false", } as const; export function get(name: VariableName): string { diff --git a/packages/stablestudio-ui/src/Plugin/index.tsx b/packages/stablestudio-ui/src/Plugin/index.tsx index 31976d8..53f44ce 100644 --- a/packages/stablestudio-ui/src/Plugin/index.tsx +++ b/packages/stablestudio-ui/src/Plugin/index.tsx @@ -1,6 +1,7 @@ import * as StableStudio from "@stability/stablestudio-plugin"; import * as StableStudioPluginExample from "@stability/stablestudio-plugin-example"; import * as StableStudioPluginStability from "@stability/stablestudio-plugin-stability"; +import * as StableStudioPluginWebUI from "@stability/stablestudio-plugin-webui"; import { Environment } from "~/Environment"; import { Generation } from "~/Generation"; @@ -115,6 +116,8 @@ namespace State { const { createPlugin: createRootPlugin } = Environment.get("USE_EXAMPLE_PLUGIN") === "true" ? StableStudioPluginExample + : Environment.get("USE_WEBUI_PLUGIN") === "true" + ? StableStudioPluginWebUI : StableStudioPluginStability; return {