Files changed (13) hide show
  1. .gitignore +0 -207
  2. README.md +1 -3
  3. app.py +850 -640
  4. constants.py +0 -606
  5. image_processor.py +0 -130
  6. lora_dict.json +0 -0
  7. model_dict.json +0 -0
  8. modutils.py +1290 -0
  9. packages.txt +1 -1
  10. pre-requirements.txt +0 -1
  11. requirements.txt +3 -12
  12. stablepy_model.py +0 -0
  13. utils.py +49 -713
.gitignore DELETED
@@ -1,207 +0,0 @@
1
- # Byte-compiled / optimized / DLL files
2
- __pycache__/
3
- *.py[codz]
4
- *$py.class
5
-
6
- # C extensions
7
- *.so
8
-
9
- # Distribution / packaging
10
- .Python
11
- build/
12
- develop-eggs/
13
- dist/
14
- downloads/
15
- eggs/
16
- .eggs/
17
- lib/
18
- lib64/
19
- parts/
20
- sdist/
21
- var/
22
- wheels/
23
- share/python-wheels/
24
- *.egg-info/
25
- .installed.cfg
26
- *.egg
27
- MANIFEST
28
-
29
- # PyInstaller
30
- # Usually these files are written by a python script from a template
31
- # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
- *.manifest
33
- *.spec
34
-
35
- # Installer logs
36
- pip-log.txt
37
- pip-delete-this-directory.txt
38
-
39
- # Unit test / coverage reports
40
- htmlcov/
41
- .tox/
42
- .nox/
43
- .coverage
44
- .coverage.*
45
- .cache
46
- nosetests.xml
47
- coverage.xml
48
- *.cover
49
- *.py.cover
50
- .hypothesis/
51
- .pytest_cache/
52
- cover/
53
-
54
- # Translations
55
- *.mo
56
- *.pot
57
-
58
- # Django stuff:
59
- *.log
60
- local_settings.py
61
- db.sqlite3
62
- db.sqlite3-journal
63
-
64
- # Flask stuff:
65
- instance/
66
- .webassets-cache
67
-
68
- # Scrapy stuff:
69
- .scrapy
70
-
71
- # Sphinx documentation
72
- docs/_build/
73
-
74
- # PyBuilder
75
- .pybuilder/
76
- target/
77
-
78
- # Jupyter Notebook
79
- .ipynb_checkpoints
80
-
81
- # IPython
82
- profile_default/
83
- ipython_config.py
84
-
85
- # pyenv
86
- # For a library or package, you might want to ignore these files since the code is
87
- # intended to run in multiple environments; otherwise, check them in:
88
- # .python-version
89
-
90
- # pipenv
91
- # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
- # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
- # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
- # install all needed dependencies.
95
- #Pipfile.lock
96
-
97
- # UV
98
- # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
- # This is especially recommended for binary packages to ensure reproducibility, and is more
100
- # commonly ignored for libraries.
101
- #uv.lock
102
-
103
- # poetry
104
- # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
- # This is especially recommended for binary packages to ensure reproducibility, and is more
106
- # commonly ignored for libraries.
107
- # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
- #poetry.lock
109
- #poetry.toml
110
-
111
- # pdm
112
- # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113
- # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
114
- # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
115
- #pdm.lock
116
- #pdm.toml
117
- .pdm-python
118
- .pdm-build/
119
-
120
- # pixi
121
- # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
122
- #pixi.lock
123
- # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
124
- # in the .venv directory. It is recommended not to include this directory in version control.
125
- .pixi
126
-
127
- # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128
- __pypackages__/
129
-
130
- # Celery stuff
131
- celerybeat-schedule
132
- celerybeat.pid
133
-
134
- # SageMath parsed files
135
- *.sage.py
136
-
137
- # Environments
138
- .env
139
- .envrc
140
- .venv
141
- env/
142
- venv/
143
- ENV/
144
- env.bak/
145
- venv.bak/
146
-
147
- # Spyder project settings
148
- .spyderproject
149
- .spyproject
150
-
151
- # Rope project settings
152
- .ropeproject
153
-
154
- # mkdocs documentation
155
- /site
156
-
157
- # mypy
158
- .mypy_cache/
159
- .dmypy.json
160
- dmypy.json
161
-
162
- # Pyre type checker
163
- .pyre/
164
-
165
- # pytype static type analyzer
166
- .pytype/
167
-
168
- # Cython debug symbols
169
- cython_debug/
170
-
171
- # PyCharm
172
- # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
173
- # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
174
- # and can be added to the global gitignore or merged into this file. For a more nuclear
175
- # option (not recommended) you can uncomment the following to ignore the entire idea folder.
176
- #.idea/
177
-
178
- # Abstra
179
- # Abstra is an AI-powered process automation framework.
180
- # Ignore directories containing user credentials, local state, and settings.
181
- # Learn more at https://abstra.io/docs
182
- .abstra/
183
-
184
- # Visual Studio Code
185
- # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
186
- # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
187
- # and can be added to the global gitignore or merged into this file. However, if you prefer,
188
- # you could uncomment the following to ignore the entire vscode folder
189
- # .vscode/
190
-
191
- # Ruff stuff:
192
- .ruff_cache/
193
-
194
- # PyPI configuration file
195
- .pypirc
196
-
197
- # Cursor
198
- # Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
199
- # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
200
- # refer to https://docs.cursor.com/context/ignore-files
201
- .cursorignore
202
- .cursorindexingignore
203
-
204
- # Marimo
205
- marimo/_static/
206
- marimo/_lsp/
207
- __marimo__/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
README.md CHANGED
@@ -4,13 +4,11 @@ emoji: 🧩🖼️
4
  colorFrom: red
5
  colorTo: pink
6
  sdk: gradio
7
- sdk_version: 5.44.1
8
  app_file: app.py
9
  pinned: true
10
  license: mit
11
  short_description: Stunning images using stable diffusion.
12
- preload_from_hub:
13
- - madebyollin/sdxl-vae-fp16-fix config.json,diffusion_pytorch_model.safetensors
14
  ---
15
 
16
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
4
  colorFrom: red
5
  colorTo: pink
6
  sdk: gradio
7
+ sdk_version: 4.31.3
8
  app_file: app.py
9
  pinned: true
10
  license: mit
11
  short_description: Stunning images using stable diffusion.
 
 
12
  ---
13
 
14
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py CHANGED
@@ -1,298 +1,517 @@
1
  import spaces
2
  import os
3
- from argparse import ArgumentParser
4
- from stablepy import (
5
- Model_Diffusers,
6
- SCHEDULE_TYPE_OPTIONS,
7
- SCHEDULE_PREDICTION_TYPE_OPTIONS,
8
- check_scheduler_compatibility,
9
- TASK_AND_PREPROCESSORS,
10
- FACE_RESTORATION_MODELS,
11
- scheduler_names,
12
- )
13
- from constants import (
14
- DIRECTORY_MODELS,
15
- DIRECTORY_LORAS,
16
- DIRECTORY_VAES,
17
- DIRECTORY_EMBEDS,
18
- DIRECTORY_UPSCALERS,
19
- DOWNLOAD_MODEL,
20
- DOWNLOAD_VAE,
21
- DOWNLOAD_LORA,
22
- LOAD_DIFFUSERS_FORMAT_MODEL,
23
- DIFFUSERS_FORMAT_LORAS,
24
- DOWNLOAD_EMBEDS,
25
- CIVITAI_API_KEY,
26
- HF_TOKEN,
27
- TASK_STABLEPY,
28
- TASK_MODEL_LIST,
29
- UPSCALER_DICT_GUI,
30
- UPSCALER_KEYS,
31
- PROMPT_W_OPTIONS,
32
- WARNING_MSG_VAE,
33
- SDXL_TASK,
34
- MODEL_TYPE_TASK,
35
- POST_PROCESSING_SAMPLER,
36
- SUBTITLE_GUI,
37
- HELP_GUI,
38
- EXAMPLES_GUI_HELP,
39
- EXAMPLES_GUI,
40
- RESOURCES,
41
- DIFFUSERS_CONTROLNET_MODEL,
42
- IP_MODELS,
43
- MODE_IP_OPTIONS,
44
- CACHE_HF_ROOT,
45
- CACHE_HF,
46
- )
47
  from stablepy.diffusers_vanilla.style_prompt_config import STYLE_NAMES
 
48
  import torch
49
  import re
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  import time
51
  from PIL import ImageFile
52
- from utils import (
53
- download_things,
54
- get_model_list,
55
- extract_parameters,
56
- get_my_lora,
57
- get_model_type,
58
- extract_exif_data,
59
- create_mask_now,
60
- download_diffuser_repo,
61
- get_used_storage_gb,
62
- delete_model,
63
- progress_step_bar,
64
- html_template_message,
65
- escape_html,
66
- clear_hf_cache,
67
- )
68
- from image_processor import preprocessor_tab
69
- from datetime import datetime
70
- import gradio as gr
71
- import logging
72
- import diffusers
73
- import warnings
74
- from stablepy import logger
75
- from diffusers import FluxPipeline
76
  # import urllib.parse
77
- import subprocess
78
-
79
- IS_ZERO_GPU = bool(os.getenv("SPACES_ZERO_GPU"))
80
- HIDE_API = bool(os.getenv("HIDE_API"))
81
- if IS_ZERO_GPU:
82
- subprocess.run("rm -rf /data-nvme/zerogpu-offload/*", env={}, shell=True)
83
- IS_GPU_MODE = True if IS_ZERO_GPU else (True if torch.cuda.is_available() else False)
84
- img_path = "./images/"
85
- allowed_path = os.path.abspath(img_path)
86
- delete_cache_time = (9600, 9600) if IS_ZERO_GPU else (86400, 86400)
87
 
88
  ImageFile.LOAD_TRUNCATED_IMAGES = True
89
- torch.backends.cuda.matmul.allow_tf32 = True
90
- # os.environ["PYTORCH_NO_CUDA_MEMORY_CACHING"] = "1"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
 
92
- directories = [DIRECTORY_MODELS, DIRECTORY_LORAS, DIRECTORY_VAES, DIRECTORY_EMBEDS, DIRECTORY_UPSCALERS]
93
- for directory in directories:
94
- os.makedirs(directory, exist_ok=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
 
96
  # Download stuffs
97
- for url in [url.strip() for url in DOWNLOAD_MODEL.split(',')]:
98
- download_things(DIRECTORY_MODELS, url, HF_TOKEN, CIVITAI_API_KEY)
99
- for url in [url.strip() for url in DOWNLOAD_VAE.split(',')]:
100
- download_things(DIRECTORY_VAES, url, HF_TOKEN, CIVITAI_API_KEY)
101
- for url in [url.strip() for url in DOWNLOAD_LORA.split(',')]:
102
- download_things(DIRECTORY_LORAS, url, HF_TOKEN, CIVITAI_API_KEY)
 
 
 
103
 
104
  # Download Embeddings
105
- for url_embed in DOWNLOAD_EMBEDS:
106
- download_things(DIRECTORY_EMBEDS, url_embed, HF_TOKEN, CIVITAI_API_KEY)
 
 
 
 
 
 
 
 
 
107
 
108
  # Build list models
109
- embed_list = get_model_list(DIRECTORY_EMBEDS)
110
- embed_list = [
111
- (os.path.splitext(os.path.basename(emb))[0], emb) for emb in embed_list
112
- ]
113
- single_file_model_list = get_model_list(DIRECTORY_MODELS)
114
- model_list = LOAD_DIFFUSERS_FORMAT_MODEL + single_file_model_list
115
- lora_model_list = get_model_list(DIRECTORY_LORAS)
116
  lora_model_list.insert(0, "None")
117
  lora_model_list = lora_model_list + DIFFUSERS_FORMAT_LORAS
118
- vae_model_list = get_model_list(DIRECTORY_VAES)
119
- vae_model_list.insert(0, "BakedVAE")
120
  vae_model_list.insert(0, "None")
121
 
122
  print('\033[33m🏁 Download and listing of valid models completed.\033[0m')
123
 
124
- components = None
125
- if IS_ZERO_GPU:
126
- flux_repo = "camenduru/FLUX.1-dev-diffusers"
127
- flux_pipe = FluxPipeline.from_pretrained(
128
- flux_repo,
129
- transformer=None,
130
- torch_dtype=torch.bfloat16,
131
- ).to("cuda")
132
- components = flux_pipe.components
133
- delete_model(flux_repo)
134
-
135
  #######################
136
  # GUI
137
  #######################
 
 
138
  logging.getLogger("diffusers").setLevel(logging.ERROR)
 
139
  diffusers.utils.logging.set_verbosity(40)
 
140
  warnings.filterwarnings(action="ignore", category=FutureWarning, module="diffusers")
141
  warnings.filterwarnings(action="ignore", category=UserWarning, module="diffusers")
142
  warnings.filterwarnings(action="ignore", category=FutureWarning, module="transformers")
 
143
 
144
- parser = ArgumentParser(description='DiffuseCraft: Create images from text prompts.', add_help=True)
145
- parser.add_argument("--share", action="store_true", dest="share_enabled", default=False, help="Enable sharing")
146
- parser.add_argument('--theme', type=str, default="NoCrypt/miku", help='Set the theme (default: NoCrypt/miku)')
147
- parser.add_argument("--ssr", action="store_true", help="Enable SSR (Server-Side Rendering)")
148
- parser.add_argument("--log-level", type=str, default="INFO", choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"], help="Set logging level (default: INFO)")
149
- args = parser.parse_args()
150
 
151
- logger.setLevel(
152
- "INFO" if IS_ZERO_GPU else getattr(logging, args.log_level.upper())
 
153
  )
154
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  CSS = """
156
  .contain { display: flex; flex-direction: column; }
157
  #component-0 { height: 100%; }
158
  #gallery { flex-grow: 1; }
159
- #load_model { height: 50px; }
160
  """
161
 
 
 
 
 
162
 
163
- def lora_chk(lora_):
164
- if isinstance(lora_, str) and lora_.strip() not in ["", "None"]:
165
- return lora_
166
- return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
 
168
 
169
  class GuiSD:
170
  def __init__(self, stream=True):
171
  self.model = None
172
- self.status_loading = False
173
- self.sleep_loading = 4
174
- self.last_load = datetime.now()
175
- self.inventory = []
176
-
177
- def update_storage_models(self, storage_floor_gb=30, required_inventory_for_purge=3):
178
- while get_used_storage_gb() > storage_floor_gb:
179
- if len(self.inventory) < required_inventory_for_purge:
180
- break
181
- removal_candidate = self.inventory.pop(0)
182
- delete_model(removal_candidate)
183
-
184
- # Cleanup after 60 seconds of inactivity
185
- lowPrioCleanup = max((datetime.now() - self.last_load).total_seconds(), 0) > 60
186
- if lowPrioCleanup and (len(self.inventory) >= required_inventory_for_purge - 1) and not self.status_loading and get_used_storage_gb(CACHE_HF_ROOT) > (storage_floor_gb * 2):
187
- print("Cleaning up Hugging Face cache...")
188
- clear_hf_cache()
189
- self.inventory = [
190
- m for m in self.inventory if os.path.exists(m)
191
- ]
192
-
193
- def update_inventory(self, model_name):
194
- if model_name not in single_file_model_list:
195
- self.inventory = [
196
- m for m in self.inventory if m != model_name
197
- ] + [model_name]
198
- print(self.inventory)
199
-
200
- def load_new_model(self, model_name, vae_model, task, controlnet_model, progress=gr.Progress(track_tqdm=True)):
201
-
202
- # download link model > model_name
203
- if model_name.startswith("http"):
204
- yield f"Downloading model: {model_name}"
205
- model_name = download_things(DIRECTORY_MODELS, model_name, HF_TOKEN, CIVITAI_API_KEY)
206
- if not model_name:
207
- raise ValueError("Error retrieving model information from URL")
208
-
209
- if IS_ZERO_GPU:
210
- self.update_storage_models()
211
-
212
- vae_model = vae_model if vae_model != "None" else None
213
- model_type = get_model_type(model_name)
214
- dtype_model = torch.bfloat16 if model_type == "FLUX" else torch.float16
215
-
216
- if not os.path.exists(model_name):
217
- logger.debug(f"model_name={model_name}, vae_model={vae_model}, task={task}, controlnet_model={controlnet_model}")
218
- _ = download_diffuser_repo(
219
- repo_name=model_name,
220
- model_type=model_type,
221
- revision="main",
222
- token=True,
223
- )
224
-
225
- self.update_inventory(model_name)
226
 
227
- for i in range(68):
228
- if not self.status_loading:
229
- self.status_loading = True
230
- if i > 0:
231
- time.sleep(self.sleep_loading)
232
- print("Previous model ops...")
233
- break
234
- time.sleep(0.5)
235
- print(f"Waiting queue {i}")
236
- yield "Waiting queue"
237
 
238
- self.status_loading = True
239
 
240
  yield f"Loading model: {model_name}"
241
 
242
- if vae_model == "BakedVAE":
243
- vae_model = model_name
244
- elif vae_model:
 
245
  vae_type = "SDXL" if "sdxl" in vae_model.lower() else "SD 1.5"
246
  if model_type != vae_type:
247
- gr.Warning(WARNING_MSG_VAE)
248
-
249
- print("Loading model...")
250
-
251
- try:
252
- start_time = time.time()
253
-
254
- if self.model is None:
255
- self.model = Model_Diffusers(
256
- base_model_id=model_name,
257
- task_name=TASK_STABLEPY[task],
258
- vae_model=vae_model,
259
- type_model_precision=dtype_model,
260
- retain_task_model_in_cache=False,
261
- controlnet_model=controlnet_model,
262
- device="cpu" if IS_ZERO_GPU else None,
263
- env_components=components,
264
- )
265
- self.model.advanced_params(image_preprocessor_cuda_active=IS_GPU_MODE)
266
- else:
267
- if self.model.base_model_id != model_name:
268
- load_now_time = datetime.now()
269
- elapsed_time = max((load_now_time - self.last_load).total_seconds(), 0)
270
-
271
- if elapsed_time <= 9:
272
- print("Waiting for the previous model's time ops...")
273
- time.sleep(9 - elapsed_time)
274
-
275
- if IS_ZERO_GPU:
276
- self.model.device = torch.device("cpu")
277
- self.model.load_pipe(
278
- model_name,
279
- task_name=TASK_STABLEPY[task],
280
- vae_model=vae_model,
281
- type_model_precision=dtype_model,
282
- retain_task_model_in_cache=False,
283
- controlnet_model=controlnet_model,
284
- )
285
 
286
- end_time = time.time()
287
- self.sleep_loading = max(min(int(end_time - start_time), 10), 4)
288
- except Exception as e:
289
- self.last_load = datetime.now()
290
- self.status_loading = False
291
- self.sleep_loading = 4
292
- raise e
293
 
294
- self.last_load = datetime.now()
295
- self.status_loading = False
 
 
 
 
 
296
 
297
  yield f"Model loaded: {model_name}"
298
 
@@ -317,13 +536,7 @@ class GuiSD:
317
  lora_scale4,
318
  lora5,
319
  lora_scale5,
320
- lora6,
321
- lora_scale6,
322
- lora7,
323
- lora_scale7,
324
  sampler,
325
- schedule_type,
326
- schedule_prediction_type,
327
  img_height,
328
  img_width,
329
  model_name,
@@ -341,8 +554,6 @@ class GuiSD:
341
  high_threshold,
342
  value_threshold,
343
  distance_threshold,
344
- recolor_gamma_correction,
345
- tile_blur_sigma,
346
  controlnet_output_scaling_in_unet,
347
  controlnet_start_threshold,
348
  controlnet_stop_threshold,
@@ -350,8 +561,8 @@ class GuiSD:
350
  syntax_weights,
351
  upscaler_model_path,
352
  upscaler_increases_size,
353
- upscaler_tile_size,
354
- upscaler_tile_overlap,
355
  hires_steps,
356
  hires_denoising_strength,
357
  hires_sampler,
@@ -359,16 +570,12 @@ class GuiSD:
359
  hires_negative_prompt,
360
  hires_before_adetailer,
361
  hires_after_adetailer,
362
- hires_schedule_type,
363
- hires_guidance_scale,
364
- controlnet_model,
365
  loop_generation,
366
  leave_progress_bar,
367
  disable_progress_bar,
368
  image_previews,
369
  display_images,
370
  save_generated_images,
371
- filename_pattern,
372
  image_storage_location,
373
  retain_compel_previous_load,
374
  retain_detailfix_model_previous_load,
@@ -403,7 +610,6 @@ class GuiSD:
403
  mask_blur_b,
404
  mask_padding_b,
405
  retain_task_cache_gui,
406
- guidance_rescale,
407
  image_ip1,
408
  mask_ip1,
409
  model_ip1,
@@ -415,19 +621,14 @@ class GuiSD:
415
  mode_ip2,
416
  scale_ip2,
417
  pag_scale,
418
- face_restoration_model,
419
- face_restoration_visibility,
420
- face_restoration_weight,
421
  ):
422
- info_state = html_template_message("Navigating latent space...")
423
- yield info_state, gr.update(), gr.update()
424
 
425
  vae_model = vae_model if vae_model != "None" else None
426
- loras_list = [lora1, lora2, lora3, lora4, lora5, lora6, lora7]
427
  vae_msg = f"VAE: {vae_model}" if vae_model else ""
428
  msg_lora = ""
429
 
430
- logger.debug(f"Config model: {model_name}, {vae_model}, {loras_list}")
431
 
432
  task = TASK_STABLEPY[task]
433
 
@@ -442,34 +643,35 @@ class GuiSD:
442
  (image_ip2, mask_ip2, model_ip2, mode_ip2, scale_ip2),
443
  ]
444
 
445
- if not hasattr(self.model.pipe, "transformer"):
446
- for imgip, mskip, modelip, modeip, scaleip in all_adapters:
447
- if imgip:
448
- params_ip_img.append(imgip)
449
- if mskip:
450
- params_ip_msk.append(mskip)
451
- params_ip_model.append(modelip)
452
- params_ip_mode.append(modeip)
453
- params_ip_scale.append(scaleip)
454
 
455
- concurrency = 5
456
- self.model.stream_config(concurrency=concurrency, latent_resize_by=1, vae_decoding=False)
457
 
458
  if task != "txt2img" and not image_control:
459
- raise ValueError("Reference image is required. Please upload one in 'Image ControlNet/Inpaint/Img2img'.")
460
 
461
- if task in ["inpaint", "repaint"] and not image_mask:
462
- raise ValueError("Mask image not found. Upload one in 'Image Mask' to proceed.")
463
 
464
- if "https://" not in str(UPSCALER_DICT_GUI[upscaler_model_path]):
465
  upscaler_model = upscaler_model_path
466
  else:
 
 
 
467
  url_upscaler = UPSCALER_DICT_GUI[upscaler_model_path]
468
 
469
- if not os.path.exists(f"./{DIRECTORY_UPSCALERS}/{url_upscaler.split('/')[-1]}"):
470
- download_things(DIRECTORY_UPSCALERS, url_upscaler, HF_TOKEN)
471
 
472
- upscaler_model = f"./{DIRECTORY_UPSCALERS}/{url_upscaler.split('/')[-1]}"
473
 
474
  logging.getLogger("ultralytics").setLevel(logging.INFO if adetailer_verbose else logging.ERROR)
475
 
@@ -523,27 +725,19 @@ class GuiSD:
523
  "high_threshold": high_threshold,
524
  "value_threshold": value_threshold,
525
  "distance_threshold": distance_threshold,
526
- "recolor_gamma_correction": float(recolor_gamma_correction),
527
- "tile_blur_sigma": int(tile_blur_sigma),
528
- "lora_A": lora_chk(lora1),
529
  "lora_scale_A": lora_scale1,
530
- "lora_B": lora_chk(lora2),
531
  "lora_scale_B": lora_scale2,
532
- "lora_C": lora_chk(lora3),
533
  "lora_scale_C": lora_scale3,
534
- "lora_D": lora_chk(lora4),
535
  "lora_scale_D": lora_scale4,
536
- "lora_E": lora_chk(lora5),
537
  "lora_scale_E": lora_scale5,
538
- "lora_F": lora_chk(lora6),
539
- "lora_scale_F": lora_scale6,
540
- "lora_G": lora_chk(lora7),
541
- "lora_scale_G": lora_scale7,
542
- "textual_inversion": embed_list if textual_inversion else [],
543
  "syntax_weights": syntax_weights, # "Classic"
544
  "sampler": sampler,
545
- "schedule_type": schedule_type,
546
- "schedule_prediction_type": schedule_prediction_type,
547
  "xformers_memory_efficient_attention": xformers_memory_efficient_attention,
548
  "gui_active": True,
549
  "loop_generation": loop_generation,
@@ -561,7 +755,6 @@ class GuiSD:
561
  "image_previews": image_previews,
562
  "display_images": display_images,
563
  "save_generated_images": save_generated_images,
564
- "filename_pattern": filename_pattern,
565
  "image_storage_location": image_storage_location,
566
  "retain_compel_previous_load": retain_compel_previous_load,
567
  "retain_detailfix_model_previous_load": retain_detailfix_model_previous_load,
@@ -571,8 +764,8 @@ class GuiSD:
571
  "t2i_adapter_conditioning_factor": float(t2i_adapter_conditioning_factor),
572
  "upscaler_model_path": upscaler_model,
573
  "upscaler_increases_size": upscaler_increases_size,
574
- "upscaler_tile_size": upscaler_tile_size,
575
- "upscaler_tile_overlap": upscaler_tile_overlap,
576
  "hires_steps": hires_steps,
577
  "hires_denoising_strength": hires_denoising_strength,
578
  "hires_prompt": hires_prompt,
@@ -580,41 +773,25 @@ class GuiSD:
580
  "hires_sampler": hires_sampler,
581
  "hires_before_adetailer": hires_before_adetailer,
582
  "hires_after_adetailer": hires_after_adetailer,
583
- "hires_schedule_type": hires_schedule_type,
584
- "hires_guidance_scale": hires_guidance_scale,
585
  "ip_adapter_image": params_ip_img,
586
  "ip_adapter_mask": params_ip_msk,
587
  "ip_adapter_model": params_ip_model,
588
  "ip_adapter_mode": params_ip_mode,
589
  "ip_adapter_scale": params_ip_scale,
590
- "face_restoration_model": face_restoration_model,
591
- "face_restoration_visibility": face_restoration_visibility,
592
- "face_restoration_weight": face_restoration_weight,
593
  }
594
 
595
- # kwargs for diffusers pipeline
596
- if guidance_rescale:
597
- pipe_params["guidance_rescale"] = guidance_rescale
598
- if IS_ZERO_GPU:
599
- self.model.device = torch.device("cuda:0")
600
- if hasattr(self.model.pipe, "transformer") and loras_list != ["None"] * self.model.num_loras:
601
- self.model.pipe.transformer.to(self.model.device)
602
- logger.debug("transformer to cuda")
603
-
604
- actual_progress = 0
605
- info_images = gr.update()
606
- for img, [seed, image_path, metadata] in self.model(**pipe_params):
607
- info_state = progress_step_bar(actual_progress, steps)
608
- actual_progress += concurrency
609
  if image_path:
610
- info_images = f"Seeds: {str(seed)}"
611
  if vae_msg:
612
- info_images = info_images + "<br>" + vae_msg
613
-
614
- if "Cannot copy out of meta tensor; no data!" in self.model.last_lora_error:
615
- msg_ram = "Unable to process the LoRAs due to high RAM usage; please try again later."
616
- print(msg_ram)
617
- msg_lora += f"<br>{msg_ram}"
618
 
619
  for status, lora in zip(self.model.lora_status, self.model.lora_memory):
620
  if status:
@@ -623,27 +800,33 @@ class GuiSD:
623
  msg_lora += f"<br>Error with: {lora}"
624
 
625
  if msg_lora:
626
- info_images += msg_lora
627
 
628
- info_images = info_images + "<br>" + "GENERATION DATA:<br>" + escape_html(metadata[-1]) + "<br>-------<br>"
629
 
630
  download_links = "<br>".join(
631
  [
632
- f'<a href="{path.replace("/images/", f"/gradio_api/file={allowed_path}/")}" download="{os.path.basename(path)}">Download Image {i + 1}</a>'
633
  for i, path in enumerate(image_path)
634
  ]
635
  )
636
  if save_generated_images:
637
- info_images += f"<br>{download_links}"
 
 
 
 
 
 
638
 
639
- info_state = "COMPLETE"
 
640
 
641
- yield info_state, img, info_images
642
 
643
 
644
  def dynamic_gpu_duration(func, duration, *args):
645
 
646
- # @torch.inference_mode()
647
  @spaces.GPU(duration=duration)
648
  def wrapped_func():
649
  yield from func(*args)
@@ -657,44 +840,35 @@ def dummy_gpu():
657
 
658
 
659
  def sd_gen_generate_pipeline(*args):
 
660
  gpu_duration_arg = int(args[-1]) if args[-1] else 59
661
  verbose_arg = int(args[-2])
662
  load_lora_cpu = args[-3]
663
  generation_args = args[:-3]
664
  lora_list = [
665
  None if item == "None" else item
666
- for item in [args[7], args[9], args[11], args[13], args[15], args[17], args[19]]
667
  ]
668
- lora_status = [None] * sd_gen.model.num_loras
669
 
670
  msg_load_lora = "Updating LoRAs in GPU..."
671
  if load_lora_cpu:
672
- msg_load_lora = "Updating LoRAs in CPU..."
673
 
674
- if lora_list != sd_gen.model.lora_memory and lora_list != [None] * sd_gen.model.num_loras:
675
- yield msg_load_lora, gr.update(), gr.update()
676
 
677
  # Load lora in CPU
678
  if load_lora_cpu:
679
- lora_status = sd_gen.model.load_lora_on_the_fly(
680
  lora_A=lora_list[0], lora_scale_A=args[8],
681
  lora_B=lora_list[1], lora_scale_B=args[10],
682
  lora_C=lora_list[2], lora_scale_C=args[12],
683
  lora_D=lora_list[3], lora_scale_D=args[14],
684
  lora_E=lora_list[4], lora_scale_E=args[16],
685
- lora_F=lora_list[5], lora_scale_F=args[18],
686
- lora_G=lora_list[6], lora_scale_G=args[20],
687
  )
688
  print(lora_status)
689
 
690
- sampler_name = args[21]
691
- schedule_type_name = args[22]
692
- _, _, msg_sampler = check_scheduler_compatibility(
693
- sd_gen.model.class_name, sampler_name, schedule_type_name
694
- )
695
- if msg_sampler:
696
- gr.Warning(msg_sampler)
697
-
698
  if verbose_arg:
699
  for status, lora in zip(lora_status, lora_list):
700
  if status:
@@ -702,21 +876,20 @@ def sd_gen_generate_pipeline(*args):
702
  elif status is not None:
703
  gr.Warning(f"Failed to load LoRA: {lora}")
704
 
705
- if lora_status == [None] * sd_gen.model.num_loras and sd_gen.model.lora_memory != [None] * sd_gen.model.num_loras and load_lora_cpu:
706
  lora_cache_msg = ", ".join(
707
  str(x) for x in sd_gen.model.lora_memory if x is not None
708
  )
709
  gr.Info(f"LoRAs in cache: {lora_cache_msg}")
710
 
711
- msg_request = f"Requesting {gpu_duration_arg}s. of GPU time.\nModel: {sd_gen.model.base_model_id}"
712
- if verbose_arg:
713
  gr.Info(msg_request)
714
  print(msg_request)
715
- yield msg_request.replace("\n", "<br>"), gr.update(), gr.update()
 
716
 
717
  start_time = time.time()
718
 
719
- # yield from sd_gen.generate_pipeline(*generation_args)
720
  yield from dynamic_gpu_duration(
721
  sd_gen.generate_pipeline,
722
  gpu_duration_arg,
@@ -724,52 +897,60 @@ def sd_gen_generate_pipeline(*args):
724
  )
725
 
726
  end_time = time.time()
727
- execution_time = end_time - start_time
728
- msg_task_complete = (
729
- f"GPU task complete in: {int(round(execution_time, 0) + 1)} seconds"
730
- )
731
 
732
  if verbose_arg:
 
 
 
 
733
  gr.Info(msg_task_complete)
734
  print(msg_task_complete)
735
 
736
- yield msg_task_complete, gr.update(), gr.update()
737
 
 
 
738
 
739
- @spaces.GPU(duration=15)
740
- def process_upscale(image, upscaler_name, upscaler_size):
741
- if image is None:
742
- return None
743
 
744
- from stablepy.diffusers_vanilla.utils import save_pil_image_with_metadata
745
- from stablepy import load_upscaler_model
 
746
 
747
- image = image.convert("RGB")
748
- exif_image = extract_exif_data(image)
 
 
749
 
750
- name_upscaler = UPSCALER_DICT_GUI[upscaler_name]
751
 
752
- if "https://" in str(name_upscaler):
 
 
 
 
 
753
 
754
- if not os.path.exists(f"./{DIRECTORY_UPSCALERS}/{name_upscaler.split('/')[-1]}"):
755
- download_things(DIRECTORY_UPSCALERS, name_upscaler, HF_TOKEN)
756
 
757
- name_upscaler = f"./{DIRECTORY_UPSCALERS}/{name_upscaler.split('/')[-1]}"
 
 
 
 
758
 
759
- scaler_beta = load_upscaler_model(model=name_upscaler, tile=(0 if IS_ZERO_GPU else 192), tile_overlap=8, device=("cuda" if IS_GPU_MODE else "cpu"), half=IS_GPU_MODE)
760
- image_up = scaler_beta.upscale(image, upscaler_size, True)
761
 
762
  image_path = save_pil_image_with_metadata(image_up, f'{os.getcwd()}/up_images', exif_image)
763
 
764
  return image_path
765
 
766
 
767
- # https://huggingface.co/spaces/BestWishYsh/ConsisID-preview-Space/discussions/1#674969a022b99c122af5d407
768
- # dynamic_gpu_duration.zerogpu = True
769
- # sd_gen_generate_pipeline.zerogpu = True
770
  sd_gen = GuiSD()
