Skip to content

Commit

Permalink
Merge pull request #24 from jtydhr88/webui-plugin
Browse files Browse the repository at this point in the history
Support local inference via the A1111 plugin
  • Loading branch information
cruhl authored May 24, 2023
2 parents 9f35bf3 + 3dc0e66 commit 552ddb4
Show file tree
Hide file tree
Showing 9 changed files with 674 additions and 13 deletions.
18 changes: 8 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,16 @@
<img src="./misc/GenerateScreenshot.png" style="width: 400px; max-width: 600px; flex-grow: 1;" />
<img src="./misc/EditScreenshot.png" style="width: 400px; max-width: 600px; flex-grow: 1;" />

<h3>
<span>👋 Welcome to StableStudio, the open-source version of <a href="https://dreamstudio.ai" target="_blank">DreamStudio</a></span>
<h3>👋 Welcome to StableStudio, the open-source version of <a href="https://dreamstudio.ai" target="_blank">DreamStudio</a>!</h3>

**🗺 Contents – [🚀 Quick Start](#quick-start) · [ℹ️ About](#about) · [🙋 FAQ](#faq) · [🧑‍💻 Contributing](#contributing)**

**📚 Documentation – [🎨 UI](./packages/stablestudio-ui/README.md) · [🔌 Plugins](./packages/stablestudio-plugin/README.md) · <a href="https://platform.stability.ai" target="_blank">⚡️ platform.stability.ai</a>**

**🔗 Links – <a href="https://discord.com/channels/1002292111942635562/1108055793674227782" target="_blank">🎮 Discord</a> · <a href="https://dreamstudio.ai" target="_blank">🌈 DreamStudio</a> · <a href="https://github.com/Stability-AI/StableStudio/issues">🛟 Bugs & Support</a> · <a href="https://github.com/Stability-AI/StableStudio/discussions">💬 Discussion</a>**

<br />
<br />
<span>[ <a href="./packages/stablestudio-ui/README.md">🎨 UI README</a> ]</span>
<span>[ <a href="./packages/stablestudio-plugin/README.md" href="./packages/stablestudio-ui/README.md">🔌 Plugins README</a> ]</span>
<span>[ <a href="https://discord.gg/stablediffusion" target="_blank">🎮 Discord</a> ]</span>
<span>[ <a href="https://github.com/Stability-AI/StableStudio/issues">🛟 Bugs & Support</a> ]</span>
<span>[ <a href="https://github.com/Stability-AI/StableStudio/discussions">💬 Discussion</a> ]</span>
</h3>

<hr />

</div>

Expand Down
Binary file added misc/Electric1111.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
68 changes: 67 additions & 1 deletion packages/stablestudio-plugin-webui/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,67 @@
Soon™️
<div align="center">

# 🔌 [`stable-diffusion-webui`](https://github.com/AUTOMATIC1111/stable-diffusion-webui) Plugin

**🗺 Contents – [ℹ️ About](#about) · [⚙️ Usage](#usage) · [⭐️ Features](#features)**

**[⬆️ Top-Level README](../../README.md)**

![Electric1111](../../misc/Electric1111.png)

</div>

# <a id="about" href="#about">ℹ️ About</a>

This plugin enables StableStudio to run using [`stable-diffusion-webui`](https://github.com/AUTOMATIC1111/stable-diffusion-webui), which means you can generate images entirely on your own machine!

Thanks goes to [Terry Jia](https://github.com/jtydhr88) for the original work on this plugin.

# <a id="usage" href="#usage">⚙️ Usage</a>

1. First, you'll need to configure your local installation of `stable-diffusion-webui` to run without the UI and with CORS enabled.

**Windows**

Edit the command line arguments within `webui-user.bat`:

```
set COMMANDLINE_ARGS=--nowebui --cors-allow-origins=http://localhost:3000
```

**Mac**

Edit the command line arguments within `webui-macos-env.sh`:

```
export COMMANDLINE_ARGS="--nowebui --cors-allow-origins=http://localhost:3000"
```

2. Start `stable-diffusion-webui` and look for `INFO: Uvicorn running on http://127.0.0.1:7861`.

You can make sure everything is running correctly by checking to see if [`http://127.0.0.1:7861/docs`](http://127.0.0.1:7861/docs) displays API documentation.

3. Within your installation of StableStudio, run `yarn dev:use-webui-plugin`.

_**That's it!**_ 🎉 You should now be able to generate images using your local machine.

## <a id="image-history" href="#image-history">💾 Image History</a>

To persist your image history, you'll need to install the [`sd-webui-StableStudio`](https://github.com/jtydhr88/sd-webui-StableStudio) extension for `stable-diffusion-webui`.

> 🛑 Be wary installing third-party extensions for `stable-diffusion-webui`, it's always a good idea to check before running untrusted code.
# <a id="features" href="#features">⭐️ Features</a>

Missing something? Please [let us know](https://github.com/Stability-AI/StableStudio/issues/new/choose)!

- [x] Text-to-image
- [x] Image-to-image
- [x] Basic features (prompt, negative prompt, steps, batch size, image size)
- [x] Model selection
- [x] Sampler selection
- [x] Masking, in-painting, and out-painting
- [x] Settings storage
- [x] Accurate plugin status
- [x] [Loading existing images]("#image-history)
- [x] Upscaling
- [ ] Lora support
184 changes: 184 additions & 0 deletions packages/stablestudio-plugin-webui/src/Utilities.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
import { StableDiffusionInput } from "@stability/stablestudio-plugin";

export function base64ToBlob(base64: string, contentType = ""): Promise<Blob> {
return fetch(`data:${contentType};base64,${base64}`).then((res) =>
res.blob()
);
}

export function blobToBase64(blob: Blob): Promise<string> {
return new Promise((resolve, reject) => {
const reader = new FileReader();

reader.onloadend = () => resolve(reader.result as string);
reader.onerror = reject;

reader.readAsDataURL(blob);
});
}

export async function fetchOptions(baseUrl: string | undefined) {
const optionsResponse = await fetch(`${baseUrl}/sdapi/v1/options`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});

return await optionsResponse.json();
}

export async function setOptions(baseUrl: string | undefined, options: any) {
const optionsResponse = await fetch(`${baseUrl}/sdapi/v1/options`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(options),
});

return await optionsResponse.json();
}

export async function getImageInfo(
baseUrl: string | undefined,
base64image: any
) {
const imageInfoResponse = await fetch(`${baseUrl}/sdapi/v1/png-info`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ image: base64image }),
});

const imageInfoJson = await imageInfoResponse.json();

const info = imageInfoJson.info.split("\n");

const data: any = {};

if (info.length === 0) {
return data;
}

data.prompt = info[0];

let detailIndex = 1;

if (info.length === 3) {
data.nagtivePrompt = info[1].split(":")[1].trim();

detailIndex = 2;
}

const details = info[detailIndex].split(",");

details.map((detail: any) => {
const detailInfo = detail.trim().split(":");

data[detailInfo[0]] = detailInfo[1].trim();
});

return data;
}

export async function testForHistoryPlugin(webuiHostUrl: string) {
// timeout after 1 second
const finished = Promise.race([
fetch(`${webuiHostUrl}/StableStudio/get-generated-images`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
limit: 1,
}),
}),
new Promise((_, reject) =>
setTimeout(() => reject(new Error("Request timed out")), 1000)
),
]);

