Files changed (9) hide show
  1. .gitignore +0 -207
  2. README.md +1 -1
  3. app.py +245 -473
  4. constants.py +47 -186
  5. image_processor.py +2 -2
  6. packages.txt +1 -0
  7. pre-requirements.txt +0 -1
  8. requirements.txt +3 -12
  9. utils.py +485 -729
.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,7 +4,7 @@ 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
 
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
app.py CHANGED
@@ -1,22 +1,17 @@
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
- PROMPT_WEIGHT_OPTIONS_PRIORITY,
12
- scheduler_names,
13
  )
14
  from constants import (
15
  DIRECTORY_MODELS,
16
  DIRECTORY_LORAS,
17
  DIRECTORY_VAES,
18
  DIRECTORY_EMBEDS,
19
- DIRECTORY_UPSCALERS,
20
  DOWNLOAD_MODEL,
21
  DOWNLOAD_VAE,
22
  DOWNLOAD_LORA,
@@ -40,16 +35,16 @@ from constants import (
40
  EXAMPLES_GUI,
41
  RESOURCES,
42
  DIFFUSERS_CONTROLNET_MODEL,
43
- IP_MODELS,
44
- MODE_IP_OPTIONS,
45
- CACHE_HF_ROOT,
46
- CACHE_HF,
47
  )
48
  from stablepy.diffusers_vanilla.style_prompt_config import STYLE_NAMES
49
  import torch
50
  import re
 
 
 
 
 
51
  import time
52
- import threading
53
  from PIL import ImageFile
54
  from utils import (
55
  download_things,
@@ -65,7 +60,6 @@ from utils import (
65
  progress_step_bar,
66
  html_template_message,
67
  escape_html,
68
- clear_hf_cache,
69
  )
70
  from image_processor import preprocessor_tab
71
  from datetime import datetime
@@ -76,37 +70,31 @@ import warnings
76
  from stablepy import logger
77
  from diffusers import FluxPipeline
78
  # import urllib.parse
79
- import subprocess
80
-
81
- os.system("pip list")
82
- IS_ZERO_GPU = bool(os.getenv("SPACES_ZERO_GPU"))
83
- HIDE_API = bool(os.getenv("HIDE_API"))
84
- if IS_ZERO_GPU:
85
- subprocess.run("rm -rf /data-nvme/zerogpu-offload/*", env={}, shell=True)
86
- IS_GPU_MODE = True if IS_ZERO_GPU else (True if torch.cuda.is_available() else False)
87
- img_path = "./images/"
88
- allowed_path = os.path.abspath(img_path)
89
- delete_cache_time = (9600, 9600) if IS_ZERO_GPU else (86400, 86400)
90
 
91
  ImageFile.LOAD_TRUNCATED_IMAGES = True
92
  torch.backends.cuda.matmul.allow_tf32 = True
93
  # os.environ["PYTORCH_NO_CUDA_MEMORY_CACHING"] = "1"
 
94
 
95
- directories = [DIRECTORY_MODELS, DIRECTORY_LORAS, DIRECTORY_VAES, DIRECTORY_EMBEDS, DIRECTORY_UPSCALERS]
96
  for directory in directories:
97
  os.makedirs(directory, exist_ok=True)
98
 
99
  # Download stuffs
100
  for url in [url.strip() for url in DOWNLOAD_MODEL.split(',')]:
101
- download_things(DIRECTORY_MODELS, url, HF_TOKEN, CIVITAI_API_KEY)
 
102
  for url in [url.strip() for url in DOWNLOAD_VAE.split(',')]:
103
- download_things(DIRECTORY_VAES, url, HF_TOKEN, CIVITAI_API_KEY)
 
104
  for url in [url.strip() for url in DOWNLOAD_LORA.split(',')]:
105
- download_things(DIRECTORY_LORAS, url, HF_TOKEN, CIVITAI_API_KEY)
 
106
 
107
  # Download Embeddings
108
  for url_embed in DOWNLOAD_EMBEDS:
109
- download_things(DIRECTORY_EMBEDS, url_embed, HF_TOKEN, CIVITAI_API_KEY)
 
110
 
111
  # Build list models
112
  embed_list = get_model_list(DIRECTORY_EMBEDS)
@@ -124,16 +112,15 @@ vae_model_list.insert(0, "None")
124
 
125
  print('\033[33m🏁 Download and listing of valid models completed.\033[0m')
126
 
127
- components = None
128
- if IS_ZERO_GPU:
129
- flux_repo = "camenduru/FLUX.1-dev-diffusers"
130
- flux_pipe = FluxPipeline.from_pretrained(
131
- flux_repo,
132
- transformer=None,
133
- torch_dtype=torch.bfloat16,
134
- ).to("cuda")
135
- components = flux_pipe.components
136
- delete_model(flux_repo)
137
 
138
  #######################
139
  # GUI
@@ -143,17 +130,7 @@ diffusers.utils.logging.set_verbosity(40)
143
  warnings.filterwarnings(action="ignore", category=FutureWarning, module="diffusers")
144
  warnings.filterwarnings(action="ignore", category=UserWarning, module="diffusers")
145
  warnings.filterwarnings(action="ignore", category=FutureWarning, module="transformers")
146
-
147
- parser = ArgumentParser(description='DiffuseCraft: Create images from text prompts.', add_help=True)
148
- parser.add_argument("--share", action="store_true", dest="share_enabled", default=False, help="Enable sharing")
149
- parser.add_argument('--theme', type=str, default="NoCrypt/miku", help='Set the theme (default: NoCrypt/miku)')
150
- parser.add_argument("--ssr", action="store_true", help="Enable SSR (Server-Side Rendering)")
151
- parser.add_argument("--log-level", type=str, default="INFO", choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"], help="Set logging level (default: INFO)")
152
- args = parser.parse_args()
153
-
154
- logger.setLevel(
155
- "INFO" if IS_ZERO_GPU else getattr(logging, args.log_level.upper())
156
- )
157
 
158
  CSS = """
159
  .contain { display: flex; flex-direction: column; }
@@ -163,12 +140,6 @@ CSS = """
163
  """
164
 
165
 
166
- def lora_chk(lora_):
167
- if isinstance(lora_, str) and lora_.strip() not in ["", "None"]:
168
- return lora_
169
- return None
170
-
171
-
172
  class GuiSD:
173
  def __init__(self, stream=True):
174
  self.model = None
@@ -177,30 +148,13 @@ class GuiSD:
177
  self.last_load = datetime.now()
178
  self.inventory = []
179
 
180
- # Avoid duplicate downloads
181
- self.active_downloads = set()
182
- self.download_lock = threading.Lock()
183
-
184
- # Anti-abuse: Track new model requests
185
- self.used_models = []
186
- self.new_model_history = []
187
-
188
- def update_storage_models(self, storage_floor_gb=30, required_inventory_for_purge=3):
189
  while get_used_storage_gb() > storage_floor_gb:
190
  if len(self.inventory) < required_inventory_for_purge:
191
  break
192
  removal_candidate = self.inventory.pop(0)
193
  delete_model(removal_candidate)
194
 
195
- # Cleanup after 60 seconds of inactivity
196
- lowPrioCleanup = max((datetime.now() - self.last_load).total_seconds(), 0) > 120
197
- 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):
198
- print("Cleaning up Hugging Face cache...")
199
- clear_hf_cache()
200
- self.inventory = [
201
- m for m in self.inventory if os.path.exists(m)
202
- ]
203
-
204
  def update_inventory(self, model_name):
205
  if model_name not in single_file_model_list:
206
  self.inventory = [
@@ -210,76 +164,23 @@ class GuiSD:
210
 
211
  def load_new_model(self, model_name, vae_model, task, controlnet_model, progress=gr.Progress(track_tqdm=True)):
212
 
213
- if model_name != model_list[0]:
214
- # --- Anti-Abuse Check Start ---
215
- if model_name in self.used_models:
216
- # Move to the end to mark as the most recently used (prevents it from being forgotten)
217
- self.used_models.remove(model_name)
218
- self.used_models.append(model_name)
219
- else:
220
- current_time = datetime.now()
221
- # Retain history of new model requests from the last 20 minutes (1200 seconds)
222
- self.new_model_history = [
223
- t for t in self.new_model_history
224
- if (current_time - t).total_seconds() < 1200
225
- ]
226
-
227
- # Allow a maximum of 5 NEW model requests per 20 minutes
228
- if len(self.new_model_history) >= 5:
229
- yield "Rate limit exceeded: Too many new models requested."
230
- raise gr.Error("Too many new models requested. Please reuse your previously loaded models or wait a few minutes before trying new ones.")
231
-
232
- # Log the new model attempt
233
- self.new_model_history.append(current_time)
234
- self.used_models.append(model_name)
235
-
236
- # Prevent the bypass list from growing infinitely (cap at 5 most recent models)
237
- if len(self.used_models) > 5:
238
- self.used_models.pop(0)
239
- # --- Anti-Abuse Check End ---
240
-
241
- lock_key = model_name
242
-
243
- while True:
244
- with self.download_lock:
245
- if lock_key not in self.active_downloads:
246
- self.active_downloads.add(lock_key)
247
- break
248
-
249
- yield f"Waiting for existing download to finish: {model_name}..."
250
- time.sleep(1)
251
 
252
- try:
253
- # download link model > model_name
254
- if model_name.startswith("http"):
255
- yield f"Downloading model: {model_name}"
256
- model_name = download_things(DIRECTORY_MODELS, model_name, HF_TOKEN, CIVITAI_API_KEY)
257
- if not model_name:
258
- raise ValueError("Error retrieving model information from URL")
259
 
260
- if IS_ZERO_GPU:
261
- self.update_storage_models()
262
-
263
- vae_model = vae_model if vae_model != "None" else None
264
- model_type = get_model_type(model_name)
265
- dtype_model = torch.bfloat16 if model_type == "FLUX" else torch.float16
266
-
267
- if not os.path.exists(model_name):
268
- logger.debug(f"model_name={model_name}, vae_model={vae_model}, task={task}, controlnet_model={controlnet_model}")
269
- _ = download_diffuser_repo(
270
- repo_name=model_name,
271
- model_type=model_type,
272
- revision="main",
273
- token=True,
274
- )
275
 
276
- self.update_inventory(model_name)
277
-
278
- except Exception as e:
279
- raise e
280
- finally:
281
- with self.download_lock:
282
- self.active_downloads.discard(lock_key)
283
 
284
  for i in range(68):
285
  if not self.status_loading:
@@ -297,7 +198,10 @@ class GuiSD:
297
  yield f"Loading model: {model_name}"
298
 
299
  if vae_model == "BakedVAE":
300
- vae_model = model_name
 
 
 
301
  elif vae_model:
302
  vae_type = "SDXL" if "sdxl" in vae_model.lower() else "SD 1.5"
303
  if model_type != vae_type:
@@ -316,10 +220,10 @@ class GuiSD:
316
  type_model_precision=dtype_model,
317
  retain_task_model_in_cache=False,
318
  controlnet_model=controlnet_model,
319
- device="cpu" if IS_ZERO_GPU else None,
320
  env_components=components,
321
  )
322
- self.model.advanced_params(image_preprocessor_cuda_active=IS_GPU_MODE)
323
  else:
324
  if self.model.base_model_id != model_name:
325
  load_now_time = datetime.now()
@@ -329,8 +233,7 @@ class GuiSD:
329
  print("Waiting for the previous model's time ops...")
330
  time.sleep(9 - elapsed_time)
331
 
332
- if IS_ZERO_GPU:
333
- self.model.device = torch.device("cpu")
334
  self.model.load_pipe(
335
  model_name,
336
  task_name=TASK_STABLEPY[task],
@@ -407,8 +310,8 @@ class GuiSD:
407
  syntax_weights,
408
  upscaler_model_path,
409
  upscaler_increases_size,
410
- upscaler_tile_size,
411
- upscaler_tile_overlap,
412
  hires_steps,
413
  hires_denoising_strength,
414
  hires_sampler,
@@ -433,7 +336,7 @@ class GuiSD:
433
  t2i_adapter_preprocessor,
434
  t2i_adapter_conditioning_scale,
435
  t2i_adapter_conditioning_factor,
436
- enable_live_preview,
437
  freeu,
438
  generator_in_cpu,
439
  adetailer_inpaint_only,
@@ -472,9 +375,6 @@ class GuiSD:
472
  mode_ip2,
473
  scale_ip2,
474
  pag_scale,
475
- face_restoration_model,
476
- face_restoration_visibility,
477
- face_restoration_weight,
478
  ):
479
  info_state = html_template_message("Navigating latent space...")
480
  yield info_state, gr.update(), gr.update()
@@ -484,7 +384,7 @@ class GuiSD:
484
  vae_msg = f"VAE: {vae_model}" if vae_model else ""
485
  msg_lora = ""
486
 
487
- logger.debug(f"Config model: {model_name}, {vae_model}, {loras_list}")
488
 
489
  task = TASK_STABLEPY[task]
490
 
@@ -513,20 +413,23 @@ class GuiSD:
513
  self.model.stream_config(concurrency=concurrency, latent_resize_by=1, vae_decoding=False)
514
 
515
  if task != "txt2img" and not image_control:
516
- raise ValueError("Reference image is required. Please upload one in 'Image ControlNet/Inpaint/Img2img'.")
517
 
518
- if task in ["inpaint", "repaint"] and not image_mask:
519
- raise ValueError("Mask image not found. Upload one in 'Image Mask' to proceed.")
520
 
521
- if "https://" not in str(UPSCALER_DICT_GUI[upscaler_model_path]):
522
  upscaler_model = upscaler_model_path
523
  else:
 
 
 
524
  url_upscaler = UPSCALER_DICT_GUI[upscaler_model_path]
525
 
526
- if not os.path.exists(f"./{DIRECTORY_UPSCALERS}/{url_upscaler.split('/')[-1]}"):
527
- download_things(DIRECTORY_UPSCALERS, url_upscaler, HF_TOKEN)
528
 
529
- upscaler_model = f"./{DIRECTORY_UPSCALERS}/{url_upscaler.split('/')[-1]}"
530
 
531
  logging.getLogger("ultralytics").setLevel(logging.INFO if adetailer_verbose else logging.ERROR)
532
 
@@ -582,26 +485,26 @@ class GuiSD:
582
  "distance_threshold": distance_threshold,
583
  "recolor_gamma_correction": float(recolor_gamma_correction),
584
  "tile_blur_sigma": int(tile_blur_sigma),
585
- "lora_A": lora_chk(lora1),
586
  "lora_scale_A": lora_scale1,
587
- "lora_B": lora_chk(lora2),
588
  "lora_scale_B": lora_scale2,
589
- "lora_C": lora_chk(lora3),
590
  "lora_scale_C": lora_scale3,
591
- "lora_D": lora_chk(lora4),
592
  "lora_scale_D": lora_scale4,
593
- "lora_E": lora_chk(lora5),
594
  "lora_scale_E": lora_scale5,
595
- "lora_F": lora_chk(lora6),
596
  "lora_scale_F": lora_scale6,
597
- "lora_G": lora_chk(lora7),
598
  "lora_scale_G": lora_scale7,
599
  "textual_inversion": embed_list if textual_inversion else [],
600
  "syntax_weights": syntax_weights, # "Classic"
601
  "sampler": sampler,
602
  "schedule_type": schedule_type,
603
  "schedule_prediction_type": schedule_prediction_type,
604
- "xformers_memory_efficient_attention": False,
605
  "gui_active": True,
606
  "loop_generation": loop_generation,
607
  "controlnet_conditioning_scale": float(controlnet_output_scaling_in_unet),
@@ -616,7 +519,7 @@ class GuiSD:
616
  "leave_progress_bar": leave_progress_bar,
617
  "disable_progress_bar": disable_progress_bar,
618
  "image_previews": image_previews,
619
- "display_images": False,
620
  "save_generated_images": save_generated_images,
621
  "filename_pattern": filename_pattern,
622
  "image_storage_location": image_storage_location,
@@ -628,8 +531,8 @@ class GuiSD:
628
  "t2i_adapter_conditioning_factor": float(t2i_adapter_conditioning_factor),
629
  "upscaler_model_path": upscaler_model,
630
  "upscaler_increases_size": upscaler_increases_size,
631
- "upscaler_tile_size": upscaler_tile_size,
632
- "upscaler_tile_overlap": upscaler_tile_overlap,
633
  "hires_steps": hires_steps,
634
  "hires_denoising_strength": hires_denoising_strength,
635
  "hires_prompt": hires_prompt,
@@ -644,19 +547,16 @@ class GuiSD:
644
  "ip_adapter_model": params_ip_model,
645
  "ip_adapter_mode": params_ip_mode,
646
  "ip_adapter_scale": params_ip_scale,
647
- "face_restoration_model": face_restoration_model,
648
- "face_restoration_visibility": face_restoration_visibility,
649
- "face_restoration_weight": face_restoration_weight,
650
  }
651
 
652
  # kwargs for diffusers pipeline
653
  if guidance_rescale:
654
  pipe_params["guidance_rescale"] = guidance_rescale
655
- if IS_ZERO_GPU:
656
- self.model.device = torch.device("cuda:0")
657
- if hasattr(self.model.pipe, "transformer") and loras_list != ["None"] * self.model.num_loras:
658
- self.model.pipe.transformer.to(self.model.device)
659
- logger.debug("transformer to cuda")
660
 
661
  actual_progress = 0
662
  info_images = gr.update()
@@ -686,20 +586,15 @@ class GuiSD:
686
 
687
  download_links = "<br>".join(
688
  [
689
- f'<a href="{path.replace("/images/", f"/gradio_api/file={allowed_path}/")}" download="{os.path.basename(path)}">Download Image {i + 1}</a>'
690
  for i, path in enumerate(image_path)
691
  ]
692
  )
693
  if save_generated_images:
694
  info_images += f"<br>{download_links}"
695
 
696
- if not display_images:
697
- img = gr.update()
698
  info_state = "COMPLETE"
699
 
700
- elif not enable_live_preview:
701
- img = gr.update()
702
-
703
  yield info_state, img, info_images
704
 
705
 
@@ -799,27 +694,22 @@ def sd_gen_generate_pipeline(*args):
799
 
800
 
801
  @spaces.GPU(duration=15)
802
- def process_upscale(image, upscaler_name, upscaler_size):
803
- if image is None:
804
- return None
805
 
806
  from stablepy.diffusers_vanilla.utils import save_pil_image_with_metadata
807
- from stablepy import load_upscaler_model
808
 
809
- image = image.convert("RGB")
810
  exif_image = extract_exif_data(image)
811
 
812
- name_upscaler = UPSCALER_DICT_GUI[upscaler_name]
813
-
814
- if "https://" in str(name_upscaler):
 
 
815
 
816
- if not os.path.exists(f"./{DIRECTORY_UPSCALERS}/{name_upscaler.split('/')[-1]}"):
817
- download_things(DIRECTORY_UPSCALERS, name_upscaler, HF_TOKEN)
818
-
819
- name_upscaler = f"./{DIRECTORY_UPSCALERS}/{name_upscaler.split('/')[-1]}"
820
-
821
- 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)
822
- image_up = scaler_beta.upscale(image, upscaler_size, True)
823
 
824
  image_path = save_pil_image_with_metadata(image_up, f'{os.getcwd()}/up_images', exif_image)
825
 
@@ -827,11 +717,11 @@ def process_upscale(image, upscaler_name, upscaler_size):
827
 
828
 
829
  # https://huggingface.co/spaces/BestWishYsh/ConsisID-preview-Space/discussions/1#674969a022b99c122af5d407
830
- # dynamic_gpu_duration.zerogpu = True
831
- # sd_gen_generate_pipeline.zerogpu = True
832
  sd_gen = GuiSD()
833
 
834
- with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as app:
835
  gr.Markdown("# 🧩 DiffuseCraft")
836
  gr.Markdown(SUBTITLE_GUI)
837
  with gr.Tab("Generation"):
@@ -847,14 +737,10 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
847
 
848
  return gr.update(value=task_name, choices=new_choices)
849
 
850
- with gr.Accordion("Model and Task", open=True, visible=True):
851
- task_gui = gr.Dropdown(label="Task", choices=SDXL_TASK, value=TASK_MODEL_LIST[0])
852
- model_name_gui = gr.Dropdown(label="Model", choices=model_list, value=model_list[0], allow_custom_value=True)
853
  prompt_gui = gr.Textbox(lines=5, placeholder="Enter prompt", label="Prompt")
854
-
855
- with gr.Accordion("Negative prompt", open=False, visible=True):
856
- neg_prompt_gui = gr.Textbox(lines=3, placeholder="Enter Neg prompt", label="Negative prompt", value="bad anatomy, ((many hands, bad hands, missing fingers)), anatomical nonsense, ugly, deformed, bad proportions, bad shadow, extra limbs, missing limbs, floating limbs, disconnected limbs, malformed hands, poorly drawn, mutation, mutated hands and fingers, extra legs, interlocked fingers, extra arms, disfigured face, long neck, asymmetrical eyes, lowres, extra digit, fewer digits, cropped, jpeg artifacts, signature, watermark, username, blurry, duplicate, bad composition, text, worst quality, normal quality, low quality, very displeasing, desaturated, low contrast, muted tones, washed out, unfinished, incomplete, draft, logo, backlighting")
857
-
858
  with gr.Row(equal_height=False):
859
  set_params_gui = gr.Button(value="↙️", variant="secondary", size="sm")
860
  clear_prompt_gui = gr.Button(value="🗑️", variant="secondary", size="sm")
@@ -884,180 +770,138 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
884
 
885
  actual_task_info = gr.HTML()
886
 
887
- with gr.Row(equal_height=False, variant="default", visible=IS_ZERO_GPU):
888
  gpu_duration_gui = gr.Number(minimum=5, maximum=240, value=59, show_label=False, container=False, info="GPU time duration (seconds)")
889
  with gr.Column():
890
  verbose_info_gui = gr.Checkbox(value=False, container=False, label="Status info")
891
  load_lora_cpu_gui = gr.Checkbox(value=False, container=False, label="Load LoRAs on CPU")
892
 
893
  with gr.Column(scale=1):
894
- with gr.Accordion("Generation settings", open=True, visible=True):
895
- steps_gui = gr.Slider(minimum=1, maximum=100, step=1, value=30, label="Steps")
896
- cfg_gui = gr.Slider(minimum=0, maximum=30, step=0.5, value=7., label="CFG")
897
- sampler_gui = gr.Dropdown(label="Sampler", choices=scheduler_names, value="Euler")
898
- schedule_type_gui = gr.Dropdown(label="Schedule type", choices=SCHEDULE_TYPE_OPTIONS, value=SCHEDULE_TYPE_OPTIONS[0])
899
- img_width_gui = gr.Slider(minimum=64, maximum=4096, step=8, value=832, label="Img Width")
900
- img_height_gui = gr.Slider(minimum=64, maximum=4096, step=8, value=1216, label="Img Height")
901
- seed_gui = gr.Number(minimum=-1, maximum=9999999999, value=-1, label="Seed")
902
- pag_scale_gui = gr.Slider(minimum=0.0, maximum=10.0, step=0.1, value=0.0, label="PAG Scale")
903
- with gr.Row():
904
- clip_skip_gui = gr.Checkbox(value=True, label="Layer 2 Clip Skip")
905
- free_u_gui = gr.Checkbox(value=True, label="FreeU")
906
-
907
- with gr.Row(equal_height=False):
908
- num_images_gui = gr.Slider(minimum=1, maximum=(16 if IS_ZERO_GPU else 20), step=1, value=1, label="Images")
909
- prompt_syntax_gui = gr.Dropdown(label="Prompt Syntax", choices=PROMPT_W_OPTIONS, value=PROMPT_W_OPTIONS[2][1])
910
- vae_model_gui = gr.Dropdown(label="VAE Model", choices=vae_model_list, value=vae_model_list[0])
911
-
912
-
913
- def run_set_params_gui(base_prompt, name_model):
914
- valid_receptors = { # default values
915
- "prompt": gr.update(value=base_prompt),
916
- "neg_prompt": gr.update(value=""),
917
- "Steps": gr.update(value=30),
918
- "width": gr.update(value=1024),
919
- "height": gr.update(value=1024),
920
- "Seed": gr.update(value=-1),
921
- "Sampler": gr.update(value="Euler"),
922
- "CFG scale": gr.update(value=7.), # cfg
923
- "Clip skip": gr.update(value=True),
924
- "Model": gr.update(value=name_model),
925
- "Schedule type": gr.update(value="Automatic"),
926
- "PAG": gr.update(value=.0),
927
- "FreeU": gr.update(value=False),
928
- "Hires upscaler": gr.update(),
929
- "Hires upscale": gr.update(),
930
- "Hires steps": gr.update(),
931
- "Hires denoising strength": gr.update(),
932
- "Hires CFG": gr.update(),
933
- "Hires sampler": gr.update(),
934
- "Hires schedule type": gr.update(),
935
- "Image resolution": gr.update(value=1024),
936
- "Strength": gr.update(),
937
- "Prompt emphasis": gr.update(),
938
- }
939
-
940
- # Generate up to 7 LoRAs
941
- for i in range(1, 8):
942
- valid_receptors[f"Lora_{i}"] = gr.update()
943
- valid_receptors[f"Lora_scale_{i}"] = gr.update()
944
-
945
- valid_keys = list(valid_receptors.keys())
946
-
947
- parameters = extract_parameters(base_prompt)
948
- # print(parameters)
949
-
950
- if "Sampler" in parameters:
951
- value_sampler = parameters["Sampler"]
952
- for s_type in SCHEDULE_TYPE_OPTIONS:
953
- if s_type in value_sampler:
954
- value_sampler = value_sampler.replace(s_type, "").strip()
955
- parameters["Sampler"] = value_sampler
956
- parameters["Schedule type"] = s_type
957
-
958
- params_lora = []
959
- if ">" in parameters["prompt"] and "<" in parameters["prompt"]:
960
- params_lora = re.findall(r'<lora:[^>]+>', parameters["prompt"])
961
- if "Loras" in parameters:
962
- params_lora += re.findall(r'<lora:[^>]+>', parameters["Loras"])
963
-
964
- if params_lora:
965
- parsed_params = []
966
- for tag_l in params_lora:
967
- try:
968
- inner = tag_l.strip("<>") # remove < >
969
- _, data_l = inner.split(":", 1) # remove the "lora:" part
970
- parts_l = data_l.split(":")
971
-
972
- name_l = parts_l[0]
973
- weight_l = float(parts_l[1]) if len(parts_l) > 1 else 1.0 # default weight = 1.0
974
-
975
- parsed_params.append((name_l, weight_l))
976
- except Exception as e:
977
- print(f"Error parsing LoRA tag {tag_l}: {e}")
978
-
979
- new_lora_model_list = get_model_list(DIRECTORY_LORAS)
980
- new_lora_model_list.insert(0, "None")
981
-
982
- num_lora = 1
983
- for parsed_l, parsed_s in parsed_params:
984
- filtered_loras = [m for m in new_lora_model_list if parsed_l in m]
985
- if filtered_loras:
986
- parameters[f"Lora_{num_lora}"] = filtered_loras[0]
987
- parameters[f"Lora_scale_{num_lora}"] = parsed_s
988
- num_lora += 1
989
-
990
- # continue = discard new value
991
- for key, val in parameters.items():
992
- # print(val)
993
- if key in valid_keys:
994
- try:
995
- if key == "Sampler":
996
- if val not in scheduler_names:
997
- continue
998
- if key in ["Schedule type", "Hires schedule type"]:
999
- if val not in SCHEDULE_TYPE_OPTIONS:
1000
- continue
1001
- if key == "Hires sampler":
1002
- if val not in POST_PROCESSING_SAMPLER:
1003
- continue
1004
- if key == "Prompt emphasis":
1005
- if val not in PROMPT_WEIGHT_OPTIONS_PRIORITY:
1006
- continue
1007
- elif key == "Clip skip":
1008
- if "," in str(val):
1009
- val = val.replace(",", "")
1010
- if int(val) >= 2:
1011
  val = True
1012
- if key == "prompt":
1013
- if ">" in val and "<" in val:
1014
- val = re.sub(r'<[^>]+>', '', val) # Delete html and loras
1015
- print("Removed LoRA written in the prompt")
1016
- if key in ["prompt", "neg_prompt"]:
1017
- val = re.sub(r'\s+', ' ', re.sub(r',+', ',', val)).strip()
1018
- if key in ["Steps", "width", "height", "Seed", "Hires steps", "Image resolution"]:
1019
- val = int(val)
1020
- if key == "FreeU":
1021
- val = True
1022
- if key in ["CFG scale", "PAG", "Hires upscale", "Hires denoising strength", "Hires CFG", "Strength"]:
1023
- val = float(val)
1024
- if key == "Model":
1025
- filtered_models = [m for m in model_list if val in m]
1026
- if filtered_models:
1027
- val = filtered_models[0]
1028
- else:
1029
- val = name_model
1030
- if key == "Hires upscaler":
1031
- if val not in UPSCALER_KEYS:
1032
  continue
1033
- if key == "Seed":
1034
- continue
1035
-
1036
- valid_receptors[key] = gr.update(value=val)
1037
- # print(val, type(val))
1038
- # print(valid_receptors)
1039
- except Exception as e:
1040
- print(str(e))
1041
- return [value for value in valid_receptors.values()]
1042
-
1043
- def run_clear_prompt_gui():
1044
- return gr.update(value=""), gr.update(value="")
1045
- clear_prompt_gui.click(
1046
- run_clear_prompt_gui, [], [prompt_gui, neg_prompt_gui]
1047
- )
 
 
 
 
 
 
 
 
 
1048
 
1049
- def run_set_random_seed():
1050
- return -1
1051
- set_random_seed.click(
1052
- run_set_random_seed, [], seed_gui
1053
- )
 
 
 
 
 
 
 
 
 
 
1054
 
1055
  with gr.Accordion("Hires fix", open=False, visible=True):
1056
 
1057
  upscaler_model_path_gui = gr.Dropdown(label="Upscaler", choices=UPSCALER_KEYS, value=UPSCALER_KEYS[0])
1058
  upscaler_increases_size_gui = gr.Slider(minimum=1.1, maximum=4., step=0.1, value=1.2, label="Upscale by")
1059
- 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")
1060
- upscaler_tile_overlap_gui = gr.Slider(minimum=0, maximum=48, step=1, value=8, label="Upscaler Tile Overlap")
1061
  hires_steps_gui = gr.Slider(minimum=0, value=30, maximum=100, step=1, label="Hires Steps")
1062
  hires_denoising_strength_gui = gr.Slider(minimum=0.1, maximum=1.0, step=0.01, value=0.55, label="Hires Denoising Strength")
1063
  hires_sampler_gui = gr.Dropdown(label="Hires Sampler", choices=POST_PROCESSING_SAMPLER, value=POST_PROCESSING_SAMPLER[0])
@@ -1073,8 +917,7 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1073
  return gr.Dropdown(label=label, choices=lora_model_list, value="None", allow_custom_value=True, visible=visible)
1074
 
1075
  def lora_scale_slider(label, visible=True):
1076
- val_lora = 8 if IS_ZERO_GPU else 10
1077
- return gr.Slider(minimum=-val_lora, maximum=val_lora, step=0.01, value=0.33, label=label, visible=visible)
1078
 
1079
  lora1_gui = lora_dropdown("Lora1")
1080
  lora_scale_1_gui = lora_scale_slider("Lora Scale 1")
@@ -1086,10 +929,10 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1086
  lora_scale_4_gui = lora_scale_slider("Lora Scale 4")
1087
  lora5_gui = lora_dropdown("Lora5")
1088
  lora_scale_5_gui = lora_scale_slider("Lora Scale 5")
1089
- lora6_gui = lora_dropdown("Lora6")
1090
- lora_scale_6_gui = lora_scale_slider("Lora Scale 6")
1091
- lora7_gui = lora_dropdown("Lora7")
1092
- lora_scale_7_gui = lora_scale_slider("Lora Scale 7")
1093
 
1094
  with gr.Accordion("From URL", open=False, visible=True):
1095
  text_lora = gr.Textbox(
@@ -1098,7 +941,7 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1098
  lines=1,
1099
  info="It has to be .safetensors files, and you can also download them from Hugging Face.",
1100
  )
1101
- romanize_text = gr.Checkbox(value=False, label="Transliterate name", visible=(not IS_ZERO_GPU))
1102
  button_lora = gr.Button("Get and Refresh the LoRA Lists")
1103
  new_lora_status = gr.HTML()
1104
  button_lora.click(
@@ -1107,16 +950,11 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1107
  [lora1_gui, lora2_gui, lora3_gui, lora4_gui, lora5_gui, lora6_gui, lora7_gui, new_lora_status]
1108
  )
1109
 
1110
- with gr.Accordion("Face restoration", open=False, visible=True):
1111
-
1112
- face_rest_options = [None] + FACE_RESTORATION_MODELS
1113
-
1114
- face_restoration_model_gui = gr.Dropdown(label="Face restoration model", choices=face_rest_options, value=face_rest_options[0])
1115
- face_restoration_visibility_gui = gr.Slider(minimum=0., maximum=1., step=0.001, value=1., label="Visibility")
1116
- face_restoration_weight_gui = gr.Slider(minimum=0., maximum=1., step=0.001, value=.5, label="Weight", info="(0 = maximum effect, 1 = minimum effect)")
1117
-
1118
  with gr.Accordion("IP-Adapter", open=False, visible=True):
1119
 
 
 
 
1120
  with gr.Accordion("IP-Adapter 1", open=False, visible=True):
1121
  image_ip1 = gr.Image(label="IP Image", type="filepath")
1122
  mask_ip1 = gr.Image(label="IP Mask", type="filepath")
@@ -1135,13 +973,13 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1135
  image_mask_gui = gr.Image(label="Image Mask", type="filepath")
1136
  strength_gui = gr.Slider(
1137
  minimum=0.01, maximum=1.0, step=0.01, value=0.55, label="Strength",
1138
- info="This option adjusts the level of changes for img2img, repaint and inpaint."
1139
  )
1140
  image_resolution_gui = gr.Slider(
1141
  minimum=64, maximum=2048, step=64, value=1024, label="Image Resolution",
1142
  info="The maximum proportional size of the generated image based on the uploaded image."
1143
  )
1144
- controlnet_model_gui = gr.Dropdown(label="ControlNet model", choices=DIFFUSERS_CONTROLNET_MODEL, value=DIFFUSERS_CONTROLNET_MODEL[0], allow_custom_value=True)
1145
  control_net_output_scaling_gui = gr.Slider(minimum=0, maximum=5.0, step=0.1, value=1, label="ControlNet Output Scaling in UNet")
1146
  control_net_start_threshold_gui = gr.Slider(minimum=0, maximum=1, step=0.01, value=0, label="ControlNet Start Threshold (%)")
1147
  control_net_stop_threshold_gui = gr.Slider(minimum=0, maximum=1, step=0.01, value=1, label="ControlNet Stop Threshold (%)")
@@ -1163,8 +1001,8 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1163
  preprocess_resolution_gui = gr.Slider(minimum=64, maximum=2048, step=64, value=512, label="Preprocessor Resolution")
1164
  low_threshold_gui = gr.Slider(minimum=1, maximum=255, step=1, value=100, label="'CANNY' low threshold")
1165
  high_threshold_gui = gr.Slider(minimum=1, maximum=255, step=1, value=200, label="'CANNY' high threshold")
1166
- value_threshold_gui = gr.Slider(minimum=0.0, maximum=2.0, step=0.01, value=0.1, label="'MLSD' Hough value threshold")
1167
- distance_threshold_gui = gr.Slider(minimum=0.0, maximum=20.0, step=0.01, value=0.1, label="'MLSD' Hough distance threshold")
1168
  recolor_gamma_correction_gui = gr.Number(minimum=0., maximum=25., value=1., step=0.001, label="'RECOLOR' gamma correction")
1169
  tile_blur_sigma_gui = gr.Number(minimum=0, maximum=100, value=9, step=1, label="'TILE' blur sigma")
1170
 
@@ -1199,7 +1037,7 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1199
  gr.Info(f"{len(sd_gen.model.STYLE_NAMES)} styles loaded")
1200
  return gr.update(value=None, choices=sd_gen.model.STYLE_NAMES)
1201
 
1202
- style_button.click(load_json_style_file, [style_json_gui], [style_prompt_gui])
1203
 
1204
  with gr.Accordion("Textual inversion", open=False, visible=False):
1205
  active_textual_inversion_gui = gr.Checkbox(value=False, label="Active Textual Inversion in prompt")
@@ -1245,67 +1083,23 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1245
  schedule_prediction_type_gui = gr.Dropdown(label="Discrete Sampling Type", choices=SCHEDULE_PREDICTION_TYPE_OPTIONS, value=SCHEDULE_PREDICTION_TYPE_OPTIONS[0])
1246
  guidance_rescale_gui = gr.Number(label="CFG rescale:", value=0., step=0.01, minimum=0., maximum=1.5)
1247
  save_generated_images_gui = gr.Checkbox(value=True, label="Create a download link for the images")
1248
- enable_live_preview_gui = gr.Checkbox(value=True, label="Enable live previews")
1249
- display_images_gui = gr.Checkbox(value=True, label="Show final results")
1250
  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)
1251
  hires_before_adetailer_gui = gr.Checkbox(value=False, label="Hires Before Adetailer")
1252
  hires_after_adetailer_gui = gr.Checkbox(value=True, label="Hires After Adetailer")
1253
  generator_in_cpu_gui = gr.Checkbox(value=False, label="Generator in CPU")
1254
- with gr.Column(visible=(not IS_ZERO_GPU)):
1255
- image_storage_location_gui = gr.Textbox(value=img_path, label="Image Storage Location")
1256
- disable_progress_bar_gui = gr.Checkbox(value=False, label="Disable Progress Bar")
1257
- leave_progress_bar_gui = gr.Checkbox(value=True, label="Leave Progress Bar")
1258
 
1259
  with gr.Accordion("More settings", open=False, visible=False):
1260
  loop_generation_gui = gr.Slider(minimum=1, value=1, label="Loop Generation")
1261
  retain_task_cache_gui = gr.Checkbox(value=False, label="Retain task model in cache")
1262
-
1263
- image_previews_gui = gr.Checkbox(value=True, label="Image Previews (alt)")
 
 
 
1264
  retain_compel_previous_load_gui = gr.Checkbox(value=False, label="Retain Compel Previous Load")
1265
  retain_detailfix_model_previous_load_gui = gr.Checkbox(value=False, label="Retain Detailfix Model Previous Load")
1266
  retain_hires_model_previous_load_gui = gr.Checkbox(value=False, label="Retain Hires Model Previous Load")
1267
-
1268
- set_params_gui.click(
1269
- run_set_params_gui, [prompt_gui, model_name_gui], [
1270
- prompt_gui,
1271
- neg_prompt_gui,
1272
- steps_gui,
1273
- img_width_gui,
1274
- img_height_gui,
1275
- seed_gui,
1276
- sampler_gui,
1277
- cfg_gui,
1278
- clip_skip_gui,
1279
- model_name_gui,
1280
- schedule_type_gui,
1281
- pag_scale_gui,
1282
- free_u_gui,
1283
- upscaler_model_path_gui,
1284
- upscaler_increases_size_gui,
1285
- hires_steps_gui,
1286
- hires_denoising_strength_gui,
1287
- hires_guidance_scale_gui,
1288
- hires_sampler_gui,
1289
- hires_schedule_type_gui,
1290
- image_resolution_gui,
1291
- strength_gui,
1292
- prompt_syntax_gui,
1293
- lora1_gui,
1294
- lora_scale_1_gui,
1295
- lora2_gui,
1296
- lora_scale_2_gui,
1297
- lora3_gui,
1298
- lora_scale_3_gui,
1299
- lora4_gui,
1300
- lora_scale_4_gui,
1301
- lora5_gui,
1302
- lora_scale_5_gui,
1303
- lora6_gui,
1304
- lora_scale_6_gui,
1305
- lora7_gui,
1306
- lora_scale_7_gui,
1307
- ],
1308
- )
1309
 
1310
  with gr.Accordion("Examples and help", open=False, visible=True):
1311
  gr.Markdown(HELP_GUI)
@@ -1362,21 +1156,10 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1362
  # "hsl(360, 120, 120)" # in fact any valid colorstring
1363
  ]
1364
  ),
1365
- eraser=gr.Eraser(default_size="16"),
1366
- render=True,
1367
- visible=False,
1368
- interactive=False,
1369
  )
1370
-
1371
- show_canvas = gr.Button("SHOW INPAINT CANVAS")
1372
-
1373
- def change_visibility_canvas():
1374
- return gr.update(visible=True, interactive=True), gr.update(visible=False)
1375
- show_canvas.click(change_visibility_canvas, [], [image_base, show_canvas])
1376
-
1377
  invert_mask = gr.Checkbox(value=False, label="Invert mask")
1378
  btn = gr.Button("Create mask")
1379
-
1380
  with gr.Column(scale=1):
1381
  img_source = gr.Image(interactive=False)
1382
  img_result = gr.Image(label="Mask image", show_label=True, interactive=False)
@@ -1407,11 +1190,8 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1407
 
1408
  with gr.Row():
1409
  with gr.Column():
1410
-
1411
- USCALER_TAB_KEYS = [name for name in UPSCALER_KEYS[9:]]
1412
-
1413
  image_up_tab = gr.Image(label="Image", type="pil", sources=["upload"])
1414
- upscaler_tab = gr.Dropdown(label="Upscaler", choices=USCALER_TAB_KEYS, value=USCALER_TAB_KEYS[5])
1415
  upscaler_size_tab = gr.Slider(minimum=1., maximum=4., step=0.1, value=1.1, label="Upscale by")
1416
  generate_button_up_tab = gr.Button(value="START UPSCALE", variant="primary")
1417
 
@@ -1419,7 +1199,7 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1419
  result_up_tab = gr.Image(label="Result", type="pil", interactive=False, format="png")
1420
 
1421
  generate_button_up_tab.click(
1422
- fn=process_upscale,
1423
  inputs=[image_up_tab, upscaler_tab, upscaler_size_tab],
1424
  outputs=[result_up_tab],
1425
  )
@@ -1438,7 +1218,6 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1438
  outputs=[load_model_gui],
1439
  queue=True,
1440
  show_progress="minimal",
1441
- api_name=(False if HIDE_API else None),
1442
  ).success(
1443
  fn=sd_gen_generate_pipeline, # fn=sd_gen.generate_pipeline,
1444
  inputs=[
@@ -1492,8 +1271,8 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1492
  prompt_syntax_gui,
1493
  upscaler_model_path_gui,
1494
  upscaler_increases_size_gui,
1495
- upscaler_tile_size_gui,
1496
- upscaler_tile_overlap_gui,
1497
  hires_steps_gui,
1498
  hires_denoising_strength_gui,
1499
  hires_sampler_gui,
@@ -1518,7 +1297,7 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1518
  t2i_adapter_preprocessor_gui,
1519
  adapter_conditioning_scale_gui,
1520
  adapter_conditioning_factor_gui,
1521
- enable_live_preview_gui,
1522
  free_u_gui,
1523
  generator_in_cpu_gui,
1524
  adetailer_inpaint_only_gui,
@@ -1557,9 +1336,6 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1557
  mode_ip2,
1558
  scale_ip2,
1559
  pag_scale_gui,
1560
- face_restoration_model_gui,
1561
- face_restoration_visibility_gui,
1562
- face_restoration_weight_gui,
1563
  load_lora_cpu_gui,
1564
  verbose_info_gui,
1565
  gpu_duration_gui,
@@ -1567,16 +1343,12 @@ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False) as
1567
  outputs=[load_model_gui, result_images, actual_task_info],
1568
  queue=True,
1569
  show_progress="minimal",
1570
- # api_name=(False if HIDE_API else None),
1571
  )
1572
 
1573
- if __name__ == "__main__":
1574
- app.queue()
1575
- app.launch(
1576
- show_error=True,
1577
- share=args.share_enabled,
1578
- debug=True,
1579
- ssr_mode=args.ssr,
1580
- allowed_paths=[allowed_path],
1581
- show_api=(not HIDE_API),
1582
- )
 
1
  import spaces
2
  import os
 
3
  from stablepy import (
4
  Model_Diffusers,
5
  SCHEDULE_TYPE_OPTIONS,
6
  SCHEDULE_PREDICTION_TYPE_OPTIONS,
7
  check_scheduler_compatibility,
8
  TASK_AND_PREPROCESSORS,
 
 
 
9
  )
10
  from constants import (
11
  DIRECTORY_MODELS,
12
  DIRECTORY_LORAS,
13
  DIRECTORY_VAES,
14
  DIRECTORY_EMBEDS,
 
15
  DOWNLOAD_MODEL,
16
  DOWNLOAD_VAE,
17
  DOWNLOAD_LORA,
 
35
  EXAMPLES_GUI,
36
  RESOURCES,
37
  DIFFUSERS_CONTROLNET_MODEL,
 
 
 
 
38
  )
39
  from stablepy.diffusers_vanilla.style_prompt_config import STYLE_NAMES
40
  import torch
41
  import re
42
+ from stablepy import (
43
+ scheduler_names,
44
+ IP_ADAPTERS_SD,
45
+ IP_ADAPTERS_SDXL,
46
+ )
47
  import time
 
48
  from PIL import ImageFile
49
  from utils import (
50
  download_things,
 
60
  progress_step_bar,
61
  html_template_message,
62
  escape_html,
 
63
  )
64
  from image_processor import preprocessor_tab
65
  from datetime import datetime
 
70
  from stablepy import logger
71
  from diffusers import FluxPipeline
72
  # import urllib.parse
 
 
 
 
 
 
 
 
 
 
 
73
 
74
  ImageFile.LOAD_TRUNCATED_IMAGES = True
75
  torch.backends.cuda.matmul.allow_tf32 = True
76
  # os.environ["PYTORCH_NO_CUDA_MEMORY_CACHING"] = "1"
77
+ print(os.getenv("SPACES_ZERO_GPU"))
78
 
79
+ directories = [DIRECTORY_MODELS, DIRECTORY_LORAS, DIRECTORY_VAES, DIRECTORY_EMBEDS]
80
  for directory in directories:
81
  os.makedirs(directory, exist_ok=True)
82
 
83
  # Download stuffs
84
  for url in [url.strip() for url in DOWNLOAD_MODEL.split(',')]:
85
+ if not os.path.exists(f"./models/{url.split('/')[-1]}"):
86
+ download_things(DIRECTORY_MODELS, url, HF_TOKEN, CIVITAI_API_KEY)
87
  for url in [url.strip() for url in DOWNLOAD_VAE.split(',')]:
88
+ if not os.path.exists(f"./vaes/{url.split('/')[-1]}"):
89
+ download_things(DIRECTORY_VAES, url, HF_TOKEN, CIVITAI_API_KEY)
90
  for url in [url.strip() for url in DOWNLOAD_LORA.split(',')]:
91
+ if not os.path.exists(f"./loras/{url.split('/')[-1]}"):
92
+ download_things(DIRECTORY_LORAS, url, HF_TOKEN, CIVITAI_API_KEY)
93
 
94
  # Download Embeddings
95
  for url_embed in DOWNLOAD_EMBEDS:
96
+ if not os.path.exists(f"./embedings/{url_embed.split('/')[-1]}"):
97
+ download_things(DIRECTORY_EMBEDS, url_embed, HF_TOKEN, CIVITAI_API_KEY)
98
 
99
  # Build list models
100
  embed_list = get_model_list(DIRECTORY_EMBEDS)
 
112
 
113
  print('\033[33m🏁 Download and listing of valid models completed.\033[0m')
114
 
115
+ flux_repo = "camenduru/FLUX.1-dev-diffusers"
116
+ flux_pipe = FluxPipeline.from_pretrained(
117
+ flux_repo,
118
+ transformer=None,
119
+ torch_dtype=torch.bfloat16,
120
+ ).to("cuda")
121
+ components = flux_pipe.components
122
+ components.pop("transformer", None)
123
+ delete_model(flux_repo)
 
124
 
125
  #######################
126
  # GUI
 
130
  warnings.filterwarnings(action="ignore", category=FutureWarning, module="diffusers")
131
  warnings.filterwarnings(action="ignore", category=UserWarning, module="diffusers")
132
  warnings.filterwarnings(action="ignore", category=FutureWarning, module="transformers")
133
+ logger.setLevel(logging.DEBUG)
 
 
 
 
 
 
 
 
 
 
134
 
135
  CSS = """
136
  .contain { display: flex; flex-direction: column; }
 
140
  """
141
 
142
 
 
 
 
 
 
 
143
  class GuiSD:
144
  def __init__(self, stream=True):
145
  self.model = None
 
148
  self.last_load = datetime.now()
149
  self.inventory = []
150
 
151
+ def update_storage_models(self, storage_floor_gb=24, required_inventory_for_purge=3):
 
 
 
 
 
 
 
 
152
  while get_used_storage_gb() > storage_floor_gb:
153
  if len(self.inventory) < required_inventory_for_purge:
154
  break
155
  removal_candidate = self.inventory.pop(0)
156
  delete_model(removal_candidate)
157
 
 
 
 
 
 
 
 
 
 
158
  def update_inventory(self, model_name):
159
  if model_name not in single_file_model_list:
160
  self.inventory = [
 
164
 
165
  def load_new_model(self, model_name, vae_model, task, controlnet_model, progress=gr.Progress(track_tqdm=True)):
166
 
167
+ # download link model > model_name
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
 
169
+ self.update_storage_models()
 
 
 
 
 
 
170
 
171
+ vae_model = vae_model if vae_model != "None" else None
172
+ model_type = get_model_type(model_name)
173
+ dtype_model = torch.bfloat16 if model_type == "FLUX" else torch.float16
174
+
175
+ if not os.path.exists(model_name):
176
+ _ = download_diffuser_repo(
177
+ repo_name=model_name,
178
+ model_type=model_type,
179
+ revision="main",
180
+ token=True,
181
+ )
 
 
 
 
182
 
183
+ self.update_inventory(model_name)
 
 
 
 
 
 
184
 
185
  for i in range(68):
186
  if not self.status_loading:
 
198
  yield f"Loading model: {model_name}"
199
 
200
  if vae_model == "BakedVAE":
201
+ if not os.path.exists(model_name):
202
+ vae_model = model_name
203
+ else:
204
+ vae_model = None
205
  elif vae_model:
206
  vae_type = "SDXL" if "sdxl" in vae_model.lower() else "SD 1.5"
207
  if model_type != vae_type:
 
220
  type_model_precision=dtype_model,
221
  retain_task_model_in_cache=False,
222
  controlnet_model=controlnet_model,
223
+ device="cpu",
224
  env_components=components,
225
  )
226
+ self.model.advanced_params(image_preprocessor_cuda_active=True)
227
  else:
228
  if self.model.base_model_id != model_name:
229
  load_now_time = datetime.now()
 
233
  print("Waiting for the previous model's time ops...")
234
  time.sleep(9 - elapsed_time)
235
 
236
+ self.model.device = torch.device("cpu")
 
237
  self.model.load_pipe(
238
  model_name,
239
  task_name=TASK_STABLEPY[task],
 
310
  syntax_weights,
311
  upscaler_model_path,
312
  upscaler_increases_size,
313
+ esrgan_tile,
314
+ esrgan_tile_overlap,
315
  hires_steps,
316
  hires_denoising_strength,
317
  hires_sampler,
 
336
  t2i_adapter_preprocessor,
337
  t2i_adapter_conditioning_scale,
338
  t2i_adapter_conditioning_factor,
339
+ xformers_memory_efficient_attention,
340
  freeu,
341
  generator_in_cpu,
342
  adetailer_inpaint_only,
 
375
  mode_ip2,
376
  scale_ip2,
377
  pag_scale,
 
 
 
378
  ):
379
  info_state = html_template_message("Navigating latent space...")
380
  yield info_state, gr.update(), gr.update()
 
384
  vae_msg = f"VAE: {vae_model}" if vae_model else ""
385
  msg_lora = ""
386
 
387
+ print("Config model:", model_name, vae_model, loras_list)
388
 
389
  task = TASK_STABLEPY[task]
390
 
 
413
  self.model.stream_config(concurrency=concurrency, latent_resize_by=1, vae_decoding=False)
414
 
415
  if task != "txt2img" and not image_control:
416
+ raise ValueError("No control image found: To use this function, you have to upload an image in 'Image ControlNet/Inpaint/Img2img'")
417
 
418
+ if task == "inpaint" and not image_mask:
419
+ raise ValueError("No mask image found: Specify one in 'Image Mask'")
420
 
421
+ if upscaler_model_path in UPSCALER_KEYS[:9]:
422
  upscaler_model = upscaler_model_path
423
  else:
424
+ directory_upscalers = 'upscalers'
425
+ os.makedirs(directory_upscalers, exist_ok=True)
426
+
427
  url_upscaler = UPSCALER_DICT_GUI[upscaler_model_path]
428
 
429
+ if not os.path.exists(f"./upscalers/{url_upscaler.split('/')[-1]}"):
430
+ download_things(directory_upscalers, url_upscaler, HF_TOKEN)
431
 
432
+ upscaler_model = f"./upscalers/{url_upscaler.split('/')[-1]}"
433
 
434
  logging.getLogger("ultralytics").setLevel(logging.INFO if adetailer_verbose else logging.ERROR)
435
 
 
485
  "distance_threshold": distance_threshold,
486
  "recolor_gamma_correction": float(recolor_gamma_correction),
487
  "tile_blur_sigma": int(tile_blur_sigma),
488
+ "lora_A": lora1 if lora1 != "None" else None,
489
  "lora_scale_A": lora_scale1,
490
+ "lora_B": lora2 if lora2 != "None" else None,
491
  "lora_scale_B": lora_scale2,
492
+ "lora_C": lora3 if lora3 != "None" else None,
493
  "lora_scale_C": lora_scale3,
494
+ "lora_D": lora4 if lora4 != "None" else None,
495
  "lora_scale_D": lora_scale4,
496
+ "lora_E": lora5 if lora5 != "None" else None,
497
  "lora_scale_E": lora_scale5,
498
+ "lora_F": lora6 if lora6 != "None" else None,
499
  "lora_scale_F": lora_scale6,
500
+ "lora_G": lora7 if lora7 != "None" else None,
501
  "lora_scale_G": lora_scale7,
502
  "textual_inversion": embed_list if textual_inversion else [],
503
  "syntax_weights": syntax_weights, # "Classic"
504
  "sampler": sampler,
505
  "schedule_type": schedule_type,
506
  "schedule_prediction_type": schedule_prediction_type,
507
+ "xformers_memory_efficient_attention": xformers_memory_efficient_attention,
508
  "gui_active": True,
509
  "loop_generation": loop_generation,
510
  "controlnet_conditioning_scale": float(controlnet_output_scaling_in_unet),
 
519
  "leave_progress_bar": leave_progress_bar,
520
  "disable_progress_bar": disable_progress_bar,
521
  "image_previews": image_previews,
522
+ "display_images": display_images,
523
  "save_generated_images": save_generated_images,
524
  "filename_pattern": filename_pattern,
525
  "image_storage_location": image_storage_location,
 
531
  "t2i_adapter_conditioning_factor": float(t2i_adapter_conditioning_factor),
532
  "upscaler_model_path": upscaler_model,
533
  "upscaler_increases_size": upscaler_increases_size,
534
+ "esrgan_tile": esrgan_tile,
535
+ "esrgan_tile_overlap": esrgan_tile_overlap,
536
  "hires_steps": hires_steps,
537
  "hires_denoising_strength": hires_denoising_strength,
538
  "hires_prompt": hires_prompt,
 
547
  "ip_adapter_model": params_ip_model,
548
  "ip_adapter_mode": params_ip_mode,
549
  "ip_adapter_scale": params_ip_scale,
 
 
 
550
  }
551
 
552
  # kwargs for diffusers pipeline
553
  if guidance_rescale:
554
  pipe_params["guidance_rescale"] = guidance_rescale
555
+
556
+ self.model.device = torch.device("cuda:0")
557
+ if hasattr(self.model.pipe, "transformer") and loras_list != ["None"] * self.model.num_loras:
558
+ self.model.pipe.transformer.to(self.model.device)
559
+ print("transformer to cuda")
560
 
561
  actual_progress = 0
562
  info_images = gr.update()
 
586
 
587
  download_links = "<br>".join(
588
  [
589
+ f'<a href="{path.replace("/images/", "/file=/home/user/app/images/")}" download="{os.path.basename(path)}">Download Image {i + 1}</a>'
590
  for i, path in enumerate(image_path)
591
  ]
592
  )
593
  if save_generated_images:
594
  info_images += f"<br>{download_links}"
595
 
 
 
596
  info_state = "COMPLETE"
597
 
 
 
 
598
  yield info_state, img, info_images
599
 
600
 
 
694
 
695
 
696
  @spaces.GPU(duration=15)
697
+ def esrgan_upscale(image, upscaler_name, upscaler_size):
698
+ if image is None: return None
 
699
 
700
  from stablepy.diffusers_vanilla.utils import save_pil_image_with_metadata
701
+ from stablepy import UpscalerESRGAN
702
 
 
703
  exif_image = extract_exif_data(image)
704
 
705
+ url_upscaler = UPSCALER_DICT_GUI[upscaler_name]
706
+ directory_upscalers = 'upscalers'
707
+ os.makedirs(directory_upscalers, exist_ok=True)
708
+ if not os.path.exists(f"./upscalers/{url_upscaler.split('/')[-1]}"):
709
+ download_things(directory_upscalers, url_upscaler, HF_TOKEN)
710
 
711
+ scaler_beta = UpscalerESRGAN(0, 0)
712
+ image_up = scaler_beta.upscale(image, upscaler_size, f"./upscalers/{url_upscaler.split('/')[-1]}")
 
 
 
 
 
713
 
714
  image_path = save_pil_image_with_metadata(image_up, f'{os.getcwd()}/up_images', exif_image)
715
 
 
717
 
718
 
719
  # https://huggingface.co/spaces/BestWishYsh/ConsisID-preview-Space/discussions/1#674969a022b99c122af5d407
720
+ dynamic_gpu_duration.zerogpu = True
721
+ sd_gen_generate_pipeline.zerogpu = True
722
  sd_gen = GuiSD()
723
 
724
+ with gr.Blocks(theme="NoCrypt/miku", css=CSS) as app:
725
  gr.Markdown("# 🧩 DiffuseCraft")
726
  gr.Markdown(SUBTITLE_GUI)
727
  with gr.Tab("Generation"):
 
737
 
738
  return gr.update(value=task_name, choices=new_choices)
739
 
740
+ task_gui = gr.Dropdown(label="Task", choices=SDXL_TASK, value=TASK_MODEL_LIST[0])
741
+ model_name_gui = gr.Dropdown(label="Model", choices=model_list, value=model_list[0], allow_custom_value=True)
 
742
  prompt_gui = gr.Textbox(lines=5, placeholder="Enter prompt", label="Prompt")
743
+ 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)")
 
 
 
744
  with gr.Row(equal_height=False):
745
  set_params_gui = gr.Button(value="↙️", variant="secondary", size="sm")
746
  clear_prompt_gui = gr.Button(value="🗑️", variant="secondary", size="sm")
 
770
 
771
  actual_task_info = gr.HTML()
772
 
773
+ with gr.Row(equal_height=False, variant="default"):
774
  gpu_duration_gui = gr.Number(minimum=5, maximum=240, value=59, show_label=False, container=False, info="GPU time duration (seconds)")
775
  with gr.Column():
776
  verbose_info_gui = gr.Checkbox(value=False, container=False, label="Status info")
777
  load_lora_cpu_gui = gr.Checkbox(value=False, container=False, label="Load LoRAs on CPU")
778
 
779
  with gr.Column(scale=1):
780
+ steps_gui = gr.Slider(minimum=1, maximum=100, step=1, value=28, label="Steps")
781
+ cfg_gui = gr.Slider(minimum=0, maximum=30, step=0.5, value=7., label="CFG")
782
+ sampler_gui = gr.Dropdown(label="Sampler", choices=scheduler_names, value="Euler")
783
+ schedule_type_gui = gr.Dropdown(label="Schedule type", choices=SCHEDULE_TYPE_OPTIONS, value=SCHEDULE_TYPE_OPTIONS[0])
784
+ img_width_gui = gr.Slider(minimum=64, maximum=4096, step=8, value=1024, label="Img Width")
785
+ img_height_gui = gr.Slider(minimum=64, maximum=4096, step=8, value=1024, label="Img Height")
786
+ seed_gui = gr.Number(minimum=-1, maximum=9999999999, value=-1, label="Seed")
787
+ pag_scale_gui = gr.Slider(minimum=0.0, maximum=10.0, step=0.1, value=0.0, label="PAG Scale")
788
+ with gr.Row():
789
+ clip_skip_gui = gr.Checkbox(value=True, label="Layer 2 Clip Skip")
790
+ free_u_gui = gr.Checkbox(value=False, label="FreeU")
791
+
792
+ with gr.Row(equal_height=False):
793
+
794
+ def run_set_params_gui(base_prompt, name_model):
795
+ valid_receptors = { # default values
796
+ "prompt": gr.update(value=base_prompt),
797
+ "neg_prompt": gr.update(value=""),
798
+ "Steps": gr.update(value=30),
799
+ "width": gr.update(value=1024),
800
+ "height": gr.update(value=1024),
801
+ "Seed": gr.update(value=-1),
802
+ "Sampler": gr.update(value="Euler"),
803
+ "CFG scale": gr.update(value=7.), # cfg
804
+ "Clip skip": gr.update(value=True),
805
+ "Model": gr.update(value=name_model),
806
+ "Schedule type": gr.update(value="Automatic"),
807
+ "PAG": gr.update(value=.0),
808
+ "FreeU": gr.update(value=False),
809
+ }
810
+ valid_keys = list(valid_receptors.keys())
811
+
812
+ parameters = extract_parameters(base_prompt)
813
+ # print(parameters)
814
+
815
+ if "Sampler" in parameters:
816
+ value_sampler = parameters["Sampler"]
817
+ for s_type in SCHEDULE_TYPE_OPTIONS:
818
+ if s_type in value_sampler:
819
+ value_sampler = value_sampler.replace(s_type, "").strip()
820
+ parameters["Sampler"] = value_sampler
821
+ parameters["Schedule type"] = s_type
822
+
823
+ for key, val in parameters.items():
824
+ # print(val)
825
+ if key in valid_keys:
826
+ try:
827
+ if key == "Sampler":
828
+ if val not in scheduler_names:
829
+ continue
830
+ if key == "Schedule type":
831
+ if val not in SCHEDULE_TYPE_OPTIONS:
832
+ val = "Automatic"
833
+ elif key == "Clip skip":
834
+ if "," in str(val):
835
+ val = val.replace(",", "")
836
+ if int(val) >= 2:
837
+ val = True
838
+ if key == "prompt":
839
+ if ">" in val and "<" in val:
840
+ val = re.sub(r'<[^>]+>', '', val)
841
+ print("Removed LoRA written in the prompt")
842
+ if key in ["prompt", "neg_prompt"]:
843
+ val = re.sub(r'\s+', ' ', re.sub(r',+', ',', val)).strip()
844
+ if key in ["Steps", "width", "height", "Seed"]:
845
+ val = int(val)
846
+ if key == "FreeU":
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
847
  val = True
848
+ if key in ["CFG scale", "PAG"]:
849
+ val = float(val)
850
+ if key == "Model":
851
+ filtered_models = [m for m in model_list if val in m]
852
+ if filtered_models:
853
+ val = filtered_models[0]
854
+ else:
855
+ val = name_model
856
+ if key == "Seed":
 
 
 
 
 
 
 
 
 
 
 
857
  continue
858
+ valid_receptors[key] = gr.update(value=val)
859
+ # print(val, type(val))
860
+ # print(valid_receptors)
861
+ except Exception as e:
862
+ print(str(e))
863
+ return [value for value in valid_receptors.values()]
864
+
865
+ set_params_gui.click(
866
+ run_set_params_gui, [prompt_gui, model_name_gui], [
867
+ prompt_gui,
868
+ neg_prompt_gui,
869
+ steps_gui,
870
+ img_width_gui,
871
+ img_height_gui,
872
+ seed_gui,
873
+ sampler_gui,
874
+ cfg_gui,
875
+ clip_skip_gui,
876
+ model_name_gui,
877
+ schedule_type_gui,
878
+ pag_scale_gui,
879
+ free_u_gui,
880
+ ],
881
+ )
882
 
883
+ def run_clear_prompt_gui():
884
+ return gr.update(value=""), gr.update(value="")
885
+ clear_prompt_gui.click(
886
+ run_clear_prompt_gui, [], [prompt_gui, neg_prompt_gui]
887
+ )
888
+
889
+ def run_set_random_seed():
890
+ return -1
891
+ set_random_seed.click(
892
+ run_set_random_seed, [], seed_gui
893
+ )
894
+
895
+ num_images_gui = gr.Slider(minimum=1, maximum=5, step=1, value=1, label="Images")
896
+ prompt_syntax_gui = gr.Dropdown(label="Prompt Syntax", choices=PROMPT_W_OPTIONS, value=PROMPT_W_OPTIONS[1][1])
897
+ vae_model_gui = gr.Dropdown(label="VAE Model", choices=vae_model_list, value=vae_model_list[0])
898
 
899
  with gr.Accordion("Hires fix", open=False, visible=True):
900
 
901
  upscaler_model_path_gui = gr.Dropdown(label="Upscaler", choices=UPSCALER_KEYS, value=UPSCALER_KEYS[0])
902
  upscaler_increases_size_gui = gr.Slider(minimum=1.1, maximum=4., step=0.1, value=1.2, label="Upscale by")
903
+ esrgan_tile_gui = gr.Slider(minimum=0, value=0, maximum=500, step=1, label="ESRGAN Tile")
904
+ esrgan_tile_overlap_gui = gr.Slider(minimum=1, maximum=200, step=1, value=8, label="ESRGAN Tile Overlap")
905
  hires_steps_gui = gr.Slider(minimum=0, value=30, maximum=100, step=1, label="Hires Steps")
906
  hires_denoising_strength_gui = gr.Slider(minimum=0.1, maximum=1.0, step=0.01, value=0.55, label="Hires Denoising Strength")
907
  hires_sampler_gui = gr.Dropdown(label="Hires Sampler", choices=POST_PROCESSING_SAMPLER, value=POST_PROCESSING_SAMPLER[0])
 
917
  return gr.Dropdown(label=label, choices=lora_model_list, value="None", allow_custom_value=True, visible=visible)
918
 
919
  def lora_scale_slider(label, visible=True):
920
+ return gr.Slider(minimum=-2, maximum=2, step=0.01, value=0.33, label=label, visible=visible)
 
921
 
922
  lora1_gui = lora_dropdown("Lora1")
923
  lora_scale_1_gui = lora_scale_slider("Lora Scale 1")
 
929
  lora_scale_4_gui = lora_scale_slider("Lora Scale 4")
930
  lora5_gui = lora_dropdown("Lora5")
931
  lora_scale_5_gui = lora_scale_slider("Lora Scale 5")
932
+ lora6_gui = lora_dropdown("Lora6", visible=False)
933
+ lora_scale_6_gui = lora_scale_slider("Lora Scale 6", visible=False)
934
+ lora7_gui = lora_dropdown("Lora7", visible=False)
935
+ lora_scale_7_gui = lora_scale_slider("Lora Scale 7", visible=False)
936
 
937
  with gr.Accordion("From URL", open=False, visible=True):
938
  text_lora = gr.Textbox(
 
941
  lines=1,
942
  info="It has to be .safetensors files, and you can also download them from Hugging Face.",
943
  )
944
+ romanize_text = gr.Checkbox(value=False, label="Transliterate name", visible=False)
945
  button_lora = gr.Button("Get and Refresh the LoRA Lists")
946
  new_lora_status = gr.HTML()
947
  button_lora.click(
 
950
  [lora1_gui, lora2_gui, lora3_gui, lora4_gui, lora5_gui, lora6_gui, lora7_gui, new_lora_status]
951
  )
952
 
 
 
 
 
 
 
 
 
953
  with gr.Accordion("IP-Adapter", open=False, visible=True):
954
 
955
+ IP_MODELS = sorted(list(set(IP_ADAPTERS_SD + IP_ADAPTERS_SDXL)))
956
+ MODE_IP_OPTIONS = ["original", "style", "layout", "style+layout"]
957
+
958
  with gr.Accordion("IP-Adapter 1", open=False, visible=True):
959
  image_ip1 = gr.Image(label="IP Image", type="filepath")
960
  mask_ip1 = gr.Image(label="IP Mask", type="filepath")
 
973
  image_mask_gui = gr.Image(label="Image Mask", type="filepath")
974
  strength_gui = gr.Slider(
975
  minimum=0.01, maximum=1.0, step=0.01, value=0.55, label="Strength",
976
+ info="This option adjusts the level of changes for img2img and inpainting."
977
  )
978
  image_resolution_gui = gr.Slider(
979
  minimum=64, maximum=2048, step=64, value=1024, label="Image Resolution",
980
  info="The maximum proportional size of the generated image based on the uploaded image."
981
  )
982
+ controlnet_model_gui = gr.Dropdown(label="ControlNet model", choices=DIFFUSERS_CONTROLNET_MODEL, value=DIFFUSERS_CONTROLNET_MODEL[0])
983
  control_net_output_scaling_gui = gr.Slider(minimum=0, maximum=5.0, step=0.1, value=1, label="ControlNet Output Scaling in UNet")
984
  control_net_start_threshold_gui = gr.Slider(minimum=0, maximum=1, step=0.01, value=0, label="ControlNet Start Threshold (%)")
985
  control_net_stop_threshold_gui = gr.Slider(minimum=0, maximum=1, step=0.01, value=1, label="ControlNet Stop Threshold (%)")
 
1001
  preprocess_resolution_gui = gr.Slider(minimum=64, maximum=2048, step=64, value=512, label="Preprocessor Resolution")
1002
  low_threshold_gui = gr.Slider(minimum=1, maximum=255, step=1, value=100, label="'CANNY' low threshold")
1003
  high_threshold_gui = gr.Slider(minimum=1, maximum=255, step=1, value=200, label="'CANNY' high threshold")
1004
+ value_threshold_gui = gr.Slider(minimum=1, maximum=2.0, step=0.01, value=0.1, label="'MLSD' Hough value threshold")
1005
+ distance_threshold_gui = gr.Slider(minimum=1, maximum=20.0, step=0.01, value=0.1, label="'MLSD' Hough distance threshold")
1006
  recolor_gamma_correction_gui = gr.Number(minimum=0., maximum=25., value=1., step=0.001, label="'RECOLOR' gamma correction")
1007
  tile_blur_sigma_gui = gr.Number(minimum=0, maximum=100, value=9, step=1, label="'TILE' blur sigma")
1008
 
 
1037
  gr.Info(f"{len(sd_gen.model.STYLE_NAMES)} styles loaded")
1038
  return gr.update(value=None, choices=sd_gen.model.STYLE_NAMES)
1039
 
1040
+ style_button.click(load_json_style_file, [style_json_gui], [style_prompt_gui])
1041
 
1042
  with gr.Accordion("Textual inversion", open=False, visible=False):
1043
  active_textual_inversion_gui = gr.Checkbox(value=False, label="Active Textual Inversion in prompt")
 
1083
  schedule_prediction_type_gui = gr.Dropdown(label="Discrete Sampling Type", choices=SCHEDULE_PREDICTION_TYPE_OPTIONS, value=SCHEDULE_PREDICTION_TYPE_OPTIONS[0])
1084
  guidance_rescale_gui = gr.Number(label="CFG rescale:", value=0., step=0.01, minimum=0., maximum=1.5)
1085
  save_generated_images_gui = gr.Checkbox(value=True, label="Create a download link for the images")
 
 
1086
  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)
1087
  hires_before_adetailer_gui = gr.Checkbox(value=False, label="Hires Before Adetailer")
1088
  hires_after_adetailer_gui = gr.Checkbox(value=True, label="Hires After Adetailer")
1089
  generator_in_cpu_gui = gr.Checkbox(value=False, label="Generator in CPU")
 
 
 
 
1090
 
1091
  with gr.Accordion("More settings", open=False, visible=False):
1092
  loop_generation_gui = gr.Slider(minimum=1, value=1, label="Loop Generation")
1093
  retain_task_cache_gui = gr.Checkbox(value=False, label="Retain task model in cache")
1094
+ leave_progress_bar_gui = gr.Checkbox(value=True, label="Leave Progress Bar")
1095
+ disable_progress_bar_gui = gr.Checkbox(value=False, label="Disable Progress Bar")
1096
+ display_images_gui = gr.Checkbox(value=False, label="Display Images")
1097
+ image_previews_gui = gr.Checkbox(value=True, label="Image Previews")
1098
+ image_storage_location_gui = gr.Textbox(value="./images", label="Image Storage Location")
1099
  retain_compel_previous_load_gui = gr.Checkbox(value=False, label="Retain Compel Previous Load")
1100
  retain_detailfix_model_previous_load_gui = gr.Checkbox(value=False, label="Retain Detailfix Model Previous Load")
1101
  retain_hires_model_previous_load_gui = gr.Checkbox(value=False, label="Retain Hires Model Previous Load")
1102
+ xformers_memory_efficient_attention_gui = gr.Checkbox(value=False, label="Xformers Memory Efficient Attention")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1103
 
1104
  with gr.Accordion("Examples and help", open=False, visible=True):
1105
  gr.Markdown(HELP_GUI)
 
1156
  # "hsl(360, 120, 120)" # in fact any valid colorstring
1157
  ]
1158
  ),
1159
+ eraser=gr.Eraser(default_size="16")
 
 
 
1160
  )
 
 
 
 
 
 
 
1161
  invert_mask = gr.Checkbox(value=False, label="Invert mask")
1162
  btn = gr.Button("Create mask")
 
1163
  with gr.Column(scale=1):
1164
  img_source = gr.Image(interactive=False)
1165
  img_result = gr.Image(label="Mask image", show_label=True, interactive=False)
 
1190
 
1191
  with gr.Row():
1192
  with gr.Column():
 
 
 
1193
  image_up_tab = gr.Image(label="Image", type="pil", sources=["upload"])
1194
+ upscaler_tab = gr.Dropdown(label="Upscaler", choices=UPSCALER_KEYS[9:], value=UPSCALER_KEYS[11])
1195
  upscaler_size_tab = gr.Slider(minimum=1., maximum=4., step=0.1, value=1.1, label="Upscale by")
1196
  generate_button_up_tab = gr.Button(value="START UPSCALE", variant="primary")
1197
 
 
1199
  result_up_tab = gr.Image(label="Result", type="pil", interactive=False, format="png")
1200
 
1201
  generate_button_up_tab.click(
1202
+ fn=esrgan_upscale,
1203
  inputs=[image_up_tab, upscaler_tab, upscaler_size_tab],
1204
  outputs=[result_up_tab],
1205
  )
 
1218
  outputs=[load_model_gui],
1219
  queue=True,
1220
  show_progress="minimal",
 
1221
  ).success(
1222
  fn=sd_gen_generate_pipeline, # fn=sd_gen.generate_pipeline,
1223
  inputs=[
 
1271
  prompt_syntax_gui,
1272
  upscaler_model_path_gui,
1273
  upscaler_increases_size_gui,
1274
+ esrgan_tile_gui,
1275
+ esrgan_tile_overlap_gui,
1276
  hires_steps_gui,
1277
  hires_denoising_strength_gui,
1278
  hires_sampler_gui,
 
1297
  t2i_adapter_preprocessor_gui,
1298
  adapter_conditioning_scale_gui,
1299
  adapter_conditioning_factor_gui,
1300
+ xformers_memory_efficient_attention_gui,
1301
  free_u_gui,
1302
  generator_in_cpu_gui,
1303
  adetailer_inpaint_only_gui,
 
1336
  mode_ip2,
1337
  scale_ip2,
1338
  pag_scale_gui,
 
 
 
1339
  load_lora_cpu_gui,
1340
  verbose_info_gui,
1341
  gpu_duration_gui,
 
1343
  outputs=[load_model_gui, result_images, actual_task_info],
1344
  queue=True,
1345
  show_progress="minimal",
 
1346
  )
1347
 
1348
+ app.queue()
1349
+
1350
+ app.launch(
1351
+ show_error=True,
1352
+ debug=True,
1353
+ allowed_paths=["./images/"],
1354
+ )
 
 
 
constants.py CHANGED
@@ -4,72 +4,51 @@ 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/Anzhc/Anzhcs-VAEs/resolve/main/SDXL%20Anime%20VAE%20Dec-only%20B3.safetensors, 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"
23
 
24
  LOAD_DIFFUSERS_FORMAT_MODEL = [
25
  'stabilityai/stable-diffusion-xl-base-1.0',
26
- 'TestOrganizationPleaseIgnore/potato_quality_anime_plzwork_sdxl',
27
- 'TestOrganizationPleaseIgnore/rinAnim8drawIllustriousXL_v20_sdxl',
28
- 'TestOrganizationPleaseIgnore/perfectrsbmixIllustrious_definitiveiota_sdxl',
29
  'Laxhar/noobai-XL-1.1',
30
- 'Laxhar/noobai-XL-Vpred-1.0',
31
  'black-forest-labs/FLUX.1-dev',
32
- 'black-forest-labs/FLUX.1-Krea-dev',
33
  'John6666/blue-pencil-flux1-v021-fp8-flux',
34
  'John6666/wai-ani-flux-v10forfp8-fp8-flux',
35
  'John6666/xe-anime-flux-v04-fp8-flux',
36
  'John6666/lyh-anime-flux-v2a1-fp8-flux',
37
  'John6666/carnival-unchained-v10-fp8-flux',
 
38
  'Freepik/flux.1-lite-8B-alpha',
39
  'shauray/FluxDev-HyperSD-merged',
40
  'mikeyandfriends/PixelWave_FLUX.1-dev_03',
41
  'terminusresearch/FluxBooru-v0.3',
42
- 'black-forest-labs/FLUX.1-schnell',
43
- # 'ostris/OpenFLUX.1',
44
  'shuttleai/shuttle-3-diffusion',
45
  'Laxhar/noobai-XL-1.0',
 
46
  'Laxhar/noobai-XL-0.77',
47
  'John6666/noobai-xl-nai-xl-epsilonpred075version-sdxl',
48
  'Laxhar/noobai-XL-0.6',
49
  'John6666/noobai-xl-nai-xl-epsilonpred05version-sdxl',
50
  'John6666/noobai-cyberfix-v10-sdxl',
51
  'John6666/noobaiiter-xl-vpred-v075-sdxl',
52
- 'John6666/ripplemix-noob-vpred10-illustrious01-v14-sdxl',
53
- 'John6666/sigmaih-15-sdxl',
54
- 'John6666/ntr-mix-illustrious-xl-noob-xl-xi-sdxl',
55
- 'John6666/ntr-mix-illustrious-xl-noob-xl-xii-sdxl',
56
- 'John6666/ntr-mix-illustrious-xl-noob-xl-xiii-sdxl',
57
- 'martineux/nova-unreal10',
58
- 'John6666/mistoon-anime-v10illustrious-sdxl',
59
- 'John6666/hassaku-xl-illustrious-v22-sdxl',
60
- 'John6666/hassaku-xl-illustrious-v31-sdxl',
61
  'John6666/haruki-mix-illustrious-v10-sdxl',
62
  'John6666/noobreal-v10-sdxl',
63
  'John6666/complicated-noobai-merge-vprediction-sdxl',
64
- 'Laxhar/noobai-XL-Vpred-0.9r',
65
- 'Laxhar/noobai-XL-Vpred-0.75s',
66
- 'Laxhar/noobai-XL-Vpred-0.75',
67
  'Laxhar/noobai-XL-Vpred-0.65s',
68
  'Laxhar/noobai-XL-Vpred-0.65',
69
  'Laxhar/noobai-XL-Vpred-0.6',
70
- 'John6666/cat-tower-noobai-xl-checkpoint-v14vpred-sdxl',
71
- 'John6666/cat-tower-noobai-xl-checkpoint-v15vpred-sdxl',
72
- 'John6666/cat-tower-noobai-xl-checkpoint-v20-vpred-sdxl',
73
  'John6666/noobai-xl-nai-xl-vpred05version-sdxl',
74
  'John6666/noobai-fusion2-vpred-itercomp-v1-sdxl',
75
  'John6666/noobai-xl-nai-xl-vpredtestversion-sdxl',
@@ -79,47 +58,18 @@ LOAD_DIFFUSERS_FORMAT_MODEL = [
79
  'John6666/illustrious-pencil-xl-v200-sdxl',
80
  'John6666/obsession-illustriousxl-v21-sdxl',
81
  'John6666/obsession-illustriousxl-v30-sdxl',
82
- 'John6666/obsession-illustriousxl-v31-sdxl',
83
- 'John6666/one-obsession-13-sdxl',
84
- 'John6666/one-obsession-14-24d-sdxl',
85
- 'John6666/one-obsession-15-noobai-sdxl',
86
- 'John6666/one-obsession-v16-noobai-sdxl',
87
- 'John6666/one-obsession-17-red-sdxl',
88
- 'martineux/oneobs18',
89
- 'martineux/oneobsession19',
90
- 'John6666/cat-tower-noobai-xl-checkpoint-v14-epsilon-pred-sdxl',
91
- 'martineux/cattower-chenkin-xl',
92
- 'John6666/prefect-illustrious-xl-v3-sdxl',
93
- 'martineux/perfect4',
94
- 'martineux/prefectIllustriousXL_v5',
95
  'John6666/wai-nsfw-illustrious-v70-sdxl',
96
- 'John6666/wai-nsfw-illustrious-sdxl-v140-sdxl',
97
- 'martineux/waiIllustriousSDXL_v160',
98
  'John6666/illustrious-pony-mix-v3-sdxl',
99
- 'John6666/nova-anime-xl-il-v90-sdxl',
100
- 'John6666/nova-anime-xl-il-v110-sdxl',
101
- 'frankjoshua/novaAnimeXL_ilV140',
102
- 'John6666/nova-orange-xl-re-v10-sdxl',
103
- 'John6666/nova-orange-xl-v110-sdxl',
104
- 'John6666/nova-orange-xl-re-v20-sdxl',
105
- 'John6666/nova-unreal-xl-v60-sdxl',
106
- 'John6666/nova-unreal-xl-v70-sdxl',
107
- 'John6666/nova-unreal-xl-v80-sdxl',
108
- 'martineux/nova-unreal10',
109
- 'John6666/nova-cartoon-xl-v40-sdxl',
110
- 'martineux/novacartoon6',
111
- 'martineux/novareal8',
112
  'John6666/silvermoon-mix03-illustrious-v10-sdxl',
113
  'eienmojiki/Anything-XL',
114
  'eienmojiki/Starry-XL-v5.2',
115
- 'votepurchase/plantMilkModelSuite_walnut',
116
  'John6666/meinaxl-v2-sdxl',
117
  'Eugeoter/artiwaifu-diffusion-2.0',
118
  'comin/IterComp',
119
- 'John6666/epicrealism-xl-v8kiss-sdxl',
120
  'John6666/epicrealism-xl-v10kiss2-sdxl',
121
- 'John6666/epicrealism-xl-vxiabeast-sdxl',
122
- 'John6666/epicrealism-xl-vxvii-crystal-clear-realism-sdxl',
123
  'misri/zavychromaxl_v80',
124
  'SG161222/RealVisXL_V4.0',
125
  'SG161222/RealVisXL_V5.0',
@@ -131,14 +81,11 @@ LOAD_DIFFUSERS_FORMAT_MODEL = [
131
  'John6666/ras-real-anime-screencap-v1-sdxl',
132
  'John6666/duchaiten-pony-xl-no-score-v60-sdxl',
133
  'John6666/mistoon-anime-ponyalpha-sdxl',
134
- 'John6666/mistoon-xl-copper-v20fast-sdxl',
135
  'John6666/ebara-mfcg-pony-mix-v12-sdxl',
136
  'John6666/t-ponynai3-v51-sdxl',
137
  'John6666/t-ponynai3-v65-sdxl',
138
- 'John6666/t-ponynai3-v7-sdxl',
139
  'John6666/prefect-pony-xl-v3-sdxl',
140
  'John6666/prefect-pony-xl-v4-sdxl',
141
- 'John6666/prefect-pony-xl-v50-sdxl',
142
  'John6666/mala-anime-mix-nsfw-pony-xl-v5-sdxl',
143
  'John6666/wai-ani-nsfw-ponyxl-v10-sdxl',
144
  'John6666/wai-real-mix-v11-sdxl',
@@ -146,48 +93,24 @@ LOAD_DIFFUSERS_FORMAT_MODEL = [
146
  'John6666/wai-c-v6-sdxl',
147
  'John6666/iniverse-mix-xl-sfwnsfw-pony-guofeng-v43-sdxl',
148
  'John6666/sifw-annihilation-xl-v2-sdxl',
149
- 'John6666/sifw-annihilation-xl-v305illustrious-beta-sdxl',
150
  'John6666/photo-realistic-pony-v5-sdxl',
151
  'John6666/pony-realism-v21main-sdxl',
152
  'John6666/pony-realism-v22main-sdxl',
153
- 'John6666/pony-realism-v23-ultra-sdxl',
 
154
  'John6666/cyberrealistic-pony-v65-sdxl',
155
- 'John6666/cyberrealistic-pony-v7-sdxl',
156
- 'John6666/cyberrealistic-pony-v127-alternative-sdxl',
157
  'GraydientPlatformAPI/realcartoon-pony-diffusion',
158
  'John6666/nova-anime-xl-pony-v5-sdxl',
159
  'John6666/autismmix-sdxl-autismmix-pony-sdxl',
160
  'John6666/aimz-dream-real-pony-mix-v3-sdxl',
161
- 'John6666/prefectious-xl-nsfw-v10-sdxl',
162
- 'GraydientPlatformAPI/iniverseponyRealGuofeng49',
163
  'John6666/duchaiten-pony-real-v11fix-sdxl',
164
  'John6666/duchaiten-pony-real-v20-sdxl',
165
  'John6666/duchaiten-pony-xl-no-score-v70-sdxl',
166
  'KBlueLeaf/Kohaku-XL-Zeta',
167
  'cagliostrolab/animagine-xl-3.1',
168
- 'cagliostrolab/animagine-xl-4.0',
169
  'yodayo-ai/kivotos-xl-2.0',
170
  'yodayo-ai/holodayo-xl-2.1',
171
  'yodayo-ai/clandestine-xl-1.0',
172
- 'Raelina/Raehoshi-illust-XL-8',
173
- 'johnkillington/chenkinxmilfynoobai_v20-MLX',
174
- 'martineux/unholydesire5-xl',
175
- 'abacaxthebrave/Unholy_Desire_Mix_ILXL',
176
- 'martineux/diving5',
177
- 'martineux/diving7',
178
- 'martineux/mergestein-animuplus-xl',
179
- 'martineux/mergestein-uncannyr2-xl',
180
- 'martineux/steincustom_V12',
181
- 'martineux/miaomiao-realskin1p25-xl',
182
- 'martineux/miaov18',
183
- 'John6666/garage-mix-noob-vpred-eps-v10-vpred-sdxl',
184
- 'TestOrganizationPleaseIgnore/perfectrsbmixIllustrious_definitivelambda_sdxl',
185
- 'TestOrganizationPleaseIgnore/rinFlanimeIllustrious_v27_sdxl',
186
- 'TestOrganizationPleaseIgnore/rinAnimepopcute_v30_sdxl',
187
- 'TestOrganizationPleaseIgnore/potato_quality_anime_zzz_sdxl',
188
- 'https://huggingface.co/chemwolf/Karmix-XL-v0/resolve/main/Karmix-XL-v0.safetensors?download=true',
189
- 'https://civitai.com/api/download/models/128713?type=Model&format=SafeTensor&size=pruned&fp=fp16',
190
- 'https://civitai.com/models/30240?modelVersionId=125771',
191
  'digiplay/majicMIX_sombre_v2',
192
  'digiplay/majicMIX_realistic_v6',
193
  'digiplay/majicMIX_realistic_v7',
@@ -197,9 +120,7 @@ LOAD_DIFFUSERS_FORMAT_MODEL = [
197
  'digiplay/darkphoenix3D_v1.1',
198
  'digiplay/BeenYouLiteL11_diffusers',
199
  'GraydientPlatformAPI/rev-animated2',
200
- 'myxlmynx/cyberrealistic_classic40',
201
- 'GraydientPlatformAPI/cyberreal6',
202
- 'GraydientPlatformAPI/cyberreal5',
203
  'youknownothing/deliberate-v6',
204
  'GraydientPlatformAPI/deliberate-cyber3',
205
  'GraydientPlatformAPI/picx-real',
@@ -213,9 +134,9 @@ LOAD_DIFFUSERS_FORMAT_MODEL = [
213
  'GraydientPlatformAPI/realcartoon3d-17',
214
  'GraydientPlatformAPI/realcartoon-pixar11',
215
  'GraydientPlatformAPI/realcartoon-real17',
 
216
  ]
217
 
218
-
219
  DIFFUSERS_FORMAT_LORAS = [
220
  "nerijs/animation2k-flux",
221
  "XLabs-AI/flux-RealismLora",
@@ -235,13 +156,9 @@ DIRECTORY_MODELS = 'models'
235
  DIRECTORY_LORAS = 'loras'
236
  DIRECTORY_VAES = 'vaes'
237
  DIRECTORY_EMBEDS = 'embedings'
238
- DIRECTORY_UPSCALERS = 'upscalers'
239
 
 
240
  STORAGE_ROOT = "/home/user/"
241
- CACHE_HF_ROOT = os.path.expanduser("~/.cache/huggingface")
242
- CACHE_HF = os.path.join(CACHE_HF_ROOT, "hub")
243
- if IS_ZERO_GPU:
244
- os.environ["HF_HOME"] = CACHE_HF
245
 
246
  TASK_STABLEPY = {
247
  'txt2img': 'txt2img',
@@ -267,23 +184,28 @@ TASK_STABLEPY = {
267
  'optical pattern ControlNet': 'pattern',
268
  'recolor ControlNet': 'recolor',
269
  'tile ControlNet': 'tile',
270
- 'repaint ControlNet': 'repaint',
271
  }
272
 
273
  TASK_MODEL_LIST = list(TASK_STABLEPY.keys())
274
 
275
  UPSCALER_DICT_GUI = {
276
  None: None,
277
- **{bu: bu for bu in ALL_BUILTIN_UPSCALERS if bu not in ["HAT x4", "DAT x4", "DAT x3", "DAT x2", "SwinIR 4x"]},
278
- # "RealESRGAN_x4plus": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth",
 
 
 
 
 
 
 
279
  "RealESRNet_x4plus": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.1/RealESRNet_x4plus.pth",
280
- # "RealESRGAN_x4plus_anime_6B": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/RealESRGAN_x4plus_anime_6B.pth",
281
- # "RealESRGAN_x2plus": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.1/RealESRGAN_x2plus.pth",
282
- # "realesr-animevideov3": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-animevideov3.pth",
283
- # "realesr-general-x4v3": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-general-x4v3.pth",
284
- # "realesr-general-wdn-x4v3": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-general-wdn-x4v3.pth",
285
  "4x-UltraSharp": "https://huggingface.co/Shandypur/ESRGAN-4x-UltraSharp/resolve/main/4x-UltraSharp.pth",
286
- "Real-ESRGAN-Anime-finetuning": "https://huggingface.co/danhtran2mind/Real-ESRGAN-Anime-finetuning/resolve/main/Real-ESRGAN-Anime-finetuning.pth",
287
  "4x_foolhardy_Remacri": "https://huggingface.co/FacehugmanIII/4x_foolhardy_Remacri/resolve/main/4x_foolhardy_Remacri.pth",
288
  "Remacri4xExtraSmoother": "https://huggingface.co/hollowstrawberry/upscalers-backup/resolve/main/ESRGAN/Remacri%204x%20ExtraSmoother.pth",
289
  "AnimeSharp4x": "https://huggingface.co/hollowstrawberry/upscalers-backup/resolve/main/ESRGAN/AnimeSharp%204x.pth",
@@ -297,7 +219,6 @@ UPSCALER_KEYS = list(UPSCALER_DICT_GUI.keys())
297
  DIFFUSERS_CONTROLNET_MODEL = [
298
  "Automatic",
299
 
300
- "brad-twinkl/controlnet-union-sdxl-1.0-promax",
301
  "xinsir/controlnet-union-sdxl-1.0",
302
  "xinsir/anime-painter",
303
  "Eugeoter/noob-sdxl-controlnet-canny",
@@ -320,6 +241,7 @@ DIFFUSERS_CONTROLNET_MODEL = [
320
  "r3gm/controlnet-recolor-sdxl-fp16",
321
  "r3gm/controlnet-openpose-twins-sdxl-1.0-fp16",
322
  "r3gm/controlnet-qr-pattern-sdxl-fp16",
 
323
  "Yakonrus/SDXL_Controlnet_Tile_Realistic_v2",
324
  "TheMistoAI/MistoLine",
325
  "briaai/BRIA-2.3-ControlNet-Recoloring",
@@ -356,9 +278,15 @@ DIFFUSERS_CONTROLNET_MODEL = [
356
  # "InstantX/FLUX.1-dev-Controlnet-Canny",
357
  ]
358
 
359
- PROMPT_W_OPTIONS = [(pwf, pwf) for pwf in PROMPT_WEIGHT_OPTIONS_PRIORITY]
360
- PROMPT_W_OPTIONS[0] = ("Classic format: (word:weight)", "Classic")
361
- PROMPT_W_OPTIONS[1] = ("Compel format: (word)weight", "Compel")
 
 
 
 
 
 
362
 
363
  WARNING_MSG_VAE = (
364
  "Use the right VAE for your model to maintain image quality. The wrong"
@@ -392,30 +320,14 @@ POST_PROCESSING_SAMPLER = ["Use same sampler"] + [
392
  name_s for name_s in scheduler_names if "Auto-Loader" not in name_s
393
  ]
394
 
395
- IP_MODELS = []
396
- ALL_IPA = sorted(set(IP_ADAPTERS_SD + IP_ADAPTERS_SDXL))
397
-
398
- for origin_name in ALL_IPA:
399
- suffixes = []
400
- if origin_name in IP_ADAPTERS_SD:
401
- suffixes.append("sd1.5")
402
- if origin_name in IP_ADAPTERS_SDXL:
403
- suffixes.append("sdxl")
404
- ref_name = f"{origin_name} ({'/'.join(suffixes)})"
405
- IP_MODELS.append((ref_name, origin_name))
406
-
407
- MODE_IP_OPTIONS = ["original", "style", "layout", "style+layout"]
408
-
409
  SUBTITLE_GUI = (
410
  "### This demo uses [diffusers](https://github.com/huggingface/diffusers)"
411
  " to perform different tasks in image generation."
412
  )
413
 
414
- 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'."
415
-
416
  HELP_GUI = (
417
- f"""### Help:
418
- {msg_zero}
419
  - 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'.
420
  - For better results with Pony Diffusion, try using sampler DPM++ 1s or DPM2 with Compel or Classic prompt weights.
421
  """
@@ -428,9 +340,7 @@ EXAMPLES_GUI_HELP = (
428
  3. ControlNet Canny SDXL
429
  4. Optical pattern (Optical illusion) SDXL
430
  5. Convert an image to a coloring drawing
431
- 6. V prediction model inference
432
- 7. V prediction model sd_embed variant inference
433
- 8. ControlNet OpenPose SD 1.5 and Latent upscale
434
 
435
  - 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.
436
  """
@@ -539,7 +449,7 @@ EXAMPLES_GUI = [
539
  20,
540
  4.0,
541
  -1,
542
- ("loras/Coloring_book_-_LineArt.safetensors" if os.path.exists("loras/Coloring_book_-_LineArt.safetensors") else "None"),
543
  1.0,
544
  "DPM++ 2M SDE",
545
  1024,
@@ -557,54 +467,6 @@ EXAMPLES_GUI = [
557
  35,
558
  False,
559
  ],
560
- [
561
- "[mochizuki_shiina], [syuri22], newest, reimu, solo, outdoors, water, flower, lantern",
562
- "worst quality, normal quality, old, sketch,",
563
- 28,
564
- 7.0,
565
- -1,
566
- "None",
567
- 0.33,
568
- "DPM 3M Ef",
569
- 1600,
570
- 1024,
571
- "Laxhar/noobai-XL-Vpred-1.0",
572
- "txt2img",
573
- "color_image.png", # img conttol
574
- 1024, # img resolution
575
- 0.35, # strength
576
- 1.0, # cn scale
577
- 0.0, # cn start
578
- 1.0, # cn end
579
- "Classic",
580
- None,
581
- 30,
582
- False,
583
- ],
584
- [
585
- "[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\\)",
586
- "worst quality, normal quality, old, sketch,",
587
- 28,
588
- 7.0,
589
- -1,
590
- "None",
591
- 0.33,
592
- "DPM 3M Ef",
593
- 1600,
594
- 1024,
595
- "Laxhar/noobai-XL-Vpred-1.0",
596
- "txt2img",
597
- "color_image.png", # img conttol
598
- 1024, # img resolution
599
- 0.35, # strength
600
- 1.0, # cn scale
601
- 0.0, # cn start
602
- 1.0, # cn end
603
- "Classic-sd_embed",
604
- None,
605
- 30,
606
- False,
607
- ],
608
  [
609
  "1girl,face,curly hair,red hair,white background,",
610
  "(worst quality:2),(low quality:2),(normal quality:2),lowres,watermark,",
@@ -634,7 +496,6 @@ EXAMPLES_GUI = [
634
  RESOURCES = (
635
  """### Resources
636
  - John6666's space has some great features you might find helpful [link](https://huggingface.co/spaces/John6666/DiffuseCraftMod).
637
- - Try the image generator in Colab’s free tier, which provides free GPU [link](https://github.com/R3gm/SD_diffusers_interactive).
638
- - `DiffuseCraft` in Colab:[link](https://github.com/R3gm/DiffuseCraft?tab=readme-ov-file#diffusecraft).
639
  """
640
  )
 
4
  scheduler_names,
5
  SD15_TASKS,
6
  SDXL_TASKS,
 
 
 
 
7
  )
8
 
 
 
9
  # - **Download Models**
10
+ DOWNLOAD_MODEL = "https://huggingface.co/TechnoByte/MilkyWonderland/resolve/main/milkyWonderland_v40.safetensors"
11
 
12
  # - **Download VAEs**
13
+ 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"
14
 
15
  # - **Download LoRAs**
16
+ 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"
17
 
18
  LOAD_DIFFUSERS_FORMAT_MODEL = [
19
  'stabilityai/stable-diffusion-xl-base-1.0',
 
 
 
20
  'Laxhar/noobai-XL-1.1',
 
21
  'black-forest-labs/FLUX.1-dev',
 
22
  'John6666/blue-pencil-flux1-v021-fp8-flux',
23
  'John6666/wai-ani-flux-v10forfp8-fp8-flux',
24
  'John6666/xe-anime-flux-v04-fp8-flux',
25
  'John6666/lyh-anime-flux-v2a1-fp8-flux',
26
  'John6666/carnival-unchained-v10-fp8-flux',
27
+ 'John6666/iniverse-mix-xl-sfwnsfw-fluxdfp16nsfwv11-fp8-flux',
28
  'Freepik/flux.1-lite-8B-alpha',
29
  'shauray/FluxDev-HyperSD-merged',
30
  'mikeyandfriends/PixelWave_FLUX.1-dev_03',
31
  'terminusresearch/FluxBooru-v0.3',
32
+ 'ostris/OpenFLUX.1',
 
33
  'shuttleai/shuttle-3-diffusion',
34
  'Laxhar/noobai-XL-1.0',
35
+ 'John6666/noobai-xl-nai-xl-epsilonpred10version-sdxl',
36
  'Laxhar/noobai-XL-0.77',
37
  'John6666/noobai-xl-nai-xl-epsilonpred075version-sdxl',
38
  'Laxhar/noobai-XL-0.6',
39
  'John6666/noobai-xl-nai-xl-epsilonpred05version-sdxl',
40
  'John6666/noobai-cyberfix-v10-sdxl',
41
  'John6666/noobaiiter-xl-vpred-v075-sdxl',
42
+ 'John6666/ntr-mix-illustrious-xl-noob-xl-v40-sdxl',
43
+ 'John6666/ntr-mix-illustrious-xl-noob-xl-ntrmix35-sdxl',
44
+ 'John6666/ntr-mix-illustrious-xl-noob-xl-v777-sdxl',
45
+ 'John6666/ntr-mix-illustrious-xl-noob-xl-v777forlora-sdxl',
 
 
 
 
 
46
  'John6666/haruki-mix-illustrious-v10-sdxl',
47
  'John6666/noobreal-v10-sdxl',
48
  'John6666/complicated-noobai-merge-vprediction-sdxl',
 
 
 
49
  'Laxhar/noobai-XL-Vpred-0.65s',
50
  'Laxhar/noobai-XL-Vpred-0.65',
51
  'Laxhar/noobai-XL-Vpred-0.6',
 
 
 
52
  'John6666/noobai-xl-nai-xl-vpred05version-sdxl',
53
  'John6666/noobai-fusion2-vpred-itercomp-v1-sdxl',
54
  'John6666/noobai-xl-nai-xl-vpredtestversion-sdxl',
 
58
  'John6666/illustrious-pencil-xl-v200-sdxl',
59
  'John6666/obsession-illustriousxl-v21-sdxl',
60
  'John6666/obsession-illustriousxl-v30-sdxl',
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  'John6666/wai-nsfw-illustrious-v70-sdxl',
 
 
62
  'John6666/illustrious-pony-mix-v3-sdxl',
63
+ 'John6666/nova-anime-xl-illustriousv10-sdxl',
64
+ 'John6666/nova-orange-xl-v30-sdxl',
 
 
 
 
 
 
 
 
 
 
 
65
  'John6666/silvermoon-mix03-illustrious-v10-sdxl',
66
  'eienmojiki/Anything-XL',
67
  'eienmojiki/Starry-XL-v5.2',
 
68
  'John6666/meinaxl-v2-sdxl',
69
  'Eugeoter/artiwaifu-diffusion-2.0',
70
  'comin/IterComp',
 
71
  'John6666/epicrealism-xl-v10kiss2-sdxl',
72
+ 'John6666/epicrealism-xl-v8kiss-sdxl',
 
73
  'misri/zavychromaxl_v80',
74
  'SG161222/RealVisXL_V4.0',
75
  'SG161222/RealVisXL_V5.0',
 
81
  'John6666/ras-real-anime-screencap-v1-sdxl',
82
  'John6666/duchaiten-pony-xl-no-score-v60-sdxl',
83
  'John6666/mistoon-anime-ponyalpha-sdxl',
 
84
  'John6666/ebara-mfcg-pony-mix-v12-sdxl',
85
  'John6666/t-ponynai3-v51-sdxl',
86
  'John6666/t-ponynai3-v65-sdxl',
 
87
  'John6666/prefect-pony-xl-v3-sdxl',
88
  'John6666/prefect-pony-xl-v4-sdxl',
 
89
  'John6666/mala-anime-mix-nsfw-pony-xl-v5-sdxl',
90
  'John6666/wai-ani-nsfw-ponyxl-v10-sdxl',
91
  'John6666/wai-real-mix-v11-sdxl',
 
93
  'John6666/wai-c-v6-sdxl',
94
  'John6666/iniverse-mix-xl-sfwnsfw-pony-guofeng-v43-sdxl',
95
  'John6666/sifw-annihilation-xl-v2-sdxl',
 
96
  'John6666/photo-realistic-pony-v5-sdxl',
97
  'John6666/pony-realism-v21main-sdxl',
98
  'John6666/pony-realism-v22main-sdxl',
99
+ 'John6666/cyberrealistic-pony-v63-sdxl',
100
+ 'John6666/cyberrealistic-pony-v64-sdxl',
101
  'John6666/cyberrealistic-pony-v65-sdxl',
 
 
102
  'GraydientPlatformAPI/realcartoon-pony-diffusion',
103
  'John6666/nova-anime-xl-pony-v5-sdxl',
104
  'John6666/autismmix-sdxl-autismmix-pony-sdxl',
105
  'John6666/aimz-dream-real-pony-mix-v3-sdxl',
 
 
106
  'John6666/duchaiten-pony-real-v11fix-sdxl',
107
  'John6666/duchaiten-pony-real-v20-sdxl',
108
  'John6666/duchaiten-pony-xl-no-score-v70-sdxl',
109
  'KBlueLeaf/Kohaku-XL-Zeta',
110
  'cagliostrolab/animagine-xl-3.1',
 
111
  'yodayo-ai/kivotos-xl-2.0',
112
  'yodayo-ai/holodayo-xl-2.1',
113
  'yodayo-ai/clandestine-xl-1.0',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  'digiplay/majicMIX_sombre_v2',
115
  'digiplay/majicMIX_realistic_v6',
116
  'digiplay/majicMIX_realistic_v7',
 
120
  'digiplay/darkphoenix3D_v1.1',
121
  'digiplay/BeenYouLiteL11_diffusers',
122
  'GraydientPlatformAPI/rev-animated2',
123
+ 'youknownothing/cyberrealistic_v50',
 
 
124
  'youknownothing/deliberate-v6',
125
  'GraydientPlatformAPI/deliberate-cyber3',
126
  'GraydientPlatformAPI/picx-real',
 
134
  'GraydientPlatformAPI/realcartoon3d-17',
135
  'GraydientPlatformAPI/realcartoon-pixar11',
136
  'GraydientPlatformAPI/realcartoon-real17',
137
+ 'nitrosocke/Ghibli-Diffusion',
138
  ]
139
 
 
140
  DIFFUSERS_FORMAT_LORAS = [
141
  "nerijs/animation2k-flux",
142
  "XLabs-AI/flux-RealismLora",
 
156
  DIRECTORY_LORAS = 'loras'
157
  DIRECTORY_VAES = 'vaes'
158
  DIRECTORY_EMBEDS = 'embedings'
 
159
 
160
+ CACHE_HF = "/home/user/.cache/huggingface/hub/"
161
  STORAGE_ROOT = "/home/user/"
 
 
 
 
162
 
163
  TASK_STABLEPY = {
164
  'txt2img': 'txt2img',
 
184
  'optical pattern ControlNet': 'pattern',
185
  'recolor ControlNet': 'recolor',
186
  'tile ControlNet': 'tile',
 
187
  }
188
 
189
  TASK_MODEL_LIST = list(TASK_STABLEPY.keys())
190
 
191
  UPSCALER_DICT_GUI = {
192
  None: None,
193
+ "Lanczos": "Lanczos",
194
+ "Nearest": "Nearest",
195
+ 'Latent': 'Latent',
196
+ 'Latent (antialiased)': 'Latent (antialiased)',
197
+ 'Latent (bicubic)': 'Latent (bicubic)',
198
+ 'Latent (bicubic antialiased)': 'Latent (bicubic antialiased)',
199
+ 'Latent (nearest)': 'Latent (nearest)',
200
+ 'Latent (nearest-exact)': 'Latent (nearest-exact)',
201
+ "RealESRGAN_x4plus": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth",
202
  "RealESRNet_x4plus": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.1/RealESRNet_x4plus.pth",
203
+ "RealESRGAN_x4plus_anime_6B": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/RealESRGAN_x4plus_anime_6B.pth",
204
+ "RealESRGAN_x2plus": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.1/RealESRGAN_x2plus.pth",
205
+ "realesr-animevideov3": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-animevideov3.pth",
206
+ "realesr-general-x4v3": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-general-x4v3.pth",
207
+ "realesr-general-wdn-x4v3": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-general-wdn-x4v3.pth",
208
  "4x-UltraSharp": "https://huggingface.co/Shandypur/ESRGAN-4x-UltraSharp/resolve/main/4x-UltraSharp.pth",
 
209
  "4x_foolhardy_Remacri": "https://huggingface.co/FacehugmanIII/4x_foolhardy_Remacri/resolve/main/4x_foolhardy_Remacri.pth",
210
  "Remacri4xExtraSmoother": "https://huggingface.co/hollowstrawberry/upscalers-backup/resolve/main/ESRGAN/Remacri%204x%20ExtraSmoother.pth",
211
  "AnimeSharp4x": "https://huggingface.co/hollowstrawberry/upscalers-backup/resolve/main/ESRGAN/AnimeSharp%204x.pth",
 
219
  DIFFUSERS_CONTROLNET_MODEL = [
220
  "Automatic",
221
 
 
222
  "xinsir/controlnet-union-sdxl-1.0",
223
  "xinsir/anime-painter",
224
  "Eugeoter/noob-sdxl-controlnet-canny",
 
241
  "r3gm/controlnet-recolor-sdxl-fp16",
242
  "r3gm/controlnet-openpose-twins-sdxl-1.0-fp16",
243
  "r3gm/controlnet-qr-pattern-sdxl-fp16",
244
+ "brad-twinkl/controlnet-union-sdxl-1.0-promax",
245
  "Yakonrus/SDXL_Controlnet_Tile_Realistic_v2",
246
  "TheMistoAI/MistoLine",
247
  "briaai/BRIA-2.3-ControlNet-Recoloring",
 
278
  # "InstantX/FLUX.1-dev-Controlnet-Canny",
279
  ]
280
 
281
+ PROMPT_W_OPTIONS = [
282
+ ("Compel format: (word)weight", "Compel"),
283
+ ("Classic format: (word:weight)", "Classic"),
284
+ ("Classic-original format: (word:weight)", "Classic-original"),
285
+ ("Classic-no_norm format: (word:weight)", "Classic-no_norm"),
286
+ ("Classic-sd_embed format: (word:weight)", "Classic-sd_embed"),
287
+ ("Classic-ignore", "Classic-ignore"),
288
+ ("None", "None"),
289
+ ]
290
 
291
  WARNING_MSG_VAE = (
292
  "Use the right VAE for your model to maintain image quality. The wrong"
 
320
  name_s for name_s in scheduler_names if "Auto-Loader" not in name_s
321
  ]
322
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
323
  SUBTITLE_GUI = (
324
  "### This demo uses [diffusers](https://github.com/huggingface/diffusers)"
325
  " to perform different tasks in image generation."
326
  )
327
 
 
 
328
  HELP_GUI = (
329
+ """### Help:
330
+ - 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'.
331
  - 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'.
332
  - For better results with Pony Diffusion, try using sampler DPM++ 1s or DPM2 with Compel or Classic prompt weights.
333
  """
 
340
  3. ControlNet Canny SDXL
341
  4. Optical pattern (Optical illusion) SDXL
342
  5. Convert an image to a coloring drawing
343
+ 6. ControlNet OpenPose SD 1.5 and Latent upscale
 
 
344
 
345
  - 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.
346
  """
 
449
  20,
450
  4.0,
451
  -1,
452
+ "loras/Coloring_book_-_LineArt.safetensors",
453
  1.0,
454
  "DPM++ 2M SDE",
455
  1024,
 
467
  35,
468
  False,
469
  ],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
470
  [
471
  "1girl,face,curly hair,red hair,white background,",
472
  "(worst quality:2),(low quality:2),(normal quality:2),lowres,watermark,",
 
496
  RESOURCES = (
497
  """### Resources
498
  - John6666's space has some great features you might find helpful [link](https://huggingface.co/spaces/John6666/DiffuseCraftMod).
499
+ - You can also try the image generator in Colab’s free tier, which provides free GPU [link](https://github.com/R3gm/SD_diffusers_interactive).
 
500
  """
501
  )
image_processor.py CHANGED
@@ -92,8 +92,8 @@ def preprocessor_tab():
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")
 
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=1, maximum=2.0, step=0.01, value=0.1, label="'MLSD' Hough value threshold")
96
+ pre_distance_threshold = gr.Slider(minimum=1, 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")
packages.txt CHANGED
@@ -1,2 +1,3 @@
1
  git-lfs
 
2
  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,14 +1,5 @@
1
- stablepy==0.6.5
2
- torch==2.8.0
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
14
- mediapipe==0.10.5
 
1
+ git+https://github.com/R3gm/stablepy.git@a9fe2dc # -b refactor_sampler_fix
2
+ torch==2.2.0
 
3
  gdown
4
  opencv-python
5
+ unidecode
 
 
 
 
 
 
 
 
utils.py CHANGED
@@ -1,729 +1,485 @@
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
- wget_command = (
279
- f'wget -c -nv '
280
- f'-O "{os.path.join(dir_, filename_base)}" "{redirect_url}"'
281
- )
282
- r_code = os.system(wget_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 wget.
297
- If an API key limit is reached, generating a new API key and using it can fix the issue. no
298
- """
299
- output_path = None
300
-
301
- url_dl = url + f"?token={civitai_api_key}"
302
-
303
- if not civ_filename:
304
- wget_command = (
305
- f'wget -c -nv '
306
- f'-P "{dir_}" "{url_dl}"'
307
- )
308
- os.system(wget_command)
309
-
310
- else:
311
- output_path = os.path.join(dir_, civ_filename)
312
-
313
- if not os.path.exists(output_path):
314
- wget_command = (
315
- f'wget -c -nv '
316
- f'-O "{output_path}" "{url_dl}"'
317
- )
318
- os.system(wget_command)
319
-
320
- return output_path
321
-
322
- def drive_down(url, dir_):
323
- import gdown
324
-
325
- output_path = None
326
-
327
- drive_id, _ = gdown.parse_url.parse_url(url, warning=False)
328
- dir_files = os.listdir(dir_)
329
-
330
- for dfile in dir_files:
331
- if drive_id in dfile:
332
- output_path = os.path.join(dir_, dfile)
333
- break
334
-
335
- if not output_path:
336
- original_path = gdown.download(url, f"{dir_}/", fuzzy=True)
337
-
338
- dir_name, base_name = os.path.split(original_path)
339
- name, ext = base_name.rsplit(".", 1)
340
- new_name = f"{name}_{drive_id}.{ext}"
341
- output_path = os.path.join(dir_name, new_name)
342
-
343
- os.rename(original_path, output_path)
344
-
345
- return output_path
346
-
347
-
348
- def hf_down(url, dir_, hf_token, romanize):
349
- url = url.replace("?download=true", "")
350
- # url = urllib.parse.quote(url, safe=':/') # fix encoding
351
-
352
- filename = unidecode(url.split('/')[-1]) if romanize else url.split('/')[-1]
353
- output_path = os.path.join(dir_, filename)
354
-
355
- if os.path.exists(output_path):
356
- return output_path
357
-
358
- if "/blob/" in url:
359
- url = url.replace("/blob/", "/resolve/")
360
-
361
- if hf_token:
362
- os.system(
363
- f'wget -c -nv '
364
- f'--header="Authorization: Bearer {hf_token}" '
365
- f'-O "{os.path.join(dir_, filename)}" "{url}"'
366
- )
367
- else:
368
- os.system(
369
- f'wget -c -nv '
370
- f'-O "{os.path.join(dir_, filename)}" "{url}"'
371
- )
372
-
373
- return output_path
374
-
375
-
376
- def download_things(directory, url, hf_token="", civitai_api_key="", romanize=False):
377
- url = url.strip()
378
- downloaded_file_path = None
379
-
380
- if "drive.google.com" in url:
381
- downloaded_file_path = drive_down(url, directory)
382
- elif "huggingface.co" in url:
383
- downloaded_file_path = hf_down(url, directory, hf_token, romanize)
384
- elif "civitai." in url:
385
- url = url.replace("civitai.red", "civitai.com")
386
- if not civitai_api_key:
387
- msg = "You need an API key to download Civitai models."
388
- print(f"\033[91m{msg}\033[0m")
389
- gr.Warning(msg)
390
- return None
391
-
392
- url, civ_filename, civ_page = get_civit_params(url)
393
- if civ_page and not IS_ZERO_GPU:
394
- print(f"\033[92mCivitai model: {civ_filename} [page: {civ_page}]\033[0m")
395
-
396
- downloaded_file_path, civ_filename = civ_redirect_down(url, directory, civitai_api_key, romanize, civ_filename)
397
-
398
- if not downloaded_file_path:
399
- msg = (
400
- "Download failed.\n"
401
- "If this is due to an API limit, generating a new API key may resolve the issue.\n"
402
- "Attempting to download using the old method..."
403
- )
404
- print(msg)
405
- gr.Warning(msg)
406
- downloaded_file_path = civ_api_down(url, directory, civitai_api_key, civ_filename)
407
- else:
408
- os.system(
409
- f'wget -c -nv '
410
- f'-P "{directory}" "{url}"'
411
- )
412
-
413
- return downloaded_file_path
414
-
415
-
416
- def get_model_list(directory_path):
417
- model_list = []
418
- valid_extensions = {'.ckpt', '.pt', '.pth', '.safetensors', '.bin'}
419
-
420
- for filename in os.listdir(directory_path):
421
- if os.path.splitext(filename)[1] in valid_extensions:
422
- # name_without_extension = os.path.splitext(filename)[0]
423
- file_path = os.path.join(directory_path, filename)
424
- # model_list.append((name_without_extension, file_path))
425
- model_list.append(file_path)
426
- print('\033[34mFILE: ' + file_path + '\033[0m')
427
- return model_list
428
-
429
-
430
- def extract_parameters(input_string):
431
- parameters = {}
432
- input_string = input_string.replace("\n", "")
433
-
434
- if "Negative prompt:" not in input_string:
435
- if "Steps:" in input_string:
436
- input_string = input_string.replace("Steps:", "Negative prompt: Steps:")
437
- else:
438
- msg = "Generation data is invalid."
439
- gr.Warning(msg)
440
- print(msg)
441
- parameters["prompt"] = input_string
442
- return parameters
443
-
444
- parm = input_string.split("Negative prompt:")
445
- parameters["prompt"] = parm[0].strip()
446
- if "Steps:" not in parm[1]:
447
- parameters["neg_prompt"] = parm[1].strip()
448
- return parameters
449
- parm = parm[1].split("Steps:")
450
- parameters["neg_prompt"] = parm[0].strip()
451
- input_string = "Steps:" + parm[1]
452
-
453
- # Extracting Steps
454
- steps_match = re.search(r'Steps: (\d+)', input_string)
455
- if steps_match:
456
- parameters['Steps'] = int(steps_match.group(1))
457
-
458
- # Extracting Size
459
- size_match = re.search(r'Size: (\d+x\d+)', input_string)
460
- if size_match:
461
- parameters['Size'] = size_match.group(1)
462
- width, height = map(int, parameters['Size'].split('x'))
463
- parameters['width'] = width
464
- parameters['height'] = height
465
-
466
- # Extracting other parameters
467
- other_parameters = re.findall(r'([^,:]+): (.*?)(?=, [^,:]+:|$)', input_string)
468
- for param in other_parameters:
469
- parameters[param[0].strip()] = param[1].strip('"')
470
-
471
- return parameters
472
-
473
-
474
- def get_my_lora(link_url, romanize):
475
- l_name = ""
476
- for url in [url.strip() for url in link_url.split(',')]:
477
- if not os.path.exists(f"./loras/{url.split('/')[-1]}"):
478
- l_name = download_things(DIRECTORY_LORAS, url, HF_TOKEN, CIVITAI_API_KEY, romanize)
479
- new_lora_model_list = get_model_list(DIRECTORY_LORAS)
480
- new_lora_model_list.insert(0, "None")
481
- new_lora_model_list = new_lora_model_list + DIFFUSERS_FORMAT_LORAS
482
- msg_lora = "Downloaded"
483
- if l_name:
484
- msg_lora += f": <b>{l_name}</b>"
485
- print(msg_lora)
486
-
487
- try:
488
- # Works with non-Civitai loras.
489
- json_data = read_safetensors_header_from_file(l_name)
490
- metadata_lora = LoraHeaderInformation(json_data)
491
- msg_lora += "<br>" + metadata_lora.to_html()
492
- except Exception:
493
- pass
494
-
495
- return gr.update(
496
- choices=new_lora_model_list
497
- ), gr.update(
498
- choices=new_lora_model_list
499
- ), gr.update(
500
- choices=new_lora_model_list
501
- ), gr.update(
502
- choices=new_lora_model_list
503
- ), gr.update(
504
- choices=new_lora_model_list
505
- ), gr.update(
506
- choices=new_lora_model_list
507
- ), gr.update(
508
- choices=new_lora_model_list
509
- ), gr.update(
510
- value=msg_lora
511
- )
512
-
513
-
514
- def info_html(json_data, title, subtitle):
515
- return f"""
516
- <div style='padding: 0; border-radius: 10px;'>
517
- <p style='margin: 0; font-weight: bold;'>{title}</p>
518
- <details>
519
- <summary>Details</summary>
520
- <p style='margin: 0; font-weight: bold;'>{subtitle}</p>
521
- </details>
522
- </div>
523
- """
524
-
525
-
526
- def get_model_type(repo_id: str):
527
- api = HfApi(token=os.environ.get("HF_TOKEN")) # if use private or gated model
528
- default = "SD 1.5"
529
- try:
530
- if os.path.exists(repo_id):
531
- tag, _, _, _ = checkpoint_model_type(repo_id)
532
- return DIFFUSECRAFT_CHECKPOINT_NAME[tag]
533
- else:
534
- model = api.model_info(repo_id=repo_id, timeout=5.0)
535
- tags = model.tags
536
- for tag in tags:
537
- if tag in MODEL_TYPE_CLASS.keys():
538
- return MODEL_TYPE_CLASS.get(tag, default)
539
-
540
- except Exception:
541
- return default
542
- return default
543
-
544
-
545
- def restart_space(repo_id: str, factory_reboot: bool):
546
- api = HfApi(token=os.environ.get("HF_TOKEN"))
547
- try:
548
- runtime = api.get_space_runtime(repo_id=repo_id)
549
- if runtime.stage == "RUNNING":
550
- api.restart_space(repo_id=repo_id, factory_reboot=factory_reboot)
551
- print(f"Restarting space: {repo_id}")
552
- else:
553
- print(f"Space {repo_id} is in stage: {runtime.stage}")
554
- except Exception as e:
555
- print(e)
556
-
557
-
558
- def extract_exif_data(image):
559
- if image is None:
560
- return ""
561
-
562
- try:
563
- metadata_keys = ['parameters', 'metadata', 'prompt', 'Comment']
564
-
565
- for key in metadata_keys:
566
- if key in image.info:
567
- return image.info[key]
568
-
569
- return str(image.info)
570
-
571
- except Exception as e:
572
- return f"Error extracting metadata: {str(e)}"
573
-
574
-
575
- def create_mask_now(img, invert):
576
- import numpy as np
577
- import time
578
-
579
- time.sleep(0.5)
580
-
581
- transparent_image = img["layers"][0]
582
-
583
- # Extract the alpha channel
584
- alpha_channel = np.array(transparent_image)[:, :, 3]
585
-
586
- # Create a binary mask by thresholding the alpha channel
587
- binary_mask = alpha_channel > 1
588
-
589
- if invert:
590
- print("Invert")
591
- # Invert the binary mask so that the drawn shape is white and the rest is black
592
- binary_mask = np.invert(binary_mask)
593
-
594
- # Convert the binary mask to a 3-channel RGB mask
595
- rgb_mask = np.stack((binary_mask,) * 3, axis=-1)
596
-
597
- # Convert the mask to uint8
598
- rgb_mask = rgb_mask.astype(np.uint8) * 255
599
-
600
- return img["background"], rgb_mask
601
-
602
-
603
- def download_diffuser_repo(repo_name: str, model_type: str, revision: str = "main", token=True):
604
-
605
- variant = None
606
- if token is True and not os.environ.get("HF_TOKEN"):
607
- token = None
608
-
609
- if model_type == "SDXL":
610
- info = model_info_data(
611
- repo_name,
612
- token=token,
613
- revision=revision,
614
- timeout=5.0,
615
- )
616
-
617
- filenames = {sibling.rfilename for sibling in info.siblings}
618
- model_filenames, variant_filenames = variant_compatible_siblings(
619
- filenames, variant="fp16"
620
- )
621
-
622
- if len(variant_filenames):
623
- variant = "fp16"
624
-
625
- if model_type == "FLUX":
626
- cached_folder = snapshot_download(
627
- repo_id=repo_name,
628
- allow_patterns="transformer/*"
629
- )
630
- else:
631
- cached_folder = DiffusionPipeline.download(
632
- pretrained_model_name=repo_name,
633
- force_download=False,
634
- token=token,
635
- revision=revision,
636
- # mirror="https://hf-mirror.com",
637
- variant=variant,
638
- use_safetensors=True,
639
- trust_remote_code=False,
640
- timeout=5.0,
641
- )
642
-
643
- if isinstance(cached_folder, PosixPath):
644
- cached_folder = cached_folder.as_posix()
645
-
646
- # Task model
647
- # from huggingface_hub import hf_hub_download
648
- # hf_hub_download(
649
- # task_model,
650
- # filename="diffusion_pytorch_model.safetensors", # fix fp16 variant
651
- # )
652
-
653
- return cached_folder
654
-
655
-
656
- def get_folder_size_gb(folder_path):
657
- result = subprocess.run(["du", "-s", folder_path], capture_output=True, text=True)
658
-
659
- total_size_kb = int(result.stdout.split()[0])
660
- total_size_gb = total_size_kb / (1024 ** 2)
661
-
662
- return total_size_gb
663
-
664
-
665
- def get_used_storage_gb(path_storage=STORAGE_ROOT):
666
- try:
667
- used_gb = get_folder_size_gb(path_storage)
668
- print(f"Used Storage: {used_gb:.2f} GB")
669
- except Exception as e:
670
- used_gb = 999
671
- print(f"Error while retrieving the used storage: {e}.")
672
-
673
- return used_gb
674
-
675
-
676
- def delete_model(removal_candidate):
677
- print(f"Removing: {removal_candidate}")
678
-
679
- if os.path.exists(removal_candidate):
680
- os.remove(removal_candidate)
681
- else:
682
- diffusers_model = f"{CACHE_HF}{DIRECTORY_MODELS}--{removal_candidate.replace('/', '--')}"
683
- if os.path.isdir(diffusers_model):
684
- shutil.rmtree(diffusers_model)
685
-
686
-
687
- def clear_hf_cache():
688
- """
689
- Clears the entire Hugging Face cache at ~/.cache/huggingface.
690
- Hugging Face will re-download models as needed later.
691
- """
692
- try:
693
- if os.path.exists(CACHE_HF):
694
- shutil.rmtree(CACHE_HF, ignore_errors=True)
695
- print(f"Hugging Face cache cleared: {CACHE_HF}")
696
- else:
697
- print(f"No Hugging Face cache found at: {CACHE_HF}")
698
- except Exception as e:
699
- print(f"Error clearing Hugging Face cache: {e}")
700
-
701
-
702
- def progress_step_bar(step, total):
703
- # Calculate the percentage for the progress bar width
704
- percentage = min(100, ((step / total) * 100))
705
-
706
- return f"""
707
- <div style="position: relative; width: 100%; background-color: gray; border-radius: 5px; overflow: hidden;">
708
- <div style="width: {percentage}%; height: 17px; background-color: #800080; transition: width 0.5s;"></div>
709
- <div style="position: absolute; width: 100%; text-align: center; color: white; top: 0; line-height: 19px; font-size: 13px;">
710
- {int(percentage)}%
711
- </div>
712
- </div>
713
- """
714
-
715
-
716
- def html_template_message(msg):
717
- return f"""
718
- <div style="position: relative; width: 100%; background-color: gray; border-radius: 5px; overflow: hidden;">
719
- <div style="width: 0%; height: 17px; background-color: #800080; transition: width 0.5s;"></div>
720
- <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;">
721
- {msg}
722
- </div>
723
- </div>
724
- """
725
-
726
-
727
- def escape_html(text):
728
- """Escapes HTML special characters in the input text."""
729
- return text.replace("<", "&lt;").replace(">", "&gt;").replace("\n", "<br>")
 
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,
13
+ STORAGE_ROOT,
14
+ )
15
+ from huggingface_hub import HfApi
16
+ from huggingface_hub import 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
+
31
+ USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:127.0) Gecko/20100101 Firefox/127.0'
32
+
33
+
34
+ def request_json_data(url):
35
+ model_version_id = url.split('/')[-1]
36
+ if "?modelVersionId=" in model_version_id:
37
+ match = re.search(r'modelVersionId=(\d+)', url)
38
+ model_version_id = match.group(1)
39
+
40
+ endpoint_url = f"https://civitai.com/api/v1/model-versions/{model_version_id}"
41
+
42
+ params = {}
43
+ headers = {'User-Agent': USER_AGENT, 'content-type': 'application/json'}
44
+ session = requests.Session()
45
+ retries = Retry(total=5, backoff_factor=1, status_forcelist=[500, 502, 503, 504])
46
+ session.mount("https://", HTTPAdapter(max_retries=retries))
47
+
48
+ try:
49
+ result = session.get(endpoint_url, params=params, headers=headers, stream=True, timeout=(3.0, 15))
50
+ result.raise_for_status()
51
+ json_data = result.json()
52
+ return json_data if json_data else None
53
+ except Exception as e:
54
+ print(f"Error: {e}")
55
+ return None
56
+
57
+
58
+ class ModelInformation:
59
+ def __init__(self, json_data):
60
+ self.model_version_id = json_data.get("id", "")
61
+ self.model_id = json_data.get("modelId", "")
62
+ self.download_url = json_data.get("downloadUrl", "")
63
+ self.model_url = f"https://civitai.com/models/{self.model_id}?modelVersionId={self.model_version_id}"
64
+ self.filename_url = next(
65
+ (v.get("name", "") for v in reversed(json_data.get("files", [])) if str(self.model_version_id) in v.get("downloadUrl", "")), ""
66
+ )
67
+ self.filename_url = self.filename_url if self.filename_url else ""
68
+ self.description = json_data.get("description", "")
69
+ if self.description is None: self.description = ""
70
+ self.model_name = json_data.get("model", {}).get("name", "")
71
+ self.model_type = json_data.get("model", {}).get("type", "")
72
+ self.nsfw = json_data.get("model", {}).get("nsfw", False)
73
+ self.poi = json_data.get("model", {}).get("poi", False)
74
+ self.images = [img.get("url", "") for img in json_data.get("images", [])]
75
+ self.example_prompt = json_data.get("trainedWords", [""])[0] if json_data.get("trainedWords") else ""
76
+ self.original_json = copy.deepcopy(json_data)
77
+
78
+
79
+ def retrieve_model_info(url):
80
+ json_data = request_json_data(url)
81
+ if not json_data:
82
+ return None
83
+ model_descriptor = ModelInformation(json_data)
84
+ return model_descriptor
85
+
86
+
87
+ def download_things(directory, url, hf_token="", civitai_api_key="", romanize=False):
88
+ url = url.strip()
89
+ downloaded_file_path = None
90
+
91
+ if "drive.google.com" in url:
92
+ original_dir = os.getcwd()
93
+ os.chdir(directory)
94
+ os.system(f"gdown --fuzzy {url}")
95
+ os.chdir(original_dir)
96
+ elif "huggingface.co" in url:
97
+ url = url.replace("?download=true", "")
98
+ # url = urllib.parse.quote(url, safe=':/') # fix encoding
99
+ if "/blob/" in url:
100
+ url = url.replace("/blob/", "/resolve/")
101
+ user_header = f'"Authorization: Bearer {hf_token}"'
102
+
103
+ filename = unidecode(url.split('/')[-1]) if romanize else url.split('/')[-1]
104
+
105
+ if hf_token:
106
+ 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 {filename}")
107
+ else:
108
+ 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 {filename}")
109
+
110
+ downloaded_file_path = os.path.join(directory, filename)
111
+
112
+ elif "civitai.com" in url:
113
+
114
+ if not civitai_api_key:
115
+ print("\033[91mYou need an API key to download Civitai models.\033[0m")
116
+
117
+ model_profile = retrieve_model_info(url)
118
+ if (
119
+ model_profile is not None
120
+ and model_profile.download_url
121
+ and model_profile.filename_url
122
+ ):
123
+ url = model_profile.download_url
124
+ filename = unidecode(model_profile.filename_url) if romanize else model_profile.filename_url
125
+ else:
126
+ if "?" in url:
127
+ url = url.split("?")[0]
128
+ filename = ""
129
+
130
+ url_dl = url + f"?token={civitai_api_key}"
131
+ print(f"Filename: {filename}")
132
+
133
+ param_filename = ""
134
+ if filename:
135
+ param_filename = f"-o '{filename}'"
136
+
137
+ aria2_command = (
138
+ f'aria2c --console-log-level=error --summary-interval=10 -c -x 16 '
139
+ f'-k 1M -s 16 -d "{directory}" {param_filename} "{url_dl}"'
140
+ )
141
+ os.system(aria2_command)
142
+
143
+ if param_filename and os.path.exists(os.path.join(directory, filename)):
144
+ downloaded_file_path = os.path.join(directory, filename)
145
+
146
+ # # PLAN B
147
+ # # Follow the redirect to get the actual download URL
148
+ # curl_command = (
149
+ # f'curl -L -sI --connect-timeout 5 --max-time 5 '
150
+ # f'-H "Content-Type: application/json" '
151
+ # f'-H "Authorization: Bearer {civitai_api_key}" "{url}"'
152
+ # )
153
+
154
+ # headers = os.popen(curl_command).read()
155
+
156
+ # # Look for the redirected "Location" URL
157
+ # location_match = re.search(r'location: (.+)', headers, re.IGNORECASE)
158
+
159
+ # if location_match:
160
+ # redirect_url = location_match.group(1).strip()
161
+
162
+ # # Extract the filename from the redirect URL's "Content-Disposition"
163
+ # filename_match = re.search(r'filename%3D%22(.+?)%22', redirect_url)
164
+ # if filename_match:
165
+ # encoded_filename = filename_match.group(1)
166
+ # # Decode the URL-encoded filename
167
+ # decoded_filename = urllib.parse.unquote(encoded_filename)
168
+
169
+ # filename = unidecode(decoded_filename) if romanize else decoded_filename
170
+ # print(f"Filename: {filename}")
171
+
172
+ # aria2_command = (
173
+ # f'aria2c --console-log-level=error --summary-interval=10 -c -x 16 '
174
+ # f'-k 1M -s 16 -d "{directory}" -o "{filename}" "{redirect_url}"'
175
+ # )
176
+ # return_code = os.system(aria2_command)
177
+
178
+ # # if return_code != 0:
179
+ # # raise RuntimeError(f"Failed to download file: {filename}. Error code: {return_code}")
180
+ # downloaded_file_path = os.path.join(directory, filename)
181
+ # if not os.path.exists(downloaded_file_path):
182
+ # downloaded_file_path = None
183
+
184
+ # if not downloaded_file_path:
185
+ # # Old method
186
+ # if "?" in url:
187
+ # url = url.split("?")[0]
188
+ # url = url + f"?token={civitai_api_key}"
189
+ # os.system(f"aria2c --console-log-level=error --summary-interval=10 -c -x 16 -k 1M -s 16 -d {directory} {url}")
190
+
191
+ else:
192
+ os.system(f"aria2c --console-log-level=error --summary-interval=10 -c -x 16 -k 1M -s 16 -d {directory} {url}")
193
+
194
+ return downloaded_file_path
195
+
196
+
197
+ def get_model_list(directory_path):
198
+ model_list = []
199
+ valid_extensions = {'.ckpt', '.pt', '.pth', '.safetensors', '.bin'}
200
+
201
+ for filename in os.listdir(directory_path):
202
+ if os.path.splitext(filename)[1] in valid_extensions:
203
+ # name_without_extension = os.path.splitext(filename)[0]
204
+ file_path = os.path.join(directory_path, filename)
205
+ # model_list.append((name_without_extension, file_path))
206
+ model_list.append(file_path)
207
+ print('\033[34mFILE: ' + file_path + '\033[0m')
208
+ return model_list
209
+
210
+
211
+ def extract_parameters(input_string):
212
+ parameters = {}
213
+ input_string = input_string.replace("\n", "")
214
+
215
+ if "Negative prompt:" not in input_string:
216
+ if "Steps:" in input_string:
217
+ input_string = input_string.replace("Steps:", "Negative prompt: Steps:")
218
+ else:
219
+ print("Invalid metadata")
220
+ parameters["prompt"] = input_string
221
+ return parameters
222
+
223
+ parm = input_string.split("Negative prompt:")
224
+ parameters["prompt"] = parm[0].strip()
225
+ if "Steps:" not in parm[1]:
226
+ print("Steps not detected")
227
+ parameters["neg_prompt"] = parm[1].strip()
228
+ return parameters
229
+ parm = parm[1].split("Steps:")
230
+ parameters["neg_prompt"] = parm[0].strip()
231
+ input_string = "Steps:" + parm[1]
232
+
233
+ # Extracting Steps
234
+ steps_match = re.search(r'Steps: (\d+)', input_string)
235
+ if steps_match:
236
+ parameters['Steps'] = int(steps_match.group(1))
237
+
238
+ # Extracting Size
239
+ size_match = re.search(r'Size: (\d+x\d+)', input_string)
240
+ if size_match:
241
+ parameters['Size'] = size_match.group(1)
242
+ width, height = map(int, parameters['Size'].split('x'))
243
+ parameters['width'] = width
244
+ parameters['height'] = height
245
+
246
+ # Extracting other parameters
247
+ other_parameters = re.findall(r'([^,:]+): (.*?)(?=, [^,:]+:|$)', input_string)
248
+ for param in other_parameters:
249
+ parameters[param[0].strip()] = param[1].strip('"')
250
+
251
+ return parameters
252
+
253
+
254
+ def get_my_lora(link_url, romanize):
255
+ l_name = ""
256
+ for url in [url.strip() for url in link_url.split(',')]:
257
+ if not os.path.exists(f"./loras/{url.split('/')[-1]}"):
258
+ l_name = download_things(DIRECTORY_LORAS, url, HF_TOKEN, CIVITAI_API_KEY, romanize)
259
+ new_lora_model_list = get_model_list(DIRECTORY_LORAS)
260
+ new_lora_model_list.insert(0, "None")
261
+ new_lora_model_list = new_lora_model_list + DIFFUSERS_FORMAT_LORAS
262
+ msg_lora = "Downloaded"
263
+ if l_name:
264
+ msg_lora += f": <b>{l_name}</b>"
265
+ print(msg_lora)
266
+
267
+ return gr.update(
268
+ choices=new_lora_model_list
269
+ ), gr.update(
270
+ choices=new_lora_model_list
271
+ ), gr.update(
272
+ choices=new_lora_model_list
273
+ ), gr.update(
274
+ choices=new_lora_model_list
275
+ ), gr.update(
276
+ choices=new_lora_model_list
277
+ ), gr.update(
278
+ choices=new_lora_model_list
279
+ ), gr.update(
280
+ choices=new_lora_model_list
281
+ ), gr.update(
282
+ value=msg_lora
283
+ )
284
+
285
+
286
+ def info_html(json_data, title, subtitle):
287
+ return f"""
288
+ <div style='padding: 0; border-radius: 10px;'>
289
+ <p style='margin: 0; font-weight: bold;'>{title}</p>
290
+ <details>
291
+ <summary>Details</summary>
292
+ <p style='margin: 0; font-weight: bold;'>{subtitle}</p>
293
+ </details>
294
+ </div>
295
+ """
296
+
297
+
298
+ def get_model_type(repo_id: str):
299
+ api = HfApi(token=os.environ.get("HF_TOKEN")) # if use private or gated model
300
+ default = "SD 1.5"
301
+ try:
302
+ if os.path.exists(repo_id):
303
+ tag = checkpoint_model_type(repo_id)
304
+ return DIFFUSECRAFT_CHECKPOINT_NAME[tag]
305
+ else:
306
+ model = api.model_info(repo_id=repo_id, timeout=5.0)
307
+ tags = model.tags
308
+ for tag in tags:
309
+ if tag in MODEL_TYPE_CLASS.keys(): return MODEL_TYPE_CLASS.get(tag, default)
310
+
311
+ except Exception:
312
+ return default
313
+ return default
314
+
315
+
316
+ def restart_space(repo_id: str, factory_reboot: bool):
317
+ api = HfApi(token=os.environ.get("HF_TOKEN"))
318
+ try:
319
+ runtime = api.get_space_runtime(repo_id=repo_id)
320
+ if runtime.stage == "RUNNING":
321
+ api.restart_space(repo_id=repo_id, factory_reboot=factory_reboot)
322
+ print(f"Restarting space: {repo_id}")
323
+ else:
324
+ print(f"Space {repo_id} is in stage: {runtime.stage}")
325
+ except Exception as e:
326
+ print(e)
327
+
328
+
329
+ def extract_exif_data(image):
330
+ if image is None:
331
+ return ""
332
+
333
+ try:
334
+ metadata_keys = ['parameters', 'metadata', 'prompt', 'Comment']
335
+
336
+ for key in metadata_keys:
337
+ if key in image.info:
338
+ return image.info[key]
339
+
340
+ return str(image.info)
341
+
342
+ except Exception as e:
343
+ return f"Error extracting metadata: {str(e)}"
344
+
345
+
346
+ def create_mask_now(img, invert):
347
+ import numpy as np
348
+ import time
349
+
350
+ time.sleep(0.5)
351
+
352
+ transparent_image = img["layers"][0]
353
+
354
+ # Extract the alpha channel
355
+ alpha_channel = np.array(transparent_image)[:, :, 3]
356
+
357
+ # Create a binary mask by thresholding the alpha channel
358
+ binary_mask = alpha_channel > 1
359
+
360
+ if invert:
361
+ print("Invert")
362
+ # Invert the binary mask so that the drawn shape is white and the rest is black
363
+ binary_mask = np.invert(binary_mask)
364
+
365
+ # Convert the binary mask to a 3-channel RGB mask
366
+ rgb_mask = np.stack((binary_mask,) * 3, axis=-1)
367
+
368
+ # Convert the mask to uint8
369
+ rgb_mask = rgb_mask.astype(np.uint8) * 255
370
+
371
+ return img["background"], rgb_mask
372
+
373
+
374
+ def download_diffuser_repo(repo_name: str, model_type: str, revision: str = "main", token=True):
375
+
376
+ variant = None
377
+ if token is True and not os.environ.get("HF_TOKEN"):
378
+ token = None
379
+
380
+ if model_type == "SDXL":
381
+ info = model_info_data(
382
+ repo_name,
383
+ token=token,
384
+ revision=revision,
385
+ timeout=5.0,
386
+ )
387
+
388
+ filenames = {sibling.rfilename for sibling in info.siblings}
389
+ model_filenames, variant_filenames = variant_compatible_siblings(
390
+ filenames, variant="fp16"
391
+ )
392
+
393
+ if len(variant_filenames):
394
+ variant = "fp16"
395
+
396
+ if model_type == "FLUX":
397
+ cached_folder = snapshot_download(
398
+ repo_id=repo_name,
399
+ allow_patterns="transformer/*"
400
+ )
401
+ else:
402
+ cached_folder = DiffusionPipeline.download(
403
+ pretrained_model_name=repo_name,
404
+ force_download=False,
405
+ token=token,
406
+ revision=revision,
407
+ # mirror="https://hf-mirror.com",
408
+ variant=variant,
409
+ use_safetensors=True,
410
+ trust_remote_code=False,
411
+ timeout=5.0,
412
+ )
413
+
414
+ if isinstance(cached_folder, PosixPath):
415
+ cached_folder = cached_folder.as_posix()
416
+
417
+ # Task model
418
+ # from huggingface_hub import hf_hub_download
419
+ # hf_hub_download(
420
+ # task_model,
421
+ # filename="diffusion_pytorch_model.safetensors", # fix fp16 variant
422
+ # )
423
+
424
+ return cached_folder
425
+
426
+
427
+ def get_folder_size_gb(folder_path):
428
+ result = subprocess.run(["du", "-s", folder_path], capture_output=True, text=True)
429
+
430
+ total_size_kb = int(result.stdout.split()[0])
431
+ total_size_gb = total_size_kb / (1024 ** 2)
432
+
433
+ return total_size_gb
434
+
435
+
436
+ def get_used_storage_gb():
437
+ try:
438
+ used_gb = get_folder_size_gb(STORAGE_ROOT)
439
+ print(f"Used Storage: {used_gb:.2f} GB")
440
+ except Exception as e:
441
+ used_gb = 999
442
+ print(f"Error while retrieving the used storage: {e}.")
443
+
444
+ return used_gb
445
+
446
+
447
+ def delete_model(removal_candidate):
448
+ print(f"Removing: {removal_candidate}")
449
+
450
+ if os.path.exists(removal_candidate):
451
+ os.remove(removal_candidate)
452
+ else:
453
+ diffusers_model = f"{CACHE_HF}{DIRECTORY_MODELS}--{removal_candidate.replace('/', '--')}"
454
+ if os.path.isdir(diffusers_model):
455
+ shutil.rmtree(diffusers_model)
456
+
457
+
458
+ def progress_step_bar(step, total):
459
+ # Calculate the percentage for the progress bar width
460
+ percentage = min(100, ((step / total) * 100))
461
+
462
+ return f"""
463
+ <div style="position: relative; width: 100%; background-color: gray; border-radius: 5px; overflow: hidden;">
464
+ <div style="width: {percentage}%; height: 17px; background-color: #800080; transition: width 0.5s;"></div>
465
+ <div style="position: absolute; width: 100%; text-align: center; color: white; top: 0; line-height: 19px; font-size: 13px;">
466
+ {int(percentage)}%
467
+ </div>
468
+ </div>
469
+ """
470
+
471
+
472
+ def html_template_message(msg):
473
+ return f"""
474
+ <div style="position: relative; width: 100%; background-color: gray; border-radius: 5px; overflow: hidden;">
475
+ <div style="width: 0%; height: 17px; background-color: #800080; transition: width 0.5s;"></div>
476
+ <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;">
477
+ {msg}
478
+ </div>
479
+ </div>
480
+ """
481
+
482
+
483
+ def escape_html(text):
484
+ """Escapes HTML special characters in the input text."""
485
+ return text.replace("<", "&lt;").replace(">", "&gt;").replace("\n", "<br>")