771
 
772
- with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as app:
773
  gr.Markdown("# 🧩 DiffuseCraft")
774
  gr.Markdown(SUBTITLE_GUI)
775
  with gr.Tab("Generation"):
@@ -777,18 +958,10 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
777
 
778
  with gr.Column(scale=2):
779
 
780
- def update_task_options(model_name, task_name):
781
- new_choices = MODEL_TYPE_TASK[get_model_type(model_name)]
782
-
783
- if task_name not in new_choices:
784
- task_name = "txt2img"
785
-
786
- return gr.update(value=task_name, choices=new_choices)
787
-
788
  task_gui = gr.Dropdown(label="Task", choices=SDXL_TASK, value=TASK_MODEL_LIST[0])
789
  model_name_gui = gr.Dropdown(label="Model", choices=model_list, value=model_list[0], allow_custom_value=True)
790
  prompt_gui = gr.Textbox(lines=5, placeholder="Enter prompt", label="Prompt")
791
- neg_prompt_gui = gr.Textbox(lines=3, placeholder="Enter Neg prompt", label="Negative prompt", value="lowres, bad anatomy, bad hands, missing fingers, extra digit, fewer digits, worst quality, low quality, very displeasing, (bad)")
792
  with gr.Row(equal_height=False):
793
  set_params_gui = gr.Button(value="↙️", variant="secondary", size="sm")
794
  clear_prompt_gui = gr.Button(value="🗑️", variant="secondary", size="sm")
@@ -801,7 +974,7 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
801
  [task_gui],
802
  )
803
 
804
- load_model_gui = gr.HTML(elem_id="load_model", elem_classes="contain")
805
 
806
  result_images = gr.Gallery(
807
  label="Generated images",
@@ -818,17 +991,16 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
818
 
819
  actual_task_info = gr.HTML()
820
 
821
- with gr.Row(equal_height=False, variant="default", visible=IS_ZERO_GPU):
822
  gpu_duration_gui = gr.Number(minimum=5, maximum=240, value=59, show_label=False, container=False, info="GPU time duration (seconds)")
823
  with gr.Column():
824
  verbose_info_gui = gr.Checkbox(value=False, container=False, label="Status info")
825
- load_lora_cpu_gui = gr.Checkbox(value=False, container=False, label="Load LoRAs on CPU")
826
 
827
  with gr.Column(scale=1):
828
- steps_gui = gr.Slider(minimum=1, maximum=100, step=1, value=28, label="Steps")
829
  cfg_gui = gr.Slider(minimum=0, maximum=30, step=0.5, value=7., label="CFG")
830
- sampler_gui = gr.Dropdown(label="Sampler", choices=scheduler_names, value="Euler")
831
- schedule_type_gui = gr.Dropdown(label="Schedule type", choices=SCHEDULE_TYPE_OPTIONS, value=SCHEDULE_TYPE_OPTIONS[0])
832
  img_width_gui = gr.Slider(minimum=64, maximum=4096, step=8, value=1024, label="Img Width")
833
  img_height_gui = gr.Slider(minimum=64, maximum=4096, step=8, value=1024, label="Img Height")
834
  seed_gui = gr.Number(minimum=-1, maximum=9999999999, value=-1, label="Seed")
@@ -847,72 +1019,15 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
847
  "width": gr.update(value=1024),
848
  "height": gr.update(value=1024),
849
  "Seed": gr.update(value=-1),
850
- "Sampler": gr.update(value="Euler"),
851
- "CFG scale": gr.update(value=7.), # cfg
852
- "Clip skip": gr.update(value=True),
853
  "Model": gr.update(value=name_model),
854
- "Schedule type": gr.update(value="Automatic"),
855
- "PAG": gr.update(value=.0),
856
- "FreeU": gr.update(value=False),
857
- "Hires upscaler": gr.update(),
858
- "Hires upscale": gr.update(),
859
- "Hires steps": gr.update(),
860
- "Hires denoising strength": gr.update(),
861
- "Hires CFG": gr.update(),
862
- "Hires sampler": gr.update(),
863
- "Hires schedule type": gr.update(),
864
- "Image resolution": gr.update(value=1024),
865
- "Strength": gr.update(),
866
  }
867
-
868
- # Generate up to 7 LoRAs
869
- for i in range(1, 8):
870
- valid_receptors[f"Lora_{i}"] = gr.update()
871
- valid_receptors[f"Lora_scale_{i}"] = gr.update()
872
-
873
  valid_keys = list(valid_receptors.keys())
874
 
875
  parameters = extract_parameters(base_prompt)
876
- # print(parameters)
877
-
878
- if "Sampler" in parameters:
879
- value_sampler = parameters["Sampler"]
880
- for s_type in SCHEDULE_TYPE_OPTIONS:
881
- if s_type in value_sampler:
882
- value_sampler = value_sampler.replace(s_type, "").strip()
883
- parameters["Sampler"] = value_sampler
884
- parameters["Schedule type"] = s_type
885
-
886
- params_lora = []
887
- if ">" in parameters["prompt"] and "<" in parameters["prompt"]:
888
- params_lora = re.findall(r'<lora:[^>]+>', parameters["prompt"])
889
- if "Loras" in parameters:
890
- params_lora += re.findall(r'<lora:[^>]+>', parameters["Loras"])
891
-
892
- if params_lora:
893
- parsed_params = []
894
- for tag_l in params_lora:
895
- try:
896
- inner = tag_l.strip("<>") # remove < >
897
- _, data_l = inner.split(":", 1) # remove the "lora:" part
898
- parts_l = data_l.split(":")
899
-
900
- name_l = parts_l[0]
901
- weight_l = float(parts_l[1]) if len(parts_l) > 1 else 1.0 # default weight = 1.0
902
-
903
- parsed_params.append((name_l, weight_l))
904
- except Exception as e:
905
- print(f"Error parsing LoRA tag {tag_l}: {e}")
906
 
907
- num_lora = 1
908
- for parsed_l, parsed_s in parsed_params:
909
- filtered_loras = [m for m in lora_model_list if parsed_l in m]
910
- if filtered_loras:
911
- parameters[f"Lora_{num_lora}"] = filtered_loras[0]
912
- parameters[f"Lora_scale_{num_lora}"] = parsed_s
913
- num_lora += 1
914
-
915
- # continue = discard new value
916
  for key, val in parameters.items():
917
  # print(val)
918
  if key in valid_keys:
@@ -920,28 +1035,20 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
920
  if key == "Sampler":
921
  if val not in scheduler_names:
922
  continue
923
- if key in ["Schedule type", "Hires schedule type"]:
924
- if val not in SCHEDULE_TYPE_OPTIONS:
925
- continue
926
- if key == "Hires sampler":
927
- if val not in POST_PROCESSING_SAMPLER:
928
- continue
929
- elif key == "Clip skip":
930
  if "," in str(val):
931
  val = val.replace(",", "")
932
  if int(val) >= 2:
933
  val = True
934
  if key == "prompt":
935
  if ">" in val and "<" in val:
936
- val = re.sub(r'<[^>]+>', '', val) # Delete html and loras
937
  print("Removed LoRA written in the prompt")
938
  if key in ["prompt", "neg_prompt"]:
939
  val = re.sub(r'\s+', ' ', re.sub(r',+', ',', val)).strip()
940
- if key in ["Steps", "width", "height", "Seed", "Hires steps", "Image resolution"]:
941
  val = int(val)
942
- if key == "FreeU":
943
- val = True
944
- if key in ["CFG scale", "PAG", "Hires upscale", "Hires denoising strength", "Hires CFG", "Strength"]:
945
  val = float(val)
946
  if key == "Model":
947
  filtered_models = [m for m in model_list if val in m]
@@ -949,12 +1056,8 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
949
  val = filtered_models[0]
950
  else:
951
  val = name_model
952
- if key == "Hires upscaler":
953
- if val not in UPSCALER_KEYS:
954
- continue
955
  if key == "Seed":
956
  continue
957
-
958
  valid_receptors[key] = gr.update(value=val)
959
  # print(val, type(val))
960
  # print(valid_receptors)
@@ -962,6 +1065,21 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
962
  print(str(e))
963
  return [value for value in valid_receptors.values()]
964
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
965
  def run_clear_prompt_gui():
966
  return gr.update(value=""), gr.update(value="")
967
  clear_prompt_gui.click(
@@ -974,33 +1092,37 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
974
  run_set_random_seed, [], seed_gui
975
  )
976
 
977
- num_images_gui = gr.Slider(minimum=1, maximum=(8 if IS_ZERO_GPU else 20), step=1, value=1, label="Images")
978
- prompt_syntax_gui = gr.Dropdown(label="Prompt Syntax", choices=PROMPT_W_OPTIONS, value=PROMPT_W_OPTIONS[0][1])
 
 
 
 
 
 
 
 
979
  vae_model_gui = gr.Dropdown(label="VAE Model", choices=vae_model_list, value=vae_model_list[0])
980
 
981
  with gr.Accordion("Hires fix", open=False, visible=True):
982
 
983
  upscaler_model_path_gui = gr.Dropdown(label="Upscaler", choices=UPSCALER_KEYS, value=UPSCALER_KEYS[0])
984
  upscaler_increases_size_gui = gr.Slider(minimum=1.1, maximum=4., step=0.1, value=1.2, label="Upscale by")
985
- upscaler_tile_size_gui = gr.Slider(minimum=0, maximum=512, step=16, value=(0 if IS_ZERO_GPU else 192), label="Upscaler Tile Size", info="0 = no tiling")
986
- upscaler_tile_overlap_gui = gr.Slider(minimum=0, maximum=48, step=1, value=8, label="Upscaler Tile Overlap")
987
  hires_steps_gui = gr.Slider(minimum=0, value=30, maximum=100, step=1, label="Hires Steps")
988
  hires_denoising_strength_gui = gr.Slider(minimum=0.1, maximum=1.0, step=0.01, value=0.55, label="Hires Denoising Strength")
989
  hires_sampler_gui = gr.Dropdown(label="Hires Sampler", choices=POST_PROCESSING_SAMPLER, value=POST_PROCESSING_SAMPLER[0])
990
- hires_schedule_list = ["Use same schedule type"] + SCHEDULE_TYPE_OPTIONS
991
- hires_schedule_type_gui = gr.Dropdown(label="Hires Schedule type", choices=hires_schedule_list, value=hires_schedule_list[0])
992
- hires_guidance_scale_gui = gr.Slider(minimum=-1., maximum=30., step=0.5, value=-1., label="Hires CFG", info="If the value is -1, the main CFG will be used")
993
  hires_prompt_gui = gr.Textbox(label="Hires Prompt", placeholder="Main prompt will be use", lines=3)
994
  hires_negative_prompt_gui = gr.Textbox(label="Hires Negative Prompt", placeholder="Main negative prompt will be use", lines=3)
995
 
996
  with gr.Accordion("LoRA", open=False, visible=True):
997
 
998
- def lora_dropdown(label, visible=True):
999
- return gr.Dropdown(label=label, choices=lora_model_list, value="None", allow_custom_value=True, visible=visible)
1000
 
1001
- def lora_scale_slider(label, visible=True):
1002
- val_lora = 8 if IS_ZERO_GPU else 10
1003
- return gr.Slider(minimum=-val_lora, maximum=val_lora, step=0.01, value=0.33, label=label, visible=visible)
1004
 
1005
  lora1_gui = lora_dropdown("Lora1")
1006
  lora_scale_1_gui = lora_scale_slider("Lora Scale 1")
@@ -1012,37 +1134,21 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1012
  lora_scale_4_gui = lora_scale_slider("Lora Scale 4")
1013
  lora5_gui = lora_dropdown("Lora5")
1014
  lora_scale_5_gui = lora_scale_slider("Lora Scale 5")
1015
- lora6_gui = lora_dropdown("Lora6", visible=(not IS_ZERO_GPU))
1016
- lora_scale_6_gui = lora_scale_slider("Lora Scale 6", visible=(not IS_ZERO_GPU))
1017
- lora7_gui = lora_dropdown("Lora7", visible=(not IS_ZERO_GPU))
1018
- lora_scale_7_gui = lora_scale_slider("Lora Scale 7", visible=(not IS_ZERO_GPU))
1019
 
1020
  with gr.Accordion("From URL", open=False, visible=True):
1021
- text_lora = gr.Textbox(
1022
- label="LoRA's download URL",
1023
- placeholder="https://civitai.com/api/download/models/28907",
1024
- lines=1,
1025
- info="It has to be .safetensors files, and you can also download them from Hugging Face.",
1026
- )
1027
- romanize_text = gr.Checkbox(value=False, label="Transliterate name", visible=(not IS_ZERO_GPU))
1028
- button_lora = gr.Button("Get and Refresh the LoRA Lists")
1029
- new_lora_status = gr.HTML()
1030
  button_lora.click(
1031
  get_my_lora,
1032
- [text_lora, romanize_text],
1033
- [lora1_gui, lora2_gui, lora3_gui, lora4_gui, lora5_gui, lora6_gui, lora7_gui, new_lora_status]
1034
  )
1035
 
1036
- with gr.Accordion("Face restoration", open=False, visible=True):
1037
-
1038
- face_rest_options = [None] + FACE_RESTORATION_MODELS
1039
-
1040
- face_restoration_model_gui = gr.Dropdown(label="Face restoration model", choices=face_rest_options, value=face_rest_options[0])
1041
- face_restoration_visibility_gui = gr.Slider(minimum=0., maximum=1., step=0.001, value=1., label="Visibility")
1042
- face_restoration_weight_gui = gr.Slider(minimum=0., maximum=1., step=0.001, value=.5, label="Weight", info="(0 = maximum effect, 1 = minimum effect)")
1043
-
1044
  with gr.Accordion("IP-Adapter", open=False, visible=True):
1045
 
 
 
 
1046
  with gr.Accordion("IP-Adapter 1", open=False, visible=True):
1047
  image_ip1 = gr.Image(label="IP Image", type="filepath")
1048
  mask_ip1 = gr.Image(label="IP Mask", type="filepath")
@@ -1061,38 +1167,32 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1061
  image_mask_gui = gr.Image(label="Image Mask", type="filepath")
1062
  strength_gui = gr.Slider(
1063
  minimum=0.01, maximum=1.0, step=0.01, value=0.55, label="Strength",
1064
- info="This option adjusts the level of changes for img2img, repaint and inpaint."
1065
  )
1066
- image_resolution_gui = gr.Slider(
1067
- minimum=64, maximum=2048, step=64, value=1024, label="Image Resolution",
1068
- info="The maximum proportional size of the generated image based on the uploaded image."
1069
- )
1070
- controlnet_model_gui = gr.Dropdown(label="ControlNet model", choices=DIFFUSERS_CONTROLNET_MODEL, value=DIFFUSERS_CONTROLNET_MODEL[0], allow_custom_value=True)
1071
- control_net_output_scaling_gui = gr.Slider(minimum=0, maximum=5.0, step=0.1, value=1, label="ControlNet Output Scaling in UNet")
1072
- control_net_start_threshold_gui = gr.Slider(minimum=0, maximum=1, step=0.01, value=0, label="ControlNet Start Threshold (%)")
1073
- control_net_stop_threshold_gui = gr.Slider(minimum=0, maximum=1, step=0.01, value=1, label="ControlNet Stop Threshold (%)")
1074
- preprocessor_name_gui = gr.Dropdown(label="Preprocessor Name", choices=TASK_AND_PREPROCESSORS["canny"])
1075
 
1076
  def change_preprocessor_choices(task):
1077
  task = TASK_STABLEPY[task]
1078
- if task in TASK_AND_PREPROCESSORS.keys():
1079
- choices_task = TASK_AND_PREPROCESSORS[task]
1080
  else:
1081
- choices_task = TASK_AND_PREPROCESSORS["canny"]
1082
  return gr.update(choices=choices_task, value=choices_task[0])
 
1083
  task_gui.change(
1084
  change_preprocessor_choices,
1085
  [task_gui],
1086
  [preprocessor_name_gui],
1087
  )
1088
-
1089
- preprocess_resolution_gui = gr.Slider(minimum=64, maximum=2048, step=64, value=512, label="Preprocessor Resolution")
1090
- low_threshold_gui = gr.Slider(minimum=1, maximum=255, step=1, value=100, label="'CANNY' low threshold")
1091
- high_threshold_gui = gr.Slider(minimum=1, maximum=255, step=1, value=200, label="'CANNY' high threshold")
1092
- value_threshold_gui = gr.Slider(minimum=0.0, maximum=2.0, step=0.01, value=0.1, label="'MLSD' Hough value threshold")
1093
- distance_threshold_gui = gr.Slider(minimum=0.0, maximum=20.0, step=0.01, value=0.1, label="'MLSD' Hough distance threshold")
1094
- recolor_gamma_correction_gui = gr.Number(minimum=0., maximum=25., value=1., step=0.001, label="'RECOLOR' gamma correction")
1095
- tile_blur_sigma_gui = gr.Number(minimum=0, maximum=100, value=9, step=1, label="'TILE' blur sigma")
1096
 
1097
  with gr.Accordion("T2I adapter", open=False, visible=False):
1098
  t2i_adapter_preprocessor_gui = gr.Checkbox(value=True, label="T2i Adapter Preprocessor")
@@ -1125,7 +1225,7 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1125
  gr.Info(f"{len(sd_gen.model.STYLE_NAMES)} styles loaded")
1126
  return gr.update(value=None, choices=sd_gen.model.STYLE_NAMES)
1127
 
1128
- style_button.click(load_json_style_file, [style_json_gui], [style_prompt_gui])
1129
 
1130
  with gr.Accordion("Textual inversion", open=False, visible=False):
1131
  active_textual_inversion_gui = gr.Checkbox(value=False, label="Active Textual Inversion in prompt")
@@ -1148,7 +1248,7 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1148
  negative_prompt_ad_a_gui = gr.Textbox(label="Negative prompt", placeholder="Main negative prompt will be use", lines=3)
1149
  strength_ad_a_gui = gr.Number(label="Strength:", value=0.35, step=0.01, minimum=0.01, maximum=1.0)
1150
  face_detector_ad_a_gui = gr.Checkbox(label="Face detector", value=True)
1151
- person_detector_ad_a_gui = gr.Checkbox(label="Person detector", value=False)
1152
  hand_detector_ad_a_gui = gr.Checkbox(label="Hand detector", value=False)
1153
  mask_dilation_a_gui = gr.Number(label="Mask dilation:", value=4, minimum=1)
1154
  mask_blur_a_gui = gr.Number(label="Mask blur:", value=4, minimum=1)
@@ -1160,7 +1260,7 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1160
  prompt_ad_b_gui = gr.Textbox(label="Main prompt", placeholder="Main prompt will be use", lines=3)
1161
  negative_prompt_ad_b_gui = gr.Textbox(label="Negative prompt", placeholder="Main negative prompt will be use", lines=3)
1162
  strength_ad_b_gui = gr.Number(label="Strength:", value=0.35, step=0.01, minimum=0.01, maximum=1.0)
1163
- face_detector_ad_b_gui = gr.Checkbox(label="Face detector", value=False)
1164
  person_detector_ad_b_gui = gr.Checkbox(label="Person detector", value=True)
1165
  hand_detector_ad_b_gui = gr.Checkbox(label="Hand detector", value=False)
1166
  mask_dilation_b_gui = gr.Number(label="Mask dilation:", value=4, minimum=1)
@@ -1168,74 +1268,191 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1168
  mask_padding_b_gui = gr.Number(label="Mask padding:", value=32, minimum=1)
1169
 
1170
  with gr.Accordion("Other settings", open=False, visible=True):
1171
- schedule_prediction_type_gui = gr.Dropdown(label="Discrete Sampling Type", choices=SCHEDULE_PREDICTION_TYPE_OPTIONS, value=SCHEDULE_PREDICTION_TYPE_OPTIONS[0])
1172
- guidance_rescale_gui = gr.Number(label="CFG rescale:", value=0., step=0.01, minimum=0., maximum=1.5)
1173
  save_generated_images_gui = gr.Checkbox(value=True, label="Create a download link for the images")
1174
- filename_pattern_gui = gr.Textbox(label="Filename pattern", value="model,seed", placeholder="model,seed,sampler,schedule_type,img_width,img_height,guidance_scale,num_steps,vae,prompt_section,neg_prompt_section", lines=1)
1175
  hires_before_adetailer_gui = gr.Checkbox(value=False, label="Hires Before Adetailer")
1176
  hires_after_adetailer_gui = gr.Checkbox(value=True, label="Hires After Adetailer")
1177
  generator_in_cpu_gui = gr.Checkbox(value=False, label="Generator in CPU")
1178
- with gr.Column(visible=(not IS_ZERO_GPU)):
1179
- image_storage_location_gui = gr.Textbox(value=img_path, label="Image Storage Location")
1180
- disable_progress_bar_gui = gr.Checkbox(value=False, label="Disable Progress Bar")
1181
- leave_progress_bar_gui = gr.Checkbox(value=True, label="Leave Progress Bar")
1182
 
1183
  with gr.Accordion("More settings", open=False, visible=False):
1184
  loop_generation_gui = gr.Slider(minimum=1, value=1, label="Loop Generation")
1185
  retain_task_cache_gui = gr.Checkbox(value=False, label="Retain task model in cache")
1186
- display_images_gui = gr.Checkbox(value=False, label="Display Images")
 
 
1187
  image_previews_gui = gr.Checkbox(value=True, label="Image Previews")
 
1188
  retain_compel_previous_load_gui = gr.Checkbox(value=False, label="Retain Compel Previous Load")
1189
  retain_detailfix_model_previous_load_gui = gr.Checkbox(value=False, label="Retain Detailfix Model Previous Load")
1190
  retain_hires_model_previous_load_gui = gr.Checkbox(value=False, label="Retain Hires Model Previous Load")
1191
  xformers_memory_efficient_attention_gui = gr.Checkbox(value=False, label="Xformers Memory Efficient Attention")
1192
 
1193
- set_params_gui.click(
1194
- run_set_params_gui, [prompt_gui, model_name_gui], [
1195
- prompt_gui,
1196
- neg_prompt_gui,
1197
- steps_gui,
1198
- img_width_gui,
1199
- img_height_gui,
1200
- seed_gui,
1201
- sampler_gui,
1202
- cfg_gui,
1203
- clip_skip_gui,
1204
- model_name_gui,
1205
- schedule_type_gui,
1206
- pag_scale_gui,
1207
- free_u_gui,
1208
- upscaler_model_path_gui,
1209
- upscaler_increases_size_gui,
1210
- hires_steps_gui,
1211
- hires_denoising_strength_gui,
1212
- hires_guidance_scale_gui,
1213
- hires_sampler_gui,
1214
- hires_schedule_type_gui,
1215
- image_resolution_gui,
1216
- strength_gui,
1217
- lora1_gui,
1218
- lora_scale_1_gui,
1219
- lora2_gui,
1220
- lora_scale_2_gui,
1221
- lora3_gui,
1222
- lora_scale_3_gui,
1223
- lora4_gui,
1224
- lora_scale_4_gui,
1225
- lora5_gui,
1226
- lora_scale_5_gui,
1227
- lora6_gui,
1228
- lora_scale_6_gui,
1229
- lora7_gui,
1230
- lora_scale_7_gui,
1231
- ],
1232
- )
1233
-
1234
  with gr.Accordion("Examples and help", open=False, visible=True):
1235
- gr.Markdown(HELP_GUI)
1236
- gr.Markdown(EXAMPLES_GUI_HELP)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1237
  gr.Examples(
1238
- examples=EXAMPLES_GUI,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1239
  fn=sd_gen.generate_pipeline,
1240
  inputs=[
1241
  prompt_gui,
@@ -1261,13 +1478,45 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1261
  gpu_duration_gui,
1262
  load_lora_cpu_gui,
1263
  ],
1264
- outputs=[load_model_gui, result_images, actual_task_info],
1265
  cache_examples=False,
1266
  )
1267
- gr.Markdown(RESOURCES)
 
 
 
 
 
1268
 
1269
  with gr.Tab("Inpaint mask maker", render=True):
1270
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1271
  with gr.Row():
1272
  with gr.Column(scale=2):
1273
  image_base = gr.ImageEditor(
@@ -1276,31 +1525,20 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1276
  # enable crop (or disable it)
1277
  # transforms=["crop"],
1278
  brush=gr.Brush(
1279
- default_size="16", # or leave it as 'auto'
1280
- color_mode="fixed", # 'fixed' hides the user swatches and colorpicker, 'defaults' shows it
1281
- # default_color="black", # html names are supported
1282
- colors=[
1283
- "rgba(0, 0, 0, 1)", # rgb(a)
1284
- "rgba(0, 0, 0, 0.1)",
1285
- "rgba(255, 255, 255, 0.1)",
1286
- # "hsl(360, 120, 120)" # in fact any valid colorstring
1287
- ]
1288
  ),
1289
- eraser=gr.Eraser(default_size="16"),
1290
- render=True,
1291
- visible=False,
1292
- interactive=False,
1293
  )
1294
-
1295
- show_canvas = gr.Button("SHOW INPAINT CANVAS")
1296
-
1297
- def change_visibility_canvas():
1298
- return gr.update(visible=True, interactive=True), gr.update(visible=False)
1299
- show_canvas.click(change_visibility_canvas, [], [image_base, show_canvas])
1300
-
1301
  invert_mask = gr.Checkbox(value=False, label="Invert mask")
1302
  btn = gr.Button("Create mask")
1303
-
1304
  with gr.Column(scale=1):
1305
  img_source = gr.Image(interactive=False)
1306
  img_result = gr.Image(label="Mask image", show_label=True, interactive=False)
@@ -1331,11 +1569,8 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1331
 
1332
  with gr.Row():
1333
  with gr.Column():
1334
-
1335
- USCALER_TAB_KEYS = [name for name in UPSCALER_KEYS[9:]]
1336
-
1337
  image_up_tab = gr.Image(label="Image", type="pil", sources=["upload"])
1338
- upscaler_tab = gr.Dropdown(label="Upscaler", choices=USCALER_TAB_KEYS, value=USCALER_TAB_KEYS[5])
1339
  upscaler_size_tab = gr.Slider(minimum=1., maximum=4., step=0.1, value=1.1, label="Upscale by")
1340
  generate_button_up_tab = gr.Button(value="START UPSCALE", variant="primary")
1341
 
@@ -1343,26 +1578,21 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1343
  result_up_tab = gr.Image(label="Result", type="pil", interactive=False, format="png")
1344
 
1345
  generate_button_up_tab.click(
1346
- fn=process_upscale,
1347
  inputs=[image_up_tab, upscaler_tab, upscaler_size_tab],
1348
  outputs=[result_up_tab],
1349
  )
1350
 
1351
- with gr.Tab("Preprocessor", render=True):
1352
- preprocessor_tab()
1353
-
1354
  generate_button.click(
1355
  fn=sd_gen.load_new_model,
1356
  inputs=[
1357
  model_name_gui,
1358
  vae_model_gui,
1359
- task_gui,
1360
- controlnet_model_gui,
1361
  ],
1362
  outputs=[load_model_gui],
1363
  queue=True,
1364
  show_progress="minimal",
1365
- api_name=(False if HIDE_API else None),
1366
  ).success(
1367
  fn=sd_gen_generate_pipeline, # fn=sd_gen.generate_pipeline,
1368
  inputs=[
@@ -1383,13 +1613,7 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1383
  lora_scale_4_gui,
1384
  lora5_gui,
1385
  lora_scale_5_gui,
1386
- lora6_gui,
1387
- lora_scale_6_gui,
1388
- lora7_gui,
1389
- lora_scale_7_gui,
1390
  sampler_gui,
1391
- schedule_type_gui,
1392
- schedule_prediction_type_gui,
1393
  img_height_gui,
1394
  img_width_gui,
1395
  model_name_gui,
@@ -1407,8 +1631,6 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1407
  high_threshold_gui,
1408
  value_threshold_gui,
1409
  distance_threshold_gui,
1410
- recolor_gamma_correction_gui,
1411
- tile_blur_sigma_gui,
1412
  control_net_output_scaling_gui,
1413
  control_net_start_threshold_gui,
1414
  control_net_stop_threshold_gui,
@@ -1416,8 +1638,8 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1416
  prompt_syntax_gui,
1417
  upscaler_model_path_gui,
1418
  upscaler_increases_size_gui,
1419
- upscaler_tile_size_gui,
1420
- upscaler_tile_overlap_gui,
1421
  hires_steps_gui,
1422
  hires_denoising_strength_gui,
1423
  hires_sampler_gui,
@@ -1425,16 +1647,12 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1425
  hires_negative_prompt_gui,
1426
  hires_before_adetailer_gui,
1427
  hires_after_adetailer_gui,
1428
- hires_schedule_type_gui,
1429
- hires_guidance_scale_gui,
1430
- controlnet_model_gui,
1431
  loop_generation_gui,
1432
  leave_progress_bar_gui,
1433
  disable_progress_bar_gui,
1434
  image_previews_gui,
1435
  display_images_gui,
1436
  save_generated_images_gui,
1437
- filename_pattern_gui,
1438
  image_storage_location_gui,
1439
  retain_compel_previous_load_gui,
1440
  retain_detailfix_model_previous_load_gui,
@@ -1469,7 +1687,6 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1469
  mask_blur_b_gui,
1470
  mask_padding_b_gui,
1471
  retain_task_cache_gui,
1472
- guidance_rescale_gui,
1473
  image_ip1,
1474
  mask_ip1,
1475
  model_ip1,
@@ -1481,26 +1698,19 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1481
  mode_ip2,
1482
  scale_ip2,
1483
  pag_scale_gui,
1484
- face_restoration_model_gui,
1485
- face_restoration_visibility_gui,
1486
- face_restoration_weight_gui,
1487
  load_lora_cpu_gui,
1488
  verbose_info_gui,
1489
  gpu_duration_gui,
1490
  ],
1491
- outputs=[load_model_gui, result_images, actual_task_info],
1492
  queue=True,
1493
  show_progress="minimal",
1494
- # api_name=(False if HIDE_API else None),
1495
  )
1496
 
1497
- if __name__ == "__main__":
1498
- app.queue()
1499
- app.launch(
1500
- show_error=True,
1501
- share=args.share_enabled,
1502
- debug=True,
1503
- ssr_mode=args.ssr,
1504
- allowed_paths=[allowed_path],
1505
- show_api=(not HIDE_API),
1506
- )
 
1
  import spaces
2
  import os
3
+ from stablepy import Model_Diffusers
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  from stablepy.diffusers_vanilla.style_prompt_config import STYLE_NAMES
5
+ from stablepy.diffusers_vanilla.constants import FLUX_CN_UNION_MODES
6
  import torch
7
  import re
8
+ from huggingface_hub import HfApi
9
+ from stablepy import (
10
+ CONTROLNET_MODEL_IDS,
11
+ VALID_TASKS,
12
+ T2I_PREPROCESSOR_NAME,
13
+ FLASH_LORA,
14
+ SCHEDULER_CONFIG_MAP,
15
+ scheduler_names,
16
+ IP_ADAPTER_MODELS,
17
+ IP_ADAPTERS_SD,
18
+ IP_ADAPTERS_SDXL,
19
+ REPO_IMAGE_ENCODER,
20
+ ALL_PROMPT_WEIGHT_OPTIONS,
21
+ SD15_TASKS,
22
+ SDXL_TASKS,
23
+ )
24
  import time
25
  from PIL import ImageFile
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  # import urllib.parse
 
 
 
 
 
 
 
 
 
 
27
 
28
  ImageFile.LOAD_TRUNCATED_IMAGES = True