try {
await finished;
return (finished as any).ok;
} catch (error) {
return false;
}
}

export async function constructPayload(
options: {
input?: StableDiffusionInput | undefined;
count?: number | undefined;
},
isUpscale = false,
upscaler: string | undefined
) {
const { sampler, prompts, initialImage, maskImage, width, height, steps } =
options?.input ?? {};

// Construct payload
const data: any = {
seed: options?.input?.seed === 0 ? -1 : options?.input?.seed,
cfgScale: options?.input?.cfgScale ?? 7,
};

if (isUpscale) {
/*
Upscaling values
*/

data.upscaling_resize_w = width ?? 512;
data.upscaling_resize_h = height ?? 512;
data.upscaler_1 = upscaler;
} else {
/*
regular image generation values
*/

data.width = width ?? 512;
data.height = height ?? 512;

data.sampler_name = sampler?.name ?? "";
data.sampler_index = sampler?.name ?? "";

data.prompt =
prompts?.find((p) => (p.text && (p.weight ?? 0) > 0) ?? 0 > 0)?.text ??
"";
data.negative_prompt =
prompts?.find((p) => (p.text && (p.weight ?? 0) < 0) ?? 0 < 0)?.text ??
"";

data.steps = steps ?? 20;
data.batch_size = options?.count;
data.save_images = true;
}

if (initialImage?.weight && !isUpscale) {
data.denoising_strength = 1 - initialImage.weight;
}

if (initialImage?.blob) {
const initImgB64 = await blobToBase64(initialImage?.blob);

if (isUpscale) {
data.image = initImgB64.split(",")[1];
} else {
data.init_images = [initImgB64.split(",")[1]];
}
}

if (maskImage?.blob) {
const maskImgB64 = await blobToBase64(maskImage?.blob);

data.mask = maskImgB64.split(",")[1];

data.inpainting_mask_invert = 1; // Mask mode
data.inpainting_fill = 1; // Masked content
data.inpaint_full_res = false; // Inpaint area
}

return data;
}
Loading

0 comments on commit 552ddb4

Please sign in to comment.