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