29
+ print(os.getenv("SPACES_ZERO_GPU"))
30
+
31
+ # - **Download SD 1.5 Models**
32
+ download_model = "https://civitai.com/api/download/models/574369, https://huggingface.co/TechnoByte/MilkyWonderland/resolve/main/milkyWonderland_v40.safetensors"
33
+ # - **Download VAEs**
34
+ download_vae = "https://huggingface.co/nubby/blessed-sdxl-vae-fp16-fix/resolve/main/sdxl_vae-fp16fix-c-1.1-b-0.5.safetensors?download=true, https://huggingface.co/nubby/blessed-sdxl-vae-fp16-fix/resolve/main/sdxl_vae-fp16fix-blessed.safetensors?download=true, https://huggingface.co/digiplay/VAE/resolve/main/vividReal_v20.safetensors?download=true, https://huggingface.co/fp16-guy/anything_kl-f8-anime2_vae-ft-mse-840000-ema-pruned_blessed_clearvae_fp16_cleaned/resolve/main/vae-ft-mse-840000-ema-pruned_fp16.safetensors?download=true"
35
+ # - **Download LoRAs**
36
+ download_lora = "https://civitai.com/api/download/models/28907, https://huggingface.co/Leopain/color/resolve/main/Coloring_book_-_LineArt.safetensors, https://civitai.com/api/download/models/135867, https://civitai.com/api/download/models/145907, https://huggingface.co/Linaqruf/anime-detailer-xl-lora/resolve/main/anime-detailer-xl.safetensors?download=true, https://huggingface.co/Linaqruf/style-enhancer-xl-lora/resolve/main/style-enhancer-xl.safetensors?download=true, https://civitai.com/api/download/models/28609, https://huggingface.co/ByteDance/Hyper-SD/resolve/main/Hyper-SD15-8steps-CFG-lora.safetensors?download=true, https://huggingface.co/ByteDance/Hyper-SD/resolve/main/Hyper-SDXL-8steps-CFG-lora.safetensors?download=true"
37
+ load_diffusers_format_model = [
38
+ 'stabilityai/stable-diffusion-xl-base-1.0',
39
+ 'black-forest-labs/FLUX.1-dev',
40
+ 'John6666/blue-pencil-flux1-v021-fp8-flux',
41
+ 'John6666/wai-ani-flux-v10forfp8-fp8-flux',
42
+ 'John6666/xe-anime-flux-v04-fp8-flux',
43
+ 'John6666/lyh-anime-flux-v2a1-fp8-flux',
44
+ 'John6666/carnival-unchained-v10-fp8-flux',
45
+ 'cagliostrolab/animagine-xl-3.1',
46
+ 'John6666/epicrealism-xl-v8kiss-sdxl',
47
+ 'misri/epicrealismXL_v7FinalDestination',
48
+ 'misri/juggernautXL_juggernautX',
49
+ 'misri/zavychromaxl_v80',
50
+ 'SG161222/RealVisXL_V4.0',
51
+ 'SG161222/RealVisXL_V5.0',
52
+ 'misri/newrealityxlAllInOne_Newreality40',
53
+ 'eienmojiki/Anything-XL',
54
+ 'eienmojiki/Starry-XL-v5.2',
55
+ 'gsdf/CounterfeitXL',
56
+ 'KBlueLeaf/Kohaku-XL-Zeta',
57
+ 'John6666/silvermoon-mix-01xl-v11-sdxl',
58
+ 'WhiteAiZ/autismmixSDXL_autismmixConfetti_diffusers',
59
+ 'kitty7779/ponyDiffusionV6XL',
60
+ 'GraydientPlatformAPI/aniverse-pony',
61
+ 'John6666/ras-real-anime-screencap-v1-sdxl',
62
+ 'John6666/duchaiten-pony-xl-no-score-v60-sdxl',
63
+ 'John6666/mistoon-anime-ponyalpha-sdxl',
64
+ 'John6666/3x3x3mixxl-v2-sdxl',
65
+ 'John6666/3x3x3mixxl-3dv01-sdxl',
66
+ 'John6666/ebara-mfcg-pony-mix-v12-sdxl',
67
+ 'John6666/t-ponynai3-v51-sdxl',
68
+ 'John6666/t-ponynai3-v65-sdxl',
69
+ 'John6666/prefect-pony-xl-v3-sdxl',
70
+ 'John6666/mala-anime-mix-nsfw-pony-xl-v5-sdxl',
71
+ 'John6666/wai-real-mix-v11-sdxl',
72
+ 'John6666/wai-c-v6-sdxl',
73
+ 'John6666/iniverse-mix-xl-sfwnsfw-pony-guofeng-v43-sdxl',
74
+ 'John6666/photo-realistic-pony-v5-sdxl',
75
+ 'John6666/pony-realism-v21main-sdxl',
76
+ 'John6666/pony-realism-v22main-sdxl',
77
+ 'John6666/cyberrealistic-pony-v63-sdxl',
78
+ 'John6666/cyberrealistic-pony-v64-sdxl',
79
+ 'GraydientPlatformAPI/realcartoon-pony-diffusion',
80
+ 'John6666/nova-anime-xl-pony-v5-sdxl',
81
+ 'John6666/autismmix-sdxl-autismmix-pony-sdxl',
82
+ 'John6666/aimz-dream-real-pony-mix-v3-sdxl',
83
+ 'John6666/duchaiten-pony-real-v11fix-sdxl',
84
+ 'John6666/duchaiten-pony-real-v20-sdxl',
85
+ 'yodayo-ai/kivotos-xl-2.0',
86
+ 'yodayo-ai/holodayo-xl-2.1',
87
+ 'yodayo-ai/clandestine-xl-1.0',
88
+ 'digiplay/majicMIX_sombre_v2',
89
+ 'digiplay/majicMIX_realistic_v6',
90
+ 'digiplay/majicMIX_realistic_v7',
91
+ 'digiplay/DreamShaper_8',
92
+ 'digiplay/BeautifulArt_v1',
93
+ 'digiplay/DarkSushi2.5D_v1',
94
+ 'digiplay/darkphoenix3D_v1.1',
95
+ 'digiplay/BeenYouLiteL11_diffusers',
96
+ 'Yntec/RevAnimatedV2Rebirth',
97
+ 'youknownothing/cyberrealistic_v50',
98
+ 'youknownothing/deliberate-v6',
99
+ 'GraydientPlatformAPI/deliberate-cyber3',
100
+ 'GraydientPlatformAPI/picx-real',
101
+ 'GraydientPlatformAPI/perfectworld6',
102
+ 'emilianJR/epiCRealism',
103
+ 'votepurchase/counterfeitV30_v30',
104
+ 'votepurchase/ChilloutMix',
105
+ 'Meina/MeinaMix_V11',
106
+ 'Meina/MeinaUnreal_V5',
107
+ 'Meina/MeinaPastel_V7',
108
+ 'GraydientPlatformAPI/realcartoon3d-17',
109
+ 'GraydientPlatformAPI/realcartoon-pixar11',
110
+ 'GraydientPlatformAPI/realcartoon-real17',
111
+ ]
112
+
113
+ DIFFUSERS_FORMAT_LORAS = [
114
+ "nerijs/animation2k-flux",
115
+ "XLabs-AI/flux-RealismLora",
116
+ ]
117
+
118
+ CIVITAI_API_KEY = os.environ.get("CIVITAI_API_KEY")
119
+ HF_TOKEN = os.environ.get("HF_READ_TOKEN")
120
+
121
+ PREPROCESSOR_CONTROLNET = {
122
+ "openpose": [
123
+ "Openpose",
124
+ "None",
125
+ ],
126
+ "scribble": [
127
+ "HED",
128
+ "PidiNet",
129
+ "None",
130
+ ],
131
+ "softedge": [
132
+ "PidiNet",
133
+ "HED",
134
+ "HED safe",
135
+ "PidiNet safe",
136
+ "None",
137
+ ],
138
+ "segmentation": [
139
+ "UPerNet",
140
+ "None",
141
+ ],
142
+ "depth": [
143
+ "DPT",
144
+ "Midas",
145
+ "None",
146
+ ],
147
+ "normalbae": [
148
+ "NormalBae",
149
+ "None",
150
+ ],
151
+ "lineart": [
152
+ "Lineart",
153
+ "Lineart coarse",
154
+ "Lineart (anime)",
155
+ "None",
156
+ "None (anime)",
157
+ ],
158
+ "lineart_anime": [
159
+ "Lineart",
160
+ "Lineart coarse",
161
+ "Lineart (anime)",
162
+ "None",
163
+ "None (anime)",
164
+ ],
165
+ "shuffle": [
166
+ "ContentShuffle",
167
+ "None",
168
+ ],
169
+ "canny": [
170
+ "Canny",
171
+ "None",
172
+ ],
173
+ "mlsd": [
174
+ "MLSD",
175
+ "None",
176
+ ],
177
+ "ip2p": [
178
+ "ip2p"
179
+ ],
180
+ "recolor": [
181
+ "Recolor luminance",
182
+ "Recolor intensity",
183
+ "None",
184
+ ],
185
+ "tile": [
186
+ "Mild Blur",
187
+ "Moderate Blur",
188
+ "Heavy Blur",
189
+ "None",
190
+ ],
191
+
192
+ }
193
+
194
+ TASK_STABLEPY = {
195
+ 'txt2img': 'txt2img',
196
+ 'img2img': 'img2img',
197
+ 'inpaint': 'inpaint',
198
+ # 'canny T2I Adapter': 'sdxl_canny_t2i', # NO HAVE STEP CALLBACK PARAMETERS SO NOT WORKS WITH DIFFUSERS 0.29.0
199
+ # 'sketch T2I Adapter': 'sdxl_sketch_t2i',
200
+ # 'lineart T2I Adapter': 'sdxl_lineart_t2i',
201
+ # 'depth-midas T2I Adapter': 'sdxl_depth-midas_t2i',
202
+ # 'openpose T2I Adapter': 'sdxl_openpose_t2i',
203
+ 'openpose ControlNet': 'openpose',
204
+ 'canny ControlNet': 'canny',
205
+ 'mlsd ControlNet': 'mlsd',
206
+ 'scribble ControlNet': 'scribble',
207
+ 'softedge ControlNet': 'softedge',
208
+ 'segmentation ControlNet': 'segmentation',
209
+ 'depth ControlNet': 'depth',
210
+ 'normalbae ControlNet': 'normalbae',
211
+ 'lineart ControlNet': 'lineart',
212
+ 'lineart_anime ControlNet': 'lineart_anime',
213
+ 'shuffle ControlNet': 'shuffle',
214
+ 'ip2p ControlNet': 'ip2p',
215
+ 'optical pattern ControlNet': 'pattern',
216
+ 'recolor ControlNet': 'recolor',
217
+ 'tile ControlNet': 'tile',
218
+ }
219
+
220
+ TASK_MODEL_LIST = list(TASK_STABLEPY.keys())
221
+
222
+ UPSCALER_DICT_GUI = {
223
+ None: None,
224
+ "Lanczos": "Lanczos",
225
+ "Nearest": "Nearest",
226
+ 'Latent': 'Latent',
227
+ 'Latent (antialiased)': 'Latent (antialiased)',
228
+ 'Latent (bicubic)': 'Latent (bicubic)',
229
+ 'Latent (bicubic antialiased)': 'Latent (bicubic antialiased)',
230
+ 'Latent (nearest)': 'Latent (nearest)',
231
+ 'Latent (nearest-exact)': 'Latent (nearest-exact)',
232
+ "RealESRGAN_x4plus": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth",
233
+ "RealESRNet_x4plus": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.1/RealESRNet_x4plus.pth",
234
+ "RealESRGAN_x4plus_anime_6B": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/RealESRGAN_x4plus_anime_6B.pth",
235
+ "RealESRGAN_x2plus": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.1/RealESRGAN_x2plus.pth",
236
+ "realesr-animevideov3": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-animevideov3.pth",
237
+ "realesr-general-x4v3": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-general-x4v3.pth",
238
+ "realesr-general-wdn-x4v3": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-general-wdn-x4v3.pth",
239
+ "4x-UltraSharp": "https://huggingface.co/Shandypur/ESRGAN-4x-UltraSharp/resolve/main/4x-UltraSharp.pth",
240
+ "4x_foolhardy_Remacri": "https://huggingface.co/FacehugmanIII/4x_foolhardy_Remacri/resolve/main/4x_foolhardy_Remacri.pth",
241
+ "Remacri4xExtraSmoother": "https://huggingface.co/hollowstrawberry/upscalers-backup/resolve/main/ESRGAN/Remacri%204x%20ExtraSmoother.pth",
242
+ "AnimeSharp4x": "https://huggingface.co/hollowstrawberry/upscalers-backup/resolve/main/ESRGAN/AnimeSharp%204x.pth",
243
+ "lollypop": "https://huggingface.co/hollowstrawberry/upscalers-backup/resolve/main/ESRGAN/lollypop.pth",
244
+ "RealisticRescaler4x": "https://huggingface.co/hollowstrawberry/upscalers-backup/resolve/main/ESRGAN/RealisticRescaler%204x.pth",
245
+ "NickelbackFS4x": "https://huggingface.co/hollowstrawberry/upscalers-backup/resolve/main/ESRGAN/NickelbackFS%204x.pth"
246
+ }
247
+
248
+ UPSCALER_KEYS = list(UPSCALER_DICT_GUI.keys())
249
+
250
+
251
+ def download_things(directory, url, hf_token="", civitai_api_key=""):
252
+ url = url.strip()
253
+
254
+ if "drive.google.com" in url:
255
+ original_dir = os.getcwd()
256
+ os.chdir(directory)
257
+ os.system(f"gdown --fuzzy {url}")
258
+ os.chdir(original_dir)
259
+ elif "huggingface.co" in url:
260
+ url = url.replace("?download=true", "")
261
+ # url = urllib.parse.quote(url, safe=':/') # fix encoding
262
+ if "/blob/" in url:
263
+ url = url.replace("/blob/", "/resolve/")
264
+ user_header = f'"Authorization: Bearer {hf_token}"'
265
+ if hf_token:
266
+ os.system(f"aria2c --console-log-level=error --summary-interval=10 --header={user_header} -c -x 16 -k 1M -s 16 {url} -d {directory} -o {url.split('/')[-1]}")
267
+ else:
268
+ os.system(f"aria2c --optimize-concurrent-downloads --console-log-level=error --summary-interval=10 -c -x 16 -k 1M -s 16 {url} -d {directory} -o {url.split('/')[-1]}")
269
+ elif "civitai.com" in url:
270
+ if "?" in url:
271
+ url = url.split("?")[0]
272
+ if civitai_api_key:
273
+ url = url + f"?token={civitai_api_key}"
274
+ os.system(f"aria2c --console-log-level=error --summary-interval=10 -c -x 16 -k 1M -s 16 -d {directory} {url}")
275
+ else:
276
+ print("\033[91mYou need an API key to download Civitai models.\033[0m")
277
+ else:
278
+ os.system(f"aria2c --console-log-level=error --summary-interval=10 -c -x 16 -k 1M -s 16 -d {directory} {url}")
279
 
280
+
281
+ def get_model_list(directory_path):
282
+ model_list = []
283
+ valid_extensions = {'.ckpt', '.pt', '.pth', '.safetensors', '.bin'}
284
+
285
+ for filename in os.listdir(directory_path):
286
+ if os.path.splitext(filename)[1] in valid_extensions:
287
+ # name_without_extension = os.path.splitext(filename)[0]
288
+ file_path = os.path.join(directory_path, filename)
289
+ # model_list.append((name_without_extension, file_path))
290
+ model_list.append(file_path)
291
+ print('\033[34mFILE: ' + file_path + '\033[0m')
292
+ return model_list
293
+
294
+
295
+ directory_models = 'models'
296
+ os.makedirs(directory_models, exist_ok=True)
297
+ directory_loras = 'loras'
298
+ os.makedirs(directory_loras, exist_ok=True)
299
+ directory_vaes = 'vaes'
300
+ os.makedirs(directory_vaes, exist_ok=True)
301
 
302
  # Download stuffs
303
+ for url in [url.strip() for url in download_model.split(',')]:
304
+ if not os.path.exists(f"./models/{url.split('/')[-1]}"):
305
+ download_things(directory_models, url, HF_TOKEN, CIVITAI_API_KEY)
306
+ for url in [url.strip() for url in download_vae.split(',')]:
307
+ if not os.path.exists(f"./vaes/{url.split('/')[-1]}"):
308
+ download_things(directory_vaes, url, HF_TOKEN, CIVITAI_API_KEY)
309
+ for url in [url.strip() for url in download_lora.split(',')]:
310
+ if not os.path.exists(f"./loras/{url.split('/')[-1]}"):
311
+ download_things(directory_loras, url, HF_TOKEN, CIVITAI_API_KEY)
312
 
313
  # Download Embeddings
314
+ directory_embeds = 'embedings'
315
+ os.makedirs(directory_embeds, exist_ok=True)
316
+ download_embeds = [
317
+ 'https://huggingface.co/datasets/Nerfgun3/bad_prompt/blob/main/bad_prompt_version2.pt',
318
+ 'https://huggingface.co/embed/negative/resolve/main/EasyNegativeV2.safetensors',
319
+ 'https://huggingface.co/embed/negative/resolve/main/bad-hands-5.pt',
320
+ ]
321
+
322
+ for url_embed in download_embeds:
323
+ if not os.path.exists(f"./embedings/{url_embed.split('/')[-1]}"):
324
+ download_things(directory_embeds, url_embed, HF_TOKEN, CIVITAI_API_KEY)
325
 
326
  # Build list models
327
+ embed_list = get_model_list(directory_embeds)
328
+ model_list = get_model_list(directory_models)
329
+ model_list = load_diffusers_format_model + model_list
330
+ lora_model_list = get_model_list(directory_loras)
 
 
 
331
  lora_model_list.insert(0, "None")
332
  lora_model_list = lora_model_list + DIFFUSERS_FORMAT_LORAS
333
+ vae_model_list = get_model_list(directory_vaes)
 
334
  vae_model_list.insert(0, "None")
335
 
336
  print('\033[33m🏁 Download and listing of valid models completed.\033[0m')
337
 
 
 
 
 
 
 
 
 
 
 
 
338
  #######################
339
  # GUI
340
  #######################
341
+ import gradio as gr
342
+ import logging
343
  logging.getLogger("diffusers").setLevel(logging.ERROR)
344
+ import diffusers
345
  diffusers.utils.logging.set_verbosity(40)
346
+ import warnings
347
  warnings.filterwarnings(action="ignore", category=FutureWarning, module="diffusers")
348
  warnings.filterwarnings(action="ignore", category=UserWarning, module="diffusers")
349
  warnings.filterwarnings(action="ignore", category=FutureWarning, module="transformers")
350
+ from stablepy import logger
351
 
352
+ logger.setLevel(logging.DEBUG)
 
 
 
 
 
353
 
354
+ msg_inc_vae = (
355
+ "Use the right VAE for your model to maintain image quality. The wrong"
356
+ " VAE can lead to poor results, like blurriness in the generated images."
357
  )
358
 
359
+ SDXL_TASK = [k for k, v in TASK_STABLEPY.items() if v in SDXL_TASKS]
360
+ SD_TASK = [k for k, v in TASK_STABLEPY.items() if v in SD15_TASKS]
361
+ FLUX_TASK = list(TASK_STABLEPY.keys())[:3] + [k for k, v in TASK_STABLEPY.items() if v in FLUX_CN_UNION_MODES.keys()]
362
+
363
+ MODEL_TYPE_TASK = {
364
+ "SD 1.5": SD_TASK,
365
+ "SDXL": SDXL_TASK,
366
+ "FLUX": FLUX_TASK,
367
+ }
368
+
369
+ MODEL_TYPE_CLASS = {
370
+ "diffusers:StableDiffusionPipeline": "SD 1.5",
371
+ "diffusers:StableDiffusionXLPipeline": "SDXL",
372
+ "diffusers:FluxPipeline": "FLUX",
373
+ }
374
+
375
+ POST_PROCESSING_SAMPLER = ["Use same sampler"] + scheduler_names[:-2]
376
+
377
  CSS = """
378
  .contain { display: flex; flex-direction: column; }
379
  #component-0 { height: 100%; }
380
  #gallery { flex-grow: 1; }
 
381
  """
382
 
383
+ SUBTITLE_GUI = (
384
+ "### This demo uses [diffusers](https://github.com/huggingface/diffusers)"
385
+ " to perform different tasks in image generation."
386
+ )
387
 
388
+
389
+ def extract_parameters(input_string):
390
+ parameters = {}
391
+ input_string = input_string.replace("\n", "")
392
+
393
+ if "Negative prompt:" not in input_string:
394
+ if "Steps:" in input_string:
395
+ input_string = input_string.replace("Steps:", "Negative prompt: Steps:")
396
+ else:
397
+ print("Invalid metadata")
398
+ parameters["prompt"] = input_string
399
+ return parameters
400
+
401
+ parm = input_string.split("Negative prompt:")
402
+ parameters["prompt"] = parm[0].strip()
403
+ if "Steps:" not in parm[1]:
404
+ print("Steps not detected")
405
+ parameters["neg_prompt"] = parm[1].strip()
406
+ return parameters
407
+ parm = parm[1].split("Steps:")
408
+ parameters["neg_prompt"] = parm[0].strip()
409
+ input_string = "Steps:" + parm[1]
410
+
411
+ # Extracting Steps
412
+ steps_match = re.search(r'Steps: (\d+)', input_string)
413
+ if steps_match:
414
+ parameters['Steps'] = int(steps_match.group(1))
415
+
416
+ # Extracting Size
417
+ size_match = re.search(r'Size: (\d+x\d+)', input_string)
418
+ if size_match:
419
+ parameters['Size'] = size_match.group(1)
420
+ width, height = map(int, parameters['Size'].split('x'))
421
+ parameters['width'] = width
422
+ parameters['height'] = height
423
+
424
+ # Extracting other parameters
425
+ other_parameters = re.findall(r'(\w+): (.*?)(?=, \w+|$)', input_string)
426
+ for param in other_parameters:
427
+ parameters[param[0]] = param[1].strip('"')
428
+
429
+ return parameters
430
+
431
+
432
+ def get_my_lora(link_url):
433
+ for url in [url.strip() for url in link_url.split(',')]:
434
+ if not os.path.exists(f"./loras/{url.split('/')[-1]}"):
435
+ download_things(directory_loras, url, HF_TOKEN, CIVITAI_API_KEY)
436
+ new_lora_model_list = get_model_list(directory_loras)
437
+ new_lora_model_list.insert(0, "None")
438
+ new_lora_model_list = new_lora_model_list + DIFFUSERS_FORMAT_LORAS
439
+
440
+ return gr.update(
441
+ choices=new_lora_model_list
442
+ ), gr.update(
443
+ choices=new_lora_model_list
444
+ ), gr.update(
445
+ choices=new_lora_model_list
446
+ ), gr.update(
447
+ choices=new_lora_model_list
448
+ ), gr.update(
449
+ choices=new_lora_model_list
450
+ ),
451
+
452
+
453
+ def info_html(json_data, title, subtitle):
454
+ return f"""
455
+ <div style='padding: 0; border-radius: 10px;'>
456
+ <p style='margin: 0; font-weight: bold;'>{title}</p>
457
+ <details>
458
+ <summary>Details</summary>
459
+ <p style='margin: 0; font-weight: bold;'>{subtitle}</p>
460
+ </details>
461
+ </div>
462
+ """
463
+
464
+
465
+ def get_model_type(repo_id: str):
466
+ api = HfApi(token=os.environ.get("HF_TOKEN")) # if use private or gated model
467
+ default = "SD 1.5"
468
+ try:
469
+ model = api.model_info(repo_id=repo_id, timeout=5.0)
470
+ tags = model.tags
471
+ for tag in tags:
472
+ if tag in MODEL_TYPE_CLASS.keys(): return MODEL_TYPE_CLASS.get(tag, default)
473
+ except Exception:
474
+ return default
475
+ return default
476
 
477
 
478
  class GuiSD:
479
  def __init__(self, stream=True):
480
  self.model = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
481
 
482
+ print("Loading model...")
483
+ self.model = Model_Diffusers(
484
+ base_model_id="Lykon/dreamshaper-8",
485
+ task_name="txt2img",
486
+ vae_model=None,
487
+ type_model_precision=torch.float16,
488
+ retain_task_model_in_cache=False,
489
+ device="cpu",
490
+ )
491
+ self.model.load_beta_styles()
492
 
493
+ def load_new_model(self, model_name, vae_model, task, progress=gr.Progress(track_tqdm=True)):
494
 
495
  yield f"Loading model: {model_name}"
496
 
497
+ vae_model = vae_model if vae_model != "None" else None
498
+ model_type = get_model_type(model_name)
499
+
500
+ if vae_model:
501
  vae_type = "SDXL" if "sdxl" in vae_model.lower() else "SD 1.5"
502
  if model_type != vae_type:
503
+ gr.Warning(msg_inc_vae)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
504
 
505
+ self.model.device = torch.device("cpu")
506
+ dtype_model = torch.bfloat16 if model_type == "FLUX" else torch.float16
 
 
 
 
 
507
 
508
+ self.model.load_pipe(
509
+ model_name,
510
+ task_name=TASK_STABLEPY[task],
511
+ vae_model=vae_model,
512
+ type_model_precision=dtype_model,
513
+ retain_task_model_in_cache=False,
514
+ )
515
 
516
  yield f"Model loaded: {model_name}"
517
 
 
536
  lora_scale4,
537
  lora5,
538
  lora_scale5,
 
 
 
 
539
  sampler,
 
 
540
  img_height,
541
  img_width,
542
  model_name,
 
554
  high_threshold,
555
  value_threshold,
556
  distance_threshold,
 
 
557
  controlnet_output_scaling_in_unet,
558
  controlnet_start_threshold,
559
  controlnet_stop_threshold,
 
561
  syntax_weights,
562
  upscaler_model_path,
563
  upscaler_increases_size,
564
+ esrgan_tile,
565
+ esrgan_tile_overlap,
566
  hires_steps,
567
  hires_denoising_strength,
568
  hires_sampler,
 
570
  hires_negative_prompt,
571
  hires_before_adetailer,
572
  hires_after_adetailer,
 
 
 
573
  loop_generation,
574
  leave_progress_bar,
575
  disable_progress_bar,
576
  image_previews,
577
  display_images,
578
  save_generated_images,
 
579
  image_storage_location,
580
  retain_compel_previous_load,
581
  retain_detailfix_model_previous_load,
 
610
  mask_blur_b,
611
  mask_padding_b,
612
  retain_task_cache_gui,
 
613
  image_ip1,
614
  mask_ip1,
615
  model_ip1,
 
621
  mode_ip2,
622
  scale_ip2,
623
  pag_scale,
 
 
 
624
  ):
 
 
625
 
626
  vae_model = vae_model if vae_model != "None" else None
627
+ loras_list = [lora1, lora2, lora3, lora4, lora5]
628
  vae_msg = f"VAE: {vae_model}" if vae_model else ""
629
  msg_lora = ""
630
 
631
+ print("Config model:", model_name, vae_model, loras_list)
632
 
633
  task = TASK_STABLEPY[task]
634
 
 
643
  (image_ip2, mask_ip2, model_ip2, mode_ip2, scale_ip2),
644
  ]
645
 
646
+ for imgip, mskip, modelip, modeip, scaleip in all_adapters:
647
+ if imgip:
648
+ params_ip_img.append(imgip)
649
+ if mskip:
650
+ params_ip_msk.append(mskip)
651
+ params_ip_model.append(modelip)
652
+ params_ip_mode.append(modeip)
653
+ params_ip_scale.append(scaleip)
 
654
 
655
+ self.model.stream_config(concurrency=5, latent_resize_by=1, vae_decoding=False)
 
656
 
657
  if task != "txt2img" and not image_control:
658
+ raise ValueError("No control image found: To use this function, you have to upload an image in 'Image ControlNet/Inpaint/Img2img'")
659
 
660
+ if task == "inpaint" and not image_mask:
661
+ raise ValueError("No mask image found: Specify one in 'Image Mask'")
662
 
663
+ if upscaler_model_path in UPSCALER_KEYS[:9]:
664
  upscaler_model = upscaler_model_path
665
  else:
666
+ directory_upscalers = 'upscalers'
667
+ os.makedirs(directory_upscalers, exist_ok=True)
668
+
669
  url_upscaler = UPSCALER_DICT_GUI[upscaler_model_path]
670
 
671
+ if not os.path.exists(f"./upscalers/{url_upscaler.split('/')[-1]}"):
672
+ download_things(directory_upscalers, url_upscaler, HF_TOKEN)
673
 
674
+ upscaler_model = f"./upscalers/{url_upscaler.split('/')[-1]}"
675
 
676
  logging.getLogger("ultralytics").setLevel(logging.INFO if adetailer_verbose else logging.ERROR)
677
 
 
725
  "high_threshold": high_threshold,
726
  "value_threshold": value_threshold,
727
  "distance_threshold": distance_threshold,
728
+ "lora_A": lora1 if lora1 != "None" else None,
 
 
729
  "lora_scale_A": lora_scale1,
730
+ "lora_B": lora2 if lora2 != "None" else None,
731
  "lora_scale_B": lora_scale2,
732
+ "lora_C": lora3 if lora3 != "None" else None,
733
  "lora_scale_C": lora_scale3,
734
+ "lora_D": lora4 if lora4 != "None" else None,
735
  "lora_scale_D": lora_scale4,
736
+ "lora_E": lora5 if lora5 != "None" else None,
737
  "lora_scale_E": lora_scale5,
738
+ "textual_inversion": embed_list if textual_inversion and self.model.class_name != "StableDiffusionXLPipeline" else [],
 
 
 
 
739
  "syntax_weights": syntax_weights, # "Classic"
740
  "sampler": sampler,
 
 
741
  "xformers_memory_efficient_attention": xformers_memory_efficient_attention,
742
  "gui_active": True,
743
  "loop_generation": loop_generation,
 
755
  "image_previews": image_previews,
756
  "display_images": display_images,
757
  "save_generated_images": save_generated_images,
 
758
  "image_storage_location": image_storage_location,
759
  "retain_compel_previous_load": retain_compel_previous_load,
760
  "retain_detailfix_model_previous_load": retain_detailfix_model_previous_load,
 
764
  "t2i_adapter_conditioning_factor": float(t2i_adapter_conditioning_factor),
765
  "upscaler_model_path": upscaler_model,
766
  "upscaler_increases_size": upscaler_increases_size,
767
+ "esrgan_tile": esrgan_tile,
768
+ "esrgan_tile_overlap": esrgan_tile_overlap,
769
  "hires_steps": hires_steps,
770
  "hires_denoising_strength": hires_denoising_strength,
771
  "hires_prompt": hires_prompt,
 
773
  "hires_sampler": hires_sampler,
774
  "hires_before_adetailer": hires_before_adetailer,
775
  "hires_after_adetailer": hires_after_adetailer,
 
 
776
  "ip_adapter_image": params_ip_img,
777
  "ip_adapter_mask": params_ip_msk,
778
  "ip_adapter_model": params_ip_model,
779
  "ip_adapter_mode": params_ip_mode,
780
  "ip_adapter_scale": params_ip_scale,
 
 
 
781
  }
782
 
783
+ self.model.device = torch.device("cuda:0")
784
+ if hasattr(self.model.pipe, "transformer") and loras_list != ["None"] * 5:
785
+ self.model.pipe.transformer.to(self.model.device)
786
+ print("transformer to cuda")
787
+
788
+ info_state = "PROCESSING "
789
+ for img, seed, image_path, metadata in self.model(**pipe_params):
790
+ info_state += ">"
 
 
 
 
 
 
791
  if image_path:
792
+ info_state = f"COMPLETE. Seeds: {str(seed)}"
793
  if vae_msg:
794
+ info_state = info_state + "<br>" + vae_msg
 
 
 
 
 
795
 
796
  for status, lora in zip(self.model.lora_status, self.model.lora_memory):
797
  if status:
 
800
  msg_lora += f"<br>Error with: {lora}"
801
 
802
  if msg_lora:
803
+ info_state += msg_lora
804
 
805
+ info_state = info_state + "<br>" + "GENERATION DATA:<br>" + metadata[0].replace("\n", "<br>") + "<br>-------<br>"
806
 
807
  download_links = "<br>".join(
808
  [
809
+ f'<a href="{path.replace("/images/", "/file=/home/user/app/images/")}" download="{os.path.basename(path)}">Download Image {i + 1}</a>'
810
  for i, path in enumerate(image_path)
811
  ]
812
  )
813
  if save_generated_images:
814
+ info_state += f"<br>{download_links}"
815
+
816
+ yield img, info_state
817
+
818
+
819
+ def update_task_options(model_name, task_name):
820
+ new_choices = MODEL_TYPE_TASK[get_model_type(model_name)]
821
 
822
+ if task_name not in new_choices:
823
+ task_name = "txt2img"
824
 
825
+ return gr.update(value=task_name, choices=new_choices)
826
 
827
 
828
  def dynamic_gpu_duration(func, duration, *args):
829
 
 
830
  @spaces.GPU(duration=duration)
831
  def wrapped_func():
832
  yield from func(*args)
 
840
 
841
 
842
  def sd_gen_generate_pipeline(*args):
843
+
844
  gpu_duration_arg = int(args[-1]) if args[-1] else 59
845
  verbose_arg = int(args[-2])
846
  load_lora_cpu = args[-3]
847
  generation_args = args[:-3]
848
  lora_list = [
849
  None if item == "None" else item
850
+ for item in [args[7], args[9], args[11], args[13], args[15]]
851
  ]
852
+ lora_status = [None] * 5
853
 
854
  msg_load_lora = "Updating LoRAs in GPU..."
855
  if load_lora_cpu:
856
+ msg_load_lora = "Updating LoRAs in CPU (Slow but saves GPU usage)..."
857
 
858
+ if lora_list != sd_gen.model.lora_memory and lora_list != [None] * 5:
859
+ yield None, msg_load_lora
860
 
861
  # Load lora in CPU
862
  if load_lora_cpu:
863
+ lora_status = sd_gen.model.lora_merge(
864
  lora_A=lora_list[0], lora_scale_A=args[8],
865
  lora_B=lora_list[1], lora_scale_B=args[10],
866
  lora_C=lora_list[2], lora_scale_C=args[12],
867
  lora_D=lora_list[3], lora_scale_D=args[14],
868
  lora_E=lora_list[4], lora_scale_E=args[16],
 
 
869
  )
870
  print(lora_status)
871
 
 
 
 
 
 
 
 
 
872
  if verbose_arg:
873
  for status, lora in zip(lora_status, lora_list):
874
  if status:
 
876
  elif status is not None:
877
  gr.Warning(f"Failed to load LoRA: {lora}")
878
 
879
+ if lora_status == [None] * 5 and sd_gen.model.lora_memory != [None] * 5 and load_lora_cpu:
880
  lora_cache_msg = ", ".join(
881
  str(x) for x in sd_gen.model.lora_memory if x is not None
882
  )
883
  gr.Info(f"LoRAs in cache: {lora_cache_msg}")
884
 
885
+ msg_request = f"Requesting {gpu_duration_arg}s. of GPU time"
 
886
  gr.Info(msg_request)
887
  print(msg_request)
888
+
889
+ # yield from sd_gen.generate_pipeline(*generation_args)
890
 
891
  start_time = time.time()
892
 
 
893
  yield from dynamic_gpu_duration(
894
  sd_gen.generate_pipeline,
895
  gpu_duration_arg,
 
897
  )
898
 
899
  end_time = time.time()
 
 
 
 
900
 
901
  if verbose_arg:
902
+ execution_time = end_time - start_time
903
+ msg_task_complete = (
904
+ f"GPU task complete in: {round(execution_time, 0) + 1} seconds"
905
+ )
906
  gr.Info(msg_task_complete)
907
  print(msg_task_complete)
908
 
 
909
 
910
+ def extract_exif_data(image):
911
+ if image is None: return ""
912
 
913
+ try:
914
+ metadata_keys = ['parameters', 'metadata', 'prompt', 'Comment']
 
 
915
 
916
+ for key in metadata_keys:
917
+ if key in image.info:
918
+ return image.info[key]
919
 
