r3gm commited on
Commit
0ee845f
·
verified ·
1 Parent(s): 2b05f96

new update

Browse files
Files changed (9) hide show
  1. .gitignore +207 -0
  2. README.md +1 -1
  3. app.py +219 -90
  4. constants.py +49 -23
  5. image_processor.py +2 -2
  6. packages.txt +1 -1
  7. pre-requirements.txt +1 -0
  8. requirements.txt +8 -2
  9. utils.py +181 -104
.gitignore ADDED
@@ -0,0 +1,207 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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: 4.31.3
8
  app_file: app.py
9
  pinned: true
10
  license: mit
 
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
app.py CHANGED
@@ -1,5 +1,6 @@
1
  import spaces
2
  import os
 
3
  from stablepy import (
4
  Model_Diffusers,
5
  SCHEDULE_TYPE_OPTIONS,
@@ -40,6 +41,7 @@ from constants import (
40
  DIFFUSERS_CONTROLNET_MODEL,
41
  IP_MODELS,
42
  MODE_IP_OPTIONS,
 
43
  )
44
  from stablepy.diffusers_vanilla.style_prompt_config import STYLE_NAMES
45
  import torch
@@ -60,6 +62,7 @@ from utils import (
60
  progress_step_bar,
61
  html_template_message,
62
  escape_html,
 
63
  )
64
  from image_processor import preprocessor_tab
65
  from datetime import datetime
@@ -72,11 +75,17 @@ from diffusers import FluxPipeline
72
  # import urllib.parse
73
  import subprocess
74
 
75
- subprocess.run("rm -rf /data-nvme/zerogpu-offload/*", env={}, shell=True)
 
 
 
 
 
 
 
76
  ImageFile.LOAD_TRUNCATED_IMAGES = True
77
  torch.backends.cuda.matmul.allow_tf32 = True
78
  # os.environ["PYTORCH_NO_CUDA_MEMORY_CACHING"] = "1"
79
- print(os.getenv("SPACES_ZERO_GPU"))
80
 
81
  directories = [DIRECTORY_MODELS, DIRECTORY_LORAS, DIRECTORY_VAES, DIRECTORY_EMBEDS, DIRECTORY_UPSCALERS]
82
  for directory in directories:
@@ -84,19 +93,15 @@ for directory in directories:
84
 
85
  # Download stuffs
86
  for url in [url.strip() for url in DOWNLOAD_MODEL.split(',')]:
87
- if not os.path.exists(f"./models/{url.split('/')[-1]}"):
88
- download_things(DIRECTORY_MODELS, url, HF_TOKEN, CIVITAI_API_KEY)
89
  for url in [url.strip() for url in DOWNLOAD_VAE.split(',')]:
90
- if not os.path.exists(f"./vaes/{url.split('/')[-1]}"):
91
- download_things(DIRECTORY_VAES, url, HF_TOKEN, CIVITAI_API_KEY)
92
  for url in [url.strip() for url in DOWNLOAD_LORA.split(',')]:
93
- if not os.path.exists(f"./loras/{url.split('/')[-1]}"):
94
- download_things(DIRECTORY_LORAS, url, HF_TOKEN, CIVITAI_API_KEY)
95
 
96
  # Download Embeddings
97
  for url_embed in DOWNLOAD_EMBEDS:
98
- if not os.path.exists(f"./embedings/{url_embed.split('/')[-1]}"):
99
- download_things(DIRECTORY_EMBEDS, url_embed, HF_TOKEN, CIVITAI_API_KEY)
100
 
101
  # Build list models
102
  embed_list = get_model_list(DIRECTORY_EMBEDS)
@@ -114,15 +119,16 @@ vae_model_list.insert(0, "None")
114
 
115
  print('\033[33m🏁 Download and listing of valid models completed.\033[0m')
116
 
117
- flux_repo = "camenduru/FLUX.1-dev-diffusers"
118
- flux_pipe = FluxPipeline.from_pretrained(
119
- flux_repo,
120
- transformer=None,
121
- torch_dtype=torch.bfloat16,
122
- ).to("cuda")
123
- components = flux_pipe.components
124
- delete_model(flux_repo)
125
- # components = None
 
126
 
127
  #######################
128
  # GUI
@@ -132,7 +138,17 @@ diffusers.utils.logging.set_verbosity(40)
132
  warnings.filterwarnings(action="ignore", category=FutureWarning, module="diffusers")
133
  warnings.filterwarnings(action="ignore", category=UserWarning, module="diffusers")
134
  warnings.filterwarnings(action="ignore", category=FutureWarning, module="transformers")
135
- logger.setLevel(logging.DEBUG)
 
 
 
 
 
 
 
 
 
 
136
 
137
  CSS = """
138
  .contain { display: flex; flex-direction: column; }
@@ -142,6 +158,12 @@ CSS = """
142
  """
143
 
144
 
 
 
 
 
 
 
145
  class GuiSD:
146
  def __init__(self, stream=True):
147
  self.model = None
@@ -157,6 +179,15 @@ class GuiSD:
157
  removal_candidate = self.inventory.pop(0)
158
  delete_model(removal_candidate)
159
 
 
 
 
 
 
 
 
 
 
160
  def update_inventory(self, model_name):
161
  if model_name not in single_file_model_list:
162
  self.inventory = [
@@ -167,15 +198,21 @@ class GuiSD:
167
  def load_new_model(self, model_name, vae_model, task, controlnet_model, progress=gr.Progress(track_tqdm=True)):
168
 
169
  # download link model > model_name
 
 
 
 
 
170
 
171
- self.update_storage_models()
 
172
 
173
  vae_model = vae_model if vae_model != "None" else None
174
  model_type = get_model_type(model_name)
175
  dtype_model = torch.bfloat16 if model_type == "FLUX" else torch.float16
176
 
177
  if not os.path.exists(model_name):
178
- print("debug", model_name, vae_model, task, controlnet_model)
179
  _ = download_diffuser_repo(
180
  repo_name=model_name,
181
  model_type=model_type,
@@ -220,10 +257,10 @@ class GuiSD:
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,7 +270,8 @@ class GuiSD:
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],
@@ -387,7 +425,7 @@ class GuiSD:
387
  vae_msg = f"VAE: {vae_model}" if vae_model else ""
388
  msg_lora = ""
389
 
390
- print("Config model:", model_name, vae_model, loras_list)
391
 
392
  task = TASK_STABLEPY[task]
393
 
@@ -485,19 +523,19 @@ class GuiSD:
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"
@@ -555,11 +593,11 @@ class GuiSD:
555
  # kwargs for diffusers pipeline
556
  if guidance_rescale:
557
  pipe_params["guidance_rescale"] = guidance_rescale
558
-
559
- self.model.device = torch.device("cuda:0")
560
- if hasattr(self.model.pipe, "transformer") and loras_list != ["None"] * self.model.num_loras:
561
- self.model.pipe.transformer.to(self.model.device)
562
- print("transformer to cuda")
563
 
564
  actual_progress = 0
565
  info_images = gr.update()
@@ -589,7 +627,7 @@ class GuiSD:
589
 
590
  download_links = "<br>".join(
591
  [
592
- f'<a href="{path.replace("/images/", "/file=/home/user/app/images/")}" download="{os.path.basename(path)}">Download Image {i + 1}</a>'
593
  for i, path in enumerate(image_path)
594
  ]
595
  )
@@ -698,7 +736,8 @@ def sd_gen_generate_pipeline(*args):
698
 
699
  @spaces.GPU(duration=15)
700
  def process_upscale(image, upscaler_name, upscaler_size):
701
- if image is None: return None
 
702
 
703
  from stablepy.diffusers_vanilla.utils import save_pil_image_with_metadata
704
  from stablepy import load_upscaler_model
@@ -715,7 +754,7 @@ def process_upscale(image, upscaler_name, upscaler_size):
715
 
716
  name_upscaler = f"./{DIRECTORY_UPSCALERS}/{name_upscaler.split('/')[-1]}"
717
 
718
- scaler_beta = load_upscaler_model(model=name_upscaler, tile=0, tile_overlap=8, device="cuda", half=True)
719
  image_up = scaler_beta.upscale(image, upscaler_size, True)
720
 
721
  image_path = save_pil_image_with_metadata(image_up, f'{os.getcwd()}/up_images', exif_image)
@@ -724,11 +763,11 @@ def process_upscale(image, upscaler_name, upscaler_size):
724
 
725
 
726
  # https://huggingface.co/spaces/BestWishYsh/ConsisID-preview-Space/discussions/1#674969a022b99c122af5d407
727
- dynamic_gpu_duration.zerogpu = True
728
- sd_gen_generate_pipeline.zerogpu = True
729
  sd_gen = GuiSD()
730
 
731
- with gr.Blocks(theme="NoCrypt/miku", css=CSS) as app:
732
  gr.Markdown("# 🧩 DiffuseCraft")
733
  gr.Markdown(SUBTITLE_GUI)
734
  with gr.Tab("Generation"):
@@ -777,7 +816,7 @@ with gr.Blocks(theme="NoCrypt/miku", css=CSS) as app:
777
 
778
  actual_task_info = gr.HTML()
779
 
780
- with gr.Row(equal_height=False, variant="default"):
781
  gpu_duration_gui = gr.Number(minimum=5, maximum=240, value=59, show_label=False, container=False, info="GPU time duration (seconds)")
782
  with gr.Column():
783
  verbose_info_gui = gr.Checkbox(value=False, container=False, label="Status info")
@@ -813,7 +852,22 @@ with gr.Blocks(theme="NoCrypt/miku", css=CSS) as app:
813
  "Schedule type": gr.update(value="Automatic"),
814
  "PAG": gr.update(value=.0),
815
  "FreeU": gr.update(value=False),
 
 
 
 
 
 
 
 
 
816
  }
 
 
 
 
 
 
817
  valid_keys = list(valid_receptors.keys())
818
 
819
  parameters = extract_parameters(base_prompt)
@@ -827,6 +881,36 @@ with gr.Blocks(theme="NoCrypt/miku", css=CSS) as app:
827
  parameters["Sampler"] = value_sampler
828
  parameters["Schedule type"] = s_type
829
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
830
  for key, val in parameters.items():
831
  # print(val)
832
  if key in valid_keys:
@@ -834,9 +918,12 @@ with gr.Blocks(theme="NoCrypt/miku", css=CSS) as app:
834
  if key == "Sampler":
835
  if val not in scheduler_names:
836
  continue
837
- if key == "Schedule type":
838
  if val not in SCHEDULE_TYPE_OPTIONS:
839
- val = "Automatic"
 
 
 
840
  elif key == "Clip skip":
841
  if "," in str(val):
842
  val = val.replace(",", "")
@@ -844,15 +931,15 @@ with gr.Blocks(theme="NoCrypt/miku", css=CSS) as app:
844
  val = True
845
  if key == "prompt":
846
  if ">" in val and "<" in val:
847
- val = re.sub(r'<[^>]+>', '', val)
848
  print("Removed LoRA written in the prompt")
849
  if key in ["prompt", "neg_prompt"]:
850
  val = re.sub(r'\s+', ' ', re.sub(r',+', ',', val)).strip()
851
- if key in ["Steps", "width", "height", "Seed"]:
852
  val = int(val)
853
  if key == "FreeU":
854
  val = True
855
- if key in ["CFG scale", "PAG"]:
856
  val = float(val)
857
  if key == "Model":
858
  filtered_models = [m for m in model_list if val in m]
@@ -860,8 +947,12 @@ with gr.Blocks(theme="NoCrypt/miku", css=CSS) as app:
860
  val = filtered_models[0]
861
  else:
862
  val = name_model
 
 
 
863
  if key == "Seed":
864
  continue
 
865
  valid_receptors[key] = gr.update(value=val)
866
  # print(val, type(val))
867
  # print(valid_receptors)
@@ -869,24 +960,6 @@ with gr.Blocks(theme="NoCrypt/miku", css=CSS) as app:
869
  print(str(e))
870
  return [value for value in valid_receptors.values()]
871
 
872
- set_params_gui.click(
873
- run_set_params_gui, [prompt_gui, model_name_gui], [
874
- prompt_gui,
875
- neg_prompt_gui,
876
- steps_gui,
877
- img_width_gui,
878
- img_height_gui,
879
- seed_gui,
880
- sampler_gui,
881
- cfg_gui,
882
- clip_skip_gui,
883
- model_name_gui,
884
- schedule_type_gui,
885
- pag_scale_gui,
886
- free_u_gui,
887
- ],
888
- )
889
-
890
  def run_clear_prompt_gui():
891
  return gr.update(value=""), gr.update(value="")
892
  clear_prompt_gui.click(
@@ -899,7 +972,7 @@ with gr.Blocks(theme="NoCrypt/miku", css=CSS) as app:
899
  run_set_random_seed, [], seed_gui
900
  )
901
 
902
- num_images_gui = gr.Slider(minimum=1, maximum=5, step=1, value=1, label="Images")
903
  prompt_syntax_gui = gr.Dropdown(label="Prompt Syntax", choices=PROMPT_W_OPTIONS, value=PROMPT_W_OPTIONS[1][1])
904
  vae_model_gui = gr.Dropdown(label="VAE Model", choices=vae_model_list, value=vae_model_list[0])
905
 
@@ -907,7 +980,7 @@ with gr.Blocks(theme="NoCrypt/miku", css=CSS) as app:
907
 
908
  upscaler_model_path_gui = gr.Dropdown(label="Upscaler", choices=UPSCALER_KEYS, value=UPSCALER_KEYS[0])
909
  upscaler_increases_size_gui = gr.Slider(minimum=1.1, maximum=4., step=0.1, value=1.2, label="Upscale by")
910
- upscaler_tile_size_gui = gr.Slider(minimum=0, maximum=512, step=16, value=0, label="Upscaler Tile Size", info="0 = no tiling")
911
  upscaler_tile_overlap_gui = gr.Slider(minimum=0, maximum=48, step=1, value=8, label="Upscaler Tile Overlap")
912
  hires_steps_gui = gr.Slider(minimum=0, value=30, maximum=100, step=1, label="Hires Steps")
913
  hires_denoising_strength_gui = gr.Slider(minimum=0.1, maximum=1.0, step=0.01, value=0.55, label="Hires Denoising Strength")
@@ -924,7 +997,8 @@ with gr.Blocks(theme="NoCrypt/miku", css=CSS) as app:
924
  return gr.Dropdown(label=label, choices=lora_model_list, value="None", allow_custom_value=True, visible=visible)
925
 
926
  def lora_scale_slider(label, visible=True):
927
- return gr.Slider(minimum=-2, maximum=2, step=0.01, value=0.33, label=label, visible=visible)
 
928
 
929
  lora1_gui = lora_dropdown("Lora1")
930
  lora_scale_1_gui = lora_scale_slider("Lora Scale 1")
@@ -936,10 +1010,10 @@ with gr.Blocks(theme="NoCrypt/miku", css=CSS) as app:
936
  lora_scale_4_gui = lora_scale_slider("Lora Scale 4")
937
  lora5_gui = lora_dropdown("Lora5")
938
  lora_scale_5_gui = lora_scale_slider("Lora Scale 5")
939
- lora6_gui = lora_dropdown("Lora6", visible=False)
940
- lora_scale_6_gui = lora_scale_slider("Lora Scale 6", visible=False)
941
- lora7_gui = lora_dropdown("Lora7", visible=False)
942
- lora_scale_7_gui = lora_scale_slider("Lora Scale 7", visible=False)
943
 
944
  with gr.Accordion("From URL", open=False, visible=True):
945
  text_lora = gr.Textbox(
@@ -948,7 +1022,7 @@ with gr.Blocks(theme="NoCrypt/miku", css=CSS) as app:
948
  lines=1,
949
  info="It has to be .safetensors files, and you can also download them from Hugging Face.",
950
  )
951
- romanize_text = gr.Checkbox(value=False, label="Transliterate name", visible=False)
952
  button_lora = gr.Button("Get and Refresh the LoRA Lists")
953
  new_lora_status = gr.HTML()
954
  button_lora.click(
@@ -1013,8 +1087,8 @@ with gr.Blocks(theme="NoCrypt/miku", css=CSS) as app:
1013
  preprocess_resolution_gui = gr.Slider(minimum=64, maximum=2048, step=64, value=512, label="Preprocessor Resolution")
1014
  low_threshold_gui = gr.Slider(minimum=1, maximum=255, step=1, value=100, label="'CANNY' low threshold")
1015
  high_threshold_gui = gr.Slider(minimum=1, maximum=255, step=1, value=200, label="'CANNY' high threshold")
1016
- value_threshold_gui = gr.Slider(minimum=1, maximum=2.0, step=0.01, value=0.1, label="'MLSD' Hough value threshold")
1017
- distance_threshold_gui = gr.Slider(minimum=1, maximum=20.0, step=0.01, value=0.1, label="'MLSD' Hough distance threshold")
1018
  recolor_gamma_correction_gui = gr.Number(minimum=0., maximum=25., value=1., step=0.001, label="'RECOLOR' gamma correction")
1019
  tile_blur_sigma_gui = gr.Number(minimum=0, maximum=100, value=9, step=1, label="'TILE' blur sigma")
1020
 
@@ -1049,7 +1123,7 @@ with gr.Blocks(theme="NoCrypt/miku", css=CSS) as app:
1049
  gr.Info(f"{len(sd_gen.model.STYLE_NAMES)} styles loaded")
1050
  return gr.update(value=None, choices=sd_gen.model.STYLE_NAMES)
1051
 
1052
- style_button.click(load_json_style_file, [style_json_gui], [style_prompt_gui])
1053
 
1054
  with gr.Accordion("Textual inversion", open=False, visible=False):
1055
  active_textual_inversion_gui = gr.Checkbox(value=False, label="Active Textual Inversion in prompt")
@@ -1099,20 +1173,62 @@ with gr.Blocks(theme="NoCrypt/miku", css=CSS) as app:
1099
  hires_before_adetailer_gui = gr.Checkbox(value=False, label="Hires Before Adetailer")
1100
  hires_after_adetailer_gui = gr.Checkbox(value=True, label="Hires After Adetailer")
1101
  generator_in_cpu_gui = gr.Checkbox(value=False, label="Generator in CPU")
 
 
 
 
1102
 
1103
  with gr.Accordion("More settings", open=False, visible=False):
1104
  loop_generation_gui = gr.Slider(minimum=1, value=1, label="Loop Generation")
1105
  retain_task_cache_gui = gr.Checkbox(value=False, label="Retain task model in cache")
1106
- leave_progress_bar_gui = gr.Checkbox(value=True, label="Leave Progress Bar")
1107
- disable_progress_bar_gui = gr.Checkbox(value=False, label="Disable Progress Bar")
1108
  display_images_gui = gr.Checkbox(value=False, label="Display Images")
1109
  image_previews_gui = gr.Checkbox(value=True, label="Image Previews")
1110
- image_storage_location_gui = gr.Textbox(value="./images", label="Image Storage Location")
1111
  retain_compel_previous_load_gui = gr.Checkbox(value=False, label="Retain Compel Previous Load")
1112
  retain_detailfix_model_previous_load_gui = gr.Checkbox(value=False, label="Retain Detailfix Model Previous Load")
1113
  retain_hires_model_previous_load_gui = gr.Checkbox(value=False, label="Retain Hires Model Previous Load")
1114
  xformers_memory_efficient_attention_gui = gr.Checkbox(value=False, label="Xformers Memory Efficient Attention")
1115
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1116
  with gr.Accordion("Examples and help", open=False, visible=True):
1117
  gr.Markdown(HELP_GUI)
1118
  gr.Markdown(EXAMPLES_GUI_HELP)
@@ -1168,10 +1284,21 @@ with gr.Blocks(theme="NoCrypt/miku", css=CSS) as app:
1168
  # "hsl(360, 120, 120)" # in fact any valid colorstring
1169
  ]
1170
  ),
1171
- eraser=gr.Eraser(default_size="16")
 
 
 
1172
  )
 
 
 
 
 
 
 
1173
  invert_mask = gr.Checkbox(value=False, label="Invert mask")
1174
  btn = gr.Button("Create mask")
 
1175
  with gr.Column(scale=1):
1176
  img_source = gr.Image(interactive=False)
1177
  img_result = gr.Image(label="Mask image", show_label=True, interactive=False)
@@ -1363,10 +1490,12 @@ with gr.Blocks(theme="NoCrypt/miku", css=CSS) as app:
1363
  show_progress="minimal",
1364
  )
1365
 
1366
- app.queue()
1367
-
1368
- app.launch(
1369
- show_error=True,
1370
- debug=True,
1371
- allowed_paths=["./images/"],
1372
- )
 
 
 
1
  import spaces
2
  import os
3
+ from argparse import ArgumentParser
4
  from stablepy import (
5
  Model_Diffusers,
6
  SCHEDULE_TYPE_OPTIONS,
 
41
  DIFFUSERS_CONTROLNET_MODEL,
42
  IP_MODELS,
43
  MODE_IP_OPTIONS,
44
+ CACHE_HF_ROOT,
45
  )
46
  from stablepy.diffusers_vanilla.style_prompt_config import STYLE_NAMES
47
  import torch
 
62
  progress_step_bar,
63
  html_template_message,
64
  escape_html,
65
+ clear_hf_cache,
66
  )
67
  from image_processor import preprocessor_tab
68
  from datetime import datetime
 
75
  # import urllib.parse
76
  import subprocess
77
 
78
+ IS_ZERO_GPU = bool(os.getenv("SPACES_ZERO_GPU"))
79
+ if IS_ZERO_GPU:
80
+ subprocess.run("rm -rf /data-nvme/zerogpu-offload/*", env={}, shell=True)
81
+ IS_GPU_MODE = True if IS_ZERO_GPU else (True if torch.cuda.is_available() else False)
82
+ img_path = "./images/"
83
+ allowed_path = os.path.abspath(img_path)
84
+ delete_cache_time = (9600, 9600) if IS_ZERO_GPU else (86400, 86400)
85
+
86
  ImageFile.LOAD_TRUNCATED_IMAGES = True
87
  torch.backends.cuda.matmul.allow_tf32 = True
88
  # os.environ["PYTORCH_NO_CUDA_MEMORY_CACHING"] = "1"
 
89
 
90
  directories = [DIRECTORY_MODELS, DIRECTORY_LORAS, DIRECTORY_VAES, DIRECTORY_EMBEDS, DIRECTORY_UPSCALERS]
91
  for directory in directories:
 
93
 
94
  # Download stuffs
95
  for url in [url.strip() for url in DOWNLOAD_MODEL.split(',')]:
96
+ download_things(DIRECTORY_MODELS, url, HF_TOKEN, CIVITAI_API_KEY)
 
97
  for url in [url.strip() for url in DOWNLOAD_VAE.split(',')]:
98
+ download_things(DIRECTORY_VAES, url, HF_TOKEN, CIVITAI_API_KEY)
 
99
  for url in [url.strip() for url in DOWNLOAD_LORA.split(',')]:
100
+ download_things(DIRECTORY_LORAS, url, HF_TOKEN, CIVITAI_API_KEY)
 
101
 
102
  # Download Embeddings
103
  for url_embed in DOWNLOAD_EMBEDS:
104
+ download_things(DIRECTORY_EMBEDS, url_embed, HF_TOKEN, CIVITAI_API_KEY)
 
105
 
106
  # Build list models
107
  embed_list = get_model_list(DIRECTORY_EMBEDS)
 
119
 
120
  print('\033[33m🏁 Download and listing of valid models completed.\033[0m')
121
 
122
+ components = None
123
+ if IS_ZERO_GPU:
124
+ flux_repo = "camenduru/FLUX.1-dev-diffusers"
125
+ flux_pipe = FluxPipeline.from_pretrained(
126
+ flux_repo,
127
+ transformer=None,
128
+ torch_dtype=torch.bfloat16,
129
+ ).to("cuda")
130
+ components = flux_pipe.components
131
+ delete_model(flux_repo)
132
 
133
  #######################
134
  # GUI
 
138
  warnings.filterwarnings(action="ignore", category=FutureWarning, module="diffusers")
139
  warnings.filterwarnings(action="ignore", category=UserWarning, module="diffusers")
140
  warnings.filterwarnings(action="ignore", category=FutureWarning, module="transformers")
141
+
142
+ parser = ArgumentParser(description='DiffuseCraft: Create images from text prompts.', add_help=True)
143
+ parser.add_argument("--share", action="store_true", dest="share_enabled", default=False, help="Enable sharing")
144
+ parser.add_argument('--theme', type=str, default="NoCrypt/miku", help='Set the theme (default: NoCrypt/miku)')
145
+ parser.add_argument("--ssr", action="store_true", help="Enable SSR (Server-Side Rendering)")
146
+ parser.add_argument("--log-level", type=str, default="INFO", choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"], help="Set logging level (default: INFO)")
147
+ args = parser.parse_args()
148
+
149
+ logger.setLevel(
150
+ "INFO" if IS_ZERO_GPU else getattr(logging, args.log_level.upper())
151
+ )
152
 
153
  CSS = """
154
  .contain { display: flex; flex-direction: column; }
 
158
  """
159
 
160
 
161
+ def lora_chk(lora_):
162
+ if isinstance(lora_, str) and lora_.strip() not in ["", "None"]:
163
+ return lora_
164
+ return None
165
+
166
+
167
  class GuiSD:
168
  def __init__(self, stream=True):
169
  self.model = None
 
179
  removal_candidate = self.inventory.pop(0)
180
  delete_model(removal_candidate)
181
 
182
+ # Cleanup after 60 seconds of inactivity
183
+ lowPrioCleanup = max((datetime.now() - self.last_load).total_seconds(), 0) > 60
184
+ if lowPrioCleanup and not self.status_loading and get_used_storage_gb(CACHE_HF_ROOT) > (storage_floor_gb * 2):
185
+ print("Cleaning up Hugging Face cache...")
186
+ clear_hf_cache()
187
+ self.inventory = [
188
+ m for m in self.inventory if os.path.exists(m)
189
+ ]
190
+
191
  def update_inventory(self, model_name):
192
  if model_name not in single_file_model_list:
193
  self.inventory = [
 
198
  def load_new_model(self, model_name, vae_model, task, controlnet_model, progress=gr.Progress(track_tqdm=True)):
199
 
200
  # download link model > model_name
201
+ if model_name.startswith("http"):
202
+ yield f"Downloading model: {model_name}"
203
+ model_name = download_things(DIRECTORY_MODELS, model_name, HF_TOKEN, CIVITAI_API_KEY)
204
+ if not model_name:
205
+ raise ValueError("Error retrieving model information from URL")
206
 
207
+ if IS_ZERO_GPU:
208
+ self.update_storage_models()
209
 
210
  vae_model = vae_model if vae_model != "None" else None
211
  model_type = get_model_type(model_name)
212
  dtype_model = torch.bfloat16 if model_type == "FLUX" else torch.float16
213
 
214
  if not os.path.exists(model_name):
215
+ logger.debug(f"model_name={model_name}, vae_model={vae_model}, task={task}, controlnet_model={controlnet_model}")
216
  _ = download_diffuser_repo(
217
  repo_name=model_name,
218
  model_type=model_type,
 
257
  type_model_precision=dtype_model,
258
  retain_task_model_in_cache=False,
259
  controlnet_model=controlnet_model,
260
+ device="cpu" if IS_ZERO_GPU else None,
261
  env_components=components,
262
  )
263
+ self.model.advanced_params(image_preprocessor_cuda_active=IS_GPU_MODE)
264
  else:
265
  if self.model.base_model_id != model_name:
266
  load_now_time = datetime.now()
 
270
  print("Waiting for the previous model's time ops...")
271
  time.sleep(9 - elapsed_time)
272
 
273
+ if IS_ZERO_GPU:
274
+ self.model.device = torch.device("cpu")
275
  self.model.load_pipe(
276
  model_name,
277
  task_name=TASK_STABLEPY[task],
 
425
  vae_msg = f"VAE: {vae_model}" if vae_model else ""
426
  msg_lora = ""
427
 
428
+ logger.debug(f"Config model: {model_name}, {vae_model}, {loras_list}")
429
 
430
  task = TASK_STABLEPY[task]
431
 
 
523
  "distance_threshold": distance_threshold,
524
  "recolor_gamma_correction": float(recolor_gamma_correction),
525
  "tile_blur_sigma": int(tile_blur_sigma),
526
+ "lora_A": lora_chk(lora1),
527
  "lora_scale_A": lora_scale1,
528
+ "lora_B": lora_chk(lora2),
529
  "lora_scale_B": lora_scale2,
530
+ "lora_C": lora_chk(lora3),
531
  "lora_scale_C": lora_scale3,
532
+ "lora_D": lora_chk(lora4),
533
  "lora_scale_D": lora_scale4,
534
+ "lora_E": lora_chk(lora5),
535
  "lora_scale_E": lora_scale5,
536
+ "lora_F": lora_chk(lora6),
537
  "lora_scale_F": lora_scale6,
538
+ "lora_G": lora_chk(lora7),
539
  "lora_scale_G": lora_scale7,
540
  "textual_inversion": embed_list if textual_inversion else [],
541
  "syntax_weights": syntax_weights, # "Classic"
 
593
  # kwargs for diffusers pipeline
594
  if guidance_rescale:
595
  pipe_params["guidance_rescale"] = guidance_rescale
596
+ if IS_ZERO_GPU:
597
+ self.model.device = torch.device("cuda:0")
598
+ if hasattr(self.model.pipe, "transformer") and loras_list != ["None"] * self.model.num_loras:
599
+ self.model.pipe.transformer.to(self.model.device)
600
+ logger.debug("transformer to cuda")
601
 
602
  actual_progress = 0
603
  info_images = gr.update()
 
627
 
628
  download_links = "<br>".join(
629
  [
630
+ f'<a href="{path.replace("/images/", f"/gradio_api/file={allowed_path}/")}" download="{os.path.basename(path)}">Download Image {i + 1}</a>'
631
  for i, path in enumerate(image_path)
632
  ]
633
  )
 
736
 
737
  @spaces.GPU(duration=15)
738
  def process_upscale(image, upscaler_name, upscaler_size):
739
+ if image is None:
740
+ return None
741
 
742
  from stablepy.diffusers_vanilla.utils import save_pil_image_with_metadata
743
  from stablepy import load_upscaler_model
 
754
 
755
  name_upscaler = f"./{DIRECTORY_UPSCALERS}/{name_upscaler.split('/')[-1]}"
756
 
757
+ 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)
758
  image_up = scaler_beta.upscale(image, upscaler_size, True)
759
 
760
  image_path = save_pil_image_with_metadata(image_up, f'{os.getcwd()}/up_images', exif_image)
 
763
 
764
 
765
  # https://huggingface.co/spaces/BestWishYsh/ConsisID-preview-Space/discussions/1#674969a022b99c122af5d407
766
+ # dynamic_gpu_duration.zerogpu = True
767
+ # sd_gen_generate_pipeline.zerogpu = True
768
  sd_gen = GuiSD()
769
 
770
+ with gr.Blocks(theme=args.theme, css=CSS, fill_width=True, fill_height=False, delete_cache=delete_cache_time) as app:
771
  gr.Markdown("# 🧩 DiffuseCraft")
772
  gr.Markdown(SUBTITLE_GUI)
773
  with gr.Tab("Generation"):
 
816
 
817
  actual_task_info = gr.HTML()
818
 
819
+ with gr.Row(equal_height=False, variant="default", visible=IS_ZERO_GPU):
820
  gpu_duration_gui = gr.Number(minimum=5, maximum=240, value=59, show_label=False, container=False, info="GPU time duration (seconds)")
821
  with gr.Column():
822
  verbose_info_gui = gr.Checkbox(value=False, container=False, label="Status info")
 
852
  "Schedule type": gr.update(value="Automatic"),
853
  "PAG": gr.update(value=.0),
854
  "FreeU": gr.update(value=False),
855
+ "Hires upscaler": gr.update(),
856
+ "Hires upscale": gr.update(),
857
+ "Hires steps": gr.update(),
858
+ "Hires denoising strength": gr.update(),
859
+ "Hires CFG": gr.update(),
860
+ "Hires sampler": gr.update(),
861
+ "Hires schedule type": gr.update(),
862
+ "Image resolution": gr.update(value=1024),
863
+ "Strength": gr.update(),
864
  }
865
+
866
+ # Generate up to 7 LoRAs
867
+ for i in range(1, 8):
868
+ valid_receptors[f"Lora_{i}"] = gr.update()
869
+ valid_receptors[f"Lora_scale_{i}"] = gr.update()
870
+
871
  valid_keys = list(valid_receptors.keys())
872
 
873
  parameters = extract_parameters(base_prompt)
 
881
  parameters["Sampler"] = value_sampler
882
  parameters["Schedule type"] = s_type
883
 
884
+ params_lora = []
885
+ if ">" in parameters["prompt"] and "<" in parameters["prompt"]:
886
+ params_lora = re.findall(r'<lora:[^>]+>', parameters["prompt"])
887
+ if "Loras" in parameters:
888
+ params_lora += re.findall(r'<lora:[^>]+>', parameters["Loras"])
889
+
890
+ if params_lora:
891
+ parsed_params = []
892
+ for tag_l in params_lora:
893
+ try:
894
+ inner = tag_l.strip("<>") # remove < >
895
+ _, data_l = inner.split(":", 1) # remove the "lora:" part
896
+ parts_l = data_l.split(":")
897
+
898
+ name_l = parts_l[0]
899
+ weight_l = float(parts_l[1]) if len(parts_l) > 1 else 1.0 # default weight = 1.0
900
+
901
+ parsed_params.append((name_l, weight_l))
902
+ except Exception as e:
903
+ print(f"Error parsing LoRA tag {tag_l}: {e}")
904
+
905
+ num_lora = 1
906
+ for parsed_l, parsed_s in parsed_params:
907
+ filtered_loras = [m for m in lora_model_list if parsed_l in m]
908
+ if filtered_loras:
909
+ parameters[f"Lora_{num_lora}"] = filtered_loras[0]
910
+ parameters[f"Lora_scale_{num_lora}"] = parsed_s
911
+ num_lora += 1
912
+
913
+ # continue = discard new value
914
  for key, val in parameters.items():
915
  # print(val)
916
  if key in valid_keys:
 
918
  if key == "Sampler":
919
  if val not in scheduler_names:
920
  continue
921
+ if key in ["Schedule type", "Hires schedule type"]:
922
  if val not in SCHEDULE_TYPE_OPTIONS:
923
+ continue
924
+ if key == "Hires sampler":
925
+ if val not in POST_PROCESSING_SAMPLER:
926
+ continue
927
  elif key == "Clip skip":
928
  if "," in str(val):
929
  val = val.replace(",", "")
 
931
  val = True
932
  if key == "prompt":
933
  if ">" in val and "<" in val:
934
+ val = re.sub(r'<[^>]+>', '', val) # Delete html and loras
935
  print("Removed LoRA written in the prompt")
936
  if key in ["prompt", "neg_prompt"]:
937
  val = re.sub(r'\s+', ' ', re.sub(r',+', ',', val)).strip()
938
+ if key in ["Steps", "width", "height", "Seed", "Hires steps", "Image resolution"]:
939
  val = int(val)
940
  if key == "FreeU":
941
  val = True
942
+ if key in ["CFG scale", "PAG", "Hires upscale", "Hires denoising strength", "Hires CFG", "Strength"]:
943
  val = float(val)
944
  if key == "Model":
945
  filtered_models = [m for m in model_list if val in m]
 
947
  val = filtered_models[0]
948
  else:
949
  val = name_model
950
+ if key == "Hires upscaler":
951
+ if val not in UPSCALER_KEYS:
952
+ continue
953
  if key == "Seed":
954
  continue
955
+
956
  valid_receptors[key] = gr.update(value=val)
957
  # print(val, type(val))
958
  # print(valid_receptors)
 
960
  print(str(e))
961
  return [value for value in valid_receptors.values()]
962
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
963
  def run_clear_prompt_gui():
964
  return gr.update(value=""), gr.update(value="")
965
  clear_prompt_gui.click(
 
972
  run_set_random_seed, [], seed_gui
973
  )
974
 
975
+ num_images_gui = gr.Slider(minimum=1, maximum=(5 if IS_ZERO_GPU else 20), step=1, value=1, label="Images")
976
  prompt_syntax_gui = gr.Dropdown(label="Prompt Syntax", choices=PROMPT_W_OPTIONS, value=PROMPT_W_OPTIONS[1][1])
977
  vae_model_gui = gr.Dropdown(label="VAE Model", choices=vae_model_list, value=vae_model_list[0])
978
 
 
980
 
981
  upscaler_model_path_gui = gr.Dropdown(label="Upscaler", choices=UPSCALER_KEYS, value=UPSCALER_KEYS[0])
982
  upscaler_increases_size_gui = gr.Slider(minimum=1.1, maximum=4., step=0.1, value=1.2, label="Upscale by")
983
+ 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")
984
  upscaler_tile_overlap_gui = gr.Slider(minimum=0, maximum=48, step=1, value=8, label="Upscaler Tile Overlap")
985
  hires_steps_gui = gr.Slider(minimum=0, value=30, maximum=100, step=1, label="Hires Steps")
986
  hires_denoising_strength_gui = gr.Slider(minimum=0.1, maximum=1.0, step=0.01, value=0.55, label="Hires Denoising Strength")
 
997
  return gr.Dropdown(label=label, choices=lora_model_list, value="None", allow_custom_value=True, visible=visible)
998
 
999
  def lora_scale_slider(label, visible=True):
1000
+ val_lora = 2 if IS_ZERO_GPU else 8
1001
+ return gr.Slider(minimum=-val_lora, maximum=val_lora, step=0.01, value=0.33, label=label, visible=visible)
1002
 
1003
  lora1_gui = lora_dropdown("Lora1")
1004
  lora_scale_1_gui = lora_scale_slider("Lora Scale 1")
 
1010
  lora_scale_4_gui = lora_scale_slider("Lora Scale 4")
1011
  lora5_gui = lora_dropdown("Lora5")
1012
  lora_scale_5_gui = lora_scale_slider("Lora Scale 5")
1013
+ lora6_gui = lora_dropdown("Lora6", visible=(not IS_ZERO_GPU))
1014
+ lora_scale_6_gui = lora_scale_slider("Lora Scale 6", visible=(not IS_ZERO_GPU))
1015
+ lora7_gui = lora_dropdown("Lora7", visible=(not IS_ZERO_GPU))
1016
+ lora_scale_7_gui = lora_scale_slider("Lora Scale 7", visible=(not IS_ZERO_GPU))
1017
 
1018
  with gr.Accordion("From URL", open=False, visible=True):
1019
  text_lora = gr.Textbox(
 
1022
  lines=1,
1023
  info="It has to be .safetensors files, and you can also download them from Hugging Face.",
1024
  )
1025
+ romanize_text = gr.Checkbox(value=False, label="Transliterate name", visible=(not IS_ZERO_GPU))
1026
  button_lora = gr.Button("Get and Refresh the LoRA Lists")
1027
  new_lora_status = gr.HTML()
1028
  button_lora.click(
 
1087
  preprocess_resolution_gui = gr.Slider(minimum=64, maximum=2048, step=64, value=512, label="Preprocessor Resolution")
1088
  low_threshold_gui = gr.Slider(minimum=1, maximum=255, step=1, value=100, label="'CANNY' low threshold")
1089
  high_threshold_gui = gr.Slider(minimum=1, maximum=255, step=1, value=200, label="'CANNY' high threshold")
1090
+ value_threshold_gui = gr.Slider(minimum=0.0, maximum=2.0, step=0.01, value=0.1, label="'MLSD' Hough value threshold")
1091
+ distance_threshold_gui = gr.Slider(minimum=0.0, maximum=20.0, step=0.01, value=0.1, label="'MLSD' Hough distance threshold")
1092
  recolor_gamma_correction_gui = gr.Number(minimum=0., maximum=25., value=1., step=0.001, label="'RECOLOR' gamma correction")
1093
  tile_blur_sigma_gui = gr.Number(minimum=0, maximum=100, value=9, step=1, label="'TILE' blur sigma")
1094
 
 
1123
  gr.Info(f"{len(sd_gen.model.STYLE_NAMES)} styles loaded")
1124
  return gr.update(value=None, choices=sd_gen.model.STYLE_NAMES)
1125
 
1126
+ style_button.click(load_json_style_file, [style_json_gui], [style_prompt_gui])
1127
 
1128
  with gr.Accordion("Textual inversion", open=False, visible=False):
1129
  active_textual_inversion_gui = gr.Checkbox(value=False, label="Active Textual Inversion in prompt")
 
1173
  hires_before_adetailer_gui = gr.Checkbox(value=False, label="Hires Before Adetailer")
1174
  hires_after_adetailer_gui = gr.Checkbox(value=True, label="Hires After Adetailer")
1175
  generator_in_cpu_gui = gr.Checkbox(value=False, label="Generator in CPU")
1176
+ with gr.Column(visible=(not IS_ZERO_GPU)):
1177
+ image_storage_location_gui = gr.Textbox(value=img_path, label="Image Storage Location")
1178
+ disable_progress_bar_gui = gr.Checkbox(value=False, label="Disable Progress Bar")
1179
+ leave_progress_bar_gui = gr.Checkbox(value=True, label="Leave Progress Bar")
1180
 
1181
  with gr.Accordion("More settings", open=False, visible=False):
1182
  loop_generation_gui = gr.Slider(minimum=1, value=1, label="Loop Generation")
1183
  retain_task_cache_gui = gr.Checkbox(value=False, label="Retain task model in cache")
 
 
1184
  display_images_gui = gr.Checkbox(value=False, label="Display Images")
1185
  image_previews_gui = gr.Checkbox(value=True, label="Image Previews")
 
1186
  retain_compel_previous_load_gui = gr.Checkbox(value=False, label="Retain Compel Previous Load")
1187
  retain_detailfix_model_previous_load_gui = gr.Checkbox(value=False, label="Retain Detailfix Model Previous Load")
1188
  retain_hires_model_previous_load_gui = gr.Checkbox(value=False, label="Retain Hires Model Previous Load")
1189
  xformers_memory_efficient_attention_gui = gr.Checkbox(value=False, label="Xformers Memory Efficient Attention")
1190
 
1191
+ set_params_gui.click(
1192
+ run_set_params_gui, [prompt_gui, model_name_gui], [
1193
+ prompt_gui,
1194
+ neg_prompt_gui,
1195
+ steps_gui,
1196
+ img_width_gui,
1197
+ img_height_gui,
1198
+ seed_gui,
1199
+ sampler_gui,
1200
+ cfg_gui,
1201
+ clip_skip_gui,
1202
+ model_name_gui,
1203
+ schedule_type_gui,
1204
+ pag_scale_gui,
1205
+ free_u_gui,
1206
+ upscaler_model_path_gui,
1207
+ upscaler_increases_size_gui,
1208
+ hires_steps_gui,
1209
+ hires_denoising_strength_gui,
1210
+ hires_guidance_scale_gui,
1211
+ hires_sampler_gui,
1212
+ hires_schedule_type_gui,
1213
+ image_resolution_gui,
1214
+ strength_gui,
1215
+ lora1_gui,
1216
+ lora_scale_1_gui,
1217
+ lora2_gui,
1218
+ lora_scale_2_gui,
1219
+ lora3_gui,
1220
+ lora_scale_3_gui,
1221
+ lora4_gui,
1222
+ lora_scale_4_gui,
1223
+ lora5_gui,
1224
+ lora_scale_5_gui,
1225
+ lora6_gui,
1226
+ lora_scale_6_gui,
1227
+ lora7_gui,
1228
+ lora_scale_7_gui,
1229
+ ],
1230
+ )
1231
+
1232
  with gr.Accordion("Examples and help", open=False, visible=True):
1233
  gr.Markdown(HELP_GUI)
1234
  gr.Markdown(EXAMPLES_GUI_HELP)
 
1284
  # "hsl(360, 120, 120)" # in fact any valid colorstring
1285
  ]
1286
  ),
1287
+ eraser=gr.Eraser(default_size="16"),
1288
+ render=True,
1289
+ visible=False,
1290
+ interactive=False,
1291
  )
1292
+
1293
+ show_canvas = gr.Button("SHOW INPAINT CANVAS")
1294
+
1295
+ def change_visibility_canvas():
1296
+ return gr.update(visible=True, interactive=True), gr.update(visible=False)
1297
+ show_canvas.click(change_visibility_canvas, [], [image_base, show_canvas])
1298
+
1299
  invert_mask = gr.Checkbox(value=False, label="Invert mask")
1300
  btn = gr.Button("Create mask")
1301
+
1302
  with gr.Column(scale=1):
1303
  img_source = gr.Image(interactive=False)
1304
  img_result = gr.Image(label="Mask image", show_label=True, interactive=False)
 
1490
  show_progress="minimal",
1491
  )
1492
 
1493
+ if __name__ == "__main__":
1494
+ app.queue()
1495
+ app.launch(
1496
+ show_error=True,
1497
+ share=args.share_enabled,
1498
+ debug=True,
1499
+ ssr_mode=args.ssr,
1500
+ allowed_paths=[allowed_path],
1501
+ )
constants.py CHANGED
@@ -9,6 +9,8 @@ from stablepy import (
9
  IP_ADAPTERS_SDXL,
10
  )
11
 
 
 
12
  # - **Download Models**
13
  DOWNLOAD_MODEL = "https://huggingface.co/TechnoByte/MilkyWonderland/resolve/main/milkyWonderland_v40.safetensors"
14
 
@@ -23,12 +25,12 @@ LOAD_DIFFUSERS_FORMAT_MODEL = [
23
  'Laxhar/noobai-XL-1.1',
24
  'Laxhar/noobai-XL-Vpred-1.0',
25
  'black-forest-labs/FLUX.1-dev',
 
26
  'John6666/blue-pencil-flux1-v021-fp8-flux',
27
  'John6666/wai-ani-flux-v10forfp8-fp8-flux',
28
  'John6666/xe-anime-flux-v04-fp8-flux',
29
  'John6666/lyh-anime-flux-v2a1-fp8-flux',
30
  'John6666/carnival-unchained-v10-fp8-flux',
31
- 'John6666/iniverse-mix-xl-sfwnsfw-fluxdfp16nsfwv11-fp8-flux',
32
  'Freepik/flux.1-lite-8B-alpha',
33
  'shauray/FluxDev-HyperSD-merged',
34
  'mikeyandfriends/PixelWave_FLUX.1-dev_03',
@@ -37,23 +39,19 @@ LOAD_DIFFUSERS_FORMAT_MODEL = [
37
  # 'ostris/OpenFLUX.1',
38
  'shuttleai/shuttle-3-diffusion',
39
  'Laxhar/noobai-XL-1.0',
40
- 'John6666/noobai-xl-nai-xl-epsilonpred10version-sdxl',
41
  'Laxhar/noobai-XL-0.77',
42
  'John6666/noobai-xl-nai-xl-epsilonpred075version-sdxl',
43
  'Laxhar/noobai-XL-0.6',
44
  'John6666/noobai-xl-nai-xl-epsilonpred05version-sdxl',
45
  'John6666/noobai-cyberfix-v10-sdxl',
46
  'John6666/noobaiiter-xl-vpred-v075-sdxl',
47
- 'John6666/ntr-mix-illustrious-xl-noob-xl-v40-sdxl',
48
- 'John6666/ntr-mix-illustrious-xl-noob-xl-ntrmix35-sdxl',
49
- 'John6666/ntr-mix-illustrious-xl-noob-xl-v777-sdxl',
50
- 'John6666/ntr-mix-illustrious-xl-noob-xl-v777forlora-sdxl',
51
  'John6666/ntr-mix-illustrious-xl-noob-xl-xi-sdxl',
52
  'John6666/ntr-mix-illustrious-xl-noob-xl-xii-sdxl',
53
  'John6666/ntr-mix-illustrious-xl-noob-xl-xiii-sdxl',
54
  'John6666/mistoon-anime-v10illustrious-sdxl',
55
- 'John6666/hassaku-xl-illustrious-v10-sdxl',
56
- 'John6666/hassaku-xl-illustrious-v10style-sdxl',
57
  'John6666/haruki-mix-illustrious-v10-sdxl',
58
  'John6666/noobreal-v10-sdxl',
59
  'John6666/complicated-noobai-merge-vprediction-sdxl',
@@ -64,6 +62,7 @@ LOAD_DIFFUSERS_FORMAT_MODEL = [
64
  'Laxhar/noobai-XL-Vpred-0.65',
65
  'Laxhar/noobai-XL-Vpred-0.6',
66
  'John6666/cat-tower-noobai-xl-checkpoint-v14vpred-sdxl',
 
67
  'John6666/noobai-xl-nai-xl-vpred05version-sdxl',
68
  'John6666/noobai-fusion2-vpred-itercomp-v1-sdxl',
69
  'John6666/noobai-xl-nai-xl-vpredtestversion-sdxl',
@@ -74,19 +73,34 @@ LOAD_DIFFUSERS_FORMAT_MODEL = [
74
  'John6666/obsession-illustriousxl-v21-sdxl',
75
  'John6666/obsession-illustriousxl-v30-sdxl',
76
  'John6666/obsession-illustriousxl-v31-sdxl',
 
 
 
 
 
77
  'John6666/wai-nsfw-illustrious-v70-sdxl',
 
78
  'John6666/illustrious-pony-mix-v3-sdxl',
79
- 'John6666/nova-anime-xl-illustriousv10-sdxl',
80
- 'John6666/nova-orange-xl-v30-sdxl',
 
 
 
 
 
 
 
81
  'John6666/silvermoon-mix03-illustrious-v10-sdxl',
82
  'eienmojiki/Anything-XL',
83
  'eienmojiki/Starry-XL-v5.2',
 
84
  'John6666/meinaxl-v2-sdxl',
85
  'Eugeoter/artiwaifu-diffusion-2.0',
86
  'comin/IterComp',
87
- 'John6666/epicrealism-xl-vxiabeast-sdxl',
88
- 'John6666/epicrealism-xl-v10kiss2-sdxl',
89
  'John6666/epicrealism-xl-v8kiss-sdxl',
 
 
 
90
  'misri/zavychromaxl_v80',
91
  'SG161222/RealVisXL_V4.0',
92
  'SG161222/RealVisXL_V5.0',
@@ -102,8 +116,10 @@ LOAD_DIFFUSERS_FORMAT_MODEL = [
102
  'John6666/ebara-mfcg-pony-mix-v12-sdxl',
103
  'John6666/t-ponynai3-v51-sdxl',
104
  'John6666/t-ponynai3-v65-sdxl',
 
105
  'John6666/prefect-pony-xl-v3-sdxl',
106
  'John6666/prefect-pony-xl-v4-sdxl',
 
107
  'John6666/mala-anime-mix-nsfw-pony-xl-v5-sdxl',
108
  'John6666/wai-ani-nsfw-ponyxl-v10-sdxl',
109
  'John6666/wai-real-mix-v11-sdxl',
@@ -111,13 +127,14 @@ LOAD_DIFFUSERS_FORMAT_MODEL = [
111
  'John6666/wai-c-v6-sdxl',
112
  'John6666/iniverse-mix-xl-sfwnsfw-pony-guofeng-v43-sdxl',
113
  'John6666/sifw-annihilation-xl-v2-sdxl',
 
114
  'John6666/photo-realistic-pony-v5-sdxl',
115
  'John6666/pony-realism-v21main-sdxl',
116
  'John6666/pony-realism-v22main-sdxl',
117
- 'John6666/cyberrealistic-pony-v63-sdxl',
118
- 'John6666/cyberrealistic-pony-v64-sdxl',
119
  'John6666/cyberrealistic-pony-v65-sdxl',
120
  'John6666/cyberrealistic-pony-v7-sdxl',
 
121
  'GraydientPlatformAPI/realcartoon-pony-diffusion',
122
  'John6666/nova-anime-xl-pony-v5-sdxl',
123
  'John6666/autismmix-sdxl-autismmix-pony-sdxl',
@@ -127,13 +144,15 @@ LOAD_DIFFUSERS_FORMAT_MODEL = [
127
  'John6666/duchaiten-pony-real-v11fix-sdxl',
128
  'John6666/duchaiten-pony-real-v20-sdxl',
129
  'John6666/duchaiten-pony-xl-no-score-v70-sdxl',
130
- 'Spestly/OdysseyXL-3.0',
131
- 'Spestly/OdysseyXL-4.0',
132
  'KBlueLeaf/Kohaku-XL-Zeta',
133
  'cagliostrolab/animagine-xl-3.1',
 
134
  'yodayo-ai/kivotos-xl-2.0',
135
  'yodayo-ai/holodayo-xl-2.1',
136
  'yodayo-ai/clandestine-xl-1.0',
 
 
 
137
  'digiplay/majicMIX_sombre_v2',
138
  'digiplay/majicMIX_realistic_v6',
139
  'digiplay/majicMIX_realistic_v7',
@@ -159,9 +178,9 @@ LOAD_DIFFUSERS_FORMAT_MODEL = [
159
  'GraydientPlatformAPI/realcartoon3d-17',
160
  'GraydientPlatformAPI/realcartoon-pixar11',
161
  'GraydientPlatformAPI/realcartoon-real17',
162
- 'nitrosocke/Ghibli-Diffusion',
163
  ]
164
 
 
165
  DIFFUSERS_FORMAT_LORAS = [
166
  "nerijs/animation2k-flux",
167
  "XLabs-AI/flux-RealismLora",
@@ -183,8 +202,11 @@ DIRECTORY_VAES = 'vaes'
183
  DIRECTORY_EMBEDS = 'embedings'
184
  DIRECTORY_UPSCALERS = 'upscalers'
185
 
186
- CACHE_HF = "/home/user/.cache/huggingface/hub/"
187
  STORAGE_ROOT = "/home/user/"
 
 
 
 
188
 
189
  TASK_STABLEPY = {
190
  'txt2img': 'txt2img',
@@ -226,6 +248,7 @@ UPSCALER_DICT_GUI = {
226
  # "realesr-general-x4v3": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-general-x4v3.pth",
227
  # "realesr-general-wdn-x4v3": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-general-wdn-x4v3.pth",
228
  "4x-UltraSharp": "https://huggingface.co/Shandypur/ESRGAN-4x-UltraSharp/resolve/main/4x-UltraSharp.pth",
 
229
  "4x_foolhardy_Remacri": "https://huggingface.co/FacehugmanIII/4x_foolhardy_Remacri/resolve/main/4x_foolhardy_Remacri.pth",
230
  "Remacri4xExtraSmoother": "https://huggingface.co/hollowstrawberry/upscalers-backup/resolve/main/ESRGAN/Remacri%204x%20ExtraSmoother.pth",
231
  "AnimeSharp4x": "https://huggingface.co/hollowstrawberry/upscalers-backup/resolve/main/ESRGAN/AnimeSharp%204x.pth",
@@ -359,9 +382,11 @@ SUBTITLE_GUI = (
359
  " to perform different tasks in image generation."
360
  )
361
 
 
 
362
  HELP_GUI = (
363
- """### Help:
364
- - 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'.
365
  - 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'.
366
  - For better results with Pony Diffusion, try using sampler DPM++ 1s or DPM2 with Compel or Classic prompt weights.
367
  """
@@ -485,7 +510,7 @@ EXAMPLES_GUI = [
485
  20,
486
  4.0,
487
  -1,
488
- "loras/Coloring_book_-_LineArt.safetensors",
489
  1.0,
490
  "DPM++ 2M SDE",
491
  1024,
@@ -580,6 +605,7 @@ EXAMPLES_GUI = [
580
  RESOURCES = (
581
  """### Resources
582
  - John6666's space has some great features you might find helpful [link](https://huggingface.co/spaces/John6666/DiffuseCraftMod).
583
- - You can also try the image generator in Colab’s free tier, which provides free GPU [link](https://github.com/R3gm/SD_diffusers_interactive).
 
584
  """
585
- )
 
9
  IP_ADAPTERS_SDXL,
10
  )
11
 
12
+ IS_ZERO_GPU = bool(os.getenv("SPACES_ZERO_GPU"))
13
+
14
  # - **Download Models**
15
  DOWNLOAD_MODEL = "https://huggingface.co/TechnoByte/MilkyWonderland/resolve/main/milkyWonderland_v40.safetensors"
16
 
 
25
  'Laxhar/noobai-XL-1.1',
26
  'Laxhar/noobai-XL-Vpred-1.0',
27
  'black-forest-labs/FLUX.1-dev',
28
+ 'black-forest-labs/FLUX.1-Krea-dev',
29
  'John6666/blue-pencil-flux1-v021-fp8-flux',
30
  'John6666/wai-ani-flux-v10forfp8-fp8-flux',
31
  'John6666/xe-anime-flux-v04-fp8-flux',
32
  'John6666/lyh-anime-flux-v2a1-fp8-flux',
33
  'John6666/carnival-unchained-v10-fp8-flux',
 
34
  'Freepik/flux.1-lite-8B-alpha',
35
  'shauray/FluxDev-HyperSD-merged',
36
  'mikeyandfriends/PixelWave_FLUX.1-dev_03',
 
39
  # 'ostris/OpenFLUX.1',
40
  'shuttleai/shuttle-3-diffusion',
41
  'Laxhar/noobai-XL-1.0',
 
42
  'Laxhar/noobai-XL-0.77',
43
  'John6666/noobai-xl-nai-xl-epsilonpred075version-sdxl',
44
  'Laxhar/noobai-XL-0.6',
45
  'John6666/noobai-xl-nai-xl-epsilonpred05version-sdxl',
46
  'John6666/noobai-cyberfix-v10-sdxl',
47
  'John6666/noobaiiter-xl-vpred-v075-sdxl',
48
+ 'John6666/ripplemix-noob-vpred10-illustrious01-v14-sdxl',
49
+ 'John6666/sigmaih-15-sdxl',
 
 
50
  'John6666/ntr-mix-illustrious-xl-noob-xl-xi-sdxl',
51
  'John6666/ntr-mix-illustrious-xl-noob-xl-xii-sdxl',
52
  'John6666/ntr-mix-illustrious-xl-noob-xl-xiii-sdxl',
53
  'John6666/mistoon-anime-v10illustrious-sdxl',
54
+ 'John6666/hassaku-xl-illustrious-v22-sdxl',
 
55
  'John6666/haruki-mix-illustrious-v10-sdxl',
56
  'John6666/noobreal-v10-sdxl',
57
  'John6666/complicated-noobai-merge-vprediction-sdxl',
 
62
  'Laxhar/noobai-XL-Vpred-0.65',
63
  'Laxhar/noobai-XL-Vpred-0.6',
64
  'John6666/cat-tower-noobai-xl-checkpoint-v14vpred-sdxl',
65
+ 'John6666/cat-tower-noobai-xl-checkpoint-v15vpred-sdxl',
66
  'John6666/noobai-xl-nai-xl-vpred05version-sdxl',
67
  'John6666/noobai-fusion2-vpred-itercomp-v1-sdxl',
68
  'John6666/noobai-xl-nai-xl-vpredtestversion-sdxl',
 
73
  'John6666/obsession-illustriousxl-v21-sdxl',
74
  'John6666/obsession-illustriousxl-v30-sdxl',
75
  'John6666/obsession-illustriousxl-v31-sdxl',
76
+ 'John6666/one-obsession-13-sdxl',
77
+ 'John6666/one-obsession-14-24d-sdxl',
78
+ 'John6666/one-obsession-15-noobai-sdxl',
79
+ 'John6666/one-obsession-v16-noobai-sdxl',
80
+ 'John6666/prefect-illustrious-xl-v3-sdxl',
81
  'John6666/wai-nsfw-illustrious-v70-sdxl',
82
+ 'John6666/wai-nsfw-illustrious-sdxl-v140-sdxl',
83
  'John6666/illustrious-pony-mix-v3-sdxl',
84
+ 'John6666/nova-anime-xl-il-v90-sdxl',
85
+ 'John6666/nova-anime-xl-il-v110-sdxl',
86
+ 'John6666/nova-orange-xl-re-v10-sdxl',
87
+ 'John6666/nova-orange-xl-v110-sdxl',
88
+ 'John6666/nova-orange-xl-re-v20-sdxl',
89
+ 'John6666/nova-unreal-xl-v60-sdxl',
90
+ 'John6666/nova-unreal-xl-v70-sdxl',
91
+ 'John6666/nova-unreal-xl-v80-sdxl',
92
+ 'John6666/nova-cartoon-xl-v40-sdxl',
93
  'John6666/silvermoon-mix03-illustrious-v10-sdxl',
94
  'eienmojiki/Anything-XL',
95
  'eienmojiki/Starry-XL-v5.2',
96
+ 'votepurchase/plantMilkModelSuite_walnut',
97
  'John6666/meinaxl-v2-sdxl',
98
  'Eugeoter/artiwaifu-diffusion-2.0',
99
  'comin/IterComp',
 
 
100
  'John6666/epicrealism-xl-v8kiss-sdxl',
101
+ 'John6666/epicrealism-xl-v10kiss2-sdxl',
102
+ 'John6666/epicrealism-xl-vxiabeast-sdxl',
103
+ 'John6666/epicrealism-xl-vxvii-crystal-clear-realism-sdxl',
104
  'misri/zavychromaxl_v80',
105
  'SG161222/RealVisXL_V4.0',
106
  'SG161222/RealVisXL_V5.0',
 
116
  'John6666/ebara-mfcg-pony-mix-v12-sdxl',
117
  'John6666/t-ponynai3-v51-sdxl',
118
  'John6666/t-ponynai3-v65-sdxl',
119
+ 'John6666/t-ponynai3-v7-sdxl',
120
  'John6666/prefect-pony-xl-v3-sdxl',
121
  'John6666/prefect-pony-xl-v4-sdxl',
122
+ 'John6666/prefect-pony-xl-v50-sdxl',
123
  'John6666/mala-anime-mix-nsfw-pony-xl-v5-sdxl',
124
  'John6666/wai-ani-nsfw-ponyxl-v10-sdxl',
125
  'John6666/wai-real-mix-v11-sdxl',
 
127
  'John6666/wai-c-v6-sdxl',
128
  'John6666/iniverse-mix-xl-sfwnsfw-pony-guofeng-v43-sdxl',
129
  'John6666/sifw-annihilation-xl-v2-sdxl',
130
+ 'John6666/sifw-annihilation-xl-v305illustrious-beta-sdxl',
131
  'John6666/photo-realistic-pony-v5-sdxl',
132
  'John6666/pony-realism-v21main-sdxl',
133
  'John6666/pony-realism-v22main-sdxl',
134
+ 'John6666/pony-realism-v23-ultra-sdxl',
 
135
  'John6666/cyberrealistic-pony-v65-sdxl',
136
  'John6666/cyberrealistic-pony-v7-sdxl',
137
+ 'John6666/cyberrealistic-pony-v127-alternative-sdxl',
138
  'GraydientPlatformAPI/realcartoon-pony-diffusion',
139
  'John6666/nova-anime-xl-pony-v5-sdxl',
140
  'John6666/autismmix-sdxl-autismmix-pony-sdxl',
 
144
  'John6666/duchaiten-pony-real-v11fix-sdxl',
145
  'John6666/duchaiten-pony-real-v20-sdxl',
146
  'John6666/duchaiten-pony-xl-no-score-v70-sdxl',
 
 
147
  'KBlueLeaf/Kohaku-XL-Zeta',
148
  'cagliostrolab/animagine-xl-3.1',
149
+ 'cagliostrolab/animagine-xl-4.0',
150
  'yodayo-ai/kivotos-xl-2.0',
151
  'yodayo-ai/holodayo-xl-2.1',
152
  'yodayo-ai/clandestine-xl-1.0',
153
+ 'https://huggingface.co/chemwolf/Karmix-XL-v0/resolve/main/Karmix-XL-v0.safetensors?download=true',
154
+ 'https://civitai.com/api/download/models/128713?type=Model&format=SafeTensor&size=pruned&fp=fp16',
155
+ 'https://civitai.com/models/30240?modelVersionId=125771',
156
  'digiplay/majicMIX_sombre_v2',
157
  'digiplay/majicMIX_realistic_v6',
158
  'digiplay/majicMIX_realistic_v7',
 
178
  'GraydientPlatformAPI/realcartoon3d-17',
179
  'GraydientPlatformAPI/realcartoon-pixar11',
180
  'GraydientPlatformAPI/realcartoon-real17',
 
181
  ]
182
 
183
+
184
  DIFFUSERS_FORMAT_LORAS = [
185
  "nerijs/animation2k-flux",
186
  "XLabs-AI/flux-RealismLora",
 
202
  DIRECTORY_EMBEDS = 'embedings'
203
  DIRECTORY_UPSCALERS = 'upscalers'
204
 
 
205
  STORAGE_ROOT = "/home/user/"
206
+ CACHE_HF_ROOT = os.path.expanduser("~/.cache/huggingface")
207
+ CACHE_HF = os.path.join(CACHE_HF_ROOT, "hub")
208
+ if IS_ZERO_GPU:
209
+ os.environ["HF_HOME"] = CACHE_HF
210
 
211
  TASK_STABLEPY = {
212
  'txt2img': 'txt2img',
 
248
  # "realesr-general-x4v3": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-general-x4v3.pth",
249
  # "realesr-general-wdn-x4v3": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-general-wdn-x4v3.pth",
250
  "4x-UltraSharp": "https://huggingface.co/Shandypur/ESRGAN-4x-UltraSharp/resolve/main/4x-UltraSharp.pth",
251
+ "Real-ESRGAN-Anime-finetuning": "https://huggingface.co/danhtran2mind/Real-ESRGAN-Anime-finetuning/resolve/main/Real-ESRGAN-Anime-finetuning.pth",
252
  "4x_foolhardy_Remacri": "https://huggingface.co/FacehugmanIII/4x_foolhardy_Remacri/resolve/main/4x_foolhardy_Remacri.pth",
253
  "Remacri4xExtraSmoother": "https://huggingface.co/hollowstrawberry/upscalers-backup/resolve/main/ESRGAN/Remacri%204x%20ExtraSmoother.pth",
254
  "AnimeSharp4x": "https://huggingface.co/hollowstrawberry/upscalers-backup/resolve/main/ESRGAN/AnimeSharp%204x.pth",
 
382
  " to perform different tasks in image generation."
383
  )
384
 
385
+ 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'."
386
+
387
  HELP_GUI = (
388
+ f"""### Help:
389
+ {msg_zero}
390
  - 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'.
391
  - For better results with Pony Diffusion, try using sampler DPM++ 1s or DPM2 with Compel or Classic prompt weights.
392
  """
 
510
  20,
511
  4.0,
512
  -1,
513
+ ("loras/Coloring_book_-_LineArt.safetensors" if os.path.exists("loras/Coloring_book_-_LineArt.safetensors") else "None"),
514
  1.0,
515
  "DPM++ 2M SDE",
516
  1024,
 
605
  RESOURCES = (
606
  """### Resources
607
  - John6666's space has some great features you might find helpful [link](https://huggingface.co/spaces/John6666/DiffuseCraftMod).
608
+ - Try the image generator in Colab’s free tier, which provides free GPU [link](https://github.com/R3gm/SD_diffusers_interactive).
609
+ - `DiffuseCraft` in Colab:[link](https://github.com/R3gm/DiffuseCraft?tab=readme-ov-file#diffusecraft).
610
  """
611
+ )
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=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")
 
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")
packages.txt CHANGED
@@ -1,3 +1,3 @@
1
  git-lfs
2
- aria2 -y
3
  ffmpeg
 
1
  git-lfs
2
+ aria2
3
  ffmpeg
pre-requirements.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ pip>=23.0.0
requirements.txt CHANGED
@@ -1,7 +1,13 @@
1
  stablepy==0.6.2
2
- torch==2.2.0
 
3
  gdown
4
  opencv-python
5
  unidecode
6
  pydantic==2.10.6
7
- huggingface_hub==0.29.3
 
 
 
 
 
 
1
  stablepy==0.6.2
2
+ torch==2.5.1
3
+ diffusers
4
  gdown
5
  opencv-python
6
  unidecode
7
  pydantic==2.10.6
8
+ huggingface_hub
9
+ hf_transfer
10
+ hf_xet
11
+ spaces
12
+ gradio==5.44.1
13
+ matplotlib-inline
utils.py CHANGED
@@ -9,6 +9,7 @@ from constants import (
9
  DIRECTORY_LORAS,
10
  DIRECTORY_MODELS,
11
  DIFFUSECRAFT_CHECKPOINT_NAME,
 
12
  CACHE_HF,
13
  STORAGE_ROOT,
14
  )
@@ -28,6 +29,7 @@ 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
 
@@ -66,7 +68,8 @@ class ModelInformation:
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)
@@ -76,118 +79,175 @@ class ModelInformation:
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
 
@@ -216,14 +276,15 @@ def extract_parameters(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:")
@@ -306,7 +367,8 @@ def get_model_type(repo_id: str):
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
@@ -433,9 +495,9 @@ def get_folder_size_gb(folder_path):
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
@@ -455,6 +517,21 @@ def delete_model(removal_candidate):
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))
 
9
  DIRECTORY_LORAS,
10
  DIRECTORY_MODELS,
11
  DIFFUSECRAFT_CHECKPOINT_NAME,
12
+ CACHE_HF_ROOT,
13
  CACHE_HF,
14
  STORAGE_ROOT,
15
  )
 
29
  import shutil
30
  import subprocess
31
 
32
+ IS_ZERO_GPU = bool(os.getenv("SPACES_ZERO_GPU"))
33
  USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:127.0) Gecko/20100101 Firefox/127.0'
34
 
35
 
 
68
  )
69
  self.filename_url = self.filename_url if self.filename_url else ""
70
  self.description = json_data.get("description", "")
71
+ if self.description is None:
72
+ self.description = ""
73
  self.model_name = json_data.get("model", {}).get("name", "")
74
  self.model_type = json_data.get("model", {}).get("type", "")
75
  self.nsfw = json_data.get("model", {}).get("nsfw", False)
 
79
  self.original_json = copy.deepcopy(json_data)
80
 
81
 
82
+ def get_civit_params(url):
83
+ try:
84
+ json_data = request_json_data(url)
85
+ mdc = ModelInformation(json_data)
86
+ if mdc.download_url and mdc.filename_url:
87
+ return mdc.download_url, mdc.filename_url, mdc.model_url
88
+ else:
89
+ ValueError("Invalid Civitai model URL")
90
+ except Exception as e:
91
+ print(f"Error retrieving Civitai metadata: {e} — fallback to direct download")
92
+ return url, None, None
93
 
94
 
95
+ def civ_redirect_down(url, dir_, civitai_api_key, romanize, alternative_name):
96
+ filename_base = filename = None
 
97
 
98
+ if alternative_name:
99
+ output_path = os.path.join(dir_, alternative_name)
100
+ if os.path.exists(output_path):
101
+ return output_path, alternative_name
 
 
 
 
 
 
 
102
 
103
+ # Follow the redirect to get the actual download URL
104
+ curl_command = (
105
+ f'curl -L -sI --connect-timeout 5 --max-time 5 '
106
+ f'-H "Content-Type: application/json" '
107
+ f'-H "Authorization: Bearer {civitai_api_key}" "{url}"'
108
+ )
109
 
110
+ headers = os.popen(curl_command).read()
 
 
 
111
 
112
+ # Look for the redirected "Location" URL
113
+ location_match = re.search(r'location: (.+)', headers, re.IGNORECASE)
114
 
115
+ if location_match:
116
+ redirect_url = location_match.group(1).strip()
117
 
118
+ # Extract the filename from the redirect URL's "Content-Disposition"
119
+ filename_match = re.search(r'filename%3D%22(.+?)%22', redirect_url)
120
+ if filename_match:
121
+ encoded_filename = filename_match.group(1)
122
+ # Decode the URL-encoded filename
123
+ decoded_filename = urllib.parse.unquote(encoded_filename)
 
 
 
 
 
 
 
 
 
124
 
125
+ filename = unidecode(decoded_filename) if romanize else decoded_filename
126
+ # print(f"Filename redirect: {filename}")
127
 
128
+ filename_base = alternative_name if alternative_name else filename
129
+ if not filename_base:
130
+ return None, None
131
+ elif os.path.exists(os.path.join(dir_, filename_base)):
132
+ return os.path.join(dir_, filename_base), filename_base
133
 
134
+ aria2_command = (
135
+ f'aria2c --console-log-level=error --summary-interval=10 -c -x 16 '
136
+ f'-k 1M -s 16 -d "{dir_}" -o "{filename_base}" "{redirect_url}"'
137
+ )
138
+ r_code = os.system(aria2_command) # noqa
139
+
140
+ # if r_code != 0:
141
+ # raise RuntimeError(f"Failed to download file: {filename_base}. Error code: {r_code}")
142
+
143
+ output_path = os.path.join(dir_, filename_base)
144
+ if not os.path.exists(output_path):
145
+ return None, filename_base
146
+
147
+ return output_path, filename_base
148
+
149
+
150
+ def civ_api_down(url, dir_, civitai_api_key, civ_filename):
151
+ """
152
+ This method is susceptible to being blocked because it generates a lot of temp redirect links with aria2c.
153
+ If an API key limit is reached, generating a new API key and using it can fix the issue.
154
+ """
155
+ output_path = None
156
+
157
+ url_dl = url + f"?token={civitai_api_key}"
158
+ if not civ_filename:
159
+ aria2_command = f'aria2c -c -x 1 -s 1 -d "{dir_}" "{url_dl}"'
160
  os.system(aria2_command)
161
+ else:
162
+ output_path = os.path.join(dir_, civ_filename)
163
+ if not os.path.exists(output_path):
164
+ aria2_command = (
165
+ f'aria2c --console-log-level=error --summary-interval=10 -c -x 16 '
166
+ f'-k 1M -s 16 -d "{dir_}" -o "{civ_filename}" "{url_dl}"'
167
+ )
168
+ os.system(aria2_command)
169
+
170
+ return output_path
171
+
172
+
173
+ def drive_down(url, dir_):
174
+ import gdown
175
+
176
+ output_path = None
177
 
178
+ drive_id, _ = gdown.parse_url.parse_url(url, warning=False)
179
+ dir_files = os.listdir(dir_)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
 
181
+ for dfile in dir_files:
182
+ if drive_id in dfile:
183
+ output_path = os.path.join(dir_, dfile)
184
+ break
185
+
186
+ if not output_path:
187
+ original_path = gdown.download(url, f"{dir_}/", fuzzy=True)
188
+
189
+ dir_name, base_name = os.path.split(original_path)
190
+ name, ext = base_name.rsplit(".", 1)
191
+ new_name = f"{name}_{drive_id}.{ext}"
192
+ output_path = os.path.join(dir_name, new_name)
193
+
194
+ os.rename(original_path, output_path)
195
+
196
+ return output_path
197
+
198
+
199
+ def hf_down(url, dir_, hf_token, romanize):
200
+ url = url.replace("?download=true", "")
201
+ # url = urllib.parse.quote(url, safe=':/') # fix encoding
202
+
203
+ filename = unidecode(url.split('/')[-1]) if romanize else url.split('/')[-1]
204
+ output_path = os.path.join(dir_, filename)
205
+
206
+ if os.path.exists(output_path):
207
+ return output_path
208
+
209
+ if "/blob/" in url:
210
+ url = url.replace("/blob/", "/resolve/")
211
+
212
+ if hf_token:
213
+ user_header = f'"Authorization: Bearer {hf_token}"'
214
+ os.system(f"aria2c --console-log-level=error --summary-interval=10 --header={user_header} -c -x 16 -k 1M -s 16 {url} -d {dir_} -o {filename}")
215
+ else:
216
+ os.system(f"aria2c --optimize-concurrent-downloads --console-log-level=error --summary-interval=10 -c -x 16 -k 1M -s 16 {url} -d {dir_} -o {filename}")
217
+
218
+ return output_path
219
+
220
+
221
+ def download_things(directory, url, hf_token="", civitai_api_key="", romanize=False):
222
+ url = url.strip()
223
+ downloaded_file_path = None
224
+
225
+ if "drive.google.com" in url:
226
+ downloaded_file_path = drive_down(url, directory)
227
+ elif "huggingface.co" in url:
228
+ downloaded_file_path = hf_down(url, directory, hf_token, romanize)
229
+ elif "civitai.com" in url:
230
+ if not civitai_api_key:
231
+ msg = "You need an API key to download Civitai models."
232
+ print(f"\033[91m{msg}\033[0m")
233
+ gr.Warning(msg)
234
+ return None
235
+
236
+ url, civ_filename, civ_page = get_civit_params(url)
237
+ if civ_page and not IS_ZERO_GPU:
238
+ print(f"\033[92mCivitai model: {civ_filename} [page: {civ_page}]\033[0m")
239
+
240
+ downloaded_file_path, civ_filename = civ_redirect_down(url, directory, civitai_api_key, romanize, civ_filename)
241
+
242
+ if not downloaded_file_path:
243
+ msg = (
244
+ "Download failed.\n"
245
+ "If this is due to an API limit, generating a new API key may resolve the issue.\n"
246
+ "Attempting to download using the old method..."
247
+ )
248
+ print(msg)
249
+ gr.Warning(msg)
250
+ downloaded_file_path = civ_api_down(url, directory, civitai_api_key, civ_filename)
251
  else:
252
  os.system(f"aria2c --console-log-level=error --summary-interval=10 -c -x 16 -k 1M -s 16 -d {directory} {url}")
253
 
 
276
  if "Steps:" in input_string:
277
  input_string = input_string.replace("Steps:", "Negative prompt: Steps:")
278
  else:
279
+ msg = "Generation data is invalid."
280
+ gr.Warning(msg)
281
+ print(msg)
282
  parameters["prompt"] = input_string
283
  return parameters
284
 
285
  parm = input_string.split("Negative prompt:")
286
  parameters["prompt"] = parm[0].strip()
287
  if "Steps:" not in parm[1]:
 
288
  parameters["neg_prompt"] = parm[1].strip()
289
  return parameters
290
  parm = parm[1].split("Steps:")
 
367
  model = api.model_info(repo_id=repo_id, timeout=5.0)
368
  tags = model.tags
369
  for tag in tags:
370
+ if tag in MODEL_TYPE_CLASS.keys():
371
+ return MODEL_TYPE_CLASS.get(tag, default)
372
 
373
  except Exception:
374
  return default
 
495
  return total_size_gb
496
 
497
 
498
+ def get_used_storage_gb(path_storage=STORAGE_ROOT):
499
  try:
500
+ used_gb = get_folder_size_gb(path_storage)
501
  print(f"Used Storage: {used_gb:.2f} GB")
502
  except Exception as e:
503
  used_gb = 999
 
517
  shutil.rmtree(diffusers_model)
518
 
519
 
520
+ def clear_hf_cache():
521
+ """
522
+ Clears the entire Hugging Face cache at ~/.cache/huggingface.
523
+ Hugging Face will re-download models as needed later.
524
+ """
525
+ try:
526
+ if os.path.exists(CACHE_HF_ROOT):
527
+ shutil.rmtree(CACHE_HF_ROOT, ignore_errors=True)
528
+ print(f"Hugging Face cache cleared: {CACHE_HF_ROOT}")
529
+ else:
530
+ print(f"No Hugging Face cache found at: {CACHE_HF_ROOT}")
531
+ except Exception as e:
532
+ print(f"Error clearing Hugging Face cache: {e}")
533
+
534
+
535
  def progress_step_bar(step, total):
536
  # Calculate the percentage for the progress bar width
537
  percentage = min(100, ((step / total) * 100))