Spaces:
Running
on
Zero
Running
on
Zero
adamelliotfields
commited on
Commit
•
0d34381
1
Parent(s):
af35186
Sync with adamelliotfields/diffusion
Browse files- DOCS.md +8 -30
- README.md +3 -7
- app.css +7 -20
- app.py +169 -171
- data/prompts.json +23 -46
- data/styles.json +0 -136
- lib/__init__.py +2 -12
- lib/config.py +12 -20
- lib/inference.py +47 -86
- lib/loader.py +73 -72
- lib/logger.py +55 -0
- lib/utils.py +18 -32
- partials/intro.html +3 -14
- requirements.txt +6 -13
DOCS.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
-
|
2 |
|
3 |
TL;DR: Enter a prompt or roll the `🎲` and press `Generate`.
|
4 |
|
5 |
-
|
6 |
|
7 |
Positive and negative prompts are embedded by [Compel](https://github.com/damian0815/compel) for weighting. See [syntax features](https://github.com/damian0815/compel/blob/main/doc/syntax.md) to learn more.
|
8 |
|
@@ -10,52 +10,30 @@ Use `+` or `-` to increase the weight of a token. The weight grows exponentially
|
|
10 |
|
11 |
For groups of tokens, wrap them in parentheses and multiply by a float between 0 and 2. For example, `a (birthday cake)1.3 on a table` will increase the weight of both `birthday` and `cake` by 1.3x. This also means the entire scene will be more birthday-like, not just the cake. To counteract this, you can use `-` inside the parentheses on specific tokens, e.g., `a (birthday-- cake)1.3`, to reduce the birthday aspect.
|
12 |
|
13 |
-
|
14 |
-
|
15 |
-
| Compel | AUTOMATIC1111 |
|
16 |
-
| ----------- | ------------- |
|
17 |
-
| `blue++` | `((blue))` |
|
18 |
-
| `blue--` | `[[blue]]` |
|
19 |
-
| `(blue)1.2` | `(blue:1.2)` |
|
20 |
-
| `(blue)0.8` | `(blue:0.8)` |
|
21 |
-
|
22 |
-
### Arrays
|
23 |
-
|
24 |
-
Arrays allow you to generate multiple different images from a single prompt. For example, `an adult [[blonde,brunette]] [[man,woman]]` will expand into **4** different prompts. This implementation was inspired by [Fooocus](https://github.com/lllyasviel/Fooocus/pull/1503).
|
25 |
-
|
26 |
-
> NB: Make sure to set `Images` to the number of images you want to generate. Otherwise, only the first prompt will be used.
|
27 |
-
|
28 |
-
## Models
|
29 |
|
30 |
Each model checkpoint has a different aesthetic:
|
31 |
|
32 |
-
* [cagliostrolab/animagine-xl-3.1](https://huggingface.co/cagliostrolab/animagine-xl-3.1): anime
|
33 |
* [cyberdelia/CyberRealisticXL](https://huggingface.co/cyberdelia/CyberRealsticXL): photorealistic
|
34 |
* [fluently/Fluently-XL-Final](https://huggingface.co/fluently/Fluently-XL-Final): general purpose
|
35 |
* [segmind/Segmind-Vega](https://huggingface.co/segmind/Segmind-Vega): lightweight general purpose (default)
|
36 |
* [SG161222/RealVisXL_V5.0](https://huggingface.co/SG161222/RealVisXL_V5.0): photorealistic
|
37 |
* [stabilityai/stable-diffusion-xl-base-1.0](https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0): base
|
38 |
|
39 |
-
|
40 |
-
|
41 |
-
[Styles](https://huggingface.co/spaces/adamelliotfields/diffusion/blob/main/data/styles.json) are prompt templates that wrap your positive and negative prompts. They were originally derived from the [twri/sdxl_prompt_styler](https://github.com/twri/sdxl_prompt_styler) Comfy node, but have since been entirely rewritten.
|
42 |
-
|
43 |
-
Start by framing a simple subject like `portrait of a young adult woman` or `landscape of a mountain range` and experiment.
|
44 |
-
|
45 |
-
## Scale
|
46 |
|
47 |
Rescale up to 4x using [Real-ESRGAN](https://github.com/xinntao/Real-ESRGAN) with weights from [ai-forever](ai-forever/Real-ESRGAN). Necessary for high-resolution images.
|
48 |
|
49 |
-
|
50 |
|
51 |
-
|
52 |
|
53 |
-
[DeepCache](https://github.com/horseee/DeepCache) caches lower UNet layers and reuses them every
|
54 |
* `1`: no caching (default)
|
55 |
* `2`: more quality
|
56 |
* `3`: balanced
|
57 |
* `4`: more speed
|
58 |
|
59 |
-
|
60 |
|
61 |
Use the [ensemble of expert denoisers](https://research.nvidia.com/labs/dir/eDiff-I/) technique, where the first 80% of timesteps are denoised by the base model and the remaining 80% by the [refiner](https://huggingface.co/stabilityai/stable-diffusion-xl-refiner-1.0). Not available with image-to-image pipelines.
|
|
|
1 |
+
## Usage
|
2 |
|
3 |
TL;DR: Enter a prompt or roll the `🎲` and press `Generate`.
|
4 |
|
5 |
+
### Prompting
|
6 |
|
7 |
Positive and negative prompts are embedded by [Compel](https://github.com/damian0815/compel) for weighting. See [syntax features](https://github.com/damian0815/compel/blob/main/doc/syntax.md) to learn more.
|
8 |
|
|
|
10 |
|
11 |
For groups of tokens, wrap them in parentheses and multiply by a float between 0 and 2. For example, `a (birthday cake)1.3 on a table` will increase the weight of both `birthday` and `cake` by 1.3x. This also means the entire scene will be more birthday-like, not just the cake. To counteract this, you can use `-` inside the parentheses on specific tokens, e.g., `a (birthday-- cake)1.3`, to reduce the birthday aspect.
|
12 |
|
13 |
+
### Models
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
|
15 |
Each model checkpoint has a different aesthetic:
|
16 |
|
|
|
17 |
* [cyberdelia/CyberRealisticXL](https://huggingface.co/cyberdelia/CyberRealsticXL): photorealistic
|
18 |
* [fluently/Fluently-XL-Final](https://huggingface.co/fluently/Fluently-XL-Final): general purpose
|
19 |
* [segmind/Segmind-Vega](https://huggingface.co/segmind/Segmind-Vega): lightweight general purpose (default)
|
20 |
* [SG161222/RealVisXL_V5.0](https://huggingface.co/SG161222/RealVisXL_V5.0): photorealistic
|
21 |
* [stabilityai/stable-diffusion-xl-base-1.0](https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0): base
|
22 |
|
23 |
+
### Scale
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
|
25 |
Rescale up to 4x using [Real-ESRGAN](https://github.com/xinntao/Real-ESRGAN) with weights from [ai-forever](ai-forever/Real-ESRGAN). Necessary for high-resolution images.
|
26 |
|
27 |
+
### Advanced
|
28 |
|
29 |
+
#### DeepCache
|
30 |
|
31 |
+
[DeepCache](https://github.com/horseee/DeepCache) caches lower UNet layers and reuses them every _n_ steps. Trade quality for speed:
|
32 |
* `1`: no caching (default)
|
33 |
* `2`: more quality
|
34 |
* `3`: balanced
|
35 |
* `4`: more speed
|
36 |
|
37 |
+
#### Refiner
|
38 |
|
39 |
Use the [ensemble of expert denoisers](https://research.nvidia.com/labs/dir/eDiff-I/) technique, where the first 80% of timesteps are denoised by the base model and the remaining 80% by the [refiner](https://huggingface.co/stabilityai/stable-diffusion-xl-refiner-1.0). Not available with image-to-image pipelines.
|
README.md
CHANGED
@@ -6,16 +6,15 @@ emoji: 🦣
|
|
6 |
colorFrom: gray
|
7 |
colorTo: red
|
8 |
sdk: gradio
|
9 |
-
sdk_version: 4.
|
10 |
python_version: 3.11.9
|
11 |
app_file: app.py
|
12 |
fullWidth: false
|
13 |
-
pinned:
|
14 |
header: mini
|
15 |
license: apache-2.0
|
16 |
models:
|
17 |
- ai-forever/Real-ESRGAN
|
18 |
-
- cagliostrolab/animagine-xl-3.1
|
19 |
- cyberdelia/CyberRealsticXL
|
20 |
- fluently/Fluently-XL-Final
|
21 |
- madebyollin/sdxl-vae-fp16-fix
|
@@ -25,7 +24,6 @@ models:
|
|
25 |
- stabilityai/stable-diffusion-xl-refiner-1.0
|
26 |
preload_from_hub:
|
27 |
- ai-forever/Real-ESRGAN RealESRGAN_x2.pth,RealESRGAN_x4.pth
|
28 |
-
- cagliostrolab/animagine-xl-3.1 animagine-xl-3.1.safetensors
|
29 |
- cyberdelia/CyberRealsticXL CyberRealisticXLPlay_V1.0.safetensors
|
30 |
- fluently/Fluently-XL-Final FluentlyXL-Final.safetensors
|
31 |
- madebyollin/sdxl-vae-fp16-fix config.json,diffusion_pytorch_model.safetensors
|
@@ -46,9 +44,7 @@ preload_from_hub:
|
|
46 |
Gradio app for Stable Diffusion XL featuring:
|
47 |
|
48 |
* txt2img pipeline with refiner (img2img with IP-Adapter and ControlNet coming soon)
|
49 |
-
*
|
50 |
-
* Compel prompt weighting
|
51 |
-
* Dozens of styles and starter prompts
|
52 |
* Multiple samplers with Karras scheduling
|
53 |
* DeepCache available
|
54 |
* Real-ESRGAN upscaling
|
|
|
6 |
colorFrom: gray
|
7 |
colorTo: red
|
8 |
sdk: gradio
|
9 |
+
sdk_version: 4.44.1
|
10 |
python_version: 3.11.9
|
11 |
app_file: app.py
|
12 |
fullWidth: false
|
13 |
+
pinned: true
|
14 |
header: mini
|
15 |
license: apache-2.0
|
16 |
models:
|
17 |
- ai-forever/Real-ESRGAN
|
|
|
18 |
- cyberdelia/CyberRealsticXL
|
19 |
- fluently/Fluently-XL-Final
|
20 |
- madebyollin/sdxl-vae-fp16-fix
|
|
|
24 |
- stabilityai/stable-diffusion-xl-refiner-1.0
|
25 |
preload_from_hub:
|
26 |
- ai-forever/Real-ESRGAN RealESRGAN_x2.pth,RealESRGAN_x4.pth
|
|
|
27 |
- cyberdelia/CyberRealsticXL CyberRealisticXLPlay_V1.0.safetensors
|
28 |
- fluently/Fluently-XL-Final FluentlyXL-Final.safetensors
|
29 |
- madebyollin/sdxl-vae-fp16-fix config.json,diffusion_pytorch_model.safetensors
|
|
|
44 |
Gradio app for Stable Diffusion XL featuring:
|
45 |
|
46 |
* txt2img pipeline with refiner (img2img with IP-Adapter and ControlNet coming soon)
|
47 |
+
* Compel prompt weighting and blending
|
|
|
|
|
48 |
* Multiple samplers with Karras scheduling
|
49 |
* DeepCache available
|
50 |
* Real-ESRGAN upscaling
|
app.css
CHANGED
@@ -26,7 +26,7 @@
|
|
26 |
overflow-y: auto;
|
27 |
}
|
28 |
.gallery, .gallery .grid-wrap {
|
29 |
-
height: calc(100vh -
|
30 |
max-height: none;
|
31 |
}
|
32 |
|
@@ -59,24 +59,6 @@
|
|
59 |
#intro > div > svg:is(.dark *) {
|
60 |
fill: #10b981 !important;
|
61 |
}
|
62 |
-
#intro nav {
|
63 |
-
display: flex;
|
64 |
-
column-gap: 0.5rem;
|
65 |
-
}
|
66 |
-
#intro nav a, #intro nav span {
|
67 |
-
white-space: nowrap;
|
68 |
-
font-family: monospace;
|
69 |
-
}
|
70 |
-
#intro nav span {
|
71 |
-
font-weight: 500;
|
72 |
-
color: var(--body-text-color);
|
73 |
-
}
|
74 |
-
#intro nav a {
|
75 |
-
color: var(--body-text-color-subdued);
|
76 |
-
}
|
77 |
-
#intro nav a:hover {
|
78 |
-
color: var(--body-text-color);
|
79 |
-
}
|
80 |
|
81 |
.popover {
|
82 |
position: relative;
|
@@ -100,12 +82,17 @@
|
|
100 |
content: 'Random prompt';
|
101 |
}
|
102 |
.popover#clear:hover::after {
|
103 |
-
content: 'Clear
|
104 |
}
|
105 |
.popover#refresh:hover::after {
|
106 |
content: var(--seed, "-1");
|
107 |
}
|
108 |
|
|
|
|
|
|
|
|
|
|
|
109 |
.tabs, .tabitem, .tab-nav, .tab-nav > .selected {
|
110 |
border-width: 0px;
|
111 |
}
|
|
|
26 |
overflow-y: auto;
|
27 |
}
|
28 |
.gallery, .gallery .grid-wrap {
|
29 |
+
height: calc(100vh - 430px);
|
30 |
max-height: none;
|
31 |
}
|
32 |
|
|
|
59 |
#intro > div > svg:is(.dark *) {
|
60 |
fill: #10b981 !important;
|
61 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
|
63 |
.popover {
|
64 |
position: relative;
|
|
|
82 |
content: 'Random prompt';
|
83 |
}
|
84 |
.popover#clear:hover::after {
|
85 |
+
content: 'Clear';
|
86 |
}
|
87 |
.popover#refresh:hover::after {
|
88 |
content: var(--seed, "-1");
|
89 |
}
|
90 |
|
91 |
+
#settings h3 {
|
92 |
+
color: var(--block-title-text-color) !important;
|
93 |
+
margin-top: 8px !important;
|
94 |
+
}
|
95 |
+
|
96 |
.tabs, .tabitem, .tab-nav, .tab-nav > .selected {
|
97 |
border-width: 0px;
|
98 |
}
|
app.py
CHANGED
@@ -1,12 +1,19 @@
|
|
1 |
import argparse
|
2 |
-
import json
|
3 |
-
import random
|
4 |
|
5 |
import gradio as gr
|
6 |
|
7 |
-
from lib import Config, async_call, disable_progress_bars, download_repo_files, generate, read_file
|
8 |
|
9 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
refresh_seed_js = """
|
11 |
() => {
|
12 |
const n = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
|
@@ -16,14 +23,7 @@ refresh_seed_js = """
|
|
16 |
}
|
17 |
"""
|
18 |
|
19 |
-
|
20 |
-
(seed) => {
|
21 |
-
const button = document.getElementById("refresh");
|
22 |
-
button.style.setProperty("--seed", `"${seed}"`);
|
23 |
-
return seed;
|
24 |
-
}
|
25 |
-
"""
|
26 |
-
|
27 |
aspect_ratio_js = """
|
28 |
(ar, w, h) => {
|
29 |
if (!ar) return [w, h];
|
@@ -32,13 +32,29 @@ aspect_ratio_js = """
|
|
32 |
}
|
33 |
"""
|
34 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
|
|
|
|
|
|
|
|
40 |
|
41 |
|
|
|
42 |
async def generate_fn(*args, progress=gr.Progress(track_tqdm=True)):
|
43 |
if len(args) > 0:
|
44 |
prompt = args[0]
|
@@ -59,7 +75,7 @@ async def generate_fn(*args, progress=gr.Progress(track_tqdm=True)):
|
|
59 |
progress=progress,
|
60 |
)
|
61 |
except RuntimeError:
|
62 |
-
raise gr.Error("Please try again
|
63 |
|
64 |
return images
|
65 |
|
@@ -78,8 +94,8 @@ with gr.Blocks(
|
|
78 |
radius_size=gr.themes.sizes.radius_sm,
|
79 |
spacing_size=gr.themes.sizes.spacing_md,
|
80 |
# fonts
|
81 |
-
font=[gr.themes.GoogleFont("Inter"),
|
82 |
-
font_mono=[gr.themes.GoogleFont("Ubuntu Mono"),
|
83 |
).set(
|
84 |
layout_gap="8px",
|
85 |
block_shadow="0 0 #0000",
|
@@ -93,27 +109,24 @@ with gr.Blocks(
|
|
93 |
with gr.Tabs():
|
94 |
with gr.TabItem("🏠 Home"):
|
95 |
with gr.Column():
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
)
|
115 |
-
|
116 |
-
# Buttons
|
117 |
with gr.Row():
|
118 |
generate_btn = gr.Button("Generate", variant="primary")
|
119 |
random_btn = gr.Button(
|
@@ -139,145 +152,130 @@ with gr.Blocks(
|
|
139 |
value="🗑️",
|
140 |
)
|
141 |
|
142 |
-
with gr.TabItem("⚙️
|
143 |
-
|
|
|
|
|
144 |
negative_prompt = gr.Textbox(
|
145 |
-
value="nsfw
|
146 |
label="Negative Prompt",
|
147 |
-
lines=
|
148 |
)
|
149 |
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
styles = json.loads(read_file("data/styles.json"))
|
168 |
-
style_ids = list(styles.keys())
|
169 |
-
style_ids = [sid for sid in style_ids if not sid.startswith("_")]
|
170 |
-
style = gr.Dropdown(
|
171 |
-
value=Config.STYLE,
|
172 |
-
label="Style",
|
173 |
-
min_width=240,
|
174 |
-
choices=[("None", None)] + [(styles[sid]["name"], sid) for sid in style_ids],
|
175 |
-
)
|
176 |
-
|
177 |
-
with gr.Row():
|
178 |
-
guidance_scale = gr.Slider(
|
179 |
-
value=Config.GUIDANCE_SCALE,
|
180 |
-
label="Guidance Scale",
|
181 |
-
minimum=1.0,
|
182 |
-
maximum=15.0,
|
183 |
-
step=0.1,
|
184 |
-
)
|
185 |
-
inference_steps = gr.Slider(
|
186 |
-
value=Config.INFERENCE_STEPS,
|
187 |
-
label="Inference Steps",
|
188 |
-
minimum=1,
|
189 |
-
maximum=50,
|
190 |
-
step=1,
|
191 |
-
)
|
192 |
-
deepcache_interval = gr.Slider(
|
193 |
-
value=Config.DEEPCACHE_INTERVAL,
|
194 |
-
label="DeepCache",
|
195 |
-
minimum=1,
|
196 |
-
maximum=4,
|
197 |
-
step=1,
|
198 |
-
)
|
199 |
-
|
200 |
-
with gr.Row():
|
201 |
-
width = gr.Slider(
|
202 |
-
value=Config.WIDTH,
|
203 |
-
label="Width",
|
204 |
-
minimum=512,
|
205 |
-
maximum=1536,
|
206 |
-
step=64,
|
207 |
-
)
|
208 |
-
height = gr.Slider(
|
209 |
-
value=Config.HEIGHT,
|
210 |
-
label="Height",
|
211 |
-
minimum=512,
|
212 |
-
maximum=1536,
|
213 |
-
step=64,
|
214 |
-
)
|
215 |
-
aspect_ratio = gr.Dropdown(
|
216 |
-
value=f"{Config.WIDTH},{Config.HEIGHT}",
|
217 |
-
label="Aspect Ratio",
|
218 |
-
filterable=False,
|
219 |
-
choices=[
|
220 |
-
("Custom", None),
|
221 |
-
("4:7 (768x1344)", "768,1344"),
|
222 |
-
("7:9 (896x1152)", "896,1152"),
|
223 |
-
("1:1 (1024x1024)", "1024,1024"),
|
224 |
-
("9:7 (1152x896)", "1152,896"),
|
225 |
-
("7:4 (1344x768)", "1344,768"),
|
226 |
-
],
|
227 |
-
)
|
228 |
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
254 |
|
255 |
-
|
256 |
-
|
257 |
-
elem_classes=["checkbox"],
|
258 |
-
label="Karras σ",
|
259 |
-
value=True,
|
260 |
-
)
|
261 |
-
use_refiner = gr.Checkbox(
|
262 |
-
elem_classes=["checkbox"],
|
263 |
-
label="Refiner",
|
264 |
-
value=False,
|
265 |
-
)
|
266 |
|
267 |
-
|
|
|
268 |
|
|
|
269 |
refresh_btn.click(None, inputs=[], outputs=[seed], js=refresh_seed_js)
|
270 |
|
|
|
271 |
seed.change(None, inputs=[seed], outputs=[], js=seed_js)
|
272 |
|
273 |
-
|
274 |
-
lambda f: gr.Gallery(format=f),
|
275 |
-
inputs=[file_format],
|
276 |
-
outputs=[output_images],
|
277 |
-
show_api=False,
|
278 |
-
)
|
279 |
-
|
280 |
-
# input events are only user input; change events are both user and programmatic
|
281 |
aspect_ratio.input(
|
282 |
None,
|
283 |
inputs=[aspect_ratio, width, height],
|
@@ -285,15 +283,16 @@ with gr.Blocks(
|
|
285 |
js=aspect_ratio_js,
|
286 |
)
|
287 |
|
288 |
-
#
|
289 |
gr.on(
|
290 |
triggers=[width.input, height.input],
|
291 |
fn=None,
|
292 |
-
inputs=[],
|
293 |
outputs=[aspect_ratio],
|
294 |
-
js=
|
295 |
)
|
296 |
|
|
|
297 |
gr.on(
|
298 |
triggers=[generate_btn.click, prompt.submit],
|
299 |
fn=generate_fn,
|
@@ -302,7 +301,6 @@ with gr.Blocks(
|
|
302 |
inputs=[
|
303 |
prompt,
|
304 |
negative_prompt,
|
305 |
-
style,
|
306 |
seed,
|
307 |
model,
|
308 |
scheduler,
|
|
|
1 |
import argparse
|
|
|
|
|
2 |
|
3 |
import gradio as gr
|
4 |
|
5 |
+
from lib import Config, async_call, disable_progress_bars, download_repo_files, generate, read_file, read_json
|
6 |
|
7 |
+
# Update refresh button hover text
|
8 |
+
seed_js = """
|
9 |
+
(seed) => {
|
10 |
+
const button = document.getElementById("refresh");
|
11 |
+
button.style.setProperty("--seed", `"${seed}"`);
|
12 |
+
return seed;
|
13 |
+
}
|
14 |
+
"""
|
15 |
+
|
16 |
+
# The CSS `content` attribute expects a string so we need to wrap the number in quotes
|
17 |
refresh_seed_js = """
|
18 |
() => {
|
19 |
const n = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
|
|
|
23 |
}
|
24 |
"""
|
25 |
|
26 |
+
# Update width and height on aspect ratio change
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
aspect_ratio_js = """
|
28 |
(ar, w, h) => {
|
29 |
if (!ar) return [w, h];
|
|
|
32 |
}
|
33 |
"""
|
34 |
|
35 |
+
# Show "Custom" aspect ratio when manually changing width or height, or one of the predefined ones
|
36 |
+
custom_aspect_ratio_js = """
|
37 |
+
(w, h) => {
|
38 |
+
if (w === 768 && h === 1344) return "768,1344";
|
39 |
+
if (w === 896 && h === 1152) return "896,1152";
|
40 |
+
if (w === 1024 && h === 1024) return "1024,1024";
|
41 |
+
if (w === 1152 && h === 896) return "1152,896";
|
42 |
+
if (w === 1344 && h === 768) return "1344,768";
|
43 |
+
return null;
|
44 |
+
}
|
45 |
+
"""
|
46 |
|
47 |
+
# Inject prompts into random function
|
48 |
+
random_prompt_js = f"""
|
49 |
+
(prompt) => {{
|
50 |
+
const prompts = {read_json("data/prompts.json")};
|
51 |
+
const filtered = prompts.filter(p => p !== prompt);
|
52 |
+
return filtered[Math.floor(Math.random() * filtered.length)];
|
53 |
+
}}
|
54 |
+
"""
|
55 |
|
56 |
|
57 |
+
# Transform the raw inputs before generation
|
58 |
async def generate_fn(*args, progress=gr.Progress(track_tqdm=True)):
|
59 |
if len(args) > 0:
|
60 |
prompt = args[0]
|
|
|
75 |
progress=progress,
|
76 |
)
|
77 |
except RuntimeError:
|
78 |
+
raise gr.Error("Error: Please try again")
|
79 |
|
80 |
return images
|
81 |
|
|
|
94 |
radius_size=gr.themes.sizes.radius_sm,
|
95 |
spacing_size=gr.themes.sizes.spacing_md,
|
96 |
# fonts
|
97 |
+
font=[gr.themes.GoogleFont("Inter"), "sans-serif"],
|
98 |
+
font_mono=[gr.themes.GoogleFont("Ubuntu Mono"), "monospace"],
|
99 |
).set(
|
100 |
layout_gap="8px",
|
101 |
block_shadow="0 0 #0000",
|
|
|
109 |
with gr.Tabs():
|
110 |
with gr.TabItem("🏠 Home"):
|
111 |
with gr.Column():
|
112 |
+
output_images = gr.Gallery(
|
113 |
+
elem_classes=["gallery"],
|
114 |
+
show_share_button=False,
|
115 |
+
object_fit="cover",
|
116 |
+
interactive=False,
|
117 |
+
show_label=False,
|
118 |
+
label="Output",
|
119 |
+
format="png",
|
120 |
+
columns=2,
|
121 |
+
)
|
122 |
+
prompt = gr.Textbox(
|
123 |
+
placeholder="What do you want to see?",
|
124 |
+
autoscroll=False,
|
125 |
+
show_label=False,
|
126 |
+
label="Prompt",
|
127 |
+
max_lines=3,
|
128 |
+
lines=3,
|
129 |
+
)
|
|
|
|
|
|
|
130 |
with gr.Row():
|
131 |
generate_btn = gr.Button("Generate", variant="primary")
|
132 |
random_btn = gr.Button(
|
|
|
152 |
value="🗑️",
|
153 |
)
|
154 |
|
155 |
+
with gr.TabItem("⚙️ Settings", elem_id="settings"):
|
156 |
+
# Prompt settings
|
157 |
+
gr.HTML("<h3>Prompt</h3>")
|
158 |
+
with gr.Row():
|
159 |
negative_prompt = gr.Textbox(
|
160 |
+
value="nsfw",
|
161 |
label="Negative Prompt",
|
162 |
+
lines=1,
|
163 |
)
|
164 |
|
165 |
+
# Model settings
|
166 |
+
gr.HTML("<h3>Settings</h3>")
|
167 |
+
with gr.Row():
|
168 |
+
model = gr.Dropdown(
|
169 |
+
choices=Config.MODELS,
|
170 |
+
value=Config.MODEL,
|
171 |
+
filterable=False,
|
172 |
+
label="Checkpoint",
|
173 |
+
min_width=240,
|
174 |
+
)
|
175 |
+
scheduler = gr.Dropdown(
|
176 |
+
choices=Config.SCHEDULERS.keys(),
|
177 |
+
value=Config.SCHEDULER,
|
178 |
+
elem_id="scheduler",
|
179 |
+
label="Scheduler",
|
180 |
+
filterable=False,
|
181 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
182 |
|
183 |
+
# Generation settings
|
184 |
+
gr.HTML("<h3>Generation</h3>")
|
185 |
+
with gr.Row():
|
186 |
+
guidance_scale = gr.Slider(
|
187 |
+
value=Config.GUIDANCE_SCALE,
|
188 |
+
label="Guidance Scale",
|
189 |
+
minimum=1.0,
|
190 |
+
maximum=15.0,
|
191 |
+
step=0.1,
|
192 |
+
)
|
193 |
+
inference_steps = gr.Slider(
|
194 |
+
value=Config.INFERENCE_STEPS,
|
195 |
+
label="Inference Steps",
|
196 |
+
minimum=1,
|
197 |
+
maximum=50,
|
198 |
+
step=1,
|
199 |
+
)
|
200 |
+
deepcache_interval = gr.Slider(
|
201 |
+
value=Config.DEEPCACHE_INTERVAL,
|
202 |
+
label="DeepCache",
|
203 |
+
minimum=1,
|
204 |
+
maximum=4,
|
205 |
+
step=1,
|
206 |
+
)
|
207 |
+
with gr.Row():
|
208 |
+
width = gr.Slider(
|
209 |
+
value=Config.WIDTH,
|
210 |
+
label="Width",
|
211 |
+
minimum=512,
|
212 |
+
maximum=1536,
|
213 |
+
step=64,
|
214 |
+
)
|
215 |
+
height = gr.Slider(
|
216 |
+
value=Config.HEIGHT,
|
217 |
+
label="Height",
|
218 |
+
minimum=512,
|
219 |
+
maximum=1536,
|
220 |
+
step=64,
|
221 |
+
)
|
222 |
+
aspect_ratio = gr.Dropdown(
|
223 |
+
value=f"{Config.WIDTH},{Config.HEIGHT}",
|
224 |
+
label="Aspect Ratio",
|
225 |
+
filterable=False,
|
226 |
+
choices=[
|
227 |
+
("Custom", None),
|
228 |
+
("4:7 (768x1344)", "768,1344"),
|
229 |
+
("7:9 (896x1152)", "896,1152"),
|
230 |
+
("1:1 (1024x1024)", "1024,1024"),
|
231 |
+
("9:7 (1152x896)", "1152,896"),
|
232 |
+
("7:4 (1344x768)", "1344,768"),
|
233 |
+
],
|
234 |
+
)
|
235 |
+
with gr.Row():
|
236 |
+
num_images = gr.Dropdown(
|
237 |
+
choices=list(range(1, 5)),
|
238 |
+
value=Config.NUM_IMAGES,
|
239 |
+
filterable=False,
|
240 |
+
label="Images",
|
241 |
+
)
|
242 |
+
scale = gr.Dropdown(
|
243 |
+
choices=[(f"{s}x", s) for s in Config.SCALES],
|
244 |
+
filterable=False,
|
245 |
+
value=Config.SCALE,
|
246 |
+
label="Scale",
|
247 |
+
)
|
248 |
+
seed = gr.Number(
|
249 |
+
value=Config.SEED,
|
250 |
+
label="Seed",
|
251 |
+
minimum=-1,
|
252 |
+
maximum=(2**64) - 1,
|
253 |
+
)
|
254 |
+
with gr.Row():
|
255 |
+
use_karras = gr.Checkbox(
|
256 |
+
elem_classes=["checkbox"],
|
257 |
+
label="Karras σ",
|
258 |
+
value=True,
|
259 |
+
)
|
260 |
+
use_refiner = gr.Checkbox(
|
261 |
+
elem_classes=["checkbox"],
|
262 |
+
label="Refiner",
|
263 |
+
value=False,
|
264 |
+
)
|
265 |
|
266 |
+
with gr.TabItem("ℹ️ Info"):
|
267 |
+
gr.Markdown(read_file("DOCS.md"))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
268 |
|
269 |
+
# Random prompt on click
|
270 |
+
random_btn.click(None, inputs=[prompt], outputs=[prompt], js=random_prompt_js)
|
271 |
|
272 |
+
# Update seed on click
|
273 |
refresh_btn.click(None, inputs=[], outputs=[seed], js=refresh_seed_js)
|
274 |
|
275 |
+
# Update seed button hover text
|
276 |
seed.change(None, inputs=[seed], outputs=[], js=seed_js)
|
277 |
|
278 |
+
# Update width and height on aspect ratio change
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
279 |
aspect_ratio.input(
|
280 |
None,
|
281 |
inputs=[aspect_ratio, width, height],
|
|
|
283 |
js=aspect_ratio_js,
|
284 |
)
|
285 |
|
286 |
+
# Show "Custom" aspect ratio when manually changing width or height
|
287 |
gr.on(
|
288 |
triggers=[width.input, height.input],
|
289 |
fn=None,
|
290 |
+
inputs=[width, height],
|
291 |
outputs=[aspect_ratio],
|
292 |
+
js=custom_aspect_ratio_js,
|
293 |
)
|
294 |
|
295 |
+
# Generate images
|
296 |
gr.on(
|
297 |
triggers=[generate_btn.click, prompt.submit],
|
298 |
fn=generate_fn,
|
|
|
301 |
inputs=[
|
302 |
prompt,
|
303 |
negative_prompt,
|
|
|
304 |
seed,
|
305 |
model,
|
306 |
scheduler,
|
data/prompts.json
CHANGED
@@ -1,48 +1,25 @@
|
|
1 |
[
|
2 |
-
"
|
3 |
-
"
|
4 |
-
"
|
5 |
-
"
|
6 |
-
|
7 |
-
"
|
8 |
-
"
|
9 |
-
"
|
10 |
-
"
|
11 |
-
"
|
12 |
-
|
13 |
-
"
|
14 |
-
"
|
15 |
-
|
16 |
-
"
|
17 |
-
"
|
18 |
-
"
|
19 |
-
"
|
20 |
-
"tranquil
|
21 |
-
"
|
22 |
-
"
|
23 |
-
"
|
24 |
-
"
|
25 |
-
"beautiful Santorini island, iconic white buildings, pristine beach, Mediterranean, charming, romantic",
|
26 |
-
"breathtaking Grand Canyon, vast, awe-inspiring, otherworldly, iconic, historic landmark",
|
27 |
-
"breathtaking Machu Picchu, set against a backdrop of towering mountains, iconic, historic landmark",
|
28 |
-
"iconic New York City skyline, with towering skyscrapers, golden-hour lighting, dramatic, atmospheric",
|
29 |
-
"iconic Great Wall of China, stretching along the countryside, historic landmark",
|
30 |
-
"iconic Sydney Opera House, with the harbor and cityscape in the background, stunning, historic landmark",
|
31 |
-
"iconic Taj Mahal, set against a backdrop of lush greenery, stunning, historic landmark",
|
32 |
-
"bowl of steaming hot ramen with a sliced egg, thin slices of meat, green onions, noodles, chopsticks, solo, minimal",
|
33 |
-
"large pizza with melted cheese, seared pepperoni, crispy crust, solo, minimal",
|
34 |
-
"sizzling hot sirloin steak with a perfect crust, seared to perfection, served with a side of roasted vegetables and mashed potatoes, solo, minimal",
|
35 |
-
"wedding cake, white frosting, colorful accent flowers, fresh berry garnish, tiers, layers, elegant, minimal",
|
36 |
-
"baked salmon fillet with a perfectly crispy skin and flaky flesh, side of steamed vegetables and quinoa, healthy, fresh, solo, minimal",
|
37 |
-
"steaming bowl of hearty chili with tender chunks of beef, rich tomato sauce, topped with grated cheddar cheese and green onions, solo, minimal",
|
38 |
-
"platter of sushi rolls, tuna, salmon, california maki, rainbow, colorful, beautiful arrangement, solo, minimal",
|
39 |
-
"stuffed bell pepper filled with browned ground beef, rice, melted cheese, parsley garnish, solo, minimal",
|
40 |
-
"pair of tacos filled with shredded chicken, red onions, cilantro, a drizzle of cream, white plate, blue tablecloth, solo, minimal",
|
41 |
-
"contemporary living room, floor-to-ceiling windows, neutral color palette, minimalistic design, modern furniture, wall-mounted television, ceiling fan, recessed lighting, open floor plan",
|
42 |
-
"rustic kitchen with reclaimed wood cabinetry, large farmhouse sink, industrial lighting fixtures, open shelving, cast iron cookware, exposed brick wall",
|
43 |
-
"luxurious bathroom with freestanding bathtub, marble tiles, brass fixtures, double-sink floating vanity, spa-like atmosphere",
|
44 |
-
"cozy bedroom with a four-poster bed, decorative throw pillows, plush bedding, single large window with natural light, statement wallpaper, relaxing atmosphere",
|
45 |
-
"formula one race car, aerodynamic design, captured in a high speed motion blur, shallow depth-of-field, dramatic lighting, epic, intense",
|
46 |
-
"luxury supercar with aerodynamic curves, high-key lighting, depth-of-field, exotic",
|
47 |
-
"stunning yacht with sleek lines, golden-hour lighting, depth-of-field, breathtaking"
|
48 |
]
|
|
|
1 |
[
|
2 |
+
"portrait of a blonde woman, detailed facial features, soft natural lighting, bokeh, professional photography, breathtaking, masterpiece, highly detailed, best quality, sharp focus, 8k, uhd",
|
3 |
+
"portrait of a young adult woman, freckled complexion, vibrant red hair, smiling, under tree, golden hour lighting, professional photography, breathtaking, masterpiece, highly detailed, best quality, sharp focus, 8k, uhd",
|
4 |
+
"portrait of an elderly woman, weathered features, gentle smile, natural window lighting, professional photography, breathtaking, masterpiece, highly detailed, best quality, sharp focus, 8k, uhd",
|
5 |
+
"headshot of a middle-aged man, salt and pepper hair, confident expression, studio lighting, neutral backdrop, professional photography, breathtaking, masterpiece, highly detailed, best quality, sharp focus, 8k, uhd",
|
6 |
+
|
7 |
+
"portrait of a majestic Norwegian forest cat, soft fur detail, green eyes, natural lighting, professional photography, breathtaking, masterpiece, highly detailed, best quality, sharp focus, 8k, uhd",
|
8 |
+
"portrait of a British shorthair cat, yellow eyes, gentle expression, soft lighting, bokeh, professional photography, breathtaking, masterpiece, highly detailed, best quality, sharp focus, 8k, uhd",
|
9 |
+
"adorable Siamese kitten, blue eyes, soft natural lighting, shallow depth of field, professional photography, breathtaking, masterpiece, highly detailed, best quality, sharp focus, 8k, uhd",
|
10 |
+
"portrait of a regal German shepherd, alert ears, noble expression, natural background, golden hour lighting, bokeh, professional photography, breathtaking, masterpiece, highly detailed, best quality, sharp focus, 8k, uhd",
|
11 |
+
"Welsh corgi in a colorful garden, cheerful expression, daylight, shallow depth of field, professional photography, breathtaking, masterpiece, highly detailed, best quality, sharp focus, 8k, uhd",
|
12 |
+
|
13 |
+
"Porsche 911 Turbo (991), front 3/4 view, motion blur, dramatic lighting, professional photography, breathtaking, masterpiece, highly detailed, best quality, sharp focus, 8k, uhd",
|
14 |
+
"BMW E92 M3 on mountain road, side profile, motion blur, daylight, professional photography, breathtaking, masterpiece, highly detailed, best quality, sharp focus, 8k, uhd",
|
15 |
+
|
16 |
+
"tropical beach at sunset, light sand, azure water, swaying palm trees, scattered clouds, distant volcano, ultra wide angle lens, HDR photography, breathtaking, masterpiece, highly detailed, best quality, sharp focus, 8k, uhd",
|
17 |
+
"lighthouse on rocky coast at dawn, crashing waves, pastel sky, cumulus clouds, soft morning light, HDR photography, breathtaking, masterpiece, highly detailed, best quality, sharp focus, 8k, uhd",
|
18 |
+
"California vineyard at sunset, rows of grapevines stretching to horizon, golden hour lighting, rolling hills, scattered oak trees, ultra wide angle lens, HDR photography, breathtaking, masterpiece, highly detailed, best quality, sharp focus, 8k, uhd",
|
19 |
+
"mountain stream in autumn, moss-covered rocks, fallen maple leaves, dappled sunlight through canopy, HDR photography, breathtaking, masterpiece, highly detailed, best quality, sharp focus, 8k, uhd",
|
20 |
+
"tranquil alpine lake at night, snow-capped mountain range in distance, scattered evergreens along shoreline, aurora borealis in sky, HDR photography, breathtaking, masterpiece, highly detailed, best quality, sharp focus, 8k, uhd",
|
21 |
+
"desert ranch house at dusk, saguaro cactus, purple mountain backdrop, last rays of sunlight, HDR photography, breathtaking, masterpiece, highly detailed, best quality, sharp focus, 8k, uhd",
|
22 |
+
"Japanese pagoda between cherry blossom trees, misty mountain backdrop, golden hour lighting, HDR photography, breathtaking, masterpiece, highly detailed, best quality, sharp focus, 8k, uhd",
|
23 |
+
"red Dutch barn, colorful tulip rows in front, low evening sun, scattered clouds, HDR photography, breathtaking, masterpiece, highly detailed, best quality, sharp focus, 8k, uhd",
|
24 |
+
"lavender field in Provence, ancient stone farmhouse, sunset lighting, scattered clouds, distant mountains, HDR photography, breathtaking, masterpiece, highly detailed, best quality, sharp focus, 8k, uhd"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
]
|
data/styles.json
DELETED
@@ -1,136 +0,0 @@
|
|
1 |
-
{
|
2 |
-
"_base": {
|
3 |
-
"positive": "good, perfect, accurate, precise, professional, highly detailed, best quality, masterpiece",
|
4 |
-
"negative": "watermark, trademark, signature, autograph, artifacts, deformed, mutated, bad, ugly, unattractive, noisy, grainy, blurry, distorted, oversaturated, undersaturated, overexposed, underexposed, amateur, sloppy, cluttered, low detail, worst quality"
|
5 |
-
},
|
6 |
-
"abstract": {
|
7 |
-
"name": "Abstract",
|
8 |
-
"positive": "({prompt}), in an abstract art style, non-representational colors and shapes, expressive, imaginative, vibrant, {_base}",
|
9 |
-
"negative": "({prompt}), discrete, objective, realism, photographic, monochrome, muted, {_base}"
|
10 |
-
},
|
11 |
-
"anime_josei": {
|
12 |
-
"name": "Anime: Josei",
|
13 |
-
"positive": "({prompt}), in a josei anime style, inspired by Paradise Kiss, by Ai Yazawa, manga, mature, emotional, sophisticated, soft colors, refined lines, {_base}",
|
14 |
-
"negative": "({prompt}), shonen, shoujo, seinen, dark, gritty, realism, photographic, {_base}"
|
15 |
-
},
|
16 |
-
"anime_seinen": {
|
17 |
-
"name": "Anime: Seinen",
|
18 |
-
"positive": "({prompt}), in a seinen anime style, inspired by Ghost in the Shell, by Masamune Shirow, manga, adult, mature, dark, gritty, intricate design, dramatic lighting, high contrast, {_base}",
|
19 |
-
"negative": "({prompt}), shonen, shoujo, josei, realism, photographic, dull, plain, low contrast, {_base}"
|
20 |
-
},
|
21 |
-
"anime_shojo": {
|
22 |
-
"name": "Anime: Shoujo",
|
23 |
-
"positive": "({prompt}), in a shoujo anime style, manga, romantic, emotional, pastel colors, soft lines, {_base}",
|
24 |
-
"negative": "({prompt}), shonen, seinen, josei, dark, gritty, realism, photographic, {_base}"
|
25 |
-
},
|
26 |
-
"anime_shonen": {
|
27 |
-
"name": "Anime: Shonen",
|
28 |
-
"positive": "({prompt}), in a shonen anime style, manga, action, adventure, heroic, youthful, vibrant, high contrast, {_base}",
|
29 |
-
"negative": "({prompt}), shoujo, seinen, josei, realism, photographic, dull, plain, monochrome, muted, low contrast, {_base}"
|
30 |
-
},
|
31 |
-
"art_deco": {
|
32 |
-
"name": "Art Deco",
|
33 |
-
"positive": "({prompt}), in an art deco style, inspired by Tamara de Lempicka, geometric shapes, bold colors, luxurious, elegant, sleek, streamlined, symmetrical, vibrant, high contrast, {_base}",
|
34 |
-
"negative": "({prompt}), realism, photographic, asymmetrical, monochrome, muted, low contrast, {_base}"
|
35 |
-
},
|
36 |
-
"biomechanical": {
|
37 |
-
"name": "Biomechanical",
|
38 |
-
"positive": "({prompt}), in a biomechanical style, organic and mechanical, flesh and metal, cyborg, cybernetic, intricate design, futuristic, sci-fi, {_base}",
|
39 |
-
"negative": "({prompt}), natural, rustic, primitive, medieval, {_base}"
|
40 |
-
},
|
41 |
-
"cubism": {
|
42 |
-
"name": "Cubism",
|
43 |
-
"positive": "({prompt}), in a cubist style, inspired by Picasso, fragmented shapes and planes, abstract forms, collage, {_base}",
|
44 |
-
"negative": "({prompt}), discrete, objective, {_base}"
|
45 |
-
},
|
46 |
-
"cyberpunk": {
|
47 |
-
"name": "Cyberpunk",
|
48 |
-
"positive": "({prompt}), in a cyberpunk style, 2077, synthwave, neon, digital, high-tech, futuristic, dystopian, vibrant, high contrast, {_base}",
|
49 |
-
"negative": "({prompt}), rustic, primitive, medieval, monochrome, muted, low contrast, {_base}"
|
50 |
-
},
|
51 |
-
"enhance": {
|
52 |
-
"name": "Enhance",
|
53 |
-
"positive": "({prompt}), {_base}",
|
54 |
-
"negative": "({prompt}), {_base}"
|
55 |
-
},
|
56 |
-
"expressionism": {
|
57 |
-
"name": "Expressionism",
|
58 |
-
"positive": "({prompt}), in an expressionist style, energetic brushwork, bold colors, abstract forms, vibrant, expressive, imaginative, high contrast, {_base}",
|
59 |
-
"negative": "({prompt}), discrete, objective, realism, photographic, dull, plain, monochrome, muted, low contrast, {_base}"
|
60 |
-
},
|
61 |
-
"fantasy": {
|
62 |
-
"name": "Fantasy",
|
63 |
-
"positive": "({prompt}), in a fantasy style, digital concept art, by Greg Rutkowski, trending on ArtStation, magical, enchanting, ethereal, dreamlike, graphic, illustration, high contrast, {_base}",
|
64 |
-
"negative": "({prompt}), realism, photographic, ordinary, mundane, monochrome, muted, low contrast, {_base}"
|
65 |
-
},
|
66 |
-
"graffiti": {
|
67 |
-
"name": "Graffiti",
|
68 |
-
"positive": "({prompt}), in a graffiti style, street art, creative composition, dynamic lines, spray paint, hip-hop, stylized, bold, vibrant, urban, mural, high contrast, {_base}",
|
69 |
-
"negative": "({prompt}), dull, plain, monochrome, muted, low contrast, {_base}"
|
70 |
-
},
|
71 |
-
"line_art": {
|
72 |
-
"name": "Line Art",
|
73 |
-
"positive": "({prompt}), in a line art drawing style, graphic, illustration, sleek, streamlined, centered composition, solo subject, isolated subject, white background, minimalist arrangement, {_base}",
|
74 |
-
"negative": "({prompt}), off-center, oil, acrylic, watercolor, {_base}"
|
75 |
-
},
|
76 |
-
"papercraft": {
|
77 |
-
"name": "Papercraft",
|
78 |
-
"positive": "({prompt}), as a papercraft model, Kirigami style, folded paper, papercut, sharp edges, intricate design, 3d, layered, textural, color block, centered composition, minimalist arrangement, {_base}",
|
79 |
-
"negative": "({prompt}), 2d, flat, {_base}"
|
80 |
-
},
|
81 |
-
"photography_food": {
|
82 |
-
"name": "Photography: Food",
|
83 |
-
"positive": "({prompt}), food photography style, fresh ingredients, delicious, culinary, real, authentic, macro details, soft natural lighting, high resolution, uhd, centered composition, minimalist arrangement, {_base}",
|
84 |
-
"negative": "({prompt}), unappetizing, fake, artificial, low resolution, {_base}"
|
85 |
-
},
|
86 |
-
"photography_hdr": {
|
87 |
-
"name": "Photography: HDR",
|
88 |
-
"positive": "({prompt}), breathtaking HDR photography, high dynamic range, vivid colors, shadows and highlights, dramatic lighting, high contrast, high resolution, uhd, {_base}",
|
89 |
-
"negative": "({prompt}), flat colors, plain, dull, low dynamic range, low contrast, low resolution, {_base}"
|
90 |
-
},
|
91 |
-
"photography_iphone": {
|
92 |
-
"name": "Photography: iPhone",
|
93 |
-
"positive": "({prompt}), taken by iPhone ProRAW camera, XDR, Retina, depth-of-field, vivid colors, dynamic range, dramatic lighting, real, authentic, high contrast, high resolution, uhd, {_base}",
|
94 |
-
"negative": "({prompt}), shallow depth-of-field, bokeh, fake, artificial, low contrast, low resolution, {_base}"
|
95 |
-
},
|
96 |
-
"photography_iphone_portrait": {
|
97 |
-
"name": "Photography: iPhone Portrait",
|
98 |
-
"positive": "({prompt}), taken by iPhone Portrait Mode, XDR, Retina, shallow depth-of-field, bokeh, vivid colors, dramatic lighting, real, authentic, high contrast, high resolution, uhd, {_base}",
|
99 |
-
"negative": "({prompt}), fake, artificial, low contrast, low resolution, {_base}"
|
100 |
-
},
|
101 |
-
"photography_real_estate": {
|
102 |
-
"name": "Photography: Real Estate",
|
103 |
-
"positive": "({prompt}), real estate photography style, on Zillow, inviting, staged, well-lit, real, authentic, high resolution, uhd, {_base}",
|
104 |
-
"negative": "({prompt}), dark, fake, artificial, low resolution, {_base}"
|
105 |
-
},
|
106 |
-
"photography_street": {
|
107 |
-
"name": "Photography: Street",
|
108 |
-
"positive": "({prompt}), street photography style, taken on Fujifilm X100V, f2 aperture, 35mm, RAW format, candid, authentic, gritty, urban, high contrast, high resolution, uhd, {_base}",
|
109 |
-
"negative": "({prompt}), staged, fake, artificial, low contrast, low resolution, {_base}"
|
110 |
-
},
|
111 |
-
"pointillism": {
|
112 |
-
"name": "Pointillism",
|
113 |
-
"positive": "({prompt}), pointillism style, composed of small dots, inspired by Georges Seurat, intricate design, vibrant, {_base}",
|
114 |
-
"negative": "({prompt}), line drawing, smooth shading, wide color gamut, dull, plain, monochrome, muted, {_base}"
|
115 |
-
},
|
116 |
-
"pop_art": {
|
117 |
-
"name": "Pop Art",
|
118 |
-
"positive": "({prompt}), in a pop art style, inspired by Warhol, bright colors, bold outlines, popular culture, kitsch, vibrant, high contrast, {_base}",
|
119 |
-
"negative": "({prompt}), discrete, objective, dull, plain, monochrome, muted, low contrast, {_base}"
|
120 |
-
},
|
121 |
-
"render": {
|
122 |
-
"name": "Render",
|
123 |
-
"positive": "({prompt}), Octane render, Unreal Engine, volumetric lighting, ray tracing, ambient occlusion, subsurface scattering, high resolution, uhd, {_base}",
|
124 |
-
"negative": "({prompt}), glitch, error, painting, sketch, low resolution, {_base}"
|
125 |
-
},
|
126 |
-
"vaporwave": {
|
127 |
-
"name": "Vaporwave",
|
128 |
-
"positive": "({prompt}), in a vaporwave style, retro aesthetic, neon colors, vibrant, high contrast, {_base}",
|
129 |
-
"negative": "({prompt}), dark, monochrome, muted, low contrast, {_base}"
|
130 |
-
},
|
131 |
-
"watercolor": {
|
132 |
-
"name": "Watercolor",
|
133 |
-
"positive": "({prompt}), painted with watercolors, colorful, painterly, artistic, fluid, {_base}",
|
134 |
-
"negative": "({prompt}), realism, photographic, oil, acrylic, digital, {_base}"
|
135 |
-
}
|
136 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lib/__init__.py
CHANGED
@@ -1,29 +1,19 @@
|
|
1 |
from .config import Config
|
2 |
from .inference import generate
|
3 |
-
from .loader import Loader
|
4 |
-
from .upscaler import RealESRGAN
|
5 |
from .utils import (
|
6 |
async_call,
|
7 |
disable_progress_bars,
|
8 |
-
download_civit_file,
|
9 |
download_repo_files,
|
10 |
-
enable_progress_bars,
|
11 |
-
load_json,
|
12 |
read_file,
|
13 |
-
|
14 |
)
|
15 |
|
16 |
__all__ = [
|
17 |
"Config",
|
18 |
-
"Loader",
|
19 |
-
"RealESRGAN",
|
20 |
"async_call",
|
21 |
"disable_progress_bars",
|
22 |
-
"download_civit_file",
|
23 |
"download_repo_files",
|
24 |
-
"enable_progress_bars",
|
25 |
"generate",
|
26 |
-
"load_json",
|
27 |
"read_file",
|
28 |
-
"
|
29 |
]
|
|
|
1 |
from .config import Config
|
2 |
from .inference import generate
|
|
|
|
|
3 |
from .utils import (
|
4 |
async_call,
|
5 |
disable_progress_bars,
|
|
|
6 |
download_repo_files,
|
|
|
|
|
7 |
read_file,
|
8 |
+
read_json,
|
9 |
)
|
10 |
|
11 |
__all__ = [
|
12 |
"Config",
|
|
|
|
|
13 |
"async_call",
|
14 |
"disable_progress_bars",
|
|
|
15 |
"download_repo_files",
|
|
|
16 |
"generate",
|
|
|
17 |
"read_file",
|
18 |
+
"read_json",
|
19 |
]
|
lib/config.py
CHANGED
@@ -16,10 +16,10 @@ from diffusers import (
|
|
16 |
from diffusers.utils import logging as diffusers_logging
|
17 |
from transformers import logging as transformers_logging
|
18 |
|
19 |
-
#
|
20 |
os.environ["ZEROGPU_V2"] = "1"
|
21 |
|
22 |
-
#
|
23 |
if find_spec("hf_transfer"):
|
24 |
os.environ["HF_HUB_ENABLE_HF_TRANSFER"] = "1"
|
25 |
|
@@ -29,6 +29,7 @@ filterwarnings("ignore", category=FutureWarning, module="transformers")
|
|
29 |
diffusers_logging.set_verbosity_error()
|
30 |
transformers_logging.set_verbosity_error()
|
31 |
|
|
|
32 |
_sdxl_refiner_files = [
|
33 |
"scheduler/scheduler_config.json",
|
34 |
"text_encoder_2/config.json",
|
@@ -44,6 +45,7 @@ _sdxl_refiner_files = [
|
|
44 |
"model_index.json",
|
45 |
]
|
46 |
|
|
|
47 |
_sdxl_files = [
|
48 |
*_sdxl_refiner_files,
|
49 |
"text_encoder/config.json",
|
@@ -54,39 +56,30 @@ _sdxl_files = [
|
|
54 |
"tokenizer/vocab.json",
|
55 |
]
|
56 |
|
|
|
57 |
Config = SimpleNamespace(
|
58 |
HF_TOKEN=os.environ.get("HF_TOKEN", None),
|
59 |
-
CIVIT_TOKEN=os.environ.get("CIVIT_TOKEN", None),
|
60 |
ZERO_GPU=import_module("spaces").config.Config.zero_gpu,
|
61 |
-
MONO_FONTS=["monospace"],
|
62 |
-
SANS_FONTS=[
|
63 |
-
"sans-serif",
|
64 |
-
"Apple Color Emoji",
|
65 |
-
"Segoe UI Emoji",
|
66 |
-
"Segoe UI Symbol",
|
67 |
-
"Noto Color Emoji",
|
68 |
-
],
|
69 |
-
PIPELINES={
|
70 |
-
"txt2img": StableDiffusionXLPipeline,
|
71 |
-
"img2img": StableDiffusionXLImg2ImgPipeline,
|
72 |
-
},
|
73 |
HF_MODELS={
|
74 |
"segmind/Segmind-Vega": [*_sdxl_files],
|
75 |
"stabilityai/stable-diffusion-xl-base-1.0": [*_sdxl_files, "vae_1_0/config.json"],
|
76 |
"stabilityai/stable-diffusion-xl-refiner-1.0": [*_sdxl_refiner_files],
|
77 |
},
|
|
|
|
|
|
|
|
|
78 |
MODEL="segmind/Segmind-Vega",
|
79 |
MODELS=[
|
80 |
-
"cagliostrolab/animagine-xl-3.1",
|
81 |
"cyberdelia/CyberRealsticXL",
|
82 |
"fluently/Fluently-XL-Final",
|
83 |
"segmind/Segmind-Vega",
|
84 |
"SG161222/RealVisXL_V5.0",
|
85 |
"stabilityai/stable-diffusion-xl-base-1.0",
|
86 |
],
|
|
|
87 |
MODEL_CHECKPOINTS={
|
88 |
-
# keep keys lowercase
|
89 |
-
"cagliostrolab/animagine-xl-3.1": "animagine-xl-3.1.safetensors",
|
90 |
"cyberdelia/cyberrealsticxl": "CyberRealisticXLPlay_V1.0.safetensors", # typo in "realistic"
|
91 |
"fluently/fluently-xl-final": "FluentlyXL-Final.safetensors",
|
92 |
"sg161222/realvisxl_v5.0": "RealVisXL_V5.0_fp16.safetensors",
|
@@ -101,12 +94,11 @@ Config = SimpleNamespace(
|
|
101 |
"Euler": EulerDiscreteScheduler,
|
102 |
"Euler a": EulerAncestralDiscreteScheduler,
|
103 |
},
|
104 |
-
STYLE="enhance",
|
105 |
WIDTH=1024,
|
106 |
HEIGHT=1024,
|
107 |
NUM_IMAGES=1,
|
108 |
SEED=-1,
|
109 |
-
GUIDANCE_SCALE=
|
110 |
INFERENCE_STEPS=40,
|
111 |
DEEPCACHE_INTERVAL=1,
|
112 |
SCALE=1,
|
|
|
16 |
from diffusers.utils import logging as diffusers_logging
|
17 |
from transformers import logging as transformers_logging
|
18 |
|
19 |
+
# Improved GPU handling and progress bars; set before importing spaces
|
20 |
os.environ["ZEROGPU_V2"] = "1"
|
21 |
|
22 |
+
# Use Rust-based downloader; errors if enabled and not installed
|
23 |
if find_spec("hf_transfer"):
|
24 |
os.environ["HF_HUB_ENABLE_HF_TRANSFER"] = "1"
|
25 |
|
|
|
29 |
diffusers_logging.set_verbosity_error()
|
30 |
transformers_logging.set_verbosity_error()
|
31 |
|
32 |
+
# Standard refiner structure
|
33 |
_sdxl_refiner_files = [
|
34 |
"scheduler/scheduler_config.json",
|
35 |
"text_encoder_2/config.json",
|
|
|
45 |
"model_index.json",
|
46 |
]
|
47 |
|
48 |
+
# Standard SDXL structure
|
49 |
_sdxl_files = [
|
50 |
*_sdxl_refiner_files,
|
51 |
"text_encoder/config.json",
|
|
|
56 |
"tokenizer/vocab.json",
|
57 |
]
|
58 |
|
59 |
+
# Using namespace instead of dataclass for simplicity
|
60 |
Config = SimpleNamespace(
|
61 |
HF_TOKEN=os.environ.get("HF_TOKEN", None),
|
|
|
62 |
ZERO_GPU=import_module("spaces").config.Config.zero_gpu,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
HF_MODELS={
|
64 |
"segmind/Segmind-Vega": [*_sdxl_files],
|
65 |
"stabilityai/stable-diffusion-xl-base-1.0": [*_sdxl_files, "vae_1_0/config.json"],
|
66 |
"stabilityai/stable-diffusion-xl-refiner-1.0": [*_sdxl_refiner_files],
|
67 |
},
|
68 |
+
PIPELINES={
|
69 |
+
"txt2img": StableDiffusionXLPipeline,
|
70 |
+
"img2img": StableDiffusionXLImg2ImgPipeline,
|
71 |
+
},
|
72 |
MODEL="segmind/Segmind-Vega",
|
73 |
MODELS=[
|
|
|
74 |
"cyberdelia/CyberRealsticXL",
|
75 |
"fluently/Fluently-XL-Final",
|
76 |
"segmind/Segmind-Vega",
|
77 |
"SG161222/RealVisXL_V5.0",
|
78 |
"stabilityai/stable-diffusion-xl-base-1.0",
|
79 |
],
|
80 |
+
# Single-file model weights
|
81 |
MODEL_CHECKPOINTS={
|
82 |
+
# keep keys lowercase for case-insensitive matching in the loader
|
|
|
83 |
"cyberdelia/cyberrealsticxl": "CyberRealisticXLPlay_V1.0.safetensors", # typo in "realistic"
|
84 |
"fluently/fluently-xl-final": "FluentlyXL-Final.safetensors",
|
85 |
"sg161222/realvisxl_v5.0": "RealVisXL_V5.0_fp16.safetensors",
|
|
|
94 |
"Euler": EulerDiscreteScheduler,
|
95 |
"Euler a": EulerAncestralDiscreteScheduler,
|
96 |
},
|
|
|
97 |
WIDTH=1024,
|
98 |
HEIGHT=1024,
|
99 |
NUM_IMAGES=1,
|
100 |
SEED=-1,
|
101 |
+
GUIDANCE_SCALE=6,
|
102 |
INFERENCE_STEPS=40,
|
103 |
DEEPCACHE_INTERVAL=1,
|
104 |
SCALE=1,
|
lib/inference.py
CHANGED
@@ -1,8 +1,5 @@
|
|
1 |
-
import gc
|
2 |
-
import re
|
3 |
import time
|
4 |
from datetime import datetime
|
5 |
-
from itertools import product
|
6 |
|
7 |
import torch
|
8 |
from compel import Compel, ReturnedEmbeddingsType
|
@@ -11,45 +8,11 @@ from spaces import GPU
|
|
11 |
|
12 |
from .config import Config
|
13 |
from .loader import Loader
|
14 |
-
from .
|
|
|
15 |
|
16 |
|
17 |
-
|
18 |
-
arrays = re.findall(r"\[\[(.*?)\]\]", prompt)
|
19 |
-
|
20 |
-
if not arrays:
|
21 |
-
return [prompt]
|
22 |
-
|
23 |
-
tokens = [item.split(",") for item in arrays] # [("a", "b"), (1, 2)]
|
24 |
-
combinations = list(product(*tokens)) # [("a", 1), ("a", 2), ("b", 1), ("b", 2)]
|
25 |
-
|
26 |
-
# find all the arrays in the prompt and replace them with tokens
|
27 |
-
prompts = []
|
28 |
-
for combo in combinations:
|
29 |
-
current_prompt = prompt
|
30 |
-
for i, token in enumerate(combo):
|
31 |
-
current_prompt = current_prompt.replace(f"[[{arrays[i]}]]", token.strip(), 1)
|
32 |
-
prompts.append(current_prompt)
|
33 |
-
return prompts
|
34 |
-
|
35 |
-
|
36 |
-
def apply_style(positive_prompt, negative_prompt, style_id="none"):
|
37 |
-
if style_id.lower() == "none":
|
38 |
-
return (positive_prompt, negative_prompt)
|
39 |
-
|
40 |
-
styles = load_json("./data/styles.json")
|
41 |
-
style = styles.get(style_id)
|
42 |
-
if style is None:
|
43 |
-
return (positive_prompt, negative_prompt)
|
44 |
-
|
45 |
-
style_base = style.get("_base", {})
|
46 |
-
return (
|
47 |
-
style.get("positive").format(prompt=positive_prompt, _base=style_base.get("positive")).strip(),
|
48 |
-
style.get("negative").format(prompt=negative_prompt, _base=style_base.get("negative")).strip(),
|
49 |
-
)
|
50 |
-
|
51 |
-
|
52 |
-
# max 60s per image
|
53 |
def gpu_duration(**kwargs):
|
54 |
loading = 15
|
55 |
duration = 15
|
@@ -76,13 +39,12 @@ def gpu_duration(**kwargs):
|
|
76 |
def generate(
|
77 |
positive_prompt,
|
78 |
negative_prompt="",
|
79 |
-
style=None,
|
80 |
seed=None,
|
81 |
model="stabilityai/stable-diffusion-xl-base-1.0",
|
82 |
-
scheduler="
|
83 |
width=1024,
|
84 |
height=1024,
|
85 |
-
guidance_scale=
|
86 |
inference_steps=40,
|
87 |
deepcache=1,
|
88 |
scale=1,
|
@@ -93,6 +55,13 @@ def generate(
|
|
93 |
Info=None,
|
94 |
progress=None,
|
95 |
):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
if not torch.cuda.is_available():
|
97 |
raise Error("CUDA not available")
|
98 |
|
@@ -108,7 +77,6 @@ def generate(
|
|
108 |
# custom progress bar for multiple images
|
109 |
def callback_on_step_end(pipeline, step, timestep, latents):
|
110 |
nonlocal CURRENT_IMAGE, CURRENT_STEP
|
111 |
-
|
112 |
if progress is not None:
|
113 |
# calculate total steps for img2img based on denoising strength
|
114 |
strength = 1
|
@@ -121,19 +89,12 @@ def generate(
|
|
121 |
else:
|
122 |
refining = True
|
123 |
CURRENT_STEP += 1
|
124 |
-
|
125 |
progress(
|
126 |
(CURRENT_STEP, total_steps),
|
127 |
desc=f"{'Refining' if refining else 'Generating'} image {CURRENT_IMAGE}/{num_images}",
|
128 |
)
|
129 |
return latents
|
130 |
|
131 |
-
start = time.perf_counter()
|
132 |
-
print(f"Generating {num_images} image{'s' if num_images > 1 else ''}")
|
133 |
-
|
134 |
-
if Config.ZERO_GPU and progress is not None:
|
135 |
-
progress((100, 100), desc="ZeroGPU init")
|
136 |
-
|
137 |
loader = Loader()
|
138 |
loader.load(
|
139 |
KIND,
|
@@ -173,19 +134,13 @@ def generate(
|
|
173 |
|
174 |
images = []
|
175 |
current_seed = seed
|
176 |
-
|
177 |
-
generator = torch.Generator(device=pipe.device).manual_seed(current_seed)
|
178 |
|
|
|
179 |
try:
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
if negative_styled.startswith("(), "):
|
185 |
-
negative_styled = negative_styled[4:]
|
186 |
-
|
187 |
-
conditioning_1, pooled_1 = compel_1([positive_styled, negative_styled])
|
188 |
-
conditioning_2, pooled_2 = compel_2([positive_styled, negative_styled])
|
189 |
except PromptParser.ParsingException:
|
190 |
raise Error("Invalid prompt")
|
191 |
|
@@ -214,46 +169,52 @@ def generate(
|
|
214 |
"negative_pooled_prompt_embeds": pooled_1[1:2],
|
215 |
}
|
216 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
217 |
if progress is not None:
|
218 |
pipe_kwargs["callback_on_step_end"] = callback_on_step_end
|
|
|
219 |
|
220 |
try:
|
221 |
image = pipe(**pipe_kwargs).images[0]
|
222 |
-
|
223 |
-
refiner_kwargs = {
|
224 |
-
"image": image,
|
225 |
-
"denoising_start": 0.8,
|
226 |
-
"generator": generator,
|
227 |
-
"output_type": refiner_output_type,
|
228 |
-
"guidance_scale": guidance_scale,
|
229 |
-
"num_inference_steps": inference_steps,
|
230 |
-
"prompt_embeds": conditioning_2[0:1],
|
231 |
-
"pooled_prompt_embeds": pooled_2[0:1],
|
232 |
-
"negative_prompt_embeds": conditioning_2[1:2],
|
233 |
-
"negative_pooled_prompt_embeds": pooled_2[1:2],
|
234 |
-
}
|
235 |
-
|
236 |
-
if progress is not None:
|
237 |
-
refiner_kwargs["callback_on_step_end"] = callback_on_step_end
|
238 |
if use_refiner:
|
|
|
239 |
image = refiner(**refiner_kwargs).images[0]
|
240 |
-
if scale > 1:
|
241 |
-
image = upscaler.predict(image)
|
242 |
images.append((image, str(current_seed)))
|
243 |
current_seed += 1
|
244 |
-
except Exception as e:
|
245 |
-
raise Error(f"{e}")
|
246 |
finally:
|
247 |
CURRENT_STEP = 0
|
248 |
CURRENT_IMAGE += 1
|
249 |
|
250 |
-
#
|
251 |
-
|
252 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
253 |
|
254 |
end = time.perf_counter()
|
255 |
msg = f"Generated {len(images)} image{'s' if len(images) > 1 else ''} in {end - start:.2f}s"
|
256 |
-
|
|
|
|
|
257 |
if Info:
|
258 |
Info(msg)
|
|
|
259 |
return images
|
|
|
|
|
|
|
1 |
import time
|
2 |
from datetime import datetime
|
|
|
3 |
|
4 |
import torch
|
5 |
from compel import Compel, ReturnedEmbeddingsType
|
|
|
8 |
|
9 |
from .config import Config
|
10 |
from .loader import Loader
|
11 |
+
from .logger import Logger
|
12 |
+
from .utils import clear_cuda_cache, safe_progress, timer
|
13 |
|
14 |
|
15 |
+
# Dynamic signature for the GPU duration function; max 60s per image
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
def gpu_duration(**kwargs):
|
17 |
loading = 15
|
18 |
duration = 15
|
|
|
39 |
def generate(
|
40 |
positive_prompt,
|
41 |
negative_prompt="",
|
|
|
42 |
seed=None,
|
43 |
model="stabilityai/stable-diffusion-xl-base-1.0",
|
44 |
+
scheduler="Euler",
|
45 |
width=1024,
|
46 |
height=1024,
|
47 |
+
guidance_scale=6.0,
|
48 |
inference_steps=40,
|
49 |
deepcache=1,
|
50 |
scale=1,
|
|
|
55 |
Info=None,
|
56 |
progress=None,
|
57 |
):
|
58 |
+
start = time.perf_counter()
|
59 |
+
log = Logger("generate")
|
60 |
+
log.info(f"Generating {num_images} image{'s' if num_images > 1 else ''}...")
|
61 |
+
|
62 |
+
if Config.ZERO_GPU:
|
63 |
+
safe_progress(progress, 100, 100, "ZeroGPU init")
|
64 |
+
|
65 |
if not torch.cuda.is_available():
|
66 |
raise Error("CUDA not available")
|
67 |
|
|
|
77 |
# custom progress bar for multiple images
|
78 |
def callback_on_step_end(pipeline, step, timestep, latents):
|
79 |
nonlocal CURRENT_IMAGE, CURRENT_STEP
|
|
|
80 |
if progress is not None:
|
81 |
# calculate total steps for img2img based on denoising strength
|
82 |
strength = 1
|
|
|
89 |
else:
|
90 |
refining = True
|
91 |
CURRENT_STEP += 1
|
|
|
92 |
progress(
|
93 |
(CURRENT_STEP, total_steps),
|
94 |
desc=f"{'Refining' if refining else 'Generating'} image {CURRENT_IMAGE}/{num_images}",
|
95 |
)
|
96 |
return latents
|
97 |
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
loader = Loader()
|
99 |
loader.load(
|
100 |
KIND,
|
|
|
134 |
|
135 |
images = []
|
136 |
current_seed = seed
|
137 |
+
safe_progress(progress, 0, num_images, f"Generating image 0/{num_images}")
|
|
|
138 |
|
139 |
+
for i in range(num_images):
|
140 |
try:
|
141 |
+
generator = torch.Generator(device=pipe.device).manual_seed(current_seed)
|
142 |
+
conditioning_1, pooled_1 = compel_1([positive_prompt, negative_prompt])
|
143 |
+
conditioning_2, pooled_2 = compel_2([positive_prompt, negative_prompt])
|
|
|
|
|
|
|
|
|
|
|
|
|
144 |
except PromptParser.ParsingException:
|
145 |
raise Error("Invalid prompt")
|
146 |
|
|
|
169 |
"negative_pooled_prompt_embeds": pooled_1[1:2],
|
170 |
}
|
171 |
|
172 |
+
refiner_kwargs = {
|
173 |
+
"denoising_start": 0.8,
|
174 |
+
"generator": generator,
|
175 |
+
"output_type": refiner_output_type,
|
176 |
+
"guidance_scale": guidance_scale,
|
177 |
+
"num_inference_steps": inference_steps,
|
178 |
+
"prompt_embeds": conditioning_2[0:1],
|
179 |
+
"pooled_prompt_embeds": pooled_2[0:1],
|
180 |
+
"negative_prompt_embeds": conditioning_2[1:2],
|
181 |
+
"negative_pooled_prompt_embeds": pooled_2[1:2],
|
182 |
+
}
|
183 |
+
|
184 |
if progress is not None:
|
185 |
pipe_kwargs["callback_on_step_end"] = callback_on_step_end
|
186 |
+
refiner_kwargs["callback_on_step_end"] = callback_on_step_end
|
187 |
|
188 |
try:
|
189 |
image = pipe(**pipe_kwargs).images[0]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
190 |
if use_refiner:
|
191 |
+
refiner_kwargs["image"] = image
|
192 |
image = refiner(**refiner_kwargs).images[0]
|
|
|
|
|
193 |
images.append((image, str(current_seed)))
|
194 |
current_seed += 1
|
|
|
|
|
195 |
finally:
|
196 |
CURRENT_STEP = 0
|
197 |
CURRENT_IMAGE += 1
|
198 |
|
199 |
+
# Upscale
|
200 |
+
if scale > 1:
|
201 |
+
msg = f"Upscaling {scale}x"
|
202 |
+
with timer(msg):
|
203 |
+
safe_progress(progress, 0, num_images, desc=msg)
|
204 |
+
for i, image in enumerate(images):
|
205 |
+
images = upscaler.predict(image[0])
|
206 |
+
images[i] = image
|
207 |
+
safe_progress(progress, i + 1, num_images, desc=msg)
|
208 |
+
|
209 |
+
# Flush memory after generating
|
210 |
+
clear_cuda_cache()
|
211 |
|
212 |
end = time.perf_counter()
|
213 |
msg = f"Generated {len(images)} image{'s' if len(images) > 1 else ''} in {end - start:.2f}s"
|
214 |
+
log.info(msg)
|
215 |
+
|
216 |
+
# Alert if notifier provided
|
217 |
if Info:
|
218 |
Info(msg)
|
219 |
+
|
220 |
return images
|
lib/loader.py
CHANGED
@@ -6,8 +6,9 @@ from DeepCache import DeepCacheSDHelper
|
|
6 |
from diffusers.models import AutoencoderKL
|
7 |
|
8 |
from .config import Config
|
|
|
9 |
from .upscaler import RealESRGAN
|
10 |
-
from .utils import timer
|
11 |
|
12 |
|
13 |
class Loader:
|
@@ -22,17 +23,9 @@ class Loader:
|
|
22 |
cls._instance.model = None
|
23 |
cls._instance.refiner = None
|
24 |
cls._instance.upscaler = None
|
|
|
25 |
return cls._instance
|
26 |
|
27 |
-
# switching models
|
28 |
-
def _should_reset_refiner(self, model=""):
|
29 |
-
if self.refiner is None:
|
30 |
-
return False
|
31 |
-
if self.model and self.model.lower() != model.lower():
|
32 |
-
return True
|
33 |
-
return False
|
34 |
-
|
35 |
-
# switching refiner
|
36 |
def _should_unload_refiner(self, refiner=False):
|
37 |
if self.refiner is None:
|
38 |
return False
|
@@ -60,13 +53,6 @@ class Loader:
|
|
60 |
return True
|
61 |
return False
|
62 |
|
63 |
-
def _reset_refiner(self):
|
64 |
-
if self.refiner is not None:
|
65 |
-
self.refiner.vae = None
|
66 |
-
self.refiner.scheduler = None
|
67 |
-
self.refiner.tokenizer_2 = None
|
68 |
-
self.refiner.text_encoder_2 = None
|
69 |
-
|
70 |
def _unload_refiner(self):
|
71 |
if self.refiner is not None:
|
72 |
with timer("Unloading refiner"):
|
@@ -79,7 +65,7 @@ class Loader:
|
|
79 |
|
80 |
def _unload_deepcache(self):
|
81 |
if self.pipe.deepcache is not None:
|
82 |
-
|
83 |
self.pipe.deepcache.disable()
|
84 |
delattr(self.pipe, "deepcache")
|
85 |
if self.refiner is not None:
|
@@ -91,15 +77,17 @@ class Loader:
|
|
91 |
if self.pipe is not None:
|
92 |
with timer(f"Unloading {self.model}"):
|
93 |
self.pipe.to("cpu", silence_dtype_warnings=True)
|
|
|
|
|
|
|
|
|
|
|
94 |
|
95 |
def _unload(self, model, refiner, deepcache, scale):
|
96 |
to_unload = []
|
97 |
if self._should_unload_deepcache(deepcache): # remove deepcache first
|
98 |
self._unload_deepcache()
|
99 |
|
100 |
-
if self._should_reset_refiner(model):
|
101 |
-
self._reset_refiner()
|
102 |
-
|
103 |
if self._should_unload_refiner(refiner):
|
104 |
self._unload_refiner()
|
105 |
to_unload.append("refiner")
|
@@ -113,59 +101,73 @@ class Loader:
|
|
113 |
to_unload.append("model")
|
114 |
to_unload.append("pipe")
|
115 |
|
116 |
-
|
|
|
117 |
for component in to_unload:
|
118 |
setattr(self, component, None)
|
119 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
120 |
|
121 |
def _load_refiner(self, refiner, progress, **kwargs):
|
122 |
-
if
|
123 |
model = Config.REFINER_MODEL
|
124 |
pipeline = Config.PIPELINES["img2img"]
|
125 |
try:
|
126 |
with timer(f"Loading {model}"):
|
127 |
self.refiner = pipeline.from_pretrained(model, **kwargs).to("cuda")
|
128 |
except Exception as e:
|
129 |
-
|
130 |
self.refiner = None
|
131 |
return
|
132 |
if self.refiner is not None:
|
133 |
self.refiner.set_progress_bar_config(disable=progress is not None)
|
134 |
|
135 |
def _load_upscaler(self, scale=1):
|
136 |
-
if self.
|
137 |
try:
|
138 |
with timer(f"Loading {scale}x upscaler"):
|
139 |
self.upscaler = RealESRGAN(scale, device=self.pipe.device)
|
140 |
self.upscaler.load_weights()
|
141 |
except Exception as e:
|
142 |
-
|
143 |
self.upscaler = None
|
144 |
|
145 |
def _load_deepcache(self, interval=1):
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
if self.refiner is not None:
|
157 |
-
refiner_has_deepcache = hasattr(self.refiner, "deepcache")
|
158 |
-
if not refiner_has_deepcache and interval == 1:
|
159 |
-
return
|
160 |
-
if refiner_has_deepcache and self.refiner.deepcache.params["cache_interval"] == interval:
|
161 |
-
return
|
162 |
-
self.refiner.deepcache = DeepCacheSDHelper(pipe=self.refiner)
|
163 |
-
self.refiner.deepcache.set_params(cache_interval=interval)
|
164 |
-
self.refiner.deepcache.enable()
|
165 |
|
166 |
def _load_pipeline(self, kind, model, progress, **kwargs):
|
167 |
pipeline = Config.PIPELINES[kind]
|
168 |
-
if self.
|
169 |
try:
|
170 |
with timer(f"Loading {model}"):
|
171 |
self.model = model
|
@@ -183,21 +185,16 @@ class Loader:
|
|
183 |
self.refiner.text_encoder_2 = self.pipe.text_encoder_2
|
184 |
self.refiner.to(self.pipe.device)
|
185 |
except Exception as e:
|
186 |
-
|
187 |
self.model = None
|
188 |
self.pipe = None
|
|
|
189 |
return
|
190 |
if not isinstance(self.pipe, pipeline):
|
191 |
self.pipe = pipeline.from_pipe(self.pipe).to("cuda")
|
192 |
if self.pipe is not None:
|
193 |
self.pipe.set_progress_bar_config(disable=progress is not None)
|
194 |
|
195 |
-
def collect(self):
|
196 |
-
torch.cuda.empty_cache()
|
197 |
-
torch.cuda.ipc_collect()
|
198 |
-
torch.cuda.reset_peak_memory_stats()
|
199 |
-
torch.cuda.synchronize()
|
200 |
-
|
201 |
def load(self, kind, model, scheduler, deepcache, scale, karras, refiner, progress):
|
202 |
scheduler_kwargs = {
|
203 |
"beta_start": 0.00085,
|
@@ -245,27 +242,31 @@ class Loader:
|
|
245 |
# same model, different scheduler
|
246 |
if self.model.lower() == model.lower():
|
247 |
if not same_scheduler:
|
248 |
-
|
249 |
if not same_karras:
|
250 |
-
|
251 |
if not same_scheduler or not same_karras:
|
252 |
self.pipe.scheduler = Config.SCHEDULERS[scheduler](**scheduler_kwargs)
|
253 |
if self.refiner is not None:
|
254 |
self.refiner.scheduler = self.pipe.scheduler
|
255 |
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
self.
|
|
|
|
|
|
|
|
|
|
6 |
from diffusers.models import AutoencoderKL
|
7 |
|
8 |
from .config import Config
|
9 |
+
from .logger import Logger
|
10 |
from .upscaler import RealESRGAN
|
11 |
+
from .utils import clear_cuda_cache, timer
|
12 |
|
13 |
|
14 |
class Loader:
|
|
|
23 |
cls._instance.model = None
|
24 |
cls._instance.refiner = None
|
25 |
cls._instance.upscaler = None
|
26 |
+
cls._instance.log = Logger("Loader")
|
27 |
return cls._instance
|
28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
def _should_unload_refiner(self, refiner=False):
|
30 |
if self.refiner is None:
|
31 |
return False
|
|
|
53 |
return True
|
54 |
return False
|
55 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
def _unload_refiner(self):
|
57 |
if self.refiner is not None:
|
58 |
with timer("Unloading refiner"):
|
|
|
65 |
|
66 |
def _unload_deepcache(self):
|
67 |
if self.pipe.deepcache is not None:
|
68 |
+
self.log.info("Disabling DeepCache")
|
69 |
self.pipe.deepcache.disable()
|
70 |
delattr(self.pipe, "deepcache")
|
71 |
if self.refiner is not None:
|
|
|
77 |
if self.pipe is not None:
|
78 |
with timer(f"Unloading {self.model}"):
|
79 |
self.pipe.to("cpu", silence_dtype_warnings=True)
|
80 |
+
if self.refiner is not None:
|
81 |
+
self.refiner.vae = None
|
82 |
+
self.refiner.scheduler = None
|
83 |
+
self.refiner.tokenizer_2 = None
|
84 |
+
self.refiner.text_encoder_2 = None
|
85 |
|
86 |
def _unload(self, model, refiner, deepcache, scale):
|
87 |
to_unload = []
|
88 |
if self._should_unload_deepcache(deepcache): # remove deepcache first
|
89 |
self._unload_deepcache()
|
90 |
|
|
|
|
|
|
|
91 |
if self._should_unload_refiner(refiner):
|
92 |
self._unload_refiner()
|
93 |
to_unload.append("refiner")
|
|
|
101 |
to_unload.append("model")
|
102 |
to_unload.append("pipe")
|
103 |
|
104 |
+
# Flush cache and run garbage collector
|
105 |
+
clear_cuda_cache()
|
106 |
for component in to_unload:
|
107 |
setattr(self, component, None)
|
108 |
+
gc.collect()
|
109 |
+
|
110 |
+
def _should_load_refiner(self, refiner=False):
|
111 |
+
if self.refiner is None and refiner:
|
112 |
+
return True
|
113 |
+
return False
|
114 |
+
|
115 |
+
def _should_load_upscaler(self, scale=1):
|
116 |
+
if self.upscaler is None and scale > 1:
|
117 |
+
return True
|
118 |
+
return False
|
119 |
+
|
120 |
+
def _should_load_deepcache(self, interval=1):
|
121 |
+
has_deepcache = hasattr(self.pipe, "deepcache")
|
122 |
+
if not has_deepcache and interval != 1:
|
123 |
+
return True
|
124 |
+
if has_deepcache and self.pipe.deepcache.params["cache_interval"] != interval:
|
125 |
+
return True
|
126 |
+
return False
|
127 |
+
|
128 |
+
def _should_load_pipeline(self):
|
129 |
+
if self.pipe is None:
|
130 |
+
return True
|
131 |
+
return False
|
132 |
|
133 |
def _load_refiner(self, refiner, progress, **kwargs):
|
134 |
+
if self._should_load_refiner(refiner):
|
135 |
model = Config.REFINER_MODEL
|
136 |
pipeline = Config.PIPELINES["img2img"]
|
137 |
try:
|
138 |
with timer(f"Loading {model}"):
|
139 |
self.refiner = pipeline.from_pretrained(model, **kwargs).to("cuda")
|
140 |
except Exception as e:
|
141 |
+
self.log.error(f"Error loading {model}: {e}")
|
142 |
self.refiner = None
|
143 |
return
|
144 |
if self.refiner is not None:
|
145 |
self.refiner.set_progress_bar_config(disable=progress is not None)
|
146 |
|
147 |
def _load_upscaler(self, scale=1):
|
148 |
+
if self._should_load_upscaler(scale):
|
149 |
try:
|
150 |
with timer(f"Loading {scale}x upscaler"):
|
151 |
self.upscaler = RealESRGAN(scale, device=self.pipe.device)
|
152 |
self.upscaler.load_weights()
|
153 |
except Exception as e:
|
154 |
+
self.log.error(f"Error loading {scale}x upscaler: {e}")
|
155 |
self.upscaler = None
|
156 |
|
157 |
def _load_deepcache(self, interval=1):
|
158 |
+
if self._should_load_deepcache(interval):
|
159 |
+
self.log.info("Enabling DeepCache")
|
160 |
+
self.pipe.deepcache = DeepCacheSDHelper(pipe=self.pipe)
|
161 |
+
self.pipe.deepcache.set_params(cache_interval=interval)
|
162 |
+
self.pipe.deepcache.enable()
|
163 |
+
if self.refiner is not None:
|
164 |
+
self.refiner.deepcache = DeepCacheSDHelper(pipe=self.refiner)
|
165 |
+
self.refiner.deepcache.set_params(cache_interval=interval)
|
166 |
+
self.refiner.deepcache.enable()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
167 |
|
168 |
def _load_pipeline(self, kind, model, progress, **kwargs):
|
169 |
pipeline = Config.PIPELINES[kind]
|
170 |
+
if self._should_load_pipeline():
|
171 |
try:
|
172 |
with timer(f"Loading {model}"):
|
173 |
self.model = model
|
|
|
185 |
self.refiner.text_encoder_2 = self.pipe.text_encoder_2
|
186 |
self.refiner.to(self.pipe.device)
|
187 |
except Exception as e:
|
188 |
+
self.log.error(f"Error loading {model}: {e}")
|
189 |
self.model = None
|
190 |
self.pipe = None
|
191 |
+
self.refiner = None
|
192 |
return
|
193 |
if not isinstance(self.pipe, pipeline):
|
194 |
self.pipe = pipeline.from_pipe(self.pipe).to("cuda")
|
195 |
if self.pipe is not None:
|
196 |
self.pipe.set_progress_bar_config(disable=progress is not None)
|
197 |
|
|
|
|
|
|
|
|
|
|
|
|
|
198 |
def load(self, kind, model, scheduler, deepcache, scale, karras, refiner, progress):
|
199 |
scheduler_kwargs = {
|
200 |
"beta_start": 0.00085,
|
|
|
242 |
# same model, different scheduler
|
243 |
if self.model.lower() == model.lower():
|
244 |
if not same_scheduler:
|
245 |
+
self.log.info(f"Enabling {scheduler}")
|
246 |
if not same_karras:
|
247 |
+
self.log.info(f"{'Enabling' if karras else 'Disabling'} Karras sigmas")
|
248 |
if not same_scheduler or not same_karras:
|
249 |
self.pipe.scheduler = Config.SCHEDULERS[scheduler](**scheduler_kwargs)
|
250 |
if self.refiner is not None:
|
251 |
self.refiner.scheduler = self.pipe.scheduler
|
252 |
|
253 |
+
if self._should_load_refiner(refiner):
|
254 |
+
# https://huggingface.co/stabilityai/stable-diffusion-xl-refiner-1.0/blob/main/model_index.json
|
255 |
+
refiner_kwargs = {
|
256 |
+
"variant": "fp16",
|
257 |
+
"torch_dtype": dtype,
|
258 |
+
"add_watermarker": False,
|
259 |
+
"requires_aesthetics_score": True,
|
260 |
+
"force_zeros_for_empty_prompt": False,
|
261 |
+
"vae": self.pipe.vae,
|
262 |
+
"scheduler": self.pipe.scheduler,
|
263 |
+
"tokenizer_2": self.pipe.tokenizer_2,
|
264 |
+
"text_encoder_2": self.pipe.text_encoder_2,
|
265 |
+
}
|
266 |
+
self._load_refiner(refiner, progress, **refiner_kwargs) # load refiner before deepcache
|
267 |
+
|
268 |
+
if self._should_load_deepcache(deepcache):
|
269 |
+
self._load_deepcache(deepcache)
|
270 |
+
|
271 |
+
if self._should_load_upscaler(scale):
|
272 |
+
self._load_upscaler(scale)
|
lib/logger.py
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import logging
|
2 |
+
from threading import Lock
|
3 |
+
|
4 |
+
|
5 |
+
class Logger:
|
6 |
+
_instances = {}
|
7 |
+
_lock = Lock()
|
8 |
+
|
9 |
+
def __new__(cls, name="root"):
|
10 |
+
with cls._lock:
|
11 |
+
if name not in cls._instances:
|
12 |
+
instance = super().__new__(cls)
|
13 |
+
instance._init(name)
|
14 |
+
cls._instances[name] = instance
|
15 |
+
return cls._instances[name]
|
16 |
+
|
17 |
+
def _init(self, name):
|
18 |
+
self.logger = logging.getLogger(name)
|
19 |
+
self.logger.setLevel(logging.DEBUG)
|
20 |
+
self.logger.propagate = False
|
21 |
+
|
22 |
+
console_handler = logging.StreamHandler()
|
23 |
+
console_handler.setLevel(logging.INFO)
|
24 |
+
|
25 |
+
file_handler = logging.FileHandler("app.log")
|
26 |
+
file_handler.setLevel(logging.DEBUG)
|
27 |
+
|
28 |
+
formatter = logging.Formatter(
|
29 |
+
"%(asctime)s [%(threadName)s] %(levelname)-5s %(name)s - %(message)s",
|
30 |
+
datefmt="%Y-%m-%d %H:%M:%S", # no milliseconds
|
31 |
+
)
|
32 |
+
console_handler.setFormatter(formatter)
|
33 |
+
file_handler.setFormatter(formatter)
|
34 |
+
|
35 |
+
self.logger.addHandler(console_handler)
|
36 |
+
self.logger.addHandler(file_handler)
|
37 |
+
|
38 |
+
def _log(self, level, message):
|
39 |
+
log_message = f"{message}".strip()
|
40 |
+
self.logger.log(level, log_message)
|
41 |
+
|
42 |
+
def debug(self, message, **kwargs):
|
43 |
+
self._log(logging.DEBUG, message, **kwargs)
|
44 |
+
|
45 |
+
def info(self, message, **kwargs):
|
46 |
+
self._log(logging.INFO, message, **kwargs)
|
47 |
+
|
48 |
+
def warning(self, message, **kwargs):
|
49 |
+
self._log(logging.WARNING, message, **kwargs)
|
50 |
+
|
51 |
+
def error(self, message, **kwargs):
|
52 |
+
self._log(logging.ERROR, message, **kwargs)
|
53 |
+
|
54 |
+
def critical(self, message, **kwargs):
|
55 |
+
self._log(logging.CRITICAL, message, **kwargs)
|
lib/utils.py
CHANGED
@@ -1,13 +1,12 @@
|
|
1 |
import functools
|
2 |
import inspect
|
3 |
import json
|
4 |
-
import os
|
5 |
import time
|
6 |
from contextlib import contextmanager
|
7 |
from typing import Callable, TypeVar
|
8 |
|
9 |
import anyio
|
10 |
-
import
|
11 |
from anyio import Semaphore
|
12 |
from diffusers.utils import logging as diffusers_logging
|
13 |
from huggingface_hub._snapshot_download import snapshot_download
|
@@ -34,9 +33,10 @@ def timer(message="Operation", logger=print):
|
|
34 |
|
35 |
|
36 |
@functools.lru_cache()
|
37 |
-
def
|
38 |
with open(path, "r", encoding="utf-8") as file:
|
39 |
-
|
|
|
40 |
|
41 |
|
42 |
@functools.lru_cache()
|
@@ -56,6 +56,19 @@ def enable_progress_bars():
|
|
56 |
diffusers_logging.enable_progress_bar()
|
57 |
|
58 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
def download_repo_files(repo_id, allow_patterns, token=None):
|
60 |
was_disabled = are_progress_bars_disabled()
|
61 |
enable_progress_bars()
|
@@ -72,34 +85,7 @@ def download_repo_files(repo_id, allow_patterns, token=None):
|
|
72 |
return snapshot_path
|
73 |
|
74 |
|
75 |
-
|
76 |
-
base_url = "https://civitai.com/api/download/models"
|
77 |
-
file = f"{file_path}/{lora_id}.{version_id}.safetensors"
|
78 |
-
|
79 |
-
if os.path.exists(file):
|
80 |
-
return
|
81 |
-
|
82 |
-
try:
|
83 |
-
params = {"token": token}
|
84 |
-
response = httpx.get(
|
85 |
-
f"{base_url}/{version_id}",
|
86 |
-
timeout=None,
|
87 |
-
params=params,
|
88 |
-
follow_redirects=True,
|
89 |
-
)
|
90 |
-
|
91 |
-
response.raise_for_status()
|
92 |
-
os.makedirs(file_path, exist_ok=True)
|
93 |
-
|
94 |
-
with open(file, "wb") as f:
|
95 |
-
f.write(response.content)
|
96 |
-
except httpx.HTTPStatusError as e:
|
97 |
-
print(f"HTTPError: {e.response.status_code} {e.response.text}")
|
98 |
-
except httpx.RequestError as e:
|
99 |
-
print(f"RequestError: {e}")
|
100 |
-
|
101 |
-
|
102 |
-
# like the original but supports args and kwargs instead of a dict
|
103 |
# https://github.com/huggingface/huggingface-inference-toolkit/blob/0.2.0/src/huggingface_inference_toolkit/async_utils.py
|
104 |
async def async_call(fn: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> T:
|
105 |
async with MAX_THREADS_GUARD:
|
|
|
1 |
import functools
|
2 |
import inspect
|
3 |
import json
|
|
|
4 |
import time
|
5 |
from contextlib import contextmanager
|
6 |
from typing import Callable, TypeVar
|
7 |
|
8 |
import anyio
|
9 |
+
import torch
|
10 |
from anyio import Semaphore
|
11 |
from diffusers.utils import logging as diffusers_logging
|
12 |
from huggingface_hub._snapshot_download import snapshot_download
|
|
|
33 |
|
34 |
|
35 |
@functools.lru_cache()
|
36 |
+
def read_json(path: str) -> dict:
|
37 |
with open(path, "r", encoding="utf-8") as file:
|
38 |
+
data = json.load(file)
|
39 |
+
return json.dumps(data, indent=4)
|
40 |
|
41 |
|
42 |
@functools.lru_cache()
|
|
|
56 |
diffusers_logging.enable_progress_bar()
|
57 |
|
58 |
|
59 |
+
def safe_progress(progress, current=0, total=0, desc=""):
|
60 |
+
if progress is not None:
|
61 |
+
progress((current, total), desc=desc)
|
62 |
+
|
63 |
+
|
64 |
+
def clear_cuda_cache():
|
65 |
+
if torch.cuda.is_available():
|
66 |
+
torch.cuda.empty_cache()
|
67 |
+
torch.cuda.ipc_collect()
|
68 |
+
torch.cuda.reset_peak_memory_stats()
|
69 |
+
torch.cuda.synchronize()
|
70 |
+
|
71 |
+
|
72 |
def download_repo_files(repo_id, allow_patterns, token=None):
|
73 |
was_disabled = are_progress_bars_disabled()
|
74 |
enable_progress_bars()
|
|
|
85 |
return snapshot_path
|
86 |
|
87 |
|
88 |
+
# Like the original but supports args and kwargs instead of a dict
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
# https://github.com/huggingface/huggingface-inference-toolkit/blob/0.2.0/src/huggingface_inference_toolkit/async_utils.py
|
90 |
async def async_call(fn: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> T:
|
91 |
async with MAX_THREADS_GUARD:
|
partials/intro.html
CHANGED
@@ -7,18 +7,7 @@
|
|
7 |
<path d="M7.48877 6.75C7.29015 6.75 7.09967 6.82902 6.95923 6.96967C6.81879 7.11032 6.73989 7.30109 6.73989 7.5C6.73989 7.69891 6.81879 7.88968 6.95923 8.03033C7.09967 8.17098 7.29015 8.25 7.48877 8.25C7.68738 8.25 7.87786 8.17098 8.0183 8.03033C8.15874 7.88968 8.23764 7.69891 8.23764 7.5C8.23764 7.30109 8.15874 7.11032 8.0183 6.96967C7.87786 6.82902 7.68738 6.75 7.48877 6.75ZM7.8632 0C11.2331 0 11.3155 2.6775 9.54818 3.5625C8.80679 3.93 8.47728 4.7175 8.335 5.415C8.69446 5.565 9.00899 5.7975 9.24863 6.0975C12.0195 4.5975 15 5.19 15 7.875C15 11.25 12.3265 11.325 11.4428 9.5475C11.0684 8.805 10.2746 8.475 9.57813 8.3325C9.42836 8.6925 9.19621 9 8.89665 9.255C10.3869 12.0225 9.79531 15 7.11433 15C3.74438 15 3.67698 12.315 5.44433 11.43C6.17823 11.0625 6.50774 10.2825 6.65751 9.5925C6.29056 9.4425 5.96855 9.2025 5.72891 8.9025C2.96555 10.3875 0 9.8025 0 7.125C0 3.75 2.666 3.6675 3.54967 5.445C3.92411 6.1875 4.71043 6.51 5.40689 6.6525C5.54918 6.2925 5.78882 5.9775 6.09586 5.7375C4.60559 2.97 5.1972 0 7.8632 0Z"></path>
|
8 |
</svg>
|
9 |
</div>
|
10 |
-
<
|
11 |
-
|
12 |
-
|
13 |
-
<span>XL</span>
|
14 |
-
<a href="https://huggingface.co/spaces/adamelliotfields/diffusion-flux" target="_blank" rel="noopener noreferrer">FLUX.1</a>
|
15 |
-
<a href="https://huggingface.co/spaces/adamelliotfields/diffusion-xl/blob/main/DOCS.md" target="_blank" rel="noopener noreferrer">Docs</a>
|
16 |
-
<a href="https://adamelliotfields-diffusion-xl.hf.space" target="_blank" rel="noopener noreferrer">
|
17 |
-
<svg style="display: inline-block" width="16px" height="16px" viewBox="0 0 12 12" fill="currentColor" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid meet">
|
18 |
-
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.5 1.75H9.75C9.88807 1.75 10 1.86193 10 2V4.25C10 4.38807 9.88807 4.5 9.75 4.5C9.61193 4.5 9.5 4.38807 9.5 4.25V2.60355L6.42678 5.67678C6.32915 5.77441 6.17085 5.77441 6.07322 5.67678C5.97559 5.57915 5.97559 5.42085 6.07322 5.32322L9.14645 2.25H7.5C7.36193 2.25 7.25 2.13807 7.25 2C7.25 1.86193 7.36193 1.75 7.5 1.75Z" fill="currentColor"></path>
|
19 |
-
<path fill-rule="evenodd" clip-rule="evenodd" d="M6 2.5C6 2.22386 5.77614 2 5.5 2H2.69388C2.50985 2 2.33336 2.07311 2.20323 2.20323C2.0731 2.33336 2 2.50986 2 2.69389V8.93885C2 9.12288 2.0731 9.29933 2.20323 9.42953C2.33336 9.55963 2.50985 9.63273 2.69388 9.63273H8.93884C9.12287 9.63273 9.29941 9.55963 9.42951 9.42953C9.55961 9.29933 9.63271 9.12288 9.63271 8.93885V6.5C9.63271 6.22386 9.40885 6 9.13271 6C8.85657 6 8.63271 6.22386 8.63271 6.5V8.63273H3V3H5.5C5.77614 3 6 2.77614 6 2.5Z" fill="currentColor" fill-opacity="0.3"></path>
|
20 |
-
</svg>
|
21 |
-
</a>
|
22 |
-
</nav>
|
23 |
-
</div>
|
24 |
</div>
|
|
|
7 |
<path d="M7.48877 6.75C7.29015 6.75 7.09967 6.82902 6.95923 6.96967C6.81879 7.11032 6.73989 7.30109 6.73989 7.5C6.73989 7.69891 6.81879 7.88968 6.95923 8.03033C7.09967 8.17098 7.29015 8.25 7.48877 8.25C7.68738 8.25 7.87786 8.17098 8.0183 8.03033C8.15874 7.88968 8.23764 7.69891 8.23764 7.5C8.23764 7.30109 8.15874 7.11032 8.0183 6.96967C7.87786 6.82902 7.68738 6.75 7.48877 6.75ZM7.8632 0C11.2331 0 11.3155 2.6775 9.54818 3.5625C8.80679 3.93 8.47728 4.7175 8.335 5.415C8.69446 5.565 9.00899 5.7975 9.24863 6.0975C12.0195 4.5975 15 5.19 15 7.875C15 11.25 12.3265 11.325 11.4428 9.5475C11.0684 8.805 10.2746 8.475 9.57813 8.3325C9.42836 8.6925 9.19621 9 8.89665 9.255C10.3869 12.0225 9.79531 15 7.11433 15C3.74438 15 3.67698 12.315 5.44433 11.43C6.17823 11.0625 6.50774 10.2825 6.65751 9.5925C6.29056 9.4425 5.96855 9.2025 5.72891 8.9025C2.96555 10.3875 0 9.8025 0 7.125C0 3.75 2.666 3.6675 3.54967 5.445C3.92411 6.1875 4.71043 6.51 5.40689 6.6525C5.54918 6.2925 5.78882 5.9775 6.09586 5.7375C4.60559 2.97 5.1972 0 7.8632 0Z"></path>
|
8 |
</svg>
|
9 |
</div>
|
10 |
+
<p>
|
11 |
+
Image generation studio for Stable Diffusion XL.
|
12 |
+
</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
</div>
|
requirements.txt
CHANGED
@@ -1,19 +1,12 @@
|
|
1 |
-
anyio==4.
|
2 |
-
accelerate
|
3 |
-
einops==0.8.0
|
4 |
compel==2.0.3
|
5 |
deepcache==0.1.1
|
6 |
-
diffusers==0.30.
|
7 |
-
|
|
|
8 |
hf-transfer
|
9 |
-
httpx
|
10 |
-
gradio==4.41.0
|
11 |
numpy==1.26.4
|
12 |
-
ruff==0.
|
13 |
-
spaces
|
14 |
torch==2.2.0
|
15 |
torchvision==0.17.0
|
16 |
-
transformers==4.43.4
|
17 |
-
# TODO: unpin once fixed upstream
|
18 |
-
# https://github.com/gradio-app/gradio/issues/9278
|
19 |
-
fastapi==0.112.2
|
|
|
1 |
+
anyio==4.6.1
|
|
|
|
|
2 |
compel==2.0.3
|
3 |
deepcache==0.1.1
|
4 |
+
diffusers==0.30.3
|
5 |
+
einops==0.8.0
|
6 |
+
gradio==4.44.1
|
7 |
hf-transfer
|
|
|
|
|
8 |
numpy==1.26.4
|
9 |
+
ruff==0.6.9
|
10 |
+
spaces==0.30.4
|
11 |
torch==2.2.0
|
12 |
torchvision==0.17.0
|
|
|
|
|
|
|
|