920
+ return str(image.info)
921
+
922
+ except Exception as e:
923
+ return f"Error extracting metadata: {str(e)}"
924
 
 
925
 
926
+ @spaces.GPU(duration=20)
927
+ def esrgan_upscale(image, upscaler_name, upscaler_size):
928
+ if image is None: return None
929
+
930
+ from stablepy.diffusers_vanilla.utils import save_pil_image_with_metadata
931
+ from stablepy import UpscalerESRGAN
932
 
933
+ exif_image = extract_exif_data(image)
 
934
 
935
+ url_upscaler = UPSCALER_DICT_GUI[upscaler_name]
936
+ directory_upscalers = 'upscalers'
937
+ os.makedirs(directory_upscalers, exist_ok=True)
938
+ if not os.path.exists(f"./upscalers/{url_upscaler.split('/')[-1]}"):
939
+ download_things(directory_upscalers, url_upscaler, HF_TOKEN)
940
 
941
+ scaler_beta = UpscalerESRGAN(0, 0)
942
+ image_up = scaler_beta.upscale(image, upscaler_size, f"./upscalers/{url_upscaler.split('/')[-1]}")
943
 
944
  image_path = save_pil_image_with_metadata(image_up, f'{os.getcwd()}/up_images', exif_image)
945
 
946
  return image_path
947
 
948
 
949
+ dynamic_gpu_duration.zerogpu = True
950
+ sd_gen_generate_pipeline.zerogpu = True
 
951
  sd_gen = GuiSD()
952
 
953
+ with gr.Blocks(theme="NoCrypt/miku", css=CSS) as app:
954
  gr.Markdown("# 🧩 DiffuseCraft")
955
  gr.Markdown(SUBTITLE_GUI)
956
  with gr.Tab("Generation"):
 
958
 
959
  with gr.Column(scale=2):
960
 
 
 
 
 
 
 
 
 
961
  task_gui = gr.Dropdown(label="Task", choices=SDXL_TASK, value=TASK_MODEL_LIST[0])
962
  model_name_gui = gr.Dropdown(label="Model", choices=model_list, value=model_list[0], allow_custom_value=True)
963
  prompt_gui = gr.Textbox(lines=5, placeholder="Enter prompt", label="Prompt")
964
+ neg_prompt_gui = gr.Textbox(lines=3, placeholder="Enter Neg prompt", label="Negative prompt")
965
  with gr.Row(equal_height=False):
966
  set_params_gui = gr.Button(value="↙️", variant="secondary", size="sm")
967
  clear_prompt_gui = gr.Button(value="🗑️", variant="secondary", size="sm")
 
974
  [task_gui],
975
  )
976
 
977
+ load_model_gui = gr.HTML()
978
 
979
  result_images = gr.Gallery(
980
  label="Generated images",
 
991
 
992
  actual_task_info = gr.HTML()
993
 
994
+ with gr.Row(equal_height=False, variant="default"):
995
  gpu_duration_gui = gr.Number(minimum=5, maximum=240, value=59, show_label=False, container=False, info="GPU time duration (seconds)")
996
  with gr.Column():
997
  verbose_info_gui = gr.Checkbox(value=False, container=False, label="Status info")
998
+ load_lora_cpu_gui = gr.Checkbox(value=False, container=False, label="Load LoRAs on CPU (Save GPU time)")
999
 
1000
  with gr.Column(scale=1):
1001
+ steps_gui = gr.Slider(minimum=1, maximum=100, step=1, value=30, label="Steps")
1002
  cfg_gui = gr.Slider(minimum=0, maximum=30, step=0.5, value=7., label="CFG")
1003
+ sampler_gui = gr.Dropdown(label="Sampler", choices=scheduler_names, value="Euler a")
 
1004
  img_width_gui = gr.Slider(minimum=64, maximum=4096, step=8, value=1024, label="Img Width")
1005
  img_height_gui = gr.Slider(minimum=64, maximum=4096, step=8, value=1024, label="Img Height")
1006
  seed_gui = gr.Number(minimum=-1, maximum=9999999999, value=-1, label="Seed")
 
1019
  "width": gr.update(value=1024),
1020
  "height": gr.update(value=1024),
1021
  "Seed": gr.update(value=-1),
1022
+ "Sampler": gr.update(value="Euler a"),
1023
+ "scale": gr.update(value=7.), # cfg
1024
+ "skip": gr.update(value=True),
1025
  "Model": gr.update(value=name_model),
 
 
 
 
 
 
 
 
 
 
 
 
1026
  }
 
 
 
 
 
 
1027
  valid_keys = list(valid_receptors.keys())
1028
 
1029
  parameters = extract_parameters(base_prompt)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1030
 
 
 
 
 
 
 
 
 
 
1031
  for key, val in parameters.items():
1032
  # print(val)
1033
  if key in valid_keys:
 
1035
  if key == "Sampler":
1036
  if val not in scheduler_names:
1037
  continue
1038
+ elif key == "skip":
 
 
 
 
 
 
1039
  if "," in str(val):
1040
  val = val.replace(",", "")
1041
  if int(val) >= 2:
1042
  val = True
1043
  if key == "prompt":
1044
  if ">" in val and "<" in val:
1045
+ val = re.sub(r'<[^>]+>', '', val)
1046
  print("Removed LoRA written in the prompt")
1047
  if key in ["prompt", "neg_prompt"]:
1048
  val = re.sub(r'\s+', ' ', re.sub(r',+', ',', val)).strip()
1049
+ if key in ["Steps", "width", "height", "Seed"]:
1050
  val = int(val)
1051
+ if key == "scale":
 
 
1052
  val = float(val)
1053
  if key == "Model":
1054
  filtered_models = [m for m in model_list if val in m]
 
1056
  val = filtered_models[0]
1057
  else:
1058
  val = name_model
 
 
 
1059
  if key == "Seed":
1060
  continue
 
1061
  valid_receptors[key] = gr.update(value=val)
1062
  # print(val, type(val))
1063
  # print(valid_receptors)
 
1065
  print(str(e))
1066
  return [value for value in valid_receptors.values()]
1067
 
1068
+ set_params_gui.click(
1069
+ run_set_params_gui, [prompt_gui, model_name_gui], [
1070
+ prompt_gui,
1071
+ neg_prompt_gui,
1072
+ steps_gui,
1073
+ img_width_gui,
1074
+ img_height_gui,
1075
+ seed_gui,
1076
+ sampler_gui,
1077
+ cfg_gui,
1078
+ clip_skip_gui,
1079
+ model_name_gui,
1080
+ ],
1081
+ )
1082
+
1083
  def run_clear_prompt_gui():
1084
  return gr.update(value=""), gr.update(value="")
1085
  clear_prompt_gui.click(
 
1092
  run_set_random_seed, [], seed_gui
1093
  )
1094
 
1095
+ num_images_gui = gr.Slider(minimum=1, maximum=5, step=1, value=1, label="Images")
1096
+ prompt_s_options = [
1097
+ ("Compel format: (word)weight", "Compel"),
1098
+ ("Classic format: (word:weight)", "Classic"),
1099
+ ("Classic-original format: (word:weight)", "Classic-original"),
1100
+ ("Classic-no_norm format: (word:weight)", "Classic-no_norm"),
1101
+ ("Classic-ignore", "Classic-ignore"),
1102
+ ("None", "None"),
1103
+ ]
1104
+ prompt_syntax_gui = gr.Dropdown(label="Prompt Syntax", choices=prompt_s_options, value=prompt_s_options[1][1])
1105
  vae_model_gui = gr.Dropdown(label="VAE Model", choices=vae_model_list, value=vae_model_list[0])
1106
 
1107
  with gr.Accordion("Hires fix", open=False, visible=True):
1108
 
1109
  upscaler_model_path_gui = gr.Dropdown(label="Upscaler", choices=UPSCALER_KEYS, value=UPSCALER_KEYS[0])
1110
  upscaler_increases_size_gui = gr.Slider(minimum=1.1, maximum=4., step=0.1, value=1.2, label="Upscale by")
1111
+ esrgan_tile_gui = gr.Slider(minimum=0, value=0, maximum=500, step=1, label="ESRGAN Tile")
1112
+ esrgan_tile_overlap_gui = gr.Slider(minimum=1, maximum=200, step=1, value=8, label="ESRGAN Tile Overlap")
1113
  hires_steps_gui = gr.Slider(minimum=0, value=30, maximum=100, step=1, label="Hires Steps")
1114
  hires_denoising_strength_gui = gr.Slider(minimum=0.1, maximum=1.0, step=0.01, value=0.55, label="Hires Denoising Strength")
1115
  hires_sampler_gui = gr.Dropdown(label="Hires Sampler", choices=POST_PROCESSING_SAMPLER, value=POST_PROCESSING_SAMPLER[0])
 
 
 
1116
  hires_prompt_gui = gr.Textbox(label="Hires Prompt", placeholder="Main prompt will be use", lines=3)
1117
  hires_negative_prompt_gui = gr.Textbox(label="Hires Negative Prompt", placeholder="Main negative prompt will be use", lines=3)
1118
 
1119
  with gr.Accordion("LoRA", open=False, visible=True):
1120
 
1121
+ def lora_dropdown(label):
1122
+ return gr.Dropdown(label=label, choices=lora_model_list, value="None", allow_custom_value=True)
1123
 
1124
+ def lora_scale_slider(label):
1125
+ return gr.Slider(minimum=-2, maximum=2, step=0.01, value=0.33, label=label)
 
1126
 
1127
  lora1_gui = lora_dropdown("Lora1")
1128
  lora_scale_1_gui = lora_scale_slider("Lora Scale 1")
 
1134
  lora_scale_4_gui = lora_scale_slider("Lora Scale 4")
1135
  lora5_gui = lora_dropdown("Lora5")
1136
  lora_scale_5_gui = lora_scale_slider("Lora Scale 5")
 
 
 
 
1137
 
1138
  with gr.Accordion("From URL", open=False, visible=True):
1139
+ text_lora = gr.Textbox(label="LoRA URL", placeholder="https://civitai.com/api/download/models/28907", lines=1)
1140
+ button_lora = gr.Button("Get and update lists of LoRAs")
 
 
 
 
 
 
 
1141
  button_lora.click(
1142
  get_my_lora,
1143
+ [text_lora],
1144
+ [lora1_gui, lora2_gui, lora3_gui, lora4_gui, lora5_gui]
1145
  )
1146
 
 
 
 
 
 
 
 
 
1147
  with gr.Accordion("IP-Adapter", open=False, visible=True):
1148
 
1149
+ IP_MODELS = sorted(list(set(IP_ADAPTERS_SD + IP_ADAPTERS_SDXL)))
1150
+ MODE_IP_OPTIONS = ["original", "style", "layout", "style+layout"]
1151
+
1152
  with gr.Accordion("IP-Adapter 1", open=False, visible=True):
1153
  image_ip1 = gr.Image(label="IP Image", type="filepath")
1154
  mask_ip1 = gr.Image(label="IP Mask", type="filepath")
 
1167
  image_mask_gui = gr.Image(label="Image Mask", type="filepath")
1168
  strength_gui = gr.Slider(
1169
  minimum=0.01, maximum=1.0, step=0.01, value=0.55, label="Strength",
1170
+ info="This option adjusts the level of changes for img2img and inpainting."
1171
  )
1172
+ image_resolution_gui = gr.Slider(minimum=64, maximum=2048, step=64, value=1024, label="Image Resolution")
1173
+ preprocessor_name_gui = gr.Dropdown(label="Preprocessor Name", choices=PREPROCESSOR_CONTROLNET["canny"])
 
 
 
 
 
 
 
1174
 
1175
  def change_preprocessor_choices(task):
1176
  task = TASK_STABLEPY[task]
1177
+ if task in PREPROCESSOR_CONTROLNET.keys():
1178
+ choices_task = PREPROCESSOR_CONTROLNET[task]
1179
  else:
1180
+ choices_task = PREPROCESSOR_CONTROLNET["canny"]
1181
  return gr.update(choices=choices_task, value=choices_task[0])
1182
+
1183
  task_gui.change(
1184
  change_preprocessor_choices,
1185
  [task_gui],
1186
  [preprocessor_name_gui],
1187
  )
1188
+ preprocess_resolution_gui = gr.Slider(minimum=64, maximum=2048, step=64, value=512, label="Preprocess Resolution")
1189
+ low_threshold_gui = gr.Slider(minimum=1, maximum=255, step=1, value=100, label="Canny low threshold")
1190
+ high_threshold_gui = gr.Slider(minimum=1, maximum=255, step=1, value=200, label="Canny high threshold")
1191
+ value_threshold_gui = gr.Slider(minimum=1, maximum=2.0, step=0.01, value=0.1, label="Hough value threshold (MLSD)")
1192
+ distance_threshold_gui = gr.Slider(minimum=1, maximum=20.0, step=0.01, value=0.1, label="Hough distance threshold (MLSD)")
1193
+ control_net_output_scaling_gui = gr.Slider(minimum=0, maximum=5.0, step=0.1, value=1, label="ControlNet Output Scaling in UNet")
1194
+ control_net_start_threshold_gui = gr.Slider(minimum=0, maximum=1, step=0.01, value=0, label="ControlNet Start Threshold (%)")
1195
+ control_net_stop_threshold_gui = gr.Slider(minimum=0, maximum=1, step=0.01, value=1, label="ControlNet Stop Threshold (%)")
1196
 
1197
  with gr.Accordion("T2I adapter", open=False, visible=False):
1198
  t2i_adapter_preprocessor_gui = gr.Checkbox(value=True, label="T2i Adapter Preprocessor")
 
1225
  gr.Info(f"{len(sd_gen.model.STYLE_NAMES)} styles loaded")
1226
  return gr.update(value=None, choices=sd_gen.model.STYLE_NAMES)
1227
 
1228
+ style_button.click(load_json_style_file, [style_json_gui], [style_prompt_gui])
1229
 
1230
  with gr.Accordion("Textual inversion", open=False, visible=False):
1231
  active_textual_inversion_gui = gr.Checkbox(value=False, label="Active Textual Inversion in prompt")
 
1248
  negative_prompt_ad_a_gui = gr.Textbox(label="Negative prompt", placeholder="Main negative prompt will be use", lines=3)
1249
  strength_ad_a_gui = gr.Number(label="Strength:", value=0.35, step=0.01, minimum=0.01, maximum=1.0)
1250
  face_detector_ad_a_gui = gr.Checkbox(label="Face detector", value=True)
1251
+ person_detector_ad_a_gui = gr.Checkbox(label="Person detector", value=True)
1252
  hand_detector_ad_a_gui = gr.Checkbox(label="Hand detector", value=False)
1253
  mask_dilation_a_gui = gr.Number(label="Mask dilation:", value=4, minimum=1)
1254
  mask_blur_a_gui = gr.Number(label="Mask blur:", value=4, minimum=1)
 
1260
  prompt_ad_b_gui = gr.Textbox(label="Main prompt", placeholder="Main prompt will be use", lines=3)
1261
  negative_prompt_ad_b_gui = gr.Textbox(label="Negative prompt", placeholder="Main negative prompt will be use", lines=3)
1262
  strength_ad_b_gui = gr.Number(label="Strength:", value=0.35, step=0.01, minimum=0.01, maximum=1.0)
1263
+ face_detector_ad_b_gui = gr.Checkbox(label="Face detector", value=True)
1264
  person_detector_ad_b_gui = gr.Checkbox(label="Person detector", value=True)
1265
  hand_detector_ad_b_gui = gr.Checkbox(label="Hand detector", value=False)
1266
  mask_dilation_b_gui = gr.Number(label="Mask dilation:", value=4, minimum=1)
 
1268
  mask_padding_b_gui = gr.Number(label="Mask padding:", value=32, minimum=1)
1269
 
1270
  with gr.Accordion("Other settings", open=False, visible=True):
 
 
1271
  save_generated_images_gui = gr.Checkbox(value=True, label="Create a download link for the images")
 
1272
  hires_before_adetailer_gui = gr.Checkbox(value=False, label="Hires Before Adetailer")
1273
  hires_after_adetailer_gui = gr.Checkbox(value=True, label="Hires After Adetailer")
1274
  generator_in_cpu_gui = gr.Checkbox(value=False, label="Generator in CPU")
 
 
 
 
1275
 
1276
  with gr.Accordion("More settings", open=False, visible=False):
1277
  loop_generation_gui = gr.Slider(minimum=1, value=1, label="Loop Generation")
1278
  retain_task_cache_gui = gr.Checkbox(value=False, label="Retain task model in cache")
1279
+ leave_progress_bar_gui = gr.Checkbox(value=True, label="Leave Progress Bar")
1280
+ disable_progress_bar_gui = gr.Checkbox(value=False, label="Disable Progress Bar")
1281
+ display_images_gui = gr.Checkbox(value=True, label="Display Images")
1282
  image_previews_gui = gr.Checkbox(value=True, label="Image Previews")
1283
+ image_storage_location_gui = gr.Textbox(value="./images", label="Image Storage Location")
1284
  retain_compel_previous_load_gui = gr.Checkbox(value=False, label="Retain Compel Previous Load")
1285
  retain_detailfix_model_previous_load_gui = gr.Checkbox(value=False, label="Retain Detailfix Model Previous Load")
1286
  retain_hires_model_previous_load_gui = gr.Checkbox(value=False, label="Retain Hires Model Previous Load")
1287
  xformers_memory_efficient_attention_gui = gr.Checkbox(value=False, label="Xformers Memory Efficient Attention")
1288
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1289
  with gr.Accordion("Examples and help", open=False, visible=True):
1290
+ gr.Markdown(
1291
+ """### Help:
1292
+ - The current space runs on a ZERO GPU which is assigned for approximately 60 seconds; Therefore, if you submit expensive tasks, the operation may be canceled upon reaching the maximum allowed time with 'GPU TASK ABORTED'.
1293
+ - Distorted or strange images often result from high prompt weights, so it's best to use low weights and scales, and consider using Classic variants like 'Classic-original'.
1294
+ - For better results with Pony Diffusion, try using sampler DPM++ 1s or DPM2 with Compel or Classic prompt weights.
1295
+ """
1296
+ )
1297
+ gr.Markdown(
1298
+ """### The following examples perform specific tasks:
1299
+ 1. Generation with SDXL and upscale
1300
+ 2. Generation with FLUX dev
1301
+ 3. ControlNet Canny SDXL
1302
+ 4. Optical pattern (Optical illusion) SDXL
1303
+ 5. Convert an image to a coloring drawing
1304
+ 6. ControlNet OpenPose SD 1.5 and Latent upscale
1305
+
1306
+ - Different tasks can be performed, such as img2img or using the IP adapter, to preserve a person's appearance or a specific style based on an image.
1307
+ """
1308
+ )
1309
  gr.Examples(
1310
+ examples=[
1311
+ [
1312
+ "1girl, souryuu asuka langley, neon genesis evangelion, rebuild of evangelion, lance of longinus, cat hat, plugsuit, pilot suit, red bodysuit, sitting, crossed legs, black eye patch, throne, looking down, from bottom, looking at viewer, outdoors, (masterpiece), (best quality), (ultra-detailed), very aesthetic, illustration, disheveled hair, perfect composition, moist skin, intricate details",
1313
+ "nfsw, lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry, unfinished, very displeasing, oldest, early, chromatic aberration, artistic error, scan, abstract",
1314
+ 28,
1315
+ 7.0,
1316
+ -1,
1317
+ "None",
1318
+ 0.33,
1319
+ "Euler a",
1320
+ 1152,
1321
+ 896,
1322
+ "cagliostrolab/animagine-xl-3.1",
1323
+ "txt2img",
1324
+ "image.webp", # img conttol
1325
+ 1024, # img resolution
1326
+ 0.35, # strength
1327
+ 1.0, # cn scale
1328
+ 0.0, # cn start
1329
+ 1.0, # cn end
1330
+ "Classic",
1331
+ "Nearest",
1332
+ 45,
1333
+ False,
1334
+ ],
1335
+ [
1336
+ "a digital illustration of a movie poster titled 'Finding Emo', finding nemo parody poster, featuring a depressed cartoon clownfish with black emo hair, eyeliner, and piercings, bored expression, swimming in a dark underwater scene, in the background, movie title in a dripping, grungy font, moody blue and purple color palette",
1337
+ "",
1338
+ 24,
1339
+ 3.5,
1340
+ -1,
1341
+ "None",
1342
+ 0.33,
1343
+ "Euler a",
1344
+ 1152,
1345
+ 896,
1346
+ "black-forest-labs/FLUX.1-dev",
1347
+ "txt2img",
1348
+ None, # img conttol
1349
+ 1024, # img resolution
1350
+ 0.35, # strength
1351
+ 1.0, # cn scale
1352
+ 0.0, # cn start
1353
+ 1.0, # cn end
1354
+ "Classic",
1355
+ None,
1356
+ 70,
1357
+ True,
1358
+ ],
1359
+ [
1360
+ "((masterpiece)), best quality, blonde disco girl, detailed face, realistic face, realistic hair, dynamic pose, pink pvc, intergalactic disco background, pastel lights, dynamic contrast, airbrush, fine detail, 70s vibe, midriff",
1361
+ "(worst quality:1.2), (bad quality:1.2), (poor quality:1.2), (missing fingers:1.2), bad-artist-anime, bad-artist, bad-picture-chill-75v",
1362
+ 48,
1363
+ 3.5,
1364
+ -1,
1365
+ "None",
1366
+ 0.33,
1367
+ "DPM++ 2M SDE Lu",
1368
+ 1024,
1369
+ 1024,
1370
+ "misri/epicrealismXL_v7FinalDestination",
1371
+ "canny ControlNet",
1372
+ "image.webp", # img conttol
1373
+ 1024, # img resolution
1374
+ 0.35, # strength
1375
+ 1.0, # cn scale
1376
+ 0.0, # cn start
1377
+ 1.0, # cn end
1378
+ "Classic",
1379
+ None,
1380
+ 44,
1381
+ False,
1382
+ ],
1383
+ [
1384
+ "cinematic scenery old city ruins",
1385
+ "(worst quality, low quality, illustration, 3d, 2d, painting, cartoons, sketch), (illustration, 3d, 2d, painting, cartoons, sketch, blurry, film grain, noise), (low quality, worst quality:1.2)",
1386
+ 50,
1387
+ 4.0,
1388
+ -1,
1389
+ "None",
1390
+ 0.33,
1391
+ "Euler a",
1392
+ 1024,
1393
+ 1024,
1394
+ "misri/juggernautXL_juggernautX",
1395
+ "optical pattern ControlNet",
1396
+ "spiral_no_transparent.png", # img conttol
1397
+ 1024, # img resolution
1398
+ 0.35, # strength
1399
+ 1.0, # cn scale
1400
+ 0.05, # cn start
1401
+ 0.75, # cn end
1402
+ "Classic",
1403
+ None,
1404
+ 35,
1405
+ False,
1406
+ ],
1407
+ [
1408
+ "black and white, line art, coloring drawing, clean line art, black strokes, no background, white, black, free lines, black scribbles, on paper, A blend of comic book art and lineart full of black and white color, masterpiece, high-resolution, trending on Pixiv fan box, palette knife, brush strokes, two-dimensional, planar vector, T-shirt design, stickers, and T-shirt design, vector art, fantasy art, Adobe Illustrator, hand-painted, digital painting, low polygon, soft lighting, aerial view, isometric style, retro aesthetics, 8K resolution, black sketch lines, monochrome, invert color",
1409
+ "color, red, green, yellow, colored, duplicate, blurry, abstract, disfigured, deformed, animated, toy, figure, framed, 3d, bad art, poorly drawn, extra limbs, close up, b&w, weird colors, blurry, watermark, blur haze, 2 heads, long neck, watermark, elongated body, cropped image, out of frame, draft, deformed hands, twisted fingers, double image, malformed hands, multiple heads, extra limb, ugly, poorly drawn hands, missing limb, cut-off, over satured, grain, lowères, bad anatomy, poorly drawn face, mutation, mutated, floating limbs, disconnected limbs, out of focus, long body, disgusting, extra fingers, groos proportions, missing arms, mutated hands, cloned face, missing legs, ugly, tiling, poorly drawn hands, poorly drawn feet, poorly drawn face, out of frame, extra limbs, disfigured, deformed, body out of frame, blurry, bad anatomy, blurred, watermark, grainy, signature, cut off, draft, deformed, blurry, bad anatomy, disfigured, poorly drawn face, mutation, bluelish, blue",
1410
+ 20,
1411
+ 4.0,
1412
+ -1,
1413
+ "loras/Coloring_book_-_LineArt.safetensors",
1414
+ 1.0,
1415
+ "DPM++ 2M SDE Karras",
1416
+ 1024,
1417
+ 1024,
1418
+ "cagliostrolab/animagine-xl-3.1",
1419
+ "lineart ControlNet",
1420
+ "color_image.png", # img conttol
1421
+ 896, # img resolution
1422
+ 0.35, # strength
1423
+ 1.0, # cn scale
1424
+ 0.0, # cn start
1425
+ 1.0, # cn end
1426
+ "Compel",
1427
+ None,
1428
+ 35,
1429
+ False,
1430
+ ],
1431
+ [
1432
+ "1girl,face,curly hair,red hair,white background,",
1433
+ "(worst quality:2),(low quality:2),(normal quality:2),lowres,watermark,",
1434
+ 38,
1435
+ 5.0,
1436
+ -1,
1437
+ "None",
1438
+ 0.33,
1439
+ "DPM++ 2M SDE Karras",
1440
+ 512,
1441
+ 512,
1442
+ "digiplay/majicMIX_realistic_v7",
1443
+ "openpose ControlNet",
1444
+ "image.webp", # img conttol
1445
+ 1024, # img resolution
1446
+ 0.35, # strength
1447
+ 1.0, # cn scale
1448
+ 0.0, # cn start
1449
+ 0.9, # cn end
1450
+ "Compel",
1451
+ "Latent (antialiased)",
1452
+ 46,
1453
+ False,
1454
+ ],
1455
+ ],
1456
  fn=sd_gen.generate_pipeline,
1457
  inputs=[
1458
  prompt_gui,
 
1478
  gpu_duration_gui,
1479
  load_lora_cpu_gui,
1480
  ],
1481
+ outputs=[result_images, actual_task_info],
1482
  cache_examples=False,
1483
  )
1484
+ gr.Markdown(
1485
+ """### Resources
1486
+ - John6666's space has some great features you might find helpful [link](https://huggingface.co/spaces/John6666/DiffuseCraftMod).
1487
+ - You can also try the image generator in Colab’s free tier, which provides free GPU [link](https://github.com/R3gm/SD_diffusers_interactive).
1488
+ """
1489
+ )
1490
 
1491
  with gr.Tab("Inpaint mask maker", render=True):
1492
 
1493
+ def create_mask_now(img, invert):
1494
+ import numpy as np
1495
+ import time
1496
+
1497
+ time.sleep(0.5)
1498
+
1499
+ transparent_image = img["layers"][0]
1500
+
1501
+ # Extract the alpha channel
1502
+ alpha_channel = np.array(transparent_image)[:, :, 3]
1503
+
1504
+ # Create a binary mask by thresholding the alpha channel
1505
+ binary_mask = alpha_channel > 1
1506
+
1507
+ if invert:
1508
+ print("Invert")
1509
+ # Invert the binary mask so that the drawn shape is white and the rest is black
1510
+ binary_mask = np.invert(binary_mask)
1511
+
1512
+ # Convert the binary mask to a 3-channel RGB mask
1513
+ rgb_mask = np.stack((binary_mask,) * 3, axis=-1)
1514
+
1515
+ # Convert the mask to uint8
1516
+ rgb_mask = rgb_mask.astype(np.uint8) * 255
1517
+
1518
+ return img["background"], rgb_mask
1519
+
1520
  with gr.Row():
1521
  with gr.Column(scale=2):
1522
  image_base = gr.ImageEditor(
 
1525
  # enable crop (or disable it)
1526
  # transforms=["crop"],
1527
  brush=gr.Brush(
1528
+ default_size="16", # or leave it as 'auto'
1529
+ color_mode="fixed", # 'fixed' hides the user swatches and colorpicker, 'defaults' shows it
1530
+ # default_color="black", # html names are supported
1531
+ colors=[
1532
+ "rgba(0, 0, 0, 1)", # rgb(a)
1533
+ "rgba(0, 0, 0, 0.1)",
1534
+ "rgba(255, 255, 255, 0.1)",
1535
+ # "hsl(360, 120, 120)" # in fact any valid colorstring
1536
+ ]
1537
  ),
1538
+ eraser=gr.Eraser(default_size="16")
 
 
 
1539
  )
 
 
 
 
 
 
 
1540
  invert_mask = gr.Checkbox(value=False, label="Invert mask")
1541
  btn = gr.Button("Create mask")
 
1542
  with gr.Column(scale=1):
1543
  img_source = gr.Image(interactive=False)
1544
  img_result = gr.Image(label="Mask image", show_label=True, interactive=False)
 
1569
 
1570
  with gr.Row():
1571
  with gr.Column():
 
 
 
1572
  image_up_tab = gr.Image(label="Image", type="pil", sources=["upload"])
1573
+ upscaler_tab = gr.Dropdown(label="Upscaler", choices=UPSCALER_KEYS[9:], value=UPSCALER_KEYS[11])
1574
  upscaler_size_tab = gr.Slider(minimum=1., maximum=4., step=0.1, value=1.1, label="Upscale by")
1575
  generate_button_up_tab = gr.Button(value="START UPSCALE", variant="primary")
1576
 
 
1578
  result_up_tab = gr.Image(label="Result", type="pil", interactive=False, format="png")
1579
 
1580
  generate_button_up_tab.click(
1581
+ fn=esrgan_upscale,
1582
  inputs=[image_up_tab, upscaler_tab, upscaler_size_tab],
1583
  outputs=[result_up_tab],
1584
  )
1585
 
 
 
 
1586
  generate_button.click(
1587
  fn=sd_gen.load_new_model,
1588
  inputs=[
1589
  model_name_gui,
1590
  vae_model_gui,
1591
+ task_gui
 
1592
  ],
1593
  outputs=[load_model_gui],
1594
  queue=True,
1595
  show_progress="minimal",
 
1596
  ).success(
1597
  fn=sd_gen_generate_pipeline, # fn=sd_gen.generate_pipeline,
1598
  inputs=[
 
1613
  lora_scale_4_gui,
1614
  lora5_gui,
1615
  lora_scale_5_gui,
 
 
 
 
1616
  sampler_gui,
 
 
1617
  img_height_gui,
1618
  img_width_gui,
1619
  model_name_gui,
 
1631
  high_threshold_gui,
1632
  value_threshold_gui,
1633
  distance_threshold_gui,
 
 
1634
  control_net_output_scaling_gui,
1635
  control_net_start_threshold_gui,
1636
  control_net_stop_threshold_gui,
 
1638
  prompt_syntax_gui,
1639
  upscaler_model_path_gui,
1640
  upscaler_increases_size_gui,
1641
+ esrgan_tile_gui,
1642
+ esrgan_tile_overlap_gui,
1643
  hires_steps_gui,
1644
  hires_denoising_strength_gui,
1645
  hires_sampler_gui,
 
1647
  hires_negative_prompt_gui,
1648
  hires_before_adetailer_gui,
1649
  hires_after_adetailer_gui,
 
 
 
1650
  loop_generation_gui,
1651
  leave_progress_bar_gui,
1652
  disable_progress_bar_gui,
1653
  image_previews_gui,
1654
  display_images_gui,
1655
  save_generated_images_gui,
 
1656
  image_storage_location_gui,
1657
  retain_compel_previous_load_gui,
1658
  retain_detailfix_model_previous_load_gui,
 
1687
  mask_blur_b_gui,
1688
  mask_padding_b_gui,
1689
  retain_task_cache_gui,
 
1690
  image_ip1,
1691
  mask_ip1,
1692
  model_ip1,
 
1698
  mode_ip2,
1699
  scale_ip2,
1700
  pag_scale_gui,
 
 
 
1701
  load_lora_cpu_gui,
1702
  verbose_info_gui,
1703
  gpu_duration_gui,
1704
  ],
1705
+ outputs=[result_images, actual_task_info],
1706
  queue=True,
1707
  show_progress="minimal",
 
1708
  )
1709
 
1710
+ app.queue()
1711
+
1712
+ app.launch(
1713
+ show_error=True,
1714
+ debug=True,
1715
+ allowed_paths=["./images/"],
1716
+ )
 
 
 
constants.py DELETED
@@ -1,606 +0,0 @@
1
- import os
2
- from stablepy.diffusers_vanilla.constants import FLUX_CN_UNION_MODES
3
- from stablepy import (
4
- scheduler_names,
5
- SD15_TASKS,
6
- SDXL_TASKS,
7
- ALL_BUILTIN_UPSCALERS,
8
- IP_ADAPTERS_SD,
9
- IP_ADAPTERS_SDXL,
10
- PROMPT_WEIGHT_OPTIONS_PRIORITY,
11
- )
12
-
13
- IS_ZERO_GPU = bool(os.getenv("SPACES_ZERO_GPU"))
14
-
15
- # - **Download Models**
16
- DOWNLOAD_MODEL = "https://huggingface.co/zuv0/test/resolve/main/milkyWonderland_v40.safetensors"
17
-
18
- # - **Download VAEs**
19
- DOWNLOAD_VAE = "https://huggingface.co/fp16-guy/anything_kl-f8-anime2_vae-ft-mse-840000-ema-pruned_blessed_clearvae_fp16_cleaned/resolve/main/vae-ft-mse-840000-ema-pruned_fp16.safetensors?download=true"
20
-
21
- # - **Download LoRAs**
22
- DOWNLOAD_LORA = "https://huggingface.co/Leopain/color/resolve/main/Coloring_book_-_LineArt.safetensors, https://civitai.com/api/download/models/135867, https://huggingface.co/Linaqruf/anime-detailer-xl-lora/resolve/main/anime-detailer-xl.safetensors?download=true, https://huggingface.co/Linaqruf/style-enhancer-xl-lora/resolve/main/style-enhancer-xl.safetensors?download=true, https://huggingface.co/ByteDance/Hyper-SD/resolve/main/Hyper-SD15-8steps-CFG-lora.safetensors?download=true, https://huggingface.co/ByteDance/Hyper-SD/resolve/main/Hyper-SDXL-8steps-CFG-lora.safetensors?download=true"
23
-
24
- LOAD_DIFFUSERS_FORMAT_MODEL = [
25
- 'stabilityai/stable-diffusion-xl-base-1.0',
26
- 'Laxhar/noobai-XL-1.1',
27
- 'Laxhar/noobai-XL-Vpred-1.0',
28
- 'black-forest-labs/FLUX.1-dev',
29
- 'black-forest-labs/FLUX.1-Krea-dev',
30
- 'John6666/blue-pencil-flux1-v021-fp8-flux',
31
- 'John6666/wai-ani-flux-v10forfp8-fp8-flux',
32
- 'John6666/xe-anime-flux-v04-fp8-flux',
33
- 'John6666/lyh-anime-flux-v2a1-fp8-flux',
34
- 'John6666/carnival-unchained-v10-fp8-flux',
35
- 'Freepik/flux.1-lite-8B-alpha',
36
- 'shauray/FluxDev-HyperSD-merged',
37
- 'mikeyandfriends/PixelWave_FLUX.1-dev_03',
38
- 'terminusresearch/FluxBooru-v0.3',
39
- 'black-forest-labs/FLUX.1-schnell',
40
- # 'ostris/OpenFLUX.1',
41
- 'shuttleai/shuttle-3-diffusion',
42
- 'Laxhar/noobai-XL-1.0',
43
- 'Laxhar/noobai-XL-0.77',
44
- 'John6666/noobai-xl-nai-xl-epsilonpred075version-sdxl',
45
- 'Laxhar/noobai-XL-0.6',
46
- 'John6666/noobai-xl-nai-xl-epsilonpred05version-sdxl',
47
- 'John6666/noobai-cyberfix-v10-sdxl',
48
- 'John6666/noobaiiter-xl-vpred-v075-sdxl',
49
- 'John6666/ripplemix-noob-vpred10-illustrious01-v14-sdxl',
50
- 'John6666/sigmaih-15-sdxl',
51
- 'John6666/ntr-mix-illustrious-xl-noob-xl-xi-sdxl',
52
- 'John6666/ntr-mix-illustrious-xl-noob-xl-xii-sdxl',
53
- 'John6666/ntr-mix-illustrious-xl-noob-xl-xiii-sdxl',
54
- 'John6666/mistoon-anime-v10illustrious-sdxl',
55
- 'John6666/hassaku-xl-illustrious-v22-sdxl',
56
- 'John6666/haruki-mix-illustrious-v10-sdxl',
57
- 'John6666/noobreal-v10-sdxl',
58
- 'John6666/complicated-noobai-merge-vprediction-sdxl',
59
- 'Laxhar/noobai-XL-Vpred-0.9r',
60
- 'Laxhar/noobai-XL-Vpred-0.75s',
61
- 'Laxhar/noobai-XL-Vpred-0.75',
62
- 'Laxhar/noobai-XL-Vpred-0.65s',
63
- 'Laxhar/noobai-XL-Vpred-0.65',
64
- 'Laxhar/noobai-XL-Vpred-0.6',
65
- 'John6666/cat-tower-noobai-xl-checkpoint-v14vpred-sdxl',
66
- 'John6666/cat-tower-noobai-xl-checkpoint-v15vpred-sdxl',
67
- 'John6666/noobai-xl-nai-xl-vpred05version-sdxl',
68
- 'John6666/noobai-fusion2-vpred-itercomp-v1-sdxl',
69
- 'John6666/noobai-xl-nai-xl-vpredtestversion-sdxl',
70
- 'John6666/chadmix-noobai075-illustrious01-v10-sdxl',
71
- 'OnomaAIResearch/Illustrious-xl-early-release-v0',
72
- 'John6666/illustriousxl-mmmix-v50-sdxl',
73
- 'John6666/illustrious-pencil-xl-v200-sdxl',
74
- 'John6666/obsession-illustriousxl-v21-sdxl',
75
- 'John6666/obsession-illustriousxl-v30-sdxl',
76
- 'John6666/obsession-illustriousxl-v31-sdxl',
77
- 'John6666/one-obsession-13-sdxl',
78
- 'John6666/one-obsession-14-24d-sdxl',
79
- 'John6666/one-obsession-15-noobai-sdxl',
80
- 'John6666/one-obsession-v16-noobai-sdxl',
81
- 'John6666/prefect-illustrious-xl-v3-sdxl',
82
- 'John6666/wai-nsfw-illustrious-v70-sdxl',
83
- 'John6666/wai-nsfw-illustrious-sdxl-v140-sdxl',
84
- 'John6666/illustrious-pony-mix-v3-sdxl',
85
- 'John6666/nova-anime-xl-il-v90-sdxl',
86
- 'John6666/nova-anime-xl-il-v110-sdxl',
87
- 'John6666/nova-orange-xl-re-v10-sdxl',
88
- 'John6666/nova-orange-xl-v110-sdxl',
89
- 'John6666/nova-orange-xl-re-v20-sdxl',
90
- 'John6666/nova-unreal-xl-v60-sdxl',
91
- 'John6666/nova-unreal-xl-v70-sdxl',
92
- 'John6666/nova-unreal-xl-v80-sdxl',
93
- 'John6666/nova-cartoon-xl-v40-sdxl',
94
- 'John6666/silvermoon-mix03-illustrious-v10-sdxl',
95
- 'eienmojiki/Anything-XL',
96
- 'eienmojiki/Starry-XL-v5.2',
97
- 'votepurchase/plantMilkModelSuite_walnut',
98
- 'John6666/meinaxl-v2-sdxl',
99
- 'Eugeoter/artiwaifu-diffusion-2.0',
100
- 'comin/IterComp',
101
- 'John6666/epicrealism-xl-v8kiss-sdxl',
102
- 'John6666/epicrealism-xl-v10kiss2-sdxl',
103
- 'John6666/epicrealism-xl-vxiabeast-sdxl',
104
- 'John6666/epicrealism-xl-vxvii-crystal-clear-realism-sdxl',
105
- 'misri/zavychromaxl_v80',
106
- 'SG161222/RealVisXL_V4.0',
107
- 'SG161222/RealVisXL_V5.0',
108
- 'misri/newrealityxlAllInOne_Newreality40',
109
- 'gsdf/CounterfeitXL',
110
- 'WhiteAiZ/autismmixSDXL_autismmixConfetti_diffusers',
111
- 'kitty7779/ponyDiffusionV6XL',
112
- 'GraydientPlatformAPI/aniverse-pony',
113
- 'John6666/ras-real-anime-screencap-v1-sdxl',
114
- 'John6666/duchaiten-pony-xl-no-score-v60-sdxl',
115
- 'John6666/mistoon-anime-ponyalpha-sdxl',
116
- 'John6666/mistoon-xl-copper-v20fast-sdxl',
117
- 'John6666/ebara-mfcg-pony-mix-v12-sdxl',
118
- 'John6666/t-ponynai3-v51-sdxl',
119
- 'John6666/t-ponynai3-v65-sdxl',
120
- 'John6666/t-ponynai3-v7-sdxl',
121
- 'John6666/prefect-pony-xl-v3-sdxl',
122
- 'John6666/prefect-pony-xl-v4-sdxl',
123
- 'John6666/prefect-pony-xl-v50-sdxl',
124
- 'John6666/mala-anime-mix-nsfw-pony-xl-v5-sdxl',
125
- 'John6666/wai-ani-nsfw-ponyxl-v10-sdxl',
126
- 'John6666/wai-real-mix-v11-sdxl',
127
- 'John6666/wai-shuffle-pdxl-v2-sdxl',
128
- 'John6666/wai-c-v6-sdxl',
129
- 'John6666/iniverse-mix-xl-sfwnsfw-pony-guofeng-v43-sdxl',
130
- 'John6666/sifw-annihilation-xl-v2-sdxl',
131
- 'John6666/sifw-annihilation-xl-v305illustrious-beta-sdxl',
132
- 'John6666/photo-realistic-pony-v5-sdxl',
133
- 'John6666/pony-realism-v21main-sdxl',
134
- 'John6666/pony-realism-v22main-sdxl',
135
- 'John6666/pony-realism-v23-ultra-sdxl',
136
- 'John6666/cyberrealistic-pony-v65-sdxl',
137
- 'John6666/cyberrealistic-pony-v7-sdxl',
138
- 'John6666/cyberrealistic-pony-v127-alternative-sdxl',
139
- 'GraydientPlatformAPI/realcartoon-pony-diffusion',
140
- 'John6666/nova-anime-xl-pony-v5-sdxl',
141
- 'John6666/autismmix-sdxl-autismmix-pony-sdxl',
142
- 'John6666/aimz-dream-real-pony-mix-v3-sdxl',
143
- 'John6666/prefectious-xl-nsfw-v10-sdxl',
144
- 'GraydientPlatformAPI/iniverseponyRealGuofeng49',
145
- 'John6666/duchaiten-pony-real-v11fix-sdxl',
146
- 'John6666/duchaiten-pony-real-v20-sdxl',
147
- 'John6666/duchaiten-pony-xl-no-score-v70-sdxl',
148
- 'KBlueLeaf/Kohaku-XL-Zeta',
149
- 'cagliostrolab/animagine-xl-3.1',
150
- 'cagliostrolab/animagine-xl-4.0',
151
- 'yodayo-ai/kivotos-xl-2.0',
152
- 'yodayo-ai/holodayo-xl-2.1',
153
- 'yodayo-ai/clandestine-xl-1.0',
154
- 'https://huggingface.co/chemwolf/Karmix-XL-v0/resolve/main/Karmix-XL-v0.safetensors?download=true',
155
- 'https://civitai.com/api/download/models/128713?type=Model&format=SafeTensor&size=pruned&fp=fp16',
156
- 'https://civitai.com/models/30240?modelVersionId=125771',
157
- 'digiplay/majicMIX_sombre_v2',
158
- 'digiplay/majicMIX_realistic_v6',
159
- 'digiplay/majicMIX_realistic_v7',
160
- 'digiplay/DreamShaper_8',
161
- 'digiplay/BeautifulArt_v1',
162
- 'digiplay/DarkSushi2.5D_v1',
163
- 'digiplay/darkphoenix3D_v1.1',
164
- 'digiplay/BeenYouLiteL11_diffusers',
165
- 'GraydientPlatformAPI/rev-animated2',
166
- 'myxlmynx/cyberrealistic_classic40',
167
- 'GraydientPlatformAPI/cyberreal6',
168
- 'GraydientPlatformAPI/cyberreal5',
169
- 'youknownothing/deliberate-v6',
170
- 'GraydientPlatformAPI/deliberate-cyber3',
171
- 'GraydientPlatformAPI/picx-real',
172
- 'GraydientPlatformAPI/perfectworld6',
173
- 'emilianJR/epiCRealism',
174
- 'votepurchase/counterfeitV30_v30',
175
- 'votepurchase/ChilloutMix',
176
- 'Meina/MeinaMix_V11',
177
- 'Meina/MeinaUnreal_V5',
178
- 'Meina/MeinaPastel_V7',
179
- 'GraydientPlatformAPI/realcartoon3d-17',
180
- 'GraydientPlatformAPI/realcartoon-pixar11',
181
- 'GraydientPlatformAPI/realcartoon-real17',
182
- ]
183
-
184
-
185
- DIFFUSERS_FORMAT_LORAS = [
186
- "nerijs/animation2k-flux",
187
- "XLabs-AI/flux-RealismLora",
188
- "Shakker-Labs/FLUX.1-dev-LoRA-Logo-Design",
189
- ]
190
-
191
- DOWNLOAD_EMBEDS = [
192
- 'https://huggingface.co/datasets/Nerfgun3/bad_prompt/blob/main/bad_prompt_version2.pt',
193
- # 'https://huggingface.co/embed/negative/resolve/main/EasyNegativeV2.safetensors',
194
- # 'https://huggingface.co/embed/negative/resolve/main/bad-hands-5.pt',
195
- ]
196
-
197
- CIVITAI_API_KEY = os.environ.get("CIVITAI_API_KEY")
198
- HF_TOKEN = os.environ.get("HF_READ_TOKEN")
199
-
200
- DIRECTORY_MODELS = 'models'
201
- DIRECTORY_LORAS = 'loras'
202
- DIRECTORY_VAES = 'vaes'
203
- DIRECTORY_EMBEDS = 'embedings'
204
- DIRECTORY_UPSCALERS = 'upscalers'
205
-
206
- STORAGE_ROOT = "/home/user/"
207
- CACHE_HF_ROOT = os.path.expanduser("~/.cache/huggingface")
208
- CACHE_HF = os.path.join(CACHE_HF_ROOT, "hub")
209
- if IS_ZERO_GPU:
210
- os.environ["HF_HOME"] = CACHE_HF
211
-
212
- TASK_STABLEPY = {
213
- 'txt2img': 'txt2img',
214
- 'img2img': 'img2img',
215
- 'inpaint': 'inpaint',
216
- # 'canny T2I Adapter': 'sdxl_canny_t2i', # NO HAVE STEP CALLBACK PARAMETERS SO NOT WORKS WITH DIFFUSERS 0.29.0
217
- # 'sketch T2I Adapter': 'sdxl_sketch_t2i',
218
- # 'lineart T2I Adapter': 'sdxl_lineart_t2i',
219
- # 'depth-midas T2I Adapter': 'sdxl_depth-midas_t2i',
220
- # 'openpose T2I Adapter': 'sdxl_openpose_t2i',
221
- 'openpose ControlNet': 'openpose',
222
- 'canny ControlNet': 'canny',
223
- 'mlsd ControlNet': 'mlsd',
224
- 'scribble ControlNet': 'scribble',
225
- 'softedge ControlNet': 'softedge',
226
- 'segmentation ControlNet': 'segmentation',
227
- 'depth ControlNet': 'depth',
228
- 'normalbae ControlNet': 'normalbae',
229
- 'lineart ControlNet': 'lineart',
230
- 'lineart_anime ControlNet': 'lineart_anime',
231
- 'shuffle ControlNet': 'shuffle',
232
- 'ip2p ControlNet': 'ip2p',
233
- 'optical pattern ControlNet': 'pattern',
234
- 'recolor ControlNet': 'recolor',
235
- 'tile ControlNet': 'tile',
236
- 'repaint ControlNet': 'repaint',
237
- }
238
-
239
- TASK_MODEL_LIST = list(TASK_STABLEPY.keys())
240
-
241
- UPSCALER_DICT_GUI = {
242
- None: None,
243
- **{bu: bu for bu in ALL_BUILTIN_UPSCALERS if bu not in ["HAT x4", "DAT x4", "DAT x3", "DAT x2", "SwinIR 4x"]},
244
- # "RealESRGAN_x4plus": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth",
245
- "RealESRNet_x4plus": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.1/RealESRNet_x4plus.pth",
246
- # "RealESRGAN_x4plus_anime_6B": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/RealESRGAN_x4plus_anime_6B.pth",
247
- # "RealESRGAN_x2plus": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.1/RealESRGAN_x2plus.pth",
248
- # "realesr-animevideov3": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-animevideov3.pth",
249
- # "realesr-general-x4v3": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-general-x4v3.pth",
250
- # "realesr-general-wdn-x4v3": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-general-wdn-x4v3.pth",
251
- "4x-UltraSharp": "https://huggingface.co/Shandypur/ESRGAN-4x-UltraSharp/resolve/main/4x-UltraSharp.pth",
252
- "Real-ESRGAN-Anime-finetuning": "https://huggingface.co/danhtran2mind/Real-ESRGAN-Anime-finetuning/resolve/main/Real-ESRGAN-Anime-finetuning.pth",
253
- "4x_foolhardy_Remacri": "https://huggingface.co/FacehugmanIII/4x_foolhardy_Remacri/resolve/main/4x_foolhardy_Remacri.pth",
254
- "Remacri4xExtraSmoother": "https://huggingface.co/hollowstrawberry/upscalers-backup/resolve/main/ESRGAN/Remacri%204x%20ExtraSmoother.pth",
255
- "AnimeSharp4x": "https://huggingface.co/hollowstrawberry/upscalers-backup/resolve/main/ESRGAN/AnimeSharp%204x.pth",
256
- "lollypop": "https://huggingface.co/hollowstrawberry/upscalers-backup/resolve/main/ESRGAN/lollypop.pth",
257
- "RealisticRescaler4x": "https://huggingface.co/hollowstrawberry/upscalers-backup/resolve/main/ESRGAN/RealisticRescaler%204x.pth",
258
- "NickelbackFS4x": "https://huggingface.co/hollowstrawberry/upscalers-backup/resolve/main/ESRGAN/NickelbackFS%204x.pth"
259
- }
260
-
261
- UPSCALER_KEYS = list(UPSCALER_DICT_GUI.keys())
262
-
263
- DIFFUSERS_CONTROLNET_MODEL = [
264
- "Automatic",
265
-
266
- "brad-twinkl/controlnet-union-sdxl-1.0-promax",
267
- "xinsir/controlnet-union-sdxl-1.0",
268
- "xinsir/anime-painter",
269
- "Eugeoter/noob-sdxl-controlnet-canny",
270
- "Eugeoter/noob-sdxl-controlnet-lineart_anime",
271
- "Eugeoter/noob-sdxl-controlnet-depth",
272
- "Eugeoter/noob-sdxl-controlnet-normal",
273
- "Eugeoter/noob-sdxl-controlnet-softedge_hed",
274
- "Eugeoter/noob-sdxl-controlnet-scribble_pidinet",
275
- "Eugeoter/noob-sdxl-controlnet-scribble_hed",
276
- "Eugeoter/noob-sdxl-controlnet-manga_line",
277
- "Eugeoter/noob-sdxl-controlnet-lineart_realistic",
278
- "Eugeoter/noob-sdxl-controlnet-depth_midas-v1-1",
279
- "dimitribarbot/controlnet-openpose-sdxl-1.0-safetensors",
280
- "r3gm/controlnet-openpose-sdxl-1.0-fp16",
281
- "r3gm/controlnet-canny-scribble-integrated-sdxl-v2-fp16",
282
- "r3gm/controlnet-union-sdxl-1.0-fp16",
283
- "r3gm/controlnet-lineart-anime-sdxl-fp16",
284
- "r3gm/control_v1p_sdxl_qrcode_monster_fp16",
285
- "r3gm/controlnet-tile-sdxl-1.0-fp16",
286
- "r3gm/controlnet-recolor-sdxl-fp16",
287
- "r3gm/controlnet-openpose-twins-sdxl-1.0-fp16",
288
- "r3gm/controlnet-qr-pattern-sdxl-fp16",
289
- "Yakonrus/SDXL_Controlnet_Tile_Realistic_v2",
290
- "TheMistoAI/MistoLine",
291
- "briaai/BRIA-2.3-ControlNet-Recoloring",
292
- "briaai/BRIA-2.3-ControlNet-Canny",
293
-
294
- "lllyasviel/control_v11p_sd15_openpose",
295
- "lllyasviel/control_v11p_sd15_canny",
296
- "lllyasviel/control_v11p_sd15_mlsd",
297
- "lllyasviel/control_v11p_sd15_scribble",
298
- "lllyasviel/control_v11p_sd15_softedge",
299
- "lllyasviel/control_v11p_sd15_seg",
300
- "lllyasviel/control_v11f1p_sd15_depth",
301
- "lllyasviel/control_v11p_sd15_normalbae",
302
- "lllyasviel/control_v11p_sd15_lineart",
303
- "lllyasviel/control_v11p_sd15s2_lineart_anime",
304
- "lllyasviel/control_v11e_sd15_shuffle",
305
- "lllyasviel/control_v11e_sd15_ip2p",
306
- "lllyasviel/control_v11p_sd15_inpaint",
307
- "monster-labs/control_v1p_sd15_qrcode_monster",
308
- "lllyasviel/control_v11f1e_sd15_tile",
309
- "latentcat/control_v1p_sd15_brightness",
310
- "yuanqiuye/qrcode_controlnet_v3",
311
-
312
- "Shakker-Labs/FLUX.1-dev-ControlNet-Union-Pro",
313
- # "Shakker-Labs/FLUX.1-dev-ControlNet-Pose",
314
- # "Shakker-Labs/FLUX.1-dev-ControlNet-Depth",
315
- # "jasperai/Flux.1-dev-Controlnet-Upscaler",
316
- # "jasperai/Flux.1-dev-Controlnet-Depth",
317
- # "jasperai/Flux.1-dev-Controlnet-Surface-Normals",
318
- # "XLabs-AI/flux-controlnet-canny-diffusers",
319
- # "XLabs-AI/flux-controlnet-hed-diffusers",
320
- # "XLabs-AI/flux-controlnet-depth-diffusers",
321
- # "InstantX/FLUX.1-dev-Controlnet-Union",
322
- # "InstantX/FLUX.1-dev-Controlnet-Canny",
323
- ]
324
-
325
- PROMPT_W_OPTIONS = [(pwf, pwf) for pwf in PROMPT_WEIGHT_OPTIONS_PRIORITY]
326
- PROMPT_W_OPTIONS[0] = ("Classic format: (word:weight)", "Classic")
327
- PROMPT_W_OPTIONS[1] = ("Compel format: (word)weight", "Compel")
328
-
329
- WARNING_MSG_VAE = (
330
- "Use the right VAE for your model to maintain image quality. The wrong"
331
- " VAE can lead to poor results, like blurriness in the generated images."
332
- )
333
-
334
- SDXL_TASK = [k for k, v in TASK_STABLEPY.items() if v in SDXL_TASKS]
335
- SD_TASK = [k for k, v in TASK_STABLEPY.items() if v in SD15_TASKS]
336
- FLUX_TASK = list(TASK_STABLEPY.keys())[:3] + [k for k, v in TASK_STABLEPY.items() if v in FLUX_CN_UNION_MODES.keys()]
337
-
338
- MODEL_TYPE_TASK = {
339
- "SD 1.5": SD_TASK,
340
- "SDXL": SDXL_TASK,
341
- "FLUX": FLUX_TASK,
342
- }
343
-
344
- MODEL_TYPE_CLASS = {
345
- "diffusers:StableDiffusionPipeline": "SD 1.5",
346
- "diffusers:StableDiffusionXLPipeline": "SDXL",
347
- "diffusers:FluxPipeline": "FLUX",
348
- }
349
-
350
- DIFFUSECRAFT_CHECKPOINT_NAME = {
351
- "sd1.5": "SD 1.5",
352
- "sdxl": "SDXL",
353
- "flux-dev": "FLUX",
354
- "flux-schnell": "FLUX",
355
- }
356
-
357
- POST_PROCESSING_SAMPLER = ["Use same sampler"] + [
358
- name_s for name_s in scheduler_names if "Auto-Loader" not in name_s
359
- ]
360
-
361
- IP_MODELS = []
362
- ALL_IPA = sorted(set(IP_ADAPTERS_SD + IP_ADAPTERS_SDXL))
363
-
364
- for origin_name in ALL_IPA:
365
- suffixes = []
366
- if origin_name in IP_ADAPTERS_SD:
367
- suffixes.append("sd1.5")
368
- if origin_name in IP_ADAPTERS_SDXL:
369
- suffixes.append("sdxl")
370
- ref_name = f"{origin_name} ({'/'.join(suffixes)})"
371
- IP_MODELS.append((ref_name, origin_name))
372
-
373
- MODE_IP_OPTIONS = ["original", "style", "layout", "style+layout"]
374
-
375
- SUBTITLE_GUI = (
376
- "### This demo uses [diffusers](https://github.com/huggingface/diffusers)"
377
- " to perform different tasks in image generation."
378
- )
379
-
380
- msg_zero = "" if not IS_ZERO_GPU else "- The current space runs on a ZERO GPU which is assigned for approximately 60 seconds; Therefore, if you submit expensive tasks, the operation may be canceled upon reaching the maximum allowed time with 'GPU TASK ABORTED'."
381
-
382
- HELP_GUI = (
383
- f"""### Help:
384
- {msg_zero}
385
- - Distorted or strange images often result from high prompt weights, so it's best to use low weights and scales, and consider using Classic variants like 'Classic-original'.
386
- - For better results with Pony Diffusion, try using sampler DPM++ 1s or DPM2 with Compel or Classic prompt weights.
387
- """
388
- )
389
-
390
- EXAMPLES_GUI_HELP = (
391
- """### The following examples perform specific tasks:
392
- 1. Generation with SDXL and upscale
393
- 2. Generation with FLUX dev
394
- 3. ControlNet Canny SDXL
395
- 4. Optical pattern (Optical illusion) SDXL
396
- 5. Convert an image to a coloring drawing
397
- 6. V prediction model inference
398
- 7. V prediction model sd_embed variant inference
399
- 8. ControlNet OpenPose SD 1.5 and Latent upscale
400
-
401
- - Different tasks can be performed, such as img2img or using the IP adapter, to preserve a person's appearance or a specific style based on an image.
402
- """
403
- )
404
-
405
- EXAMPLES_GUI = [
406
- [
407
- "splatter paint theme, 1girl, frame center, pretty face, face with artistic paint artwork, feminism, long hair, upper body view, futuristic expression illustrative painted background, origami, stripes, explosive paint splashes behind her, hand on cheek pose, strobe lighting, masterpiece photography creative artwork, golden morning light, highly detailed, masterpiece, best quality, very aesthetic, absurdres",
408
- "logo, artist name, (worst quality, normal quality), bad-artist, ((bad anatomy)), ((bad hands)), ((bad proportions)), ((duplicate limbs)), ((fused limbs)), ((interlocking fingers)), ((poorly drawn face)), high contrast., score_6, score_5, score_4, lowres, (bad), text, error, fewer, extra, missing, worst quality, jpeg artifacts, low quality, watermark, unfinished, displeasing, oldest, early, chromatic aberration, signature, extra digits, artistic error, username, scan, [abstract]",
409
- 28,
410
- 5.0,
411
- -1,
412
- "None",
413
- 0.33,
414
- "DPM++ 2M SDE",
415
- 1152,
416
- 896,
417
- "John6666/noobai-xl-nai-xl-epsilonpred10version-sdxl",
418
- "txt2img",
419
- "image.webp", # img conttol
420
- 1024, # img resolution
421
- 0.35, # strength
422
- 1.0, # cn scale
423
- 0.0, # cn start
424
- 1.0, # cn end
425
- "Classic-no_norm",
426
- "Nearest",
427
- 45,
428
- False,
429
- ],
430
- [
431
- "a digital illustration of a movie poster titled 'Finding Emo', finding nemo parody poster, featuring a depressed cartoon clownfish with black emo hair, eyeliner, and piercings, bored expression, swimming in a dark underwater scene, in the background, movie title in a dripping, grungy font, moody blue and purple color palette",
432
- "",
433
- 24,
434
- 3.5,
435
- -1,
436
- "None",
437
- 0.33,
438
- "FlowMatch Euler",
439
- 1152,
440
- 896,
441
- "black-forest-labs/FLUX.1-dev",
442
- "txt2img",
443
- None, # img conttol
444
- 1024, # img resolution
445
- 0.35, # strength
446
- 1.0, # cn scale
447
- 0.0, # cn start
448
- 1.0, # cn end
449
- "Classic",
450
- None,
451
- 70,
452
- True,
453
- ],
454
- [
455
- "((masterpiece)), best quality, blonde disco girl, detailed face, realistic face, realistic hair, dynamic pose, pink pvc, intergalactic disco background, pastel lights, dynamic contrast, airbrush, fine detail, 70s vibe, midriff",
456
- "(worst quality:1.2), (bad quality:1.2), (poor quality:1.2), (missing fingers:1.2), bad-artist-anime, bad-artist, bad-picture-chill-75v",
457
- 48,
458
- 3.5,
459
- -1,
460
- "None",
461
- 0.33,
462
- "DPM++ 2M SDE Ef",
463
- 1024,
464
- 1024,
465
- "John6666/epicrealism-xl-v10kiss2-sdxl",
466
- "canny ControlNet",
467
- "image.webp", # img conttol
468
- 1024, # img resolution
469
- 0.35, # strength
470
- 1.0, # cn scale
471
- 0.0, # cn start
472
- 1.0, # cn end
473
- "Classic",
474
- None,
475
- 44,
476
- False,
477
- ],
478
- [
479
- "cinematic scenery old city ruins",
480
- "(worst quality, low quality, illustration, 3d, 2d, painting, cartoons, sketch), (illustration, 3d, 2d, painting, cartoons, sketch, blurry, film grain, noise), (low quality, worst quality:1.2)",
481
- 50,
482
- 4.0,
483
- -1,
484
- "None",
485
- 0.33,
486
- "Euler a",
487
- 1024,
488
- 1024,
489
- "SG161222/RealVisXL_V5.0",
490
- "optical pattern ControlNet",
491
- "spiral_no_transparent.png", # img conttol
492
- 1024, # img resolution
493
- 0.35, # strength
494
- 1.0, # cn scale
495
- 0.05, # cn start
496
- 0.8, # cn end
497
- "Classic",
498
- None,
499
- 35,
500
- False,
501
- ],
502
- [
503
- "black and white, line art, coloring drawing, clean line art, black strokes, no background, white, black, free lines, black scribbles, on paper, A blend of comic book art and lineart full of black and white color, masterpiece, high-resolution, trending on Pixiv fan box, palette knife, brush strokes, two-dimensional, planar vector, T-shirt design, stickers, and T-shirt design, vector art, fantasy art, Adobe Illustrator, hand-painted, digital painting, low polygon, soft lighting, aerial view, isometric style, retro aesthetics, 8K resolution, black sketch lines, monochrome, invert color",
504
- "color, red, green, yellow, colored, duplicate, blurry, abstract, disfigured, deformed, animated, toy, figure, framed, 3d, bad art, poorly drawn, extra limbs, close up, b&w, weird colors, blurry, watermark, blur haze, 2 heads, long neck, watermark, elongated body, cropped image, out of frame, draft, deformed hands, twisted fingers, double image, malformed hands, multiple heads, extra limb, ugly, poorly drawn hands, missing limb, cut-off, over satured, grain, lowères, bad anatomy, poorly drawn face, mutation, mutated, floating limbs, disconnected limbs, out of focus, long body, disgusting, extra fingers, groos proportions, missing arms, mutated hands, cloned face, missing legs, ugly, tiling, poorly drawn hands, poorly drawn feet, poorly drawn face, out of frame, extra limbs, disfigured, deformed, body out of frame, blurry, bad anatomy, blurred, watermark, grainy, signature, cut off, draft, deformed, blurry, bad anatomy, disfigured, poorly drawn face, mutation, bluelish, blue",
505
- 20,
506
- 4.0,
507
- -1,
508
- ("loras/Coloring_book_-_LineArt.safetensors" if os.path.exists("loras/Coloring_book_-_LineArt.safetensors") else "None"),
509
- 1.0,
510
- "DPM++ 2M SDE",
511
- 1024,
512
- 1024,
513
- "eienmojiki/Anything-XL",
514
- "lineart ControlNet",
515
- "color_image.png", # img conttol
516
- 896, # img resolution
517
- 0.35, # strength
518
- 1.0, # cn scale
519
- 0.0, # cn start
520
- 1.0, # cn end
521
- "Compel",
522
- None,
523
- 35,
524
- False,
525
- ],
526
- [
527
- "[mochizuki_shiina], [syuri22], newest, reimu, solo, outdoors, water, flower, lantern",
528
- "worst quality, normal quality, old, sketch,",
529
- 28,
530
- 7.0,
531
- -1,
532
- "None",
533
- 0.33,
534
- "DPM 3M Ef",
535
- 1600,
536
- 1024,
537
- "Laxhar/noobai-XL-Vpred-1.0",
538
- "txt2img",
539
- "color_image.png", # img conttol
540
- 1024, # img resolution
541
- 0.35, # strength
542
- 1.0, # cn scale
543
- 0.0, # cn start
544
- 1.0, # cn end
545
- "Classic",
546
- None,
547
- 30,
548
- False,
549
- ],
550
- [
551
- "[mochizuki_shiina], [syuri22], newest, multiple girls, 2girls, earrings, jewelry, gloves, purple eyes, black hair, looking at viewer, nail polish, hat, smile, open mouth, fingerless gloves, sleeveless, :d, upper body, blue eyes, closed mouth, black gloves, hands up, long hair, shirt, bare shoulders, white headwear, blush, black headwear, blue nails, upper teeth only, short hair, white gloves, white shirt, teeth, rabbit hat, star earrings, purple nails, pink hair, detached sleeves, fingernails, fake animal ears, animal hat, sleeves past wrists, black shirt, medium hair, fur trim, sleeveless shirt, turtleneck, long sleeves, rabbit ears, star \\(symbol\\)",
552
- "worst quality, normal quality, old, sketch,",
553
- 28,
554
- 7.0,
555
- -1,
556
- "None",
557
- 0.33,
558
- "DPM 3M Ef",
559
- 1600,
560
- 1024,
561
- "Laxhar/noobai-XL-Vpred-1.0",
562
- "txt2img",
563
- "color_image.png", # img conttol
564
- 1024, # img resolution
565
- 0.35, # strength
566
- 1.0, # cn scale
567
- 0.0, # cn start
568
- 1.0, # cn end
569
- "Classic-sd_embed",
570
- None,
571
- 30,
572
- False,
573
- ],
574
- [
575
- "1girl,face,curly hair,red hair,white background,",
576
- "(worst quality:2),(low quality:2),(normal quality:2),lowres,watermark,",
577
- 38,
578
- 5.0,
579
- -1,
580
- "None",
581
- 0.33,
582
- "DPM++ 2M SDE",
583
- 512,
584
- 512,
585
- "digiplay/majicMIX_realistic_v7",
586
- "openpose ControlNet",
587
- "image.webp", # img conttol
588
- 1024, # img resolution
589
- 0.35, # strength
590
- 1.0, # cn scale
591
- 0.0, # cn start
592
- 0.9, # cn end
593
- "Classic-original",
594
- "Latent (antialiased)",
595
- 46,
596
- False,
597
- ],
598
- ]
599
-
600
- RESOURCES = (
601
- """### Resources
602
- - John6666's space has some great features you might find helpful [link](https://huggingface.co/spaces/John6666/DiffuseCraftMod).
603
- - Try the image generator in Colab’s free tier, which provides free GPU [link](https://github.com/R3gm/SD_diffusers_interactive).
604
- - `DiffuseCraft` in Colab:[link](https://github.com/R3gm/DiffuseCraft?tab=readme-ov-file#diffusecraft).
605
- """
606
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
image_processor.py DELETED
@@ -1,130 +0,0 @@
1
- import spaces
2
- import gradio as gr
3
- from stablepy import Preprocessor
4
-
5
- PREPROCESSOR_TASKS_LIST = [
6
- "Canny",
7
- "Openpose",
8
- "DPT",
9
- "Midas",
10
- "ZoeDepth",
11
- "DepthAnything",
12
- "HED",
13
- "PidiNet",
14
- "TEED",
15
- "Lineart",
16
- "LineartAnime",
17
- "Anyline",
18
- "Lineart standard",
19
- "SegFormer",
20
- "UPerNet",
21
- "ContentShuffle",
22
- "Recolor",
23
- "Blur",
24
- "MLSD",
25
- "NormalBae",
26
- ]
27
-
28
- preprocessor = Preprocessor()
29
-
30
-
31
- def process_inputs(
32
- image,
33
- name,
34
- resolution,
35
- precessor_resolution,
36
- low_threshold,
37
- high_threshold,
38
- value_threshod,
39
- distance_threshold,
40
- recolor_mode,
41
- recolor_gamma_correction,
42
- blur_k_size,
43
- pre_openpose_extra,
44
- hed_scribble,
45
- pre_pidinet_safe,
46
- pre_lineart_coarse,
47
- use_cuda,
48
- ):
49
- if not image:
50
- raise ValueError("To use this, simply upload an image.")
51
-
52
- preprocessor.load(name, False)
53
-
54
- params = dict(
55
- image_resolution=resolution,
56
- detect_resolution=precessor_resolution,
57
- low_threshold=low_threshold,
58
- high_threshold=high_threshold,
59
- thr_v=value_threshod,
60
- thr_d=distance_threshold,
61
- mode=recolor_mode,
62
- gamma_correction=recolor_gamma_correction,
63
- blur_sigma=blur_k_size,
64
- hand_and_face=pre_openpose_extra,
65
- scribble=hed_scribble,
66
- safe=pre_pidinet_safe,
67
- coarse=pre_lineart_coarse,
68
- )
69
-
70
- if use_cuda:
71
- @spaces.GPU(duration=15)
72
- def wrapped_func():
73
- preprocessor.to("cuda")
74
- return preprocessor(image, **params)
75
- return wrapped_func()
76
-
77
- return preprocessor(image, **params)
78
-
79
-
80
- def preprocessor_tab():
81
- with gr.Row():
82
- with gr.Column():
83
- pre_image = gr.Image(label="Image", type="pil", sources=["upload"])
84
- pre_options = gr.Dropdown(label="Preprocessor", choices=PREPROCESSOR_TASKS_LIST, value=PREPROCESSOR_TASKS_LIST[0])
85
- pre_img_resolution = gr.Slider(
86
- minimum=64, maximum=4096, step=64, value=1024, label="Image Resolution",
87
- info="The maximum proportional size of the generated image based on the uploaded image."
88
- )
89
- pre_start = gr.Button(value="PROCESS IMAGE", variant="primary")
90
- with gr.Accordion("Advanced Settings", open=False):
91
- with gr.Column():
92
- pre_processor_resolution = gr.Slider(minimum=64, maximum=2048, step=64, value=512, label="Preprocessor Resolution")
93
- pre_low_threshold = gr.Slider(minimum=1, maximum=255, step=1, value=100, label="'CANNY' low threshold")
94
- pre_high_threshold = gr.Slider(minimum=1, maximum=255, step=1, value=200, label="'CANNY' high threshold")
95
- pre_value_threshold = gr.Slider(minimum=0., maximum=2.0, step=0.01, value=0.1, label="'MLSD' Hough value threshold")
96
- pre_distance_threshold = gr.Slider(minimum=0., maximum=20.0, step=0.01, value=0.1, label="'MLSD' Hough distance threshold")
97
- pre_recolor_mode = gr.Dropdown(label="'RECOLOR' mode", choices=["luminance", "intensity"], value="luminance")
98
- pre_recolor_gamma_correction = gr.Number(minimum=0., maximum=25., value=1., step=0.001, label="'RECOLOR' gamma correction")
99
- pre_blur_k_size = gr.Number(minimum=0, maximum=100, value=9, step=1, label="'BLUR' sigma")
100
- pre_openpose_extra = gr.Checkbox(value=True, label="'OPENPOSE' face and hand")
101
- pre_hed_scribble = gr.Checkbox(value=False, label="'HED' scribble")
102
- pre_pidinet_safe = gr.Checkbox(value=False, label="'PIDINET' safe")
103
- pre_lineart_coarse = gr.Checkbox(value=False, label="'LINEART' coarse")
104
- pre_use_cuda = gr.Checkbox(value=False, label="Use CUDA")
105
-
106
- with gr.Column():
107
- pre_result = gr.Image(label="Result", type="pil", interactive=False, format="png")
108
-
109
- pre_start.click(
110
- fn=process_inputs,
111
- inputs=[
112
- pre_image,
113
- pre_options,
114
- pre_img_resolution,
115
- pre_processor_resolution,
116
- pre_low_threshold,
117
- pre_high_threshold,
118
- pre_value_threshold,
119
- pre_distance_threshold,
120
- pre_recolor_mode,
121
- pre_recolor_gamma_correction,
122
- pre_blur_k_size,
123
- pre_openpose_extra,
124
- pre_hed_scribble,
125
- pre_pidinet_safe,
126
- pre_lineart_coarse,
127
- pre_use_cuda,
128
- ],
129
- outputs=[pre_result],
130
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lora_dict.json ADDED
File without changes
model_dict.json ADDED
File without changes
modutils.py ADDED
@@ -0,0 +1,1290 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import spaces
2
+ import json
3
+ import gradio as gr
4
+ from huggingface_hub import HfApi
5
+ import os
6
+ from pathlib import Path
7
+ from PIL import Image
8
+
9
+
10
+ from env import (HF_LORA_PRIVATE_REPOS1, HF_LORA_PRIVATE_REPOS2,
11
+ HF_MODEL_USER_EX, HF_MODEL_USER_LIKES, DIFFUSERS_FORMAT_LORAS,
12
+ directory_loras, hf_read_token, HF_TOKEN, CIVITAI_API_KEY)
13
+
14
+
15
+ MODEL_TYPE_DICT = {
16
+ "diffusers:StableDiffusionPipeline": "SD 1.5",
17
+ "diffusers:StableDiffusionXLPipeline": "SDXL",
18
+ "diffusers:FluxPipeline": "FLUX",
19
+ }
20
+
21
+
22
+ def get_user_agent():
23
+ return 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:127.0) Gecko/20100101 Firefox/127.0'
24
+
25
+
26
+ def to_list(s):
27
+ return [x.strip() for x in s.split(",") if not s == ""]
28
+
29
+
30
+ def list_uniq(l):
31
+ return sorted(set(l), key=l.index)
32
+
33
+
34
+ def list_sub(a, b):
35
+ return [e for e in a if e not in b]
36
+
37
+
38
+ def is_repo_name(s):
39
+ import re
40
+ return re.fullmatch(r'^[^/]+?/[^/]+?$', s)
41
+
42
+
43
+ from translatepy import Translator
44
+ translator = Translator()
45
+ def translate_to_en(input: str):
46
+ try:
47
+ output = str(translator.translate(input, 'English'))
48
+ except Exception as e:
49
+ output = input
50
+ print(e)
51
+ return output
52
+
53
+
54
+ def get_local_model_list(dir_path):
55
+ model_list = []
56
+ valid_extensions = ('.ckpt', '.pt', '.pth', '.safetensors', '.bin')
57
+ for file in Path(dir_path).glob("*"):
58
+ if file.suffix in valid_extensions:
59
+ file_path = str(Path(f"{dir_path}/{file.name}"))
60
+ model_list.append(file_path)
61
+ return model_list
62
+
63
+
64
+ def download_things(directory, url, hf_token="", civitai_api_key=""):
65
+ url = url.strip()
66
+ if "drive.google.com" in url:
67
+ original_dir = os.getcwd()
68
+ os.chdir(directory)
69
+ os.system(f"gdown --fuzzy {url}")
70
+ os.chdir(original_dir)
71
+ elif "huggingface.co" in url:
72
+ url = url.replace("?download=true", "")
73
+ # url = urllib.parse.quote(url, safe=':/') # fix encoding
74
+ if "/blob/" in url:
75
+ url = url.replace("/blob/", "/resolve/")
76
+ user_header = f'"Authorization: Bearer {hf_token}"'
77
+ if hf_token:
78
+ os.system(f"aria2c --console-log-level=error --summary-interval=10 --header={user_header} -c -x 16 -k 1M -s 16 {url} -d {directory} -o {url.split('/')[-1]}")
79
+ else:
80
+ os.system(f"aria2c --optimize-concurrent-downloads --console-log-level=error --summary-interval=10 -c -x 16 -k 1M -s 16 {url} -d {directory} -o {url.split('/')[-1]}")
81
+ elif "civitai.com" in url:
82
+ if "?" in url:
83
+ url = url.split("?")[0]
84
+ if civitai_api_key:
85
+ url = url + f"?token={civitai_api_key}"
86
+ os.system(f"aria2c --console-log-level=error --summary-interval=10 -c -x 16 -k 1M -s 16 -d {directory} {url}")
87
+ else:
88
+ print("\033[91mYou need an API key to download Civitai models.\033[0m")
89
+ else:
90
+ os.system(f"aria2c --console-log-level=error --summary-interval=10 -c -x 16 -k 1M -s 16 -d {directory} {url}")
91
+
92
+
93
+ def escape_lora_basename(basename: str):
94
+ return basename.replace(".", "_").replace(" ", "_").replace(",", "")
95
+
96
+
97
+ def to_lora_key(path: str):
98
+ return escape_lora_basename(Path(path).stem)
99
+
100
+
101
+ def to_lora_path(key: str):
102
+ if Path(key).is_file(): return key
103
+ path = Path(f"{directory_loras}/{escape_lora_basename(key)}.safetensors")
104
+ return str(path)
105
+
106
+
107
+ def safe_float(input):
108
+ output = 1.0
109
+ try:
110
+ output = float(input)
111
+ except Exception:
112
+ output = 1.0
113
+ return output
114
+
115
+
116
+ def save_images(images: list[Image.Image], metadatas: list[str]):
117
+ from PIL import PngImagePlugin
118
+ import uuid
119
+ try:
120
+ output_images = []
121
+ for image, metadata in zip(images, metadatas):
122
+ info = PngImagePlugin.PngInfo()
123
+ info.add_text("parameters", metadata)
124
+ savefile = f"{str(uuid.uuid4())}.png"
125
+ image.save(savefile, "PNG", pnginfo=info)
126
+ output_images.append(str(Path(savefile).resolve()))
127
+ return output_images
128
+ except Exception as e:
129
+ print(f"Failed to save image file: {e}")
130
+ raise Exception(f"Failed to save image file:") from e
131
+
132
+
133
+ def save_gallery_images(images, progress=gr.Progress(track_tqdm=True)):
134
+ from datetime import datetime, timezone, timedelta
135
+ progress(0, desc="Updating gallery...")
136
+ dt_now = datetime.now(timezone(timedelta(hours=9)))
137
+ basename = dt_now.strftime('%Y%m%d_%H%M%S_')
138
+ i = 1
139
+ if not images: return images, gr.update(visible=False)
140
+ output_images = []
141
+ output_paths = []
142
+ for image in images:
143
+ filename = basename + str(i) + ".png"
144
+ i += 1
145
+ oldpath = Path(image[0])
146
+ newpath = oldpath
147
+ try:
148
+ if oldpath.exists():
149
+ newpath = oldpath.resolve().rename(Path(filename).resolve())
150
+ except Exception as e:
151
+ print(e)
152
+ finally:
153
+ output_paths.append(str(newpath))
154
+ output_images.append((str(newpath), str(filename)))
155
+ progress(1, desc="Gallery updated.")
156
+ return gr.update(value=output_images), gr.update(value=output_paths, visible=True)
157
+
158
+
159
+ def download_private_repo(repo_id, dir_path, is_replace):
160
+ from huggingface_hub import snapshot_download
161
+ if not hf_read_token: return
162
+ try:
163
+ snapshot_download(repo_id=repo_id, local_dir=dir_path, allow_patterns=['*.ckpt', '*.pt', '*.pth', '*.safetensors', '*.bin'], use_auth_token=hf_read_token)
164
+ except Exception as e:
165
+ print(f"Error: Failed to download {repo_id}.")
166
+ print(e)
167
+ return
168
+ if is_replace:
169
+ for file in Path(dir_path).glob("*"):
170
+ if file.exists() and "." in file.stem or " " in file.stem and file.suffix in ['.ckpt', '.pt', '.pth', '.safetensors', '.bin']:
171
+ newpath = Path(f'{file.parent.name}/{escape_lora_basename(file.stem)}{file.suffix}')
172
+ file.resolve().rename(newpath.resolve())
173
+
174
+
175
+ private_model_path_repo_dict = {} # {"local filepath": "huggingface repo_id", ...}
176
+
177
+
178
+ def get_private_model_list(repo_id, dir_path):
179
+ global private_model_path_repo_dict
180
+ api = HfApi()
181
+ if not hf_read_token: return []
182
+ try:
183
+ files = api.list_repo_files(repo_id, token=hf_read_token)
184
+ except Exception as e:
185
+ print(f"Error: Failed to list {repo_id}.")
186
+ print(e)
187
+ return []
188
+ model_list = []
189
+ for file in files:
190
+ path = Path(f"{dir_path}/{file}")
191
+ if path.suffix in ['.ckpt', '.pt', '.pth', '.safetensors', '.bin']:
192
+ model_list.append(str(path))
193
+ for model in model_list:
194
+ private_model_path_repo_dict[model] = repo_id
195
+ return model_list
196
+
197
+
198
+ def download_private_file(repo_id, path, is_replace):
199
+ from huggingface_hub import hf_hub_download
200
+ file = Path(path)
201
+ newpath = Path(f'{file.parent.name}/{escape_lora_basename(file.stem)}{file.suffix}') if is_replace else file
202
+ if not hf_read_token or newpath.exists(): return
203
+ filename = file.name
204
+ dirname = file.parent.name
205
+ try:
206
+ hf_hub_download(repo_id=repo_id, filename=filename, local_dir=dirname, use_auth_token=hf_read_token)
207
+ except Exception as e:
208
+ print(f"Error: Failed to download {filename}.")
209
+ print(e)
210
+ return
211
+ if is_replace:
212
+ file.resolve().rename(newpath.resolve())
213
+
214
+
215
+ def download_private_file_from_somewhere(path, is_replace):
216
+ if not path in private_model_path_repo_dict.keys(): return
217
+ repo_id = private_model_path_repo_dict.get(path, None)
218
+ download_private_file(repo_id, path, is_replace)
219
+
220
+
221
+ model_id_list = []
222
+ def get_model_id_list():
223
+ global model_id_list
224
+ if len(model_id_list) != 0: return model_id_list
225
+ api = HfApi()
226
+ model_ids = []
227
+ try:
228
+ models_likes = []
229
+ for author in HF_MODEL_USER_LIKES:
230
+ models_likes.extend(api.list_models(author=author, task="text-to-image", cardData=True, sort="likes"))
231
+ models_ex = []
232
+ for author in HF_MODEL_USER_EX:
233
+ models_ex = api.list_models(author=author, task="text-to-image", cardData=True, sort="last_modified")
234
+ except Exception as e:
235
+ print(f"Error: Failed to list {author}'s models.")
236
+ print(e)
237
+ return model_ids
238
+ for model in models_likes:
239
+ model_ids.append(model.id) if not model.private else ""
240
+ anime_models = []
241
+ real_models = []
242
+ anime_models_flux = []
243
+ real_models_flux = []
244
+ for model in models_ex:
245
+ if not model.private and not model.gated:
246
+ if "diffusers:FluxPipeline" in model.tags: anime_models_flux.append(model.id) if "anime" in model.tags else real_models_flux.append(model.id)
247
+ else: anime_models.append(model.id) if "anime" in model.tags else real_models.append(model.id)
248
+ model_ids.extend(anime_models)
249
+ model_ids.extend(real_models)
250
+ model_ids.extend(anime_models_flux)
251
+ model_ids.extend(real_models_flux)
252
+ model_id_list = model_ids.copy()
253
+ return model_ids
254
+
255
+
256
+ model_id_list = get_model_id_list()
257
+
258
+
259
+ def get_t2i_model_info(repo_id: str):
260
+ api = HfApi(token=HF_TOKEN)
261
+ try:
262
+ if not is_repo_name(repo_id): return ""
263
+ model = api.model_info(repo_id=repo_id, timeout=5.0)
264
+ except Exception as e:
265
+ print(f"Error: Failed to get {repo_id}'s info.")
266
+ print(e)
267
+ return ""
268
+ if model.private or model.gated: return ""
269
+ tags = model.tags
270
+ info = []
271
+ url = f"https://huggingface.co/{repo_id}/"
272
+ if not 'diffusers' in tags: return ""
273
+ for k, v in MODEL_TYPE_DICT.items():
274
+ if k in tags: info.append(v)
275
+ if model.card_data and model.card_data.tags:
276
+ info.extend(list_sub(model.card_data.tags, ['text-to-image', 'stable-diffusion', 'stable-diffusion-api', 'safetensors', 'stable-diffusion-xl']))
277
+ info.append(f"DLs: {model.downloads}")
278
+ info.append(f"likes: {model.likes}")
279
+ info.append(model.last_modified.strftime("lastmod: %Y-%m-%d"))
280
+ md = f"Model Info: {', '.join(info)}, [Model Repo]({url})"
281
+ return gr.update(value=md)
282
+
283
+
284
+ def get_tupled_model_list(model_list):
285
+ if not model_list: return []
286
+ tupled_list = []
287
+ for repo_id in model_list:
288
+ api = HfApi()
289
+ try:
290
+ if not api.repo_exists(repo_id): continue
291
+ model = api.model_info(repo_id=repo_id)
292
+ except Exception as e:
293
+ print(e)
294
+ continue
295
+ if model.private or model.gated: continue
296
+ tags = model.tags
297
+ info = []
298
+ if not 'diffusers' in tags: continue
299
+ for k, v in MODEL_TYPE_DICT.items():
300
+ if k in tags: info.append(v)
301
+ if model.card_data and model.card_data.tags:
302
+ info.extend(list_sub(model.card_data.tags, ['text-to-image', 'stable-diffusion', 'stable-diffusion-api', 'safetensors', 'stable-diffusion-xl']))
303
+ if "pony" in info:
304
+ info.remove("pony")
305
+ name = f"{repo_id} (Pony🐴, {', '.join(info)})"
306
+ else:
307
+ name = f"{repo_id} ({', '.join(info)})"
308
+ tupled_list.append((name, repo_id))
309
+ return tupled_list
310
+
311
+
312
+ private_lora_dict = {}
313
+ try:
314
+ with open('lora_dict.json', encoding='utf-8') as f:
315
+ d = json.load(f)
316
+ for k, v in d.items():
317
+ private_lora_dict[escape_lora_basename(k)] = v
318
+ except Exception as e:
319
+ print(e)
320
+ loras_dict = {"None": ["", "", "", "", ""], "": ["", "", "", "", ""]} | private_lora_dict.copy()
321
+ civitai_not_exists_list = []
322
+ loras_url_to_path_dict = {} # {"URL to download": "local filepath", ...}
323
+ civitai_lora_last_results = {} # {"URL to download": {search results}, ...}
324
+ all_lora_list = []
325
+
326
+
327
+ private_lora_model_list = []
328
+ def get_private_lora_model_lists():
329
+ global private_lora_model_list
330
+ if len(private_lora_model_list) != 0: return private_lora_model_list
331
+ models1 = []
332
+ models2 = []
333
+ for repo in HF_LORA_PRIVATE_REPOS1:
334
+ models1.extend(get_private_model_list(repo, directory_loras))
335
+ for repo in HF_LORA_PRIVATE_REPOS2:
336
+ models2.extend(get_private_model_list(repo, directory_loras))
337
+ models = list_uniq(models1 + sorted(models2))
338
+ private_lora_model_list = models.copy()
339
+ return models
340
+
341
+
342
+ private_lora_model_list = get_private_lora_model_lists()
343
+
344
+
345
+ def get_civitai_info(path):
346
+ global civitai_not_exists_list
347
+ import requests
348
+ from urllib3.util import Retry
349
+ from requests.adapters import HTTPAdapter
350
+ if path in set(civitai_not_exists_list): return ["", "", "", "", ""]
351
+ if not Path(path).exists(): return None
352
+ user_agent = get_user_agent()
353
+ headers = {'User-Agent': user_agent, 'content-type': 'application/json'}
354
+ base_url = 'https://civitai.com/api/v1/model-versions/by-hash/'
355
+ params = {}
356
+ session = requests.Session()
357
+ retries = Retry(total=5, backoff_factor=1, status_forcelist=[500, 502, 503, 504])
358
+ session.mount("https://", HTTPAdapter(max_retries=retries))
359
+ import hashlib
360
+ with open(path, 'rb') as file:
361
+ file_data = file.read()
362
+ hash_sha256 = hashlib.sha256(file_data).hexdigest()
363
+ url = base_url + hash_sha256
364
+ try:
365
+ r = session.get(url, params=params, headers=headers, stream=True, timeout=(3.0, 15))
366
+ except Exception as e:
367
+ print(e)
368
+ return ["", "", "", "", ""]
369
+ if not r.ok: return None
370
+ json = r.json()
371
+ if not 'baseModel' in json:
372
+ civitai_not_exists_list.append(path)
373
+ return ["", "", "", "", ""]
374
+ items = []
375
+ items.append(" / ".join(json['trainedWords']))
376
+ items.append(json['baseModel'])
377
+ items.append(json['model']['name'])
378
+ items.append(f"https://civitai.com/models/{json['modelId']}")
379
+ items.append(json['images'][0]['url'])
380
+ return items
381
+
382
+
383
+ def get_lora_model_list():
384
+ loras = list_uniq(get_private_lora_model_lists() + get_local_model_list(directory_loras) + DIFFUSERS_FORMAT_LORAS)
385
+ loras.insert(0, "None")
386
+ loras.insert(0, "")
387
+ return loras
388
+
389
+
390
+ def get_all_lora_list():
391
+ global all_lora_list
392
+ loras = get_lora_model_list()
393
+ all_lora_list = loras.copy()
394
+ return loras
395
+
396
+
397
+ def get_all_lora_tupled_list():
398
+ global loras_dict
399
+ models = get_all_lora_list()
400
+ if not models: return []
401
+ tupled_list = []
402
+ for model in models:
403
+ #if not model: continue # to avoid GUI-related bug
404
+ basename = Path(model).stem
405
+ key = to_lora_key(model)
406
+ items = None
407
+ if key in loras_dict.keys():
408
+ items = loras_dict.get(key, None)
409
+ else:
410
+ items = get_civitai_info(model)
411
+ if items != None:
412
+ loras_dict[key] = items
413
+ name = basename
414
+ value = model
415
+ if items and items[2] != "":
416
+ if items[1] == "Pony":
417
+ name = f"{basename} (for {items[1]}🐴, {items[2]})"
418
+ else:
419
+ name = f"{basename} (for {items[1]}, {items[2]})"
420
+ tupled_list.append((name, value))
421
+ return tupled_list
422
+
423
+
424
+ def update_lora_dict(path):
425
+ global loras_dict
426
+ key = escape_lora_basename(Path(path).stem)
427
+ if key in loras_dict.keys(): return
428
+ items = get_civitai_info(path)
429
+ if items == None: return
430
+ loras_dict[key] = items
431
+
432
+
433
+ def download_lora(dl_urls: str):
434
+ global loras_url_to_path_dict
435
+ dl_path = ""
436
+ before = get_local_model_list(directory_loras)
437
+ urls = []
438
+ for url in [url.strip() for url in dl_urls.split(',')]:
439
+ local_path = f"{directory_loras}/{url.split('/')[-1]}"
440
+ if not Path(local_path).exists():
441
+ download_things(directory_loras, url, HF_TOKEN, CIVITAI_API_KEY)
442
+ urls.append(url)
443
+ after = get_local_model_list(directory_loras)
444
+ new_files = list_sub(after, before)
445
+ i = 0
446
+ for file in new_files:
447
+ path = Path(file)
448
+ if path.exists():
449
+ new_path = Path(f'{path.parent.name}/{escape_lora_basename(path.stem)}{path.suffix}')
450
+ path.resolve().rename(new_path.resolve())
451
+ loras_url_to_path_dict[urls[i]] = str(new_path)
452
+ update_lora_dict(str(new_path))
453
+ dl_path = str(new_path)
454
+ i += 1
455
+ return dl_path
456
+
457
+
458
+ def copy_lora(path: str, new_path: str):
459
+ import shutil
460
+ if path == new_path: return new_path
461
+ cpath = Path(path)
462
+ npath = Path(new_path)
463
+ if cpath.exists():
464
+ try:
465
+ shutil.copy(str(cpath.resolve()), str(npath.resolve()))
466
+ except Exception as e:
467
+ print(e)
468
+ return None
469
+ update_lora_dict(str(npath))
470
+ return new_path
471
+ else:
472
+ return None
473
+
474
+
475
+ def download_my_lora(dl_urls: str, lora1: str, lora2: str, lora3: str, lora4: str, lora5: str):
476
+ path = download_lora(dl_urls)
477
+ if path:
478
+ if not lora1 or lora1 == "None":
479
+ lora1 = path
480
+ elif not lora2 or lora2 == "None":
481
+ lora2 = path
482
+ elif not lora3 or lora3 == "None":
483
+ lora3 = path
484
+ elif not lora4 or lora4 == "None":
485
+ lora4 = path
486
+ elif not lora5 or lora5 == "None":
487
+ lora5 = path
488
+ choices = get_all_lora_tupled_list()
489
+ return gr.update(value=lora1, choices=choices), gr.update(value=lora2, choices=choices), gr.update(value=lora3, choices=choices),\
490
+ gr.update(value=lora4, choices=choices), gr.update(value=lora5, choices=choices)
491
+
492
+
493
+ def get_valid_lora_name(query: str, model_name: str):
494
+ path = "None"
495
+ if not query or query == "None": return "None"
496
+ if to_lora_key(query) in loras_dict.keys(): return query
497
+ if query in loras_url_to_path_dict.keys():
498
+ path = loras_url_to_path_dict[query]
499
+ else:
500
+ path = to_lora_path(query.strip().split('/')[-1])
501
+ if Path(path).exists():
502
+ return path
503
+ elif "http" in query:
504
+ dl_file = download_lora(query)
505
+ if dl_file and Path(dl_file).exists(): return dl_file
506
+ else:
507
+ dl_file = find_similar_lora(query, model_name)
508
+ if dl_file and Path(dl_file).exists(): return dl_file
509
+ return "None"
510
+
511
+
512
+ def get_valid_lora_path(query: str):
513
+ path = None
514
+ if not query or query == "None": return None
515
+ if to_lora_key(query) in loras_dict.keys(): return query
516
+ if Path(path).exists():
517
+ return path
518
+ else:
519
+ return None
520
+
521
+
522
+ def get_valid_lora_wt(prompt: str, lora_path: str, lora_wt: float):
523
+ import re
524
+ wt = lora_wt
525
+ result = re.findall(f'<lora:{to_lora_key(lora_path)}:(.+?)>', prompt)
526
+ if not result: return wt
527
+ wt = safe_float(result[0][0])
528
+ return wt
529
+
530
+
531
+ def set_prompt_loras(prompt, prompt_syntax, model_name, lora1, lora1_wt, lora2, lora2_wt, lora3, lora3_wt, lora4, lora4_wt, lora5, lora5_wt):
532
+ import re
533
+ if not "Classic" in str(prompt_syntax): return lora1, lora1_wt, lora2, lora2_wt, lora3, lora3_wt, lora4, lora4_wt, lora5, lora5_wt
534
+ lora1 = get_valid_lora_name(lora1, model_name)
535
+ lora2 = get_valid_lora_name(lora2, model_name)
536
+ lora3 = get_valid_lora_name(lora3, model_name)
537
+ lora4 = get_valid_lora_name(lora4, model_name)
538
+ lora5 = get_valid_lora_name(lora5, model_name)
539
+ if not "<lora" in prompt: return lora1, lora1_wt, lora2, lora2_wt, lora3, lora3_wt, lora4, lora4_wt, lora5, lora5_wt
540
+ lora1_wt = get_valid_lora_wt(prompt, lora1, lora1_wt)
541
+ lora2_wt = get_valid_lora_wt(prompt, lora2, lora2_wt)
542
+ lora3_wt = get_valid_lora_wt(prompt, lora3, lora3_wt)
543
+ lora4_wt = get_valid_lora_wt(prompt, lora4, lora4_wt)
544
+ lora5_wt = get_valid_lora_wt(prompt, lora5, lora5_wt)
545
+ on1, label1, tag1, md1 = get_lora_info(lora1)
546
+ on2, label2, tag2, md2 = get_lora_info(lora2)
547
+ on3, label3, tag3, md3 = get_lora_info(lora3)
548
+ on4, label4, tag4, md4 = get_lora_info(lora4)
549
+ on5, label5, tag5, md5 = get_lora_info(lora5)
550
+ lora_paths = [lora1, lora2, lora3, lora4, lora5]
551
+ prompts = prompt.split(",") if prompt else []
552
+ for p in prompts:
553
+ p = str(p).strip()
554
+ if "<lora" in p:
555
+ result = re.findall(r'<lora:(.+?):(.+?)>', p)
556
+ if not result: continue
557
+ key = result[0][0]
558
+ wt = result[0][1]
559
+ path = to_lora_path(key)
560
+ if not key in loras_dict.keys() or not path:
561
+ path = get_valid_lora_name(path)
562
+ if not path or path == "None": continue
563
+ if path in lora_paths:
564
+ continue
565
+ elif not on1:
566
+ lora1 = path
567
+ lora_paths = [lora1, lora2, lora3, lora4, lora5]
568
+ lora1_wt = safe_float(wt)
569
+ on1 = True
570
+ elif not on2:
571
+ lora2 = path
572
+ lora_paths = [lora1, lora2, lora3, lora4, lora5]
573
+ lora2_wt = safe_float(wt)
574
+ on2 = True
575
+ elif not on3:
576
+ lora3 = path
577
+ lora_paths = [lora1, lora2, lora3, lora4, lora5]
578
+ lora3_wt = safe_float(wt)
579
+ on3 = True
580
+ elif not on4:
581
+ lora4 = path
582
+ lora_paths = [lora1, lora2, lora3, lora4, lora5]
583
+ lora4_wt = safe_float(wt)
584
+ on4, label4, tag4, md4 = get_lora_info(lora4)
585
+ elif not on5:
586
+ lora5 = path
587
+ lora_paths = [lora1, lora2, lora3, lora4, lora5]
588
+ lora5_wt = safe_float(wt)
589
+ on5 = True
590
+ return lora1, lora1_wt, lora2, lora2_wt, lora3, lora3_wt, lora4, lora4_wt, lora5, lora5_wt
591
+
592
+
593
+ def get_lora_info(lora_path: str):
594
+ is_valid = False
595
+ tag = ""
596
+ label = ""
597
+ md = "None"
598
+ if not lora_path or lora_path == "None":
599
+ print("LoRA file not found.")
600
+ return is_valid, label, tag, md
601
+ path = Path(lora_path)
602
+ new_path = Path(f'{path.parent.name}/{escape_lora_basename(path.stem)}{path.suffix}')
603
+ if not to_lora_key(str(new_path)) in loras_dict.keys() and str(path) not in set(get_all_lora_list()):
604
+ print("LoRA file is not registered.")
605
+ return tag, label, tag, md
606
+ if not new_path.exists():
607
+ download_private_file_from_somewhere(str(path), True)
608
+ basename = new_path.stem
609
+ label = f'Name: {basename}'
610
+ items = loras_dict.get(basename, None)
611
+ if items == None:
612
+ items = get_civitai_info(str(new_path))
613
+ if items != None:
614
+ loras_dict[basename] = items
615
+ if items and items[2] != "":
616
+ tag = items[0]
617
+ label = f'Name: {basename}'
618
+ if items[1] == "Pony":
619
+ label = f'Name: {basename} (for Pony🐴)'
620
+ if items[4]:
621
+ md = f'<img src="{items[4]}" alt="thumbnail" width="150" height="240"><br>[LoRA Model URL]({items[3]})'
622
+ elif items[3]:
623
+ md = f'[LoRA Model URL]({items[3]})'
624
+ is_valid = True
625
+ return is_valid, label, tag, md
626
+
627
+
628
+ def normalize_prompt_list(tags: list[str]):
629
+ prompts = []
630
+ for tag in tags:
631
+ tag = str(tag).strip()
632
+ if tag:
633
+ prompts.append(tag)
634
+ return prompts
635
+
636
+
637
+ def apply_lora_prompt(prompt: str = "", lora_info: str = ""):
638
+ if lora_info == "None": return gr.update(value=prompt)
639
+ tags = prompt.split(",") if prompt else []
640
+ prompts = normalize_prompt_list(tags)
641
+
642
+ lora_tag = lora_info.replace("/",",")
643
+ lora_tags = lora_tag.split(",") if str(lora_info) != "None" else []
644
+ lora_prompts = normalize_prompt_list(lora_tags)
645
+
646
+ empty = [""]
647
+ prompt = ", ".join(list_uniq(prompts + lora_prompts) + empty)
648
+ return gr.update(value=prompt)
649
+
650
+
651
+ def update_loras(prompt, prompt_syntax, lora1, lora1_wt, lora2, lora2_wt, lora3, lora3_wt, lora4, lora4_wt, lora5, lora5_wt):
652
+ import re
653
+ on1, label1, tag1, md1 = get_lora_info(lora1)
654
+ on2, label2, tag2, md2 = get_lora_info(lora2)
655
+ on3, label3, tag3, md3 = get_lora_info(lora3)
656
+ on4, label4, tag4, md4 = get_lora_info(lora4)
657
+ on5, label5, tag5, md5 = get_lora_info(lora5)
658
+ lora_paths = [lora1, lora2, lora3, lora4, lora5]
659
+
660
+ output_prompt = prompt
661
+ if "Classic" in str(prompt_syntax):
662
+ prompts = prompt.split(",") if prompt else []
663
+ output_prompts = []
664
+ for p in prompts:
665
+ p = str(p).strip()
666
+ if "<lora" in p:
667
+ result = re.findall(r'<lora:(.+?):(.+?)>', p)
668
+ if not result: continue
669
+ key = result[0][0]
670
+ wt = result[0][1]
671
+ path = to_lora_path(key)
672
+ if not key in loras_dict.keys() or not path: continue
673
+ if path in lora_paths:
674
+ output_prompts.append(f"<lora:{to_lora_key(path)}:{safe_float(wt):.2f}>")
675
+ elif p:
676
+ output_prompts.append(p)
677
+ lora_prompts = []
678
+ if on1: lora_prompts.append(f"<lora:{to_lora_key(lora1)}:{lora1_wt:.2f}>")
679
+ if on2: lora_prompts.append(f"<lora:{to_lora_key(lora2)}:{lora2_wt:.2f}>")
680
+ if on3: lora_prompts.append(f"<lora:{to_lora_key(lora3)}:{lora3_wt:.2f}>")
681
+ if on4: lora_prompts.append(f"<lora:{to_lora_key(lora4)}:{lora4_wt:.2f}>")
682
+ if on5: lora_prompts.append(f"<lora:{to_lora_key(lora5)}:{lora5_wt:.2f}>")
683
+ output_prompt = ", ".join(list_uniq(output_prompts + lora_prompts + [""]))
684
+ choices = get_all_lora_tupled_list()
685
+
686
+ return gr.update(value=output_prompt), gr.update(value=lora1, choices=choices), gr.update(value=lora1_wt),\
687
+ gr.update(value=tag1, label=label1, visible=on1), gr.update(visible=on1), gr.update(value=md1, visible=on1),\
688
+ gr.update(value=lora2, choices=choices), gr.update(value=lora2_wt),\
689
+ gr.update(value=tag2, label=label2, visible=on2), gr.update(visible=on2), gr.update(value=md2, visible=on2),\
690
+ gr.update(value=lora3, choices=choices), gr.update(value=lora3_wt),\
691
+ gr.update(value=tag3, label=label3, visible=on3), gr.update(visible=on3), gr.update(value=md3, visible=on3),\
692
+ gr.update(value=lora4, choices=choices), gr.update(value=lora4_wt),\
693
+ gr.update(value=tag4, label=label4, visible=on4), gr.update(visible=on4), gr.update(value=md4, visible=on4),\
694
+ gr.update(value=lora5, choices=choices), gr.update(value=lora5_wt),\
695
+ gr.update(value=tag5, label=label5, visible=on5), gr.update(visible=on5), gr.update(value=md5, visible=on5)
696
+
697
+
698
+ def get_my_lora(link_url):
699
+ from pathlib import Path
700
+ before = get_local_model_list(directory_loras)
701
+ for url in [url.strip() for url in link_url.split(',')]:
702
+ if not Path(f"{directory_loras}/{url.split('/')[-1]}").exists():
703
+ download_things(directory_loras, url, HF_TOKEN, CIVITAI_API_KEY)
704
+ after = get_local_model_list(directory_loras)
705
+ new_files = list_sub(after, before)
706
+ for file in new_files:
707
+ path = Path(file)
708
+ if path.exists():
709
+ new_path = Path(f'{path.parent.name}/{escape_lora_basename(path.stem)}{path.suffix}')
710
+ path.resolve().rename(new_path.resolve())
711
+ update_lora_dict(str(new_path))
712
+ new_lora_model_list = get_lora_model_list()
713
+ new_lora_tupled_list = get_all_lora_tupled_list()
714
+
715
+ return gr.update(
716
+ choices=new_lora_tupled_list, value=new_lora_model_list[-1]
717
+ ), gr.update(
718
+ choices=new_lora_tupled_list
719
+ ), gr.update(
720
+ choices=new_lora_tupled_list
721
+ ), gr.update(
722
+ choices=new_lora_tupled_list
723
+ ), gr.update(
724
+ choices=new_lora_tupled_list
725
+ )
726
+
727
+
728
+ def upload_file_lora(files, progress=gr.Progress(track_tqdm=True)):
729
+ progress(0, desc="Uploading...")
730
+ file_paths = [file.name for file in files]
731
+ progress(1, desc="Uploaded.")
732
+ return gr.update(value=file_paths, visible=True), gr.update(visible=True)
733
+
734
+
735
+ def move_file_lora(filepaths):
736
+ import shutil
737
+ for file in filepaths:
738
+ path = Path(shutil.move(Path(file).resolve(), Path(f"./{directory_loras}").resolve()))
739
+ newpath = Path(f'{path.parent.name}/{escape_lora_basename(path.stem)}{path.suffix}')
740
+ path.resolve().rename(newpath.resolve())
741
+ update_lora_dict(str(newpath))
742
+
743
+ new_lora_model_list = get_lora_model_list()
744
+ new_lora_tupled_list = get_all_lora_tupled_list()
745
+
746
+ return gr.update(
747
+ choices=new_lora_tupled_list, value=new_lora_model_list[-1]
748
+ ), gr.update(
749
+ choices=new_lora_tupled_list
750
+ ), gr.update(
751
+ choices=new_lora_tupled_list
752
+ ), gr.update(
753
+ choices=new_lora_tupled_list
754
+ ), gr.update(
755
+ choices=new_lora_tupled_list
756
+ )
757
+
758
+
759
+ def get_civitai_info(path):
760
+ global civitai_not_exists_list, loras_url_to_path_dict
761
+ import requests
762
+ from requests.adapters import HTTPAdapter
763
+ from urllib3.util import Retry
764
+ default = ["", "", "", "", ""]
765
+ if path in set(civitai_not_exists_list): return default
766
+ if not Path(path).exists(): return None
767
+ user_agent = get_user_agent()
768
+ headers = {'User-Agent': user_agent, 'content-type': 'application/json'}
769
+ base_url = 'https://civitai.com/api/v1/model-versions/by-hash/'
770
+ params = {}
771
+ session = requests.Session()
772
+ retries = Retry(total=5, backoff_factor=1, status_forcelist=[500, 502, 503, 504])
773
+ session.mount("https://", HTTPAdapter(max_retries=retries))
774
+ import hashlib
775
+ with open(path, 'rb') as file:
776
+ file_data = file.read()
777
+ hash_sha256 = hashlib.sha256(file_data).hexdigest()
778
+ url = base_url + hash_sha256
779
+ try:
780
+ r = session.get(url, params=params, headers=headers, stream=True, timeout=(3.0, 15))
781
+ except Exception as e:
782
+ print(e)
783
+ return default
784
+ else:
785
+ if not r.ok: return None
786
+ json = r.json()
787
+ if 'baseModel' not in json:
788
+ civitai_not_exists_list.append(path)
789
+ return default
790
+ items = []
791
+ items.append(" / ".join(json['trainedWords'])) # The words (prompts) used to trigger the model
792
+ items.append(json['baseModel']) # Base model (SDXL1.0, Pony, ...)
793
+ items.append(json['model']['name']) # The name of the model version
794
+ items.append(f"https://civitai.com/models/{json['modelId']}") # The repo url for the model
795
+ items.append(json['images'][0]['url']) # The url for a sample image
796
+ loras_url_to_path_dict[path] = json['downloadUrl'] # The download url to get the model file for this specific version
797
+ return items
798
+
799
+
800
+ def search_lora_on_civitai(query: str, allow_model: list[str] = ["Pony", "SDXL 1.0"], limit: int = 100,
801
+ sort: str = "Highest Rated", period: str = "AllTime", tag: str = ""):
802
+ import requests
803
+ from requests.adapters import HTTPAdapter
804
+ from urllib3.util import Retry
805
+ user_agent = get_user_agent()
806
+ headers = {'User-Agent': user_agent, 'content-type': 'application/json'}
807
+ base_url = 'https://civitai.com/api/v1/models'
808
+ params = {'types': ['LORA'], 'sort': sort, 'period': period, 'limit': limit, 'nsfw': 'true'}
809
+ if query: params["query"] = query
810
+ if tag: params["tag"] = tag
811
+ session = requests.Session()
812
+ retries = Retry(total=5, backoff_factor=1, status_forcelist=[500, 502, 503, 504])
813
+ session.mount("https://", HTTPAdapter(max_retries=retries))
814
+ try:
815
+ r = session.get(base_url, params=params, headers=headers, stream=True, timeout=(3.0, 30))
816
+ except Exception as e:
817
+ print(e)
818
+ return None
819
+ else:
820
+ if not r.ok: return None
821
+ json = r.json()
822
+ if 'items' not in json: return None
823
+ items = []
824
+ for j in json['items']:
825
+ for model in j['modelVersions']:
826
+ item = {}
827
+ if model['baseModel'] not in set(allow_model): continue
828
+ item['name'] = j['name']
829
+ item['creator'] = j['creator']['username']
830
+ item['tags'] = j['tags']
831
+ item['model_name'] = model['name']
832
+ item['base_model'] = model['baseModel']
833
+ item['dl_url'] = model['downloadUrl']
834
+ item['md'] = f'<img src="{model["images"][0]["url"]}" alt="thumbnail" width="150" height="240"><br>[LoRA Model URL](https://civitai.com/models/{j["id"]})'
835
+ items.append(item)
836
+ return items
837
+
838
+
839
+ def search_civitai_lora(query, base_model, sort="Highest Rated", period="AllTime", tag=""):
840
+ global civitai_lora_last_results
841
+ items = search_lora_on_civitai(query, base_model, 100, sort, period, tag)
842
+ if not items: return gr.update(choices=[("", "")], value="", visible=False),\
843
+ gr.update(value="", visible=False), gr.update(visible=True), gr.update(visible=True)
844
+ civitai_lora_last_results = {}
845
+ choices = []
846
+ for item in items:
847
+ base_model_name = "Pony🐴" if item['base_model'] == "Pony" else item['base_model']
848
+ name = f"{item['name']} (for {base_model_name} / By: {item['creator']} / Tags: {', '.join(item['tags'])})"
849
+ value = item['dl_url']
850
+ choices.append((name, value))
851
+ civitai_lora_last_results[value] = item
852
+ if not choices: return gr.update(choices=[("", "")], value="", visible=False),\
853
+ gr.update(value="", visible=False), gr.update(visible=True), gr.update(visible=True)
854
+ result = civitai_lora_last_results.get(choices[0][1], "None")
855
+ md = result['md'] if result else ""
856
+ return gr.update(choices=choices, value=choices[0][1], visible=True), gr.update(value=md, visible=True),\
857
+ gr.update(visible=True), gr.update(visible=True)
858
+
859
+
860
+ def select_civitai_lora(search_result):
861
+ if not "http" in search_result: return gr.update(value=""), gr.update(value="None", visible=True)
862
+ result = civitai_lora_last_results.get(search_result, "None")
863
+ md = result['md'] if result else ""
864
+ return gr.update(value=search_result), gr.update(value=md, visible=True)
865
+
866
+
867
+ LORA_BASE_MODEL_DICT = {
868
+ "diffusers:StableDiffusionPipeline": ["SD 1.5"],
869
+ "diffusers:StableDiffusionXLPipeline": ["Pony", "SDXL 1.0"],
870
+ "diffusers:FluxPipeline": ["Flux.1 D", "Flux.1 S"],
871
+ }
872
+
873
+
874
+ def get_lora_base_model(model_name: str):
875
+ api = HfApi(token=HF_TOKEN)
876
+ default = ["Pony", "SDXL 1.0"]
877
+ try:
878
+ model = api.model_info(repo_id=model_name, timeout=5.0)
879
+ tags = model.tags
880
+ for tag in tags:
881
+ if tag in LORA_BASE_MODEL_DICT.keys(): return LORA_BASE_MODEL_DICT.get(tag, default)
882
+ except Exception:
883
+ return default
884
+ return default
885
+
886
+
887
+ def find_similar_lora(q: str, model_name: str):
888
+ from rapidfuzz.process import extractOne
889
+ from rapidfuzz.utils import default_process
890
+ query = to_lora_key(q)
891
+ print(f"Finding <lora:{query}:...>...")
892
+ keys = list(private_lora_dict.keys())
893
+ values = [x[2] for x in list(private_lora_dict.values())]
894
+ s = default_process(query)
895
+ e1 = extractOne(s, keys + values, processor=default_process, score_cutoff=80.0)
896
+ key = ""
897
+ if e1:
898
+ e = e1[0]
899
+ if e in set(keys): key = e
900
+ elif e in set(values): key = keys[values.index(e)]
901
+ if key:
902
+ path = to_lora_path(key)
903
+ new_path = to_lora_path(query)
904
+ if not Path(path).exists():
905
+ if not Path(new_path).exists(): download_private_file_from_somewhere(path, True)
906
+ if Path(path).exists() and copy_lora(path, new_path): return new_path
907
+ print(f"Finding <lora:{query}:...> on Civitai...")
908
+ civitai_query = Path(query).stem if Path(query).is_file() else query
909
+ civitai_query = civitai_query.replace("_", " ").replace("-", " ")
910
+ base_model = get_lora_base_model(model_name)
911
+ items = search_lora_on_civitai(civitai_query, base_model, 1)
912
+ if items:
913
+ item = items[0]
914
+ path = download_lora(item['dl_url'])
915
+ new_path = query if Path(query).is_file() else to_lora_path(query)
916
+ if path and copy_lora(path, new_path): return new_path
917
+ return None
918
+
919
+
920
+ def change_interface_mode(mode: str):
921
+ if mode == "Fast":
922
+ return gr.update(open=False), gr.update(visible=True), gr.update(open=False), gr.update(open=False),\
923
+ gr.update(visible=True), gr.update(open=False), gr.update(visible=True), gr.update(open=False),\
924
+ gr.update(visible=True), gr.update(value="Fast")
925
+ elif mode == "Simple": # t2i mode
926
+ return gr.update(open=True), gr.update(visible=True), gr.update(open=False), gr.update(open=False),\
927
+ gr.update(visible=True), gr.update(open=False), gr.update(visible=False), gr.update(open=True),\
928
+ gr.update(visible=False), gr.update(value="Standard")
929
+ elif mode == "LoRA": # t2i LoRA mode
930
+ return gr.update(open=True), gr.update(visible=True), gr.update(open=True), gr.update(open=False),\
931
+ gr.update(visible=True), gr.update(open=True), gr.update(visible=True), gr.update(open=False),\
932
+ gr.update(visible=False), gr.update(value="Standard")
933
+ else: # Standard
934
+ return gr.update(open=False), gr.update(visible=True), gr.update(open=False), gr.update(open=False),\
935
+ gr.update(visible=True), gr.update(open=False), gr.update(visible=True), gr.update(open=False),\
936
+ gr.update(visible=True), gr.update(value="Standard")
937
+
938
+
939
+ quality_prompt_list = [
940
+ {
941
+ "name": "None",
942
+ "prompt": "",
943
+ "negative_prompt": "lowres",
944
+ },
945
+ {
946
+ "name": "Animagine Common",
947
+ "prompt": "anime artwork, anime style, vibrant, studio anime, highly detailed, masterpiece, best quality, very aesthetic, absurdres",
948
+ "negative_prompt": "lowres, (bad), text, error, fewer, extra, missing, worst quality, jpeg artifacts, low quality, watermark, unfinished, displeasing, oldest, early, chromatic aberration, signature, extra digits, artistic error, username, scan, [abstract]",
949
+ },
950
+ {
951
+ "name": "Pony Anime Common",
952
+ "prompt": "source_anime, score_9, score_8_up, score_7_up, masterpiece, best quality, very aesthetic, absurdres",
953
+ "negative_prompt": "source_pony, source_furry, source_cartoon, score_6, score_5, score_4, busty, ugly face, mutated hands, low res, blurry face, black and white, the simpsons, overwatch, apex legends",
954
+ },
955
+ {
956
+ "name": "Pony Common",
957
+ "prompt": "source_anime, score_9, score_8_up, score_7_up",
958
+ "negative_prompt": "source_pony, source_furry, source_cartoon, score_6, score_5, score_4, busty, ugly face, mutated hands, low res, blurry face, black and white, the simpsons, overwatch, apex legends",
959
+ },
960
+ {
961
+ "name": "Animagine Standard v3.0",
962
+ "prompt": "masterpiece, best quality",
963
+ "negative_prompt": "lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry, artist name",
964
+ },
965
+ {
966
+ "name": "Animagine Standard v3.1",
967
+ "prompt": "masterpiece, best quality, very aesthetic, absurdres",
968
+ "negative_prompt": "lowres, (bad), text, error, fewer, extra, missing, worst quality, jpeg artifacts, low quality, watermark, unfinished, displeasing, oldest, early, chromatic aberration, signature, extra digits, artistic error, username, scan, [abstract]",
969
+ },
970
+ {
971
+ "name": "Animagine Light v3.1",
972
+ "prompt": "(masterpiece), best quality, very aesthetic, perfect face",
973
+ "negative_prompt": "(low quality, worst quality:1.2), very displeasing, 3d, watermark, signature, ugly, poorly drawn",
974
+ },
975
+ {
976
+ "name": "Animagine Heavy v3.1",
977
+ "prompt": "(masterpiece), (best quality), (ultra-detailed), very aesthetic, illustration, disheveled hair, perfect composition, moist skin, intricate details",
978
+ "negative_prompt": "longbody, lowres, bad anatomy, bad hands, missing fingers, pubic hair, extra digit, fewer digits, cropped, worst quality, low quality, very displeasing",
979
+ },
980
+ ]
981
+
982
+
983
+ style_list = [
984
+ {
985
+ "name": "None",
986
+ "prompt": "",
987
+ "negative_prompt": "",
988
+ },
989
+ {
990
+ "name": "Cinematic",
991
+ "prompt": "cinematic still, emotional, harmonious, vignette, highly detailed, high budget, bokeh, cinemascope, moody, epic, gorgeous, film grain, grainy",
992
+ "negative_prompt": "cartoon, graphic, text, painting, crayon, graphite, abstract, glitch, deformed, mutated, ugly, disfigured",
993
+ },
994
+ {
995
+ "name": "Photographic",
996
+ "prompt": "cinematic photo, 35mm photograph, film, bokeh, professional, 4k, highly detailed",
997
+ "negative_prompt": "drawing, painting, crayon, sketch, graphite, impressionist, noisy, blurry, soft, deformed, ugly",
998
+ },
999
+ {
1000
+ "name": "Anime",
1001
+ "prompt": "anime artwork, anime style, vibrant, studio anime, highly detailed",
1002
+ "negative_prompt": "photo, deformed, black and white, realism, disfigured, low contrast",
1003
+ },
1004
+ {
1005
+ "name": "Manga",
1006
+ "prompt": "manga style, vibrant, high-energy, detailed, iconic, Japanese comic style",
1007
+ "negative_prompt": "ugly, deformed, noisy, blurry, low contrast, realism, photorealistic, Western comic style",
1008
+ },
1009
+ {
1010
+ "name": "Digital Art",
1011
+ "prompt": "concept art, digital artwork, illustrative, painterly, matte painting, highly detailed",
1012
+ "negative_prompt": "photo, photorealistic, realism, ugly",
1013
+ },
1014
+ {
1015
+ "name": "Pixel art",
1016
+ "prompt": "pixel-art, low-res, blocky, pixel art style, 8-bit graphics",
1017
+ "negative_prompt": "sloppy, messy, blurry, noisy, highly detailed, ultra textured, photo, realistic",
1018
+ },
1019
+ {
1020
+ "name": "Fantasy art",
1021
+ "prompt": "ethereal fantasy concept art, magnificent, celestial, ethereal, painterly, epic, majestic, magical, fantasy art, cover art, dreamy",
1022
+ "negative_prompt": "photographic, realistic, realism, 35mm film, dslr, cropped, frame, text, deformed, glitch, noise, noisy, off-center, deformed, cross-eyed, closed eyes, bad anatomy, ugly, disfigured, sloppy, duplicate, mutated, black and white",
1023
+ },
1024
+ {
1025
+ "name": "Neonpunk",
1026
+ "prompt": "neonpunk style, cyberpunk, vaporwave, neon, vibes, vibrant, stunningly beautiful, crisp, detailed, sleek, ultramodern, magenta highlights, dark purple shadows, high contrast, cinematic, ultra detailed, intricate, professional",
1027
+ "negative_prompt": "painting, drawing, illustration, glitch, deformed, mutated, cross-eyed, ugly, disfigured",
1028
+ },
1029
+ {
1030
+ "name": "3D Model",
1031
+ "prompt": "professional 3d model, octane render, highly detailed, volumetric, dramatic lighting",
1032
+ "negative_prompt": "ugly, deformed, noisy, low poly, blurry, painting",
1033
+ },
1034
+ ]
1035
+
1036
+
1037
+ optimization_list = {
1038
+ "None": [28, 7., 'Euler a', False, 'None', 1.],
1039
+ "Default": [28, 7., 'Euler a', False, 'None', 1.],
1040
+ "SPO": [28, 7., 'Euler a', True, 'loras/spo_sdxl_10ep_4k-data_lora_diffusers.safetensors', 1.],
1041
+ "DPO": [28, 7., 'Euler a', True, 'loras/sdxl-DPO-LoRA.safetensors', 1.],
1042
+ "DPO Turbo": [8, 2.5, 'LCM', True, 'loras/sd_xl_dpo_turbo_lora_v1-128dim.safetensors', 1.],
1043
+ "SDXL Turbo": [8, 2.5, 'LCM', True, 'loras/sd_xl_turbo_lora_v1.safetensors', 1.],
1044
+ "Hyper-SDXL 12step": [12, 5., 'TCD', True, 'loras/Hyper-SDXL-12steps-CFG-lora.safetensors', 1.],
1045
+ "Hyper-SDXL 8step": [8, 5., 'TCD', True, 'loras/Hyper-SDXL-8steps-CFG-lora.safetensors', 1.],
1046
+ "Hyper-SDXL 4step": [4, 0, 'TCD', True, 'loras/Hyper-SDXL-4steps-lora.safetensors', 1.],
1047
+ "Hyper-SDXL 2step": [2, 0, 'TCD', True, 'loras/Hyper-SDXL-2steps-lora.safetensors', 1.],
1048
+ "Hyper-SDXL 1step": [1, 0, 'TCD', True, 'loras/Hyper-SDXL-1steps-lora.safetensors', 1.],
1049
+ "PCM 16step": [16, 4., 'Euler a trailing', True, 'loras/pcm_sdxl_normalcfg_16step_converted.safetensors', 1.],
1050
+ "PCM 8step": [8, 4., 'Euler a trailing', True, 'loras/pcm_sdxl_normalcfg_8step_converted.safetensors', 1.],
1051
+ "PCM 4step": [4, 2., 'Euler a trailing', True, 'loras/pcm_sdxl_smallcfg_4step_converted.safetensors', 1.],
1052
+ "PCM 2step": [2, 1., 'Euler a trailing', True, 'loras/pcm_sdxl_smallcfg_2step_converted.safetensors', 1.],
1053
+ }
1054
+
1055
+
1056
+ def set_optimization(opt, steps_gui, cfg_gui, sampler_gui, clip_skip_gui, lora_gui, lora_scale_gui):
1057
+ if not opt in list(optimization_list.keys()): opt = "None"
1058
+ def_steps_gui = 28
1059
+ def_cfg_gui = 7.
1060
+ steps = optimization_list.get(opt, "None")[0]
1061
+ cfg = optimization_list.get(opt, "None")[1]
1062
+ sampler = optimization_list.get(opt, "None")[2]
1063
+ clip_skip = optimization_list.get(opt, "None")[3]
1064
+ lora = optimization_list.get(opt, "None")[4]
1065
+ lora_scale = optimization_list.get(opt, "None")[5]
1066
+ if opt == "None":
1067
+ steps = max(steps_gui, def_steps_gui)
1068
+ cfg = max(cfg_gui, def_cfg_gui)
1069
+ clip_skip = clip_skip_gui
1070
+ elif opt == "SPO" or opt == "DPO":
1071
+ steps = max(steps_gui, def_steps_gui)
1072
+ cfg = max(cfg_gui, def_cfg_gui)
1073
+
1074
+ return gr.update(value=steps), gr.update(value=cfg), gr.update(value=sampler),\
1075
+ gr.update(value=clip_skip), gr.update(value=lora), gr.update(value=lora_scale),
1076
+
1077
+
1078
+ # [sampler_gui, steps_gui, cfg_gui, clip_skip_gui, img_width_gui, img_height_gui, optimization_gui]
1079
+ preset_sampler_setting = {
1080
+ "None": ["Euler a", 28, 7., True, 1024, 1024, "None"],
1081
+ "Anime 3:4 Fast": ["LCM", 8, 2.5, True, 896, 1152, "DPO Turbo"],
1082
+ "Anime 3:4 Standard": ["Euler a", 28, 7., True, 896, 1152, "None"],
1083
+ "Anime 3:4 Heavy": ["Euler a", 40, 7., True, 896, 1152, "None"],
1084
+ "Anime 1:1 Fast": ["LCM", 8, 2.5, True, 1024, 1024, "DPO Turbo"],
1085
+ "Anime 1:1 Standard": ["Euler a", 28, 7., True, 1024, 1024, "None"],
1086
+ "Anime 1:1 Heavy": ["Euler a", 40, 7., True, 1024, 1024, "None"],
1087
+ "Photo 3:4 Fast": ["LCM", 8, 2.5, False, 896, 1152, "DPO Turbo"],
1088
+ "Photo 3:4 Standard": ["DPM++ 2M Karras", 28, 7., False, 896, 1152, "None"],
1089
+ "Photo 3:4 Heavy": ["DPM++ 2M Karras", 40, 7., False, 896, 1152, "None"],
1090
+ "Photo 1:1 Fast": ["LCM", 8, 2.5, False, 1024, 1024, "DPO Turbo"],
1091
+ "Photo 1:1 Standard": ["DPM++ 2M Karras", 28, 7., False, 1024, 1024, "None"],
1092
+ "Photo 1:1 Heavy": ["DPM++ 2M Karras", 40, 7., False, 1024, 1024, "None"],
1093
+ }
1094
+
1095
+
1096
+ def set_sampler_settings(sampler_setting):
1097
+ if not sampler_setting in list(preset_sampler_setting.keys()) or sampler_setting == "None":
1098
+ return gr.update(value="Euler a"), gr.update(value=28), gr.update(value=7.), gr.update(value=True),\
1099
+ gr.update(value=1024), gr.update(value=1024), gr.update(value="None")
1100
+ v = preset_sampler_setting.get(sampler_setting, ["Euler a", 28, 7., True, 1024, 1024])
1101
+ # sampler, steps, cfg, clip_skip, width, height, optimization
1102
+ return gr.update(value=v[0]), gr.update(value=v[1]), gr.update(value=v[2]), gr.update(value=v[3]),\
1103
+ gr.update(value=v[4]), gr.update(value=v[5]), gr.update(value=v[6])
1104
+
1105
+
1106
+ preset_styles = {k["name"]: (k["prompt"], k["negative_prompt"]) for k in style_list}
1107
+ preset_quality = {k["name"]: (k["prompt"], k["negative_prompt"]) for k in quality_prompt_list}
1108
+
1109
+
1110
+ def process_style_prompt(prompt: str, neg_prompt: str, styles_key: str = "None", quality_key: str = "None", type: str = "Auto"):
1111
+ def to_list(s):
1112
+ return [x.strip() for x in s.split(",") if not s == ""]
1113
+
1114
+ def list_sub(a, b):
1115
+ return [e for e in a if e not in b]
1116
+
1117
+ def list_uniq(l):
1118
+ return sorted(set(l), key=l.index)
1119
+
1120
+ animagine_ps = to_list("anime artwork, anime style, vibrant, studio anime, highly detailed, masterpiece, best quality, very aesthetic, absurdres")
1121
+ animagine_nps = to_list("lowres, (bad), text, error, fewer, extra, missing, worst quality, jpeg artifacts, low quality, watermark, unfinished, displeasing, oldest, early, chromatic aberration, signature, extra digits, artistic error, username, scan, [abstract]")
1122
+ pony_ps = to_list("source_anime, score_9, score_8_up, score_7_up, masterpiece, best quality, very aesthetic, absurdres")
1123
+ pony_nps = to_list("source_pony, source_furry, source_cartoon, score_6, score_5, score_4, busty, ugly face, mutated hands, low res, blurry face, black and white, the simpsons, overwatch, apex legends")
1124
+ prompts = to_list(prompt)
1125
+ neg_prompts = to_list(neg_prompt)
1126
+
1127
+ all_styles_ps = []
1128
+ all_styles_nps = []
1129
+ for d in style_list:
1130
+ all_styles_ps.extend(to_list(str(d.get("prompt", ""))))
1131
+ all_styles_nps.extend(to_list(str(d.get("negative_prompt", ""))))
1132
+
1133
+ all_quality_ps = []
1134
+ all_quality_nps = []
1135
+ for d in quality_prompt_list:
1136
+ all_quality_ps.extend(to_list(str(d.get("prompt", ""))))
1137
+ all_quality_nps.extend(to_list(str(d.get("negative_prompt", ""))))
1138
+
1139
+ quality_ps = to_list(preset_quality[quality_key][0])
1140
+ quality_nps = to_list(preset_quality[quality_key][1])
1141
+ styles_ps = to_list(preset_styles[styles_key][0])
1142
+ styles_nps = to_list(preset_styles[styles_key][1])
1143
+
1144
+ prompts = list_sub(prompts, animagine_ps + pony_ps + all_styles_ps + all_quality_ps)
1145
+ neg_prompts = list_sub(neg_prompts, animagine_nps + pony_nps + all_styles_nps + all_quality_nps)
1146
+
1147
+ last_empty_p = [""] if not prompts and type != "None" and type != "Auto" and styles_key != "None" and quality_key != "None" else []
1148
+ last_empty_np = [""] if not neg_prompts and type != "None" and type != "Auto" and styles_key != "None" and quality_key != "None" else []
1149
+
1150
+ if type == "Animagine":
1151
+ prompts = prompts + animagine_ps
1152
+ neg_prompts = neg_prompts + animagine_nps
1153
+ elif type == "Pony":
1154
+ prompts = prompts + pony_ps
1155
+ neg_prompts = neg_prompts + pony_nps
1156
+
1157
+ prompts = prompts + styles_ps + quality_ps
1158
+ neg_prompts = neg_prompts + styles_nps + quality_nps
1159
+
1160
+ prompt = ", ".join(list_uniq(prompts) + last_empty_p)
1161
+ neg_prompt = ", ".join(list_uniq(neg_prompts) + last_empty_np)
1162
+
1163
+ return gr.update(value=prompt), gr.update(value=neg_prompt), gr.update(value=type)
1164
+
1165
+
1166
+ def set_quick_presets(genre:str = "None", type:str = "Auto", speed:str = "None", aspect:str = "None"):
1167
+ quality = "None"
1168
+ style = "None"
1169
+ sampler = "None"
1170
+ opt = "None"
1171
+
1172
+ if genre == "Anime":
1173
+ if type != "None" and type != "Auto": style = "Anime"
1174
+ if aspect == "1:1":
1175
+ if speed == "Heavy":
1176
+ sampler = "Anime 1:1 Heavy"
1177
+ elif speed == "Fast":
1178
+ sampler = "Anime 1:1 Fast"
1179
+ else:
1180
+ sampler = "Anime 1:1 Standard"
1181
+ elif aspect == "3:4":
1182
+ if speed == "Heavy":
1183
+ sampler = "Anime 3:4 Heavy"
1184
+ elif speed == "Fast":
1185
+ sampler = "Anime 3:4 Fast"
1186
+ else:
1187
+ sampler = "Anime 3:4 Standard"
1188
+ if type == "Pony":
1189
+ quality = "Pony Anime Common"
1190
+ elif type == "Animagine":
1191
+ quality = "Animagine Common"
1192
+ else:
1193
+ quality = "None"
1194
+ elif genre == "Photo":
1195
+ if type != "None" and type != "Auto": style = "Photographic"
1196
+ if aspect == "1:1":
1197
+ if speed == "Heavy":
1198
+ sampler = "Photo 1:1 Heavy"
1199
+ elif speed == "Fast":
1200
+ sampler = "Photo 1:1 Fast"
1201
+ else:
1202
+ sampler = "Photo 1:1 Standard"
1203
+ elif aspect == "3:4":
1204
+ if speed == "Heavy":
1205
+ sampler = "Photo 3:4 Heavy"
1206
+ elif speed == "Fast":
1207
+ sampler = "Photo 3:4 Fast"
1208
+ else:
1209
+ sampler = "Photo 3:4 Standard"
1210
+ if type == "Pony":
1211
+ quality = "Pony Common"
1212
+ else:
1213
+ quality = "None"
1214
+
1215
+ if speed == "Fast":
1216
+ opt = "DPO Turbo"
1217
+ if genre == "Anime" and type != "Pony" and type != "Auto": quality = "Animagine Light v3.1"
1218
+
1219
+ return gr.update(value=quality), gr.update(value=style), gr.update(value=sampler), gr.update(value=opt), gr.update(value=type)
1220
+
1221
+
1222
+ textual_inversion_dict = {}
1223
+ try:
1224
+ with open('textual_inversion_dict.json', encoding='utf-8') as f:
1225
+ textual_inversion_dict = json.load(f)
1226
+ except Exception:
1227
+ pass
1228
+ textual_inversion_file_token_list = []
1229
+
1230
+
1231
+ def get_tupled_embed_list(embed_list):
1232
+ global textual_inversion_file_list
1233
+ tupled_list = []
1234
+ for file in embed_list:
1235
+ token = textual_inversion_dict.get(Path(file).name, [Path(file).stem.replace(",",""), False])[0]
1236
+ tupled_list.append((token, file))
1237
+ textual_inversion_file_token_list.append(token)
1238
+ return tupled_list
1239
+
1240
+
1241
+ def set_textual_inversion_prompt(textual_inversion_gui, prompt_gui, neg_prompt_gui, prompt_syntax_gui):
1242
+ ti_tags = list(textual_inversion_dict.values()) + textual_inversion_file_token_list
1243
+ tags = prompt_gui.split(",") if prompt_gui else []
1244
+ prompts = []
1245
+ for tag in tags:
1246
+ tag = str(tag).strip()
1247
+ if tag and not tag in ti_tags:
1248
+ prompts.append(tag)
1249
+ ntags = neg_prompt_gui.split(",") if neg_prompt_gui else []
1250
+ neg_prompts = []
1251
+ for tag in ntags:
1252
+ tag = str(tag).strip()
1253
+ if tag and not tag in ti_tags:
1254
+ neg_prompts.append(tag)
1255
+ ti_prompts = []
1256
+ ti_neg_prompts = []
1257
+ for ti in textual_inversion_gui:
1258
+ tokens = textual_inversion_dict.get(Path(ti).name, [Path(ti).stem.replace(",",""), False])
1259
+ is_positive = tokens[1] == True or "positive" in Path(ti).parent.name
1260
+ if is_positive: # positive prompt
1261
+ ti_prompts.append(tokens[0])
1262
+ else: # negative prompt (default)
1263
+ ti_neg_prompts.append(tokens[0])
1264
+ empty = [""]
1265
+ prompt = ", ".join(prompts + ti_prompts + empty)
1266
+ neg_prompt = ", ".join(neg_prompts + ti_neg_prompts + empty)
1267
+ return gr.update(value=prompt), gr.update(value=neg_prompt),
1268
+
1269
+
1270
+ def get_model_pipeline(repo_id: str):
1271
+ from huggingface_hub import HfApi
1272
+ api = HfApi(token=HF_TOKEN)
1273
+ default = "StableDiffusionPipeline"
1274
+ try:
1275
+ if not is_repo_name(repo_id): return default
1276
+ model = api.model_info(repo_id=repo_id, timeout=5.0)
1277
+ except Exception:
1278
+ return default
1279
+ if model.private or model.gated: return default
1280
+ tags = model.tags
1281
+ if not 'diffusers' in tags: return default
1282
+ if 'diffusers:FluxPipeline' in tags:
1283
+ return "FluxPipeline"
1284
+ if 'diffusers:StableDiffusionXLPipeline' in tags:
1285
+ return "StableDiffusionXLPipeline"
1286
+ elif 'diffusers:StableDiffusionPipeline' in tags:
1287
+ return "StableDiffusionPipeline"
1288
+ else:
1289
+ return default
1290
+
packages.txt CHANGED
@@ -1,3 +1,3 @@
1
  git-lfs
2
- aria2
3
  ffmpeg
 
1
  git-lfs
2
+ aria2 -y
3
  ffmpeg
pre-requirements.txt DELETED
@@ -1 +0,0 @@
1
- pip>=23.0.0
 
 
requirements.txt CHANGED
@@ -1,13 +1,4 @@
1
- stablepy==0.6.5
2
- torch==2.5.1
3
- diffusers
4
  gdown
5
- opencv-python
6
- unidecode
7
- pydantic==2.10.6
8
- huggingface_hub
9
- hf_transfer
10
- hf_xet
11
- spaces
12
- gradio==5.44.1
13
- matplotlib-inline
 
1
+ git+https://github.com/R3gm/stablepy.git@flux_beta
2
+ torch==2.2.0
 
3
  gdown
4
+ opencv-python
 
 
 
 
 
 
 
 
stablepy_model.py ADDED
File without changes
utils.py CHANGED
@@ -1,714 +1,50 @@
1
- import os
2
- import re
3
  import gradio as gr
4
- from constants import (
5
- DIFFUSERS_FORMAT_LORAS,
6
- CIVITAI_API_KEY,
7
- HF_TOKEN,
8
- MODEL_TYPE_CLASS,
9
- DIRECTORY_LORAS,
10
- DIRECTORY_MODELS,
11
- DIFFUSECRAFT_CHECKPOINT_NAME,
12
- CACHE_HF_ROOT,
13
- CACHE_HF,
14
- STORAGE_ROOT,
15
- )
16
- from huggingface_hub import HfApi, get_hf_file_metadata, snapshot_download
17
- from diffusers import DiffusionPipeline
18
- from huggingface_hub import model_info as model_info_data
19
- from diffusers.pipelines.pipeline_loading_utils import variant_compatible_siblings
20
- from stablepy.diffusers_vanilla.utils import checkpoint_model_type
21
- from pathlib import PosixPath
22
- from unidecode import unidecode
23
- import urllib.parse
24
- import copy
25
- import requests
26
- from requests.adapters import HTTPAdapter
27
- from urllib3.util import Retry
28
- import shutil
29
- import subprocess
30
- import json
31
- import html as _html
32
-
33
- IS_ZERO_GPU = bool(os.getenv("SPACES_ZERO_GPU"))
34
- USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:127.0) Gecko/20100101 Firefox/127.0'
35
- MODEL_ARCH = {
36
- 'stable-diffusion-xl-v1-base/lora': "Stable Diffusion XL (Illustrious, Pony, NoobAI)",
37
- 'stable-diffusion-v1/lora': "Stable Diffusion 1.5",
38
- 'flux-1-dev/lora': "Flux",
39
- }
40
-
41
-
42
- def read_safetensors_header_from_url(url: str):
43
- """Read safetensors header from a remote Hugging Face file."""
44
- meta = get_hf_file_metadata(url)
45
-
46
- # Step 1: first 8 bytes → header length
47
- resp = requests.get(meta.location, headers={"Range": "bytes=0-7"})
48
- resp.raise_for_status()
49
- header_len = int.from_bytes(resp.content, "little")
50
-
51
- # Step 2: fetch full header JSON
52
- end = 8 + header_len - 1
53
- resp = requests.get(meta.location, headers={"Range": f"bytes=8-{end}"})
54
- resp.raise_for_status()
55
- header_json = resp.content.decode("utf-8")
56
-
57
- return json.loads(header_json)
58
-
59
-
60
- def read_safetensors_header_from_file(path: str):
61
- """Read safetensors header from a local file."""
62
- with open(path, "rb") as f:
63
- # Step 1: first 8 bytes → header length
64
- header_len = int.from_bytes(f.read(8), "little")
65
-
66
- # Step 2: read header JSON
67
- header_json = f.read(header_len).decode("utf-8")
68
-
69
- return json.loads(header_json)
70
-
71
-
72
- class LoraHeaderInformation:
73
- """
74
- Encapsulates parsed info from a LoRA JSON header and provides
75
- a compact HTML summary via .to_html().
76
- """
77
-
78
- def __init__(self, json_data):
79
- self.original_json = copy.deepcopy(json_data or {})
80
-
81
- # Check if text encoder was trained
82
- # guard for json_data being a mapping
83
- try:
84
- self.text_encoder_trained = any("text_model" in ln for ln in json_data)
85
- except Exception:
86
- self.text_encoder_trained = False
87
-
88
- # Metadata (may be None)
89
- metadata = (json_data or {}).get("__metadata__", None)
90
- self.metadata = metadata
91
-
92
- # Default values
93
- self.architecture = "undefined"
94
- self.prediction_type = "undefined"
95
- self.base_model = "undefined"
96
- self.author = "undefined"
97
- self.title = "undefined"
98
- self.common_tags_list = []
99
-
100
- if metadata:
101
- self.architecture = MODEL_ARCH.get(
102
- metadata.get('modelspec.architecture', None),
103
- "undefined"
104
- )
105
-
106
- self.prediction_type = metadata.get('modelspec.prediction_type', "undefined")
107
- self.base_model = metadata.get('ss_sd_model_name', "undefined")
108
- self.author = metadata.get('modelspec.author', "undefined")
109
- self.title = metadata.get('modelspec.title', "undefined")
110
-
111
- base_model_hash = metadata.get('ss_new_sd_model_hash', None) # SHA256
112
- # AUTOV1 ss_sd_model_hash
113
- # https://civitai.com/api/v1/model-versions/by-hash/{base_model_hash} # Info
114
- if base_model_hash:
115
- self.base_model += f" hash={base_model_hash}"
116
-
117
- # Extract tags
118
- try:
119
- tags = metadata.get('ss_tag_frequency') if "ss_tag_frequency" in metadata else metadata.get('ss_datasets', "")
120
- tags = json.loads(tags) if tags else ""
121
-
122
- if isinstance(tags, list):
123
- tags = tags[0].get("tag_frequency", {})
124
-
125
- if tags:
126
- self.common_tags_list = list(tags[list(tags.keys())[0]].keys())
127
- except Exception:
128
- self.common_tags_list = []
129
-
130
- def to_dict(self):
131
- """Return a plain dict summary of parsed fields."""
132
- return {
133
- "architecture": self.architecture,
134
- "prediction_type": self.prediction_type,
135
- "base_model": self.base_model,
136
- "author": self.author,
137
- "title": self.title,
138
- "text_encoder_trained": bool(self.text_encoder_trained),
139
- "common_tags": self.common_tags_list,
140
- }
141
-
142
- def to_html(self, limit_tags=20):
143
- """
144
- Return a compact HTML snippet (string) showing the parsed info
145
- in a small font. Values are HTML-escaped.
146
- """
147
- # helper to escape
148
- esc = _html.escape
149
-
150
- rows = [
151
- ("Title", esc(str(self.title))),
152
- ("Author", esc(str(self.author))),
153
- ("Architecture", esc(str(self.architecture))),
154
- ("Base model", esc(str(self.base_model))),
155
- ("Prediction type", esc(str(self.prediction_type))),
156
- ("Text encoder trained", esc(str(self.text_encoder_trained))),
157
- ("Reference tags", esc(str(", ".join(self.common_tags_list[:limit_tags])))),
158
- ]
159
-
160
- # small, compact table with inline styling (small font)
161
- html_rows = "".join(
162
- f"<tr><th style='text-align:left;padding:2px 6px;white-space:nowrap'>{k}</th>"
163
- f"<td style='padding:2px 6px'>{v}</td></tr>"
164
- for k, v in rows
165
- )
166
-
167
- html_snippet = (
168
- "<div style='font-family:system-ui, -apple-system, \"Segoe UI\", Roboto, "
169
- "Helvetica, Arial, \"Noto Sans\", sans-serif; font-size:12px; line-height:1.2; "
170
- "'>"
171
- f"<table style='border-collapse:collapse; font-size:12px;'>"
172
- f"{html_rows}"
173
- "</table>"
174
- "</div>"
175
- )
176
-
177
- return html_snippet
178
-
179
-
180
- def request_json_data(url):
181
- model_version_id = url.split('/')[-1]
182
- if "?modelVersionId=" in model_version_id:
183
- match = re.search(r'modelVersionId=(\d+)', url)
184
- model_version_id = match.group(1)
185
-
186
- endpoint_url = f"https://civitai.com/api/v1/model-versions/{model_version_id}"
187
-
188
- params = {}
189
- headers = {'User-Agent': USER_AGENT, 'content-type': 'application/json'}
190
- session = requests.Session()
191
- retries = Retry(total=5, backoff_factor=1, status_forcelist=[500, 502, 503, 504])
192
- session.mount("https://", HTTPAdapter(max_retries=retries))
193
-
194
- try:
195
- result = session.get(endpoint_url, params=params, headers=headers, stream=True, timeout=(3.0, 15))
196
- result.raise_for_status()
197
- json_data = result.json()
198
- return json_data if json_data else None
199
- except Exception as e:
200
- print(f"Error: {e}")
201
- return None
202
-
203
-
204
- class ModelInformation:
205
- def __init__(self, json_data):
206
- self.model_version_id = json_data.get("id", "")
207
- self.model_id = json_data.get("modelId", "")
208
- self.download_url = json_data.get("downloadUrl", "")
209
- self.model_url = f"https://civitai.com/models/{self.model_id}?modelVersionId={self.model_version_id}"
210
- self.filename_url = next(
211
- (v.get("name", "") for v in json_data.get("files", []) if str(self.model_version_id) in v.get("downloadUrl", "") and v.get("type", "Model") == "Model"), ""
212
- )
213
- self.filename_url = self.filename_url if self.filename_url else ""
214
- self.description = json_data.get("description", "")
215
- if self.description is None:
216
- self.description = ""
217
- self.model_name = json_data.get("model", {}).get("name", "")
218
- self.model_type = json_data.get("model", {}).get("type", "")
219
- self.nsfw = json_data.get("model", {}).get("nsfw", False)
220
- self.poi = json_data.get("model", {}).get("poi", False)
221
- self.images = [img.get("url", "") for img in json_data.get("images", [])]
222
- self.example_prompt = json_data.get("trainedWords", [""])[0] if json_data.get("trainedWords") else ""
223
- self.original_json = copy.deepcopy(json_data)
224
-
225
-
226
- def get_civit_params(url):
227
- try:
228
- json_data = request_json_data(url)
229
- mdc = ModelInformation(json_data)
230
- if mdc.download_url and mdc.filename_url:
231
- return mdc.download_url, mdc.filename_url, mdc.model_url
232
- else:
233
- ValueError("Invalid Civitai model URL")
234
- except Exception as e:
235
- print(f"Error retrieving Civitai metadata: {e} — fallback to direct download")
236
- return url, None, None
237
-
238
-
239
- def civ_redirect_down(url, dir_, civitai_api_key, romanize, alternative_name):
240
- filename_base = filename = None
241
-
242
- if alternative_name:
243
- output_path = os.path.join(dir_, alternative_name)
244
- if os.path.exists(output_path):
245
- return output_path, alternative_name
246
-
247
- # Follow the redirect to get the actual download URL
248
- curl_command = (
249
- f'curl -L -sI --connect-timeout 5 --max-time 5 '
250
- f'-H "Content-Type: application/json" '
251
- f'-H "Authorization: Bearer {civitai_api_key}" "{url}"'
252
- )
253
-
254
- headers = os.popen(curl_command).read()
255
-
256
- # Look for the redirected "Location" URL
257
- location_match = re.search(r'location: (.+)', headers, re.IGNORECASE)
258
-
259
- if location_match:
260
- redirect_url = location_match.group(1).strip()
261
-
262
- # Extract the filename from the redirect URL's "Content-Disposition"
263
- filename_match = re.search(r'filename%3D%22(.+?)%22', redirect_url)
264
- if filename_match:
265
- encoded_filename = filename_match.group(1)
266
- # Decode the URL-encoded filename
267
- decoded_filename = urllib.parse.unquote(encoded_filename)
268
-
269
- filename = unidecode(decoded_filename) if romanize else decoded_filename
270
- # print(f"Filename redirect: {filename}")
271
-
272
- filename_base = alternative_name if alternative_name else filename
273
- if not filename_base:
274
- return None, None
275
- elif os.path.exists(os.path.join(dir_, filename_base)):
276
- return os.path.join(dir_, filename_base), filename_base
277
-
278
- aria2_command = (
279
- f'aria2c --console-log-level=error --summary-interval=10 -c -x 16 '
280
- f'-k 1M -s 16 -d "{dir_}" -o "{filename_base}" "{redirect_url}"'
281
- )
282
- r_code = os.system(aria2_command) # noqa
283
-
284
- # if r_code != 0:
285
- # raise RuntimeError(f"Failed to download file: {filename_base}. Error code: {r_code}")
286
-
287
- output_path = os.path.join(dir_, filename_base)
288
- if not os.path.exists(output_path):
289
- return None, filename_base
290
-
291
- return output_path, filename_base
292
-
293
-
294
- def civ_api_down(url, dir_, civitai_api_key, civ_filename):
295
- """
296
- This method is susceptible to being blocked because it generates a lot of temp redirect links with aria2c.
297
- If an API key limit is reached, generating a new API key and using it can fix the issue.
298
- """
299
- output_path = None
300
-
301
- url_dl = url + f"?token={civitai_api_key}"
302
- if not civ_filename:
303
- aria2_command = f'aria2c -c -x 1 -s 1 -d "{dir_}" "{url_dl}"'
304
- os.system(aria2_command)
305
- else:
306
- output_path = os.path.join(dir_, civ_filename)
307
- if not os.path.exists(output_path):
308
- aria2_command = (
309
- f'aria2c --console-log-level=error --summary-interval=10 -c -x 16 '
310
- f'-k 1M -s 16 -d "{dir_}" -o "{civ_filename}" "{url_dl}"'
311
- )
312
- os.system(aria2_command)
313
-
314
- return output_path
315
-
316
-
317
- def drive_down(url, dir_):
318
- import gdown
319
-
320
- output_path = None
321
-
322
- drive_id, _ = gdown.parse_url.parse_url(url, warning=False)
323
- dir_files = os.listdir(dir_)
324
-
325
- for dfile in dir_files:
326
- if drive_id in dfile:
327
- output_path = os.path.join(dir_, dfile)
328
- break
329
-
330
- if not output_path:
331
- original_path = gdown.download(url, f"{dir_}/", fuzzy=True)
332
-
333
- dir_name, base_name = os.path.split(original_path)
334
- name, ext = base_name.rsplit(".", 1)
335
- new_name = f"{name}_{drive_id}.{ext}"
336
- output_path = os.path.join(dir_name, new_name)
337
-
338
- os.rename(original_path, output_path)
339
-
340
- return output_path
341
-
342
-
343
- def hf_down(url, dir_, hf_token, romanize):
344
- url = url.replace("?download=true", "")
345
- # url = urllib.parse.quote(url, safe=':/') # fix encoding
346
-
347
- filename = unidecode(url.split('/')[-1]) if romanize else url.split('/')[-1]
348
- output_path = os.path.join(dir_, filename)
349
-
350
- if os.path.exists(output_path):
351
- return output_path
352
-
353
- if "/blob/" in url:
354
- url = url.replace("/blob/", "/resolve/")
355
-
356
- if hf_token:
357
- user_header = f'"Authorization: Bearer {hf_token}"'
358
- os.system(f"aria2c --console-log-level=error --summary-interval=10 --header={user_header} -c -x 16 -k 1M -s 16 {url} -d {dir_} -o {filename}")
359
- else:
360
- os.system(f"aria2c --optimize-concurrent-downloads --console-log-level=error --summary-interval=10 -c -x 16 -k 1M -s 16 {url} -d {dir_} -o {filename}")
361
-
362
- return output_path
363
-
364
-
365
- def download_things(directory, url, hf_token="", civitai_api_key="", romanize=False):
366
- url = url.strip()
367
- downloaded_file_path = None
368
-
369
- if "drive.google.com" in url:
370
- downloaded_file_path = drive_down(url, directory)
371
- elif "huggingface.co" in url:
372
- downloaded_file_path = hf_down(url, directory, hf_token, romanize)
373
- elif "civitai.com" in url:
374
- if not civitai_api_key:
375
- msg = "You need an API key to download Civitai models."
376
- print(f"\033[91m{msg}\033[0m")
377
- gr.Warning(msg)
378
- return None
379
-
380
- url, civ_filename, civ_page = get_civit_params(url)
381
- if civ_page and not IS_ZERO_GPU:
382
- print(f"\033[92mCivitai model: {civ_filename} [page: {civ_page}]\033[0m")
383
-
384
- downloaded_file_path, civ_filename = civ_redirect_down(url, directory, civitai_api_key, romanize, civ_filename)
385
-
386
- if not downloaded_file_path:
387
- msg = (
388
- "Download failed.\n"
389
- "If this is due to an API limit, generating a new API key may resolve the issue.\n"
390
- "Attempting to download using the old method..."
391
- )
392
- print(msg)
393
- gr.Warning(msg)
394
- downloaded_file_path = civ_api_down(url, directory, civitai_api_key, civ_filename)
395
- else:
396
- os.system(f"aria2c --console-log-level=error --summary-interval=10 -c -x 16 -k 1M -s 16 -d {directory} {url}")
397
-
398
- return downloaded_file_path
399
-
400
-
401
- def get_model_list(directory_path):
402
- model_list = []
403
- valid_extensions = {'.ckpt', '.pt', '.pth', '.safetensors', '.bin'}
404
-
405
- for filename in os.listdir(directory_path):
406
- if os.path.splitext(filename)[1] in valid_extensions:
407
- # name_without_extension = os.path.splitext(filename)[0]
408
- file_path = os.path.join(directory_path, filename)
409
- # model_list.append((name_without_extension, file_path))
410
- model_list.append(file_path)
411
- print('\033[34mFILE: ' + file_path + '\033[0m')
412
- return model_list
413
-
414
-
415
- def extract_parameters(input_string):
416
- parameters = {}
417
- input_string = input_string.replace("\n", "")
418
-
419
- if "Negative prompt:" not in input_string:
420
- if "Steps:" in input_string:
421
- input_string = input_string.replace("Steps:", "Negative prompt: Steps:")
422
- else:
423
- msg = "Generation data is invalid."
424
- gr.Warning(msg)
425
- print(msg)
426
- parameters["prompt"] = input_string
427
- return parameters
428
-
429
- parm = input_string.split("Negative prompt:")
430
- parameters["prompt"] = parm[0].strip()
431
- if "Steps:" not in parm[1]:
432
- parameters["neg_prompt"] = parm[1].strip()
433
- return parameters
434
- parm = parm[1].split("Steps:")
435
- parameters["neg_prompt"] = parm[0].strip()
436
- input_string = "Steps:" + parm[1]
437
-
438
- # Extracting Steps
439
- steps_match = re.search(r'Steps: (\d+)', input_string)
440
- if steps_match:
441
- parameters['Steps'] = int(steps_match.group(1))
442
-
443
- # Extracting Size
444
- size_match = re.search(r'Size: (\d+x\d+)', input_string)
445
- if size_match:
446
- parameters['Size'] = size_match.group(1)
447
- width, height = map(int, parameters['Size'].split('x'))
448
- parameters['width'] = width
449
- parameters['height'] = height
450
-
451
- # Extracting other parameters
452
- other_parameters = re.findall(r'([^,:]+): (.*?)(?=, [^,:]+:|$)', input_string)
453
- for param in other_parameters:
454
- parameters[param[0].strip()] = param[1].strip('"')
455
-
456
- return parameters
457
-
458
-
459
- def get_my_lora(link_url, romanize):
460
- l_name = ""
461
- for url in [url.strip() for url in link_url.split(',')]:
462
- if not os.path.exists(f"./loras/{url.split('/')[-1]}"):
463
- l_name = download_things(DIRECTORY_LORAS, url, HF_TOKEN, CIVITAI_API_KEY, romanize)
464
- new_lora_model_list = get_model_list(DIRECTORY_LORAS)
465
- new_lora_model_list.insert(0, "None")
466
- new_lora_model_list = new_lora_model_list + DIFFUSERS_FORMAT_LORAS
467
- msg_lora = "Downloaded"
468
- if l_name:
469
- msg_lora += f": <b>{l_name}</b>"
470
- print(msg_lora)
471
-
472
- try:
473
- # Works with non-Civitai loras.
474
- json_data = read_safetensors_header_from_file(l_name)
475
- metadata_lora = LoraHeaderInformation(json_data)
476
- msg_lora += "<br>" + metadata_lora.to_html()
477
- except Exception:
478
- pass
479
-
480
- return gr.update(
481
- choices=new_lora_model_list
482
- ), gr.update(
483
- choices=new_lora_model_list
484
- ), gr.update(
485
- choices=new_lora_model_list
486
- ), gr.update(
487
- choices=new_lora_model_list
488
- ), gr.update(
489
- choices=new_lora_model_list
490
- ), gr.update(
491
- choices=new_lora_model_list
492
- ), gr.update(
493
- choices=new_lora_model_list
494
- ), gr.update(
495
- value=msg_lora
496
- )
497
-
498
-
499
- def info_html(json_data, title, subtitle):
500
- return f"""
501
- <div style='padding: 0; border-radius: 10px;'>
502
- <p style='margin: 0; font-weight: bold;'>{title}</p>
503
- <details>
504
- <summary>Details</summary>
505
- <p style='margin: 0; font-weight: bold;'>{subtitle}</p>
506
- </details>
507
- </div>
508
- """
509
-
510
-
511
- def get_model_type(repo_id: str):
512
- api = HfApi(token=os.environ.get("HF_TOKEN")) # if use private or gated model
513
- default = "SD 1.5"
514
- try:
515
- if os.path.exists(repo_id):
516
- tag, _, _, _ = checkpoint_model_type(repo_id)
517
- return DIFFUSECRAFT_CHECKPOINT_NAME[tag]
518
- else:
519
- model = api.model_info(repo_id=repo_id, timeout=5.0)
520
- tags = model.tags
521
- for tag in tags:
522
- if tag in MODEL_TYPE_CLASS.keys():
523
- return MODEL_TYPE_CLASS.get(tag, default)
524
-
525
- except Exception:
526
- return default
527
- return default
528
-
529
-
530
- def restart_space(repo_id: str, factory_reboot: bool):
531
- api = HfApi(token=os.environ.get("HF_TOKEN"))
532
- try:
533
- runtime = api.get_space_runtime(repo_id=repo_id)
534
- if runtime.stage == "RUNNING":
535
- api.restart_space(repo_id=repo_id, factory_reboot=factory_reboot)
536
- print(f"Restarting space: {repo_id}")
537
- else:
538
- print(f"Space {repo_id} is in stage: {runtime.stage}")
539
- except Exception as e:
540
- print(e)
541
-
542
-
543
- def extract_exif_data(image):
544
- if image is None:
545
- return ""
546
-
547
- try:
548
- metadata_keys = ['parameters', 'metadata', 'prompt', 'Comment']
549
-
550
- for key in metadata_keys:
551
- if key in image.info:
552
- return image.info[key]
553
-
554
- return str(image.info)
555
-
556
- except Exception as e:
557
- return f"Error extracting metadata: {str(e)}"
558
-
559
-
560
- def create_mask_now(img, invert):
561
- import numpy as np
562
- import time
563
-
564
- time.sleep(0.5)
565
-
566
- transparent_image = img["layers"][0]
567
-
568
- # Extract the alpha channel
569
- alpha_channel = np.array(transparent_image)[:, :, 3]
570
-
571
- # Create a binary mask by thresholding the alpha channel
572
- binary_mask = alpha_channel > 1
573
-
574
- if invert:
575
- print("Invert")
576
- # Invert the binary mask so that the drawn shape is white and the rest is black
577
- binary_mask = np.invert(binary_mask)
578
-
579
- # Convert the binary mask to a 3-channel RGB mask
580
- rgb_mask = np.stack((binary_mask,) * 3, axis=-1)
581
-
582
- # Convert the mask to uint8
583
- rgb_mask = rgb_mask.astype(np.uint8) * 255
584
-
585
- return img["background"], rgb_mask
586
-
587
-
588
- def download_diffuser_repo(repo_name: str, model_type: str, revision: str = "main", token=True):
589
-
590
- variant = None
591
- if token is True and not os.environ.get("HF_TOKEN"):
592
- token = None
593
-
594
- if model_type == "SDXL":
595
- info = model_info_data(
596
- repo_name,
597
- token=token,
598
- revision=revision,
599
- timeout=5.0,
600
- )
601
-
602
- filenames = {sibling.rfilename for sibling in info.siblings}
603
- model_filenames, variant_filenames = variant_compatible_siblings(
604
- filenames, variant="fp16"
605
- )
606
-
607
- if len(variant_filenames):
608
- variant = "fp16"
609
-
610
- if model_type == "FLUX":
611
- cached_folder = snapshot_download(
612
- repo_id=repo_name,
613
- allow_patterns="transformer/*"
614
- )
615
- else:
616
- cached_folder = DiffusionPipeline.download(
617
- pretrained_model_name=repo_name,
618
- force_download=False,
619
- token=token,
620
- revision=revision,
621
- # mirror="https://hf-mirror.com",
622
- variant=variant,
623
- use_safetensors=True,
624
- trust_remote_code=False,
625
- timeout=5.0,
626
- )
627
-
628
- if isinstance(cached_folder, PosixPath):
629
- cached_folder = cached_folder.as_posix()
630
-
631
- # Task model
632
- # from huggingface_hub import hf_hub_download
633
- # hf_hub_download(
634
- # task_model,
635
- # filename="diffusion_pytorch_model.safetensors", # fix fp16 variant
636
- # )
637
-
638
- return cached_folder
639
-
640
-
641
- def get_folder_size_gb(folder_path):
642
- result = subprocess.run(["du", "-s", folder_path], capture_output=True, text=True)
643
-
644
- total_size_kb = int(result.stdout.split()[0])
645
- total_size_gb = total_size_kb / (1024 ** 2)
646
-
647
- return total_size_gb
648
-
649
-
650
- def get_used_storage_gb(path_storage=STORAGE_ROOT):
651
- try:
652
- used_gb = get_folder_size_gb(path_storage)
653
- print(f"Used Storage: {used_gb:.2f} GB")
654
- except Exception as e:
655
- used_gb = 999
656
- print(f"Error while retrieving the used storage: {e}.")
657
-
658
- return used_gb
659
-
660
-
661
- def delete_model(removal_candidate):
662
- print(f"Removing: {removal_candidate}")
663
-
664
- if os.path.exists(removal_candidate):
665
- os.remove(removal_candidate)
666
- else:
667
- diffusers_model = f"{CACHE_HF}{DIRECTORY_MODELS}--{removal_candidate.replace('/', '--')}"
668
- if os.path.isdir(diffusers_model):
669
- shutil.rmtree(diffusers_model)
670
-
671
-
672
- def clear_hf_cache():
673
- """
674
- Clears the entire Hugging Face cache at ~/.cache/huggingface.
675
- Hugging Face will re-download models as needed later.
676
- """
677
- try:
678
- if os.path.exists(CACHE_HF):
679
- shutil.rmtree(CACHE_HF, ignore_errors=True)
680
- print(f"Hugging Face cache cleared: {CACHE_HF}")
681
- else:
682
- print(f"No Hugging Face cache found at: {CACHE_HF}")
683
- except Exception as e:
684
- print(f"Error clearing Hugging Face cache: {e}")
685
-
686
-
687
- def progress_step_bar(step, total):
688
- # Calculate the percentage for the progress bar width
689
- percentage = min(100, ((step / total) * 100))
690
-
691
- return f"""
692
- <div style="position: relative; width: 100%; background-color: gray; border-radius: 5px; overflow: hidden;">
693
- <div style="width: {percentage}%; height: 17px; background-color: #800080; transition: width 0.5s;"></div>
694
- <div style="position: absolute; width: 100%; text-align: center; color: white; top: 0; line-height: 19px; font-size: 13px;">
695
- {int(percentage)}%
696
- </div>
697
- </div>
698
- """
699
-
700
-
701
- def html_template_message(msg):
702
- return f"""
703
- <div style="position: relative; width: 100%; background-color: gray; border-radius: 5px; overflow: hidden;">
704
- <div style="width: 0%; height: 17px; background-color: #800080; transition: width 0.5s;"></div>
705
- <div style="position: absolute; width: 100%; text-align: center; color: white; top: 0; line-height: 19px; font-size: 14px; font-weight: bold; text-shadow: 1px 1px 2px black;">
706
- {msg}
707
- </div>
708
- </div>
709
- """
710
-
711
-
712
- def escape_html(text):
713
- """Escapes HTML special characters in the input text."""
714
- return text.replace("<", "&lt;").replace(">", "&gt;").replace("\n", "<br>")
 
 
 
1
  import gradio as gr
2
+ from dartrs.v2 import AspectRatioTag, LengthTag, RatingTag, IdentityTag
3
+
4
+
5
+ V2_ASPECT_RATIO_OPTIONS: list[AspectRatioTag] = [
6
+ "ultra_wide",
7
+ "wide",
8
+ "square",
9
+ "tall",
10
+ "ultra_tall",
11
+ ]
12
+ V2_RATING_OPTIONS: list[RatingTag] = [
13
+ "sfw",
14
+ "general",
15
+ "sensitive",
16
+ "nsfw",
17
+ "questionable",
18
+ "explicit",
19
+ ]
20
+ V2_LENGTH_OPTIONS: list[LengthTag] = [
21
+ "very_short",
22
+ "short",
23
+ "medium",
24
+ "long",
25
+ "very_long",
26
+ ]
27
+ V2_IDENTITY_OPTIONS: list[IdentityTag] = [
28
+ "none",
29
+ "lax",
30
+ "strict",
31
+ ]
32
+
33
+
34
+ # ref: https://qiita.com/tregu148/items/fccccbbc47d966dd2fc2
35
+ def gradio_copy_text(_text: None):
36
+ gr.Info("Copied!")
37
+
38
+
39
+ COPY_ACTION_JS = """\
40
+ (inputs, _outputs) => {
41
+ // inputs is the string value of the input_text
42
+ if (inputs.trim() !== "") {
43
+ navigator.clipboard.writeText(inputs);
44
+ }
45
+ }"""
46
+
47
+
48
+ def gradio_copy_prompt(prompt: str):
49
+ gr.Info("Copied!")
50
+ return prompt