Upload sd-webui-weight-helper-main using SD-Hub
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- sd-webui-weight-helper-main/.flake8 +2 -0
- sd-webui-weight-helper-main/.github/FUNDING.yml +2 -0
- sd-webui-weight-helper-main/.github/ISSUE_TEMPLATE/bug_report.yml +67 -0
- sd-webui-weight-helper-main/.gitignore +164 -0
- sd-webui-weight-helper-main/.prettierrc.json +7 -0
- sd-webui-weight-helper-main/LICENSE +21 -0
- sd-webui-weight-helper-main/README.md +69 -0
- sd-webui-weight-helper-main/README_JP.md +69 -0
- sd-webui-weight-helper-main/backup_before_patch/scripts/analyzer.py +189 -0
- sd-webui-weight-helper-main/backup_before_patch/scripts/api.py +145 -0
- sd-webui-weight-helper-main/backup_before_patch/scripts/const.py +11 -0
- sd-webui-weight-helper-main/backup_before_patch/scripts/env.py +29 -0
- sd-webui-weight-helper-main/backup_before_patch/scripts/utils.py +58 -0
- sd-webui-weight-helper-main/backup_before_patch/scripts/weight_helper.py +82 -0
- sd-webui-weight-helper-main/esbuild.config.mjs +16 -0
- sd-webui-weight-helper-main/eslint.config.mjs +19 -0
- sd-webui-weight-helper-main/javascript/weight_helper.js +188 -0
- sd-webui-weight-helper-main/javascript/weight_helper.js.map +0 -0
- sd-webui-weight-helper-main/package.json +32 -0
- sd-webui-weight-helper-main/scripts/__pycache__/weight_helper.cpython-310.pyc +0 -0
- sd-webui-weight-helper-main/scripts/__pycache__/weight_helper.cpython-313.pyc +0 -0
- sd-webui-weight-helper-main/scripts/__pycache__/wh_analyzer.cpython-310.pyc +0 -0
- sd-webui-weight-helper-main/scripts/__pycache__/wh_analyzer.cpython-313.pyc +0 -0
- sd-webui-weight-helper-main/scripts/__pycache__/wh_api.cpython-310.pyc +0 -0
- sd-webui-weight-helper-main/scripts/__pycache__/wh_api.cpython-313.pyc +0 -0
- sd-webui-weight-helper-main/scripts/__pycache__/wh_const.cpython-310.pyc +0 -0
- sd-webui-weight-helper-main/scripts/__pycache__/wh_const.cpython-313.pyc +0 -0
- sd-webui-weight-helper-main/scripts/__pycache__/wh_env.cpython-310.pyc +0 -0
- sd-webui-weight-helper-main/scripts/__pycache__/wh_env.cpython-313.pyc +0 -0
- sd-webui-weight-helper-main/scripts/__pycache__/wh_utils.cpython-310.pyc +0 -0
- sd-webui-weight-helper-main/scripts/__pycache__/wh_utils.cpython-313.pyc +0 -0
- sd-webui-weight-helper-main/scripts/weight_helper.py +91 -0
- sd-webui-weight-helper-main/scripts/wh_analyzer.py +196 -0
- sd-webui-weight-helper-main/scripts/wh_api.py +154 -0
- sd-webui-weight-helper-main/scripts/wh_const.py +11 -0
- sd-webui-weight-helper-main/scripts/wh_env.py +36 -0
- sd-webui-weight-helper-main/scripts/wh_utils.py +65 -0
- sd-webui-weight-helper-main/src/components/sections/common-section.ts +139 -0
- sd-webui-weight-helper-main/src/components/sections/header-section.ts +129 -0
- sd-webui-weight-helper-main/src/components/sections/lbw-section.ts +42 -0
- sd-webui-weight-helper-main/src/components/sections/lora-settings-section.ts +143 -0
- sd-webui-weight-helper-main/src/components/sections/metadata-section.ts +84 -0
- sd-webui-weight-helper-main/src/components/sections/preview-section.ts +167 -0
- sd-webui-weight-helper-main/src/components/ui-template.ts +309 -0
- sd-webui-weight-helper-main/src/index.ts +61 -0
- sd-webui-weight-helper-main/src/shared/constants/common-const.ts +172 -0
- sd-webui-weight-helper-main/src/shared/hooks/use-global-state.ts +11 -0
- sd-webui-weight-helper-main/src/shared/manager/api-manager.ts +50 -0
- sd-webui-weight-helper-main/src/shared/manager/cache-manager.ts +62 -0
- sd-webui-weight-helper-main/src/shared/manager/config-manager.ts +167 -0
sd-webui-weight-helper-main/.flake8
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[flake8]
|
| 2 |
+
max-line-length = 160
|
sd-webui-weight-helper-main/.github/FUNDING.yml
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
ko_fi: nihedon
|
| 2 |
+
buy_me_a_coffee: nihedon
|
sd-webui-weight-helper-main/.github/ISSUE_TEMPLATE/bug_report.yml
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: Bug Report
|
| 2 |
+
description: Report a problem or unexpected behavior in the application.
|
| 3 |
+
title: "[Bug] Brief description of the issue"
|
| 4 |
+
labels: ["bug"]
|
| 5 |
+
body:
|
| 6 |
+
- type: markdown
|
| 7 |
+
attributes:
|
| 8 |
+
value: |
|
| 9 |
+
Please fill out the following form to help us reproduce and resolve the issue.
|
| 10 |
+
|
| 11 |
+
- type: checkboxes
|
| 12 |
+
id: environment
|
| 13 |
+
attributes:
|
| 14 |
+
label: Operating Environment
|
| 15 |
+
description: Please select the environment you are using.
|
| 16 |
+
options:
|
| 17 |
+
- label: Windows
|
| 18 |
+
- label: macOS
|
| 19 |
+
- label: Other (e.g., virtual environment)
|
| 20 |
+
validations:
|
| 21 |
+
required: true
|
| 22 |
+
|
| 23 |
+
- type: input
|
| 24 |
+
id: browser
|
| 25 |
+
attributes:
|
| 26 |
+
label: Browser
|
| 27 |
+
description: Please specify the browser you are using (e.g., Chrome, Firefox).
|
| 28 |
+
validations:
|
| 29 |
+
required: true
|
| 30 |
+
|
| 31 |
+
- type: checkboxes
|
| 32 |
+
id: webui
|
| 33 |
+
attributes:
|
| 34 |
+
label: WebUI
|
| 35 |
+
description: Please select the WebUI(s) you are using.
|
| 36 |
+
options:
|
| 37 |
+
- label: A1111
|
| 38 |
+
- label: Forge
|
| 39 |
+
- label: ReForge
|
| 40 |
+
- label: SD-Next
|
| 41 |
+
- label: Other
|
| 42 |
+
validations:
|
| 43 |
+
required: true
|
| 44 |
+
|
| 45 |
+
- type: textarea
|
| 46 |
+
id: console_log
|
| 47 |
+
attributes:
|
| 48 |
+
label: Console Log
|
| 49 |
+
description: Paste any relevant console logs here.
|
| 50 |
+
validations:
|
| 51 |
+
required: false
|
| 52 |
+
|
| 53 |
+
- type: textarea
|
| 54 |
+
id: browser_log
|
| 55 |
+
attributes:
|
| 56 |
+
label: Browser Log
|
| 57 |
+
description: Paste any relevant browser logs here.
|
| 58 |
+
validations:
|
| 59 |
+
required: false
|
| 60 |
+
|
| 61 |
+
- type: textarea
|
| 62 |
+
id: description
|
| 63 |
+
attributes:
|
| 64 |
+
label: Description of the Issue
|
| 65 |
+
description: Please describe the issue you encountered in detail.
|
| 66 |
+
validations:
|
| 67 |
+
required: true
|
sd-webui-weight-helper-main/.gitignore
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Byte-compiled / optimized / DLL files
|
| 2 |
+
__pycache__/
|
| 3 |
+
*.py[cod]
|
| 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 |
+
# poetry
|
| 98 |
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
| 99 |
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
| 100 |
+
# commonly ignored for libraries.
|
| 101 |
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
| 102 |
+
#poetry.lock
|
| 103 |
+
|
| 104 |
+
# pdm
|
| 105 |
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
| 106 |
+
#pdm.lock
|
| 107 |
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
| 108 |
+
# in version control.
|
| 109 |
+
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
| 110 |
+
.pdm.toml
|
| 111 |
+
.pdm-python
|
| 112 |
+
.pdm-build/
|
| 113 |
+
|
| 114 |
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
| 115 |
+
__pypackages__/
|
| 116 |
+
|
| 117 |
+
# Celery stuff
|
| 118 |
+
celerybeat-schedule
|
| 119 |
+
celerybeat.pid
|
| 120 |
+
|
| 121 |
+
# SageMath parsed files
|
| 122 |
+
*.sage.py
|
| 123 |
+
|
| 124 |
+
# Environments
|
| 125 |
+
.env
|
| 126 |
+
.venv
|
| 127 |
+
env/
|
| 128 |
+
venv/
|
| 129 |
+
ENV/
|
| 130 |
+
env.bak/
|
| 131 |
+
venv.bak/
|
| 132 |
+
|
| 133 |
+
# Spyder project settings
|
| 134 |
+
.spyderproject
|
| 135 |
+
.spyproject
|
| 136 |
+
|
| 137 |
+
# Rope project settings
|
| 138 |
+
.ropeproject
|
| 139 |
+
|
| 140 |
+
# mkdocs documentation
|
| 141 |
+
/site
|
| 142 |
+
|
| 143 |
+
# mypy
|
| 144 |
+
.mypy_cache/
|
| 145 |
+
.dmypy.json
|
| 146 |
+
dmypy.json
|
| 147 |
+
|
| 148 |
+
# Pyre type checker
|
| 149 |
+
.pyre/
|
| 150 |
+
|
| 151 |
+
# pytype static type analyzer
|
| 152 |
+
.pytype/
|
| 153 |
+
|
| 154 |
+
# Cython debug symbols
|
| 155 |
+
cython_debug/
|
| 156 |
+
|
| 157 |
+
# PyCharm
|
| 158 |
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
| 159 |
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
| 160 |
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
| 161 |
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
| 162 |
+
#.idea/
|
| 163 |
+
node_modules/
|
| 164 |
+
package-lock.json
|
sd-webui-weight-helper-main/.prettierrc.json
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"semi": true,
|
| 3 |
+
"singleQuote": true,
|
| 4 |
+
"tabWidth": 4,
|
| 5 |
+
"trailingComma": "all",
|
| 6 |
+
"printWidth": 160
|
| 7 |
+
}
|
sd-webui-weight-helper-main/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2023 t.nihei
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in
|
| 13 |
+
all copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
| 21 |
+
THE SOFTWARE.
|
sd-webui-weight-helper-main/README.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[English](README.md) | [日本語](README_JP.md)
|
| 2 |
+
|
| 3 |
+
<img src="https://github.com/nihedon/sd-webui-weight-helper/assets/66118290/08f8d818-ac5d-4125-b2aa-45c302f626f8" height="600px">
|
| 4 |
+
|
| 5 |
+
# Weight Helper Extension
|
| 6 |
+
|
| 7 |
+
## Overview
|
| 8 |
+
|
| 9 |
+
**Weight Helper** is an extension that allows you to visually adjust the weights of Lora and Lyco with mouse operations.<br>
|
| 10 |
+
You can adjust the magnification of each weight block through the context menu.<br>
|
| 11 |
+
Note: The LoRA Block Weight extension is required to use this extension.
|
| 12 |
+
|
| 13 |
+
## Installation
|
| 14 |
+
|
| 15 |
+
1. Open the [Extensions] tab in Stable Diffusion Web UI.
|
| 16 |
+
2. Select [Install from URL].
|
| 17 |
+
3. Enter the following URL and execute the installation.
|
| 18 |
+
```
|
| 19 |
+
https://github.com/nihedon/sd-webui-weight-helper.git
|
| 20 |
+
```
|
| 21 |
+
|
| 22 |
+
## Usage
|
| 23 |
+
|
| 24 |
+
1. Right-click on a Lora or Lyco tag to open the context menu.
|
| 25 |
+
- `<lora:lora_name:1.0>`
|
| 26 |
+
- `<lyco:lyco_name:1.0>`
|
| 27 |
+
2. Choose "LoRA" or "LyCORIS" according to the tag, and select "SDXL" if it's for the SDXL version.
|
| 28 |
+
3. Move the weight slider to adjust the magnification of each weight block.
|
| 29 |
+
4. UNet, Dyn, Start, and Stop will be hidden by default, but if configured, you can display them by pressing the "show more options" button.
|
| 30 |
+
5. Save your favorite weight settings by clicking the "★" icon at the top left of the context menu.
|
| 31 |
+
Important: Saved settings are stored in LocalStorage, but any unsaved history will be deleted upon refreshing the screen.
|
| 32 |
+
|
| 33 |
+
## Features
|
| 34 |
+
|
| 35 |
+
- Easy to set weight values with mouse operations.
|
| 36 |
+
- Use of preset values from Lora Block Weight is possible.
|
| 37 |
+
- You can check LoRA information and add trigger words from the icons displayed on the preview screen.
|
| 38 |
+
- Information from the readme file attached to LoRA can be displayed on the preview screen. ({loraname}.txt, {loraname}.description.txt)
|
| 39 |
+
- The SD version of LoRA is displayed based on the metadata of LoRA. (If there is metadata text from Civitai, the SD version registered with Civitai will also be displayed.)
|
| 40 |
+
|
| 41 |
+
## Known Issues
|
| 42 |
+
- The algorithm is deduced from the metadata of LoRA, but it is incomplete. Bug reports and suggestions for the correct algorithm would be appreciated.
|
| 43 |
+
|
| 44 |
+
## Configuration Options
|
| 45 |
+
|
| 46 |
+
- Scale adjustment in the context menu.
|
| 47 |
+
- Use of the `execCommand` function for text replacement (Note: execCommand is a deprecated function, but it allows for "undo" and "redo").
|
| 48 |
+
- Display of UNet, Dyn, Start, and Stop sliders.
|
| 49 |
+
- Setting of minimum, maximum, and step values for each weight slider.
|
| 50 |
+
- Detailed settings for LBW's Lora and Lyco blocks.
|
| 51 |
+
- Option to display or hide previews, and settings for preview size and position.
|
| 52 |
+
- Settings for block weight segmentation.
|
| 53 |
+
|
| 54 |
+
## Guaranteed Operating Environment
|
| 55 |
+
|
| 56 |
+
- Stable Diffusion AUTOMATIC1111
|
| 57 |
+
- Windows
|
| 58 |
+
- Google Chrome
|
| 59 |
+
|
| 60 |
+
## Acknowledgments
|
| 61 |
+
|
| 62 |
+
We would like to express our deep gratitude to **hako-mikan**, the author of **LoRA Block Weight**, for creating this extension.
|
| 63 |
+
```
|
| 64 |
+
https://github.com/hako-mikan/sd-webui-lora-block-weight
|
| 65 |
+
```
|
| 66 |
+
|
| 67 |
+
## License
|
| 68 |
+
|
| 69 |
+
This project is published under the [MIT License](LICENSE).
|
sd-webui-weight-helper-main/README_JP.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[English](README.md) | [日本語](README_JP.md)
|
| 2 |
+
|
| 3 |
+
<img src="https://github.com/nihedon/sd-webui-weight-helper/assets/66118290/08f8d818-ac5d-4125-b2aa-45c302f626f8" height="600px">
|
| 4 |
+
|
| 5 |
+
# Weight Helper 拡張機能
|
| 6 |
+
|
| 7 |
+
## 概要
|
| 8 |
+
|
| 9 |
+
**Weight Helper** はLoraやLycoのウェイトをマウス操作で視覚的に調整できる拡張機能です。<br>
|
| 10 |
+
コンテキストメニューを通じて各ウェイトブロックの倍率を調整できます。<br>
|
| 11 |
+
注:この拡張機能を利用するにはLoRA Block Weight拡張機能が必要です。
|
| 12 |
+
|
| 13 |
+
## インストール
|
| 14 |
+
|
| 15 |
+
1. Stable Diffusion Web UIの[拡張機能]タブを開く
|
| 16 |
+
2. [URLからインストール]を選択
|
| 17 |
+
3. 以下のURLを入力し、インストールを実行
|
| 18 |
+
```
|
| 19 |
+
https://github.com/nihedon/sd-webui-weight-helper.git
|
| 20 |
+
```
|
| 21 |
+
|
| 22 |
+
## 使い方
|
| 23 |
+
|
| 24 |
+
1. LoraまたはLycoのタグを右クリックしてコンテキストメニューを開く
|
| 25 |
+
- `<lora:lora_name:1.0>`
|
| 26 |
+
- `<lyco:lyco_name:1.0>`
|
| 27 |
+
2. LoRA(またはLyCORIS)に合わせて"LoRA"か"LyCORIS"を選択し、SDXLバージョンの場合は"SDXL"を選択します。
|
| 28 |
+
3. ウェイトスライダーを動かして各ウェイトブロックの倍率を調整します。
|
| 29 |
+
4. UNet、Dyn、Start、Stopは非表示となっているため、設定した場合は"show more options"ボタンを押下して表示できます。
|
| 30 |
+
5. お気に入りのウェイト設定はコンテキストメニュー左上の"★"アイコンをクリックし保存します。
|
| 31 |
+
重要:保存した場合はLocalStrageに保存されますが、保存していない履歴は画面更新時にすべて削除されます。
|
| 32 |
+
|
| 33 |
+
## 特徴
|
| 34 |
+
|
| 35 |
+
- マウス操作でウェイト値を容易に設定できます。
|
| 36 |
+
- Lora Block Weightのプリセット値の利用が可能です。
|
| 37 |
+
- プレビュー画面に表示されるアイコンからLoRA情報の確認、トリガーワードの追加ができます。
|
| 38 |
+
- LoRAに付属するreadmeファイルの情報をプレビュー画面に表示できます。({loraname}.txt, {loraname}.description.txt)
|
| 39 |
+
- LoRAのメタ情報からLoRAのSDバージョンが表示されます。(Civitaiのメタテキストが存在する場合、civitaiに登録したSDバージョンも表示します。)
|
| 40 |
+
|
| 41 |
+
## 既知の問題
|
| 42 |
+
- LoRAのメタ情報からアルゴリズムを割り出していますが不完全です。不具合報告や正しいアルゴリズムを提示していただけると助かります(_ _)
|
| 43 |
+
|
| 44 |
+
## 設定オプション
|
| 45 |
+
|
| 46 |
+
- コンテキストメニューのスケール調整
|
| 47 |
+
- テキスト置換に `execCommand` 関数の使用(注:execCommandは非推奨関数ですが、「元に戻す」「やり直し」が使えます)
|
| 48 |
+
- UNet、Dyn、Start、およびStopスライダーの表示
|
| 49 |
+
- 各ウェイトスライダーの最小値、最大値、ステップ数の設定
|
| 50 |
+
- LBWのLoraおよびLycoブロックの詳細設定
|
| 51 |
+
- プレビューの表示有無、表示サイズと表示位置の設定
|
| 52 |
+
- ブロックウェイトの区切り設定
|
| 53 |
+
|
| 54 |
+
## 動作保証環境
|
| 55 |
+
|
| 56 |
+
- Stable Difusion AUTOMATIC1111
|
| 57 |
+
- Windows
|
| 58 |
+
- Google Chrome
|
| 59 |
+
|
| 60 |
+
## 謝辞
|
| 61 |
+
|
| 62 |
+
この拡張機能を作成するにあたり、**LoRA Block Weight** の作者である **hako-mikan** 様に深く感謝申し上げます。
|
| 63 |
+
```
|
| 64 |
+
https://github.com/hako-mikan/sd-webui-lora-block-weight
|
| 65 |
+
```
|
| 66 |
+
|
| 67 |
+
## ライセンス
|
| 68 |
+
|
| 69 |
+
このプロジェクトは[MITライセンス](LICENSE)の下で公開されています。
|
sd-webui-weight-helper-main/backup_before_patch/scripts/analyzer.py
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import pickle
|
| 3 |
+
import re
|
| 4 |
+
from typing import Optional
|
| 5 |
+
from scripts import const, env
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def get_model_type(lora) -> Optional[str]:
|
| 9 |
+
if env.ui_type == const.UI_TYPE.A1111:
|
| 10 |
+
sd_version: Optional[str] = lora.sd_version.name
|
| 11 |
+
if sd_version and env.network:
|
| 12 |
+
if sd_version == env.network.SdVersion.SD1.name or sd_version == env.network.SdVersion.SD2.name:
|
| 13 |
+
return "SD"
|
| 14 |
+
elif sd_version == env.network.SdVersion.SDXL.name:
|
| 15 |
+
return "SDXL"
|
| 16 |
+
return sd_version
|
| 17 |
+
elif env.ui_type == const.UI_TYPE.NEW_FORGE:
|
| 18 |
+
base_model_version: Optional[str] = lora.metadata.get("ss_base_model_version")
|
| 19 |
+
if base_model_version:
|
| 20 |
+
base_model_version = base_model_version.lower()
|
| 21 |
+
if "sd_" in base_model_version:
|
| 22 |
+
return "SD"
|
| 23 |
+
if "sd3" in base_model_version:
|
| 24 |
+
return "SD"
|
| 25 |
+
elif "sdxl" in base_model_version:
|
| 26 |
+
return "SDXL"
|
| 27 |
+
elif "flux" in base_model_version:
|
| 28 |
+
return "Flux"
|
| 29 |
+
return None
|
| 30 |
+
return None
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def get_algorithm(metadata, ss_network_args) -> Optional[str]:
|
| 34 |
+
ss_network_module = metadata.get("ss_network_module")
|
| 35 |
+
if not ss_network_module or ss_network_module == "Unknown":
|
| 36 |
+
return None
|
| 37 |
+
|
| 38 |
+
conv_dim = float(ss_network_args.get("conv_dim", "-1"))
|
| 39 |
+
conv_alpha = float(ss_network_args.get("conv_alpha", "-1"))
|
| 40 |
+
algo = ss_network_args.get("algo", "").lower()
|
| 41 |
+
unit = ss_network_args.get("unit", "").lower()
|
| 42 |
+
dora_wd = ss_network_args.get("dora_wd", False)
|
| 43 |
+
|
| 44 |
+
if ss_network_module.find("locon.locon_kohya") >= 0:
|
| 45 |
+
return "LoCon"
|
| 46 |
+
|
| 47 |
+
elif ss_network_module.find("lycoris.kohya") >= 0:
|
| 48 |
+
algoName = ""
|
| 49 |
+
if dora_wd:
|
| 50 |
+
algoName = "(DoRA)"
|
| 51 |
+
elif algo == "lora":
|
| 52 |
+
algoName += "(LoCon)"
|
| 53 |
+
elif algo == "locon":
|
| 54 |
+
if unit:
|
| 55 |
+
algoName += "(DyLoRA)"
|
| 56 |
+
else:
|
| 57 |
+
algoName += "(LoCon)"
|
| 58 |
+
elif algo == "loha":
|
| 59 |
+
algoName += "(LoHa)"
|
| 60 |
+
elif algo == "lokr":
|
| 61 |
+
algoName += "(Lokr)"
|
| 62 |
+
elif algo == "ia3":
|
| 63 |
+
algoName += "(IA3)"
|
| 64 |
+
elif algo == "full":
|
| 65 |
+
algoName += "(Full)"
|
| 66 |
+
elif algo == "glora":
|
| 67 |
+
algoName += "(GLoRA)"
|
| 68 |
+
|
| 69 |
+
return f"LyCORIS{algoName}"
|
| 70 |
+
|
| 71 |
+
elif ss_network_module.find("networks.dylora") >= 0:
|
| 72 |
+
if algo == "dylora" and unit:
|
| 73 |
+
if conv_dim > 0 or conv_alpha > 0:
|
| 74 |
+
return "DyLoRA(C3Lier)"
|
| 75 |
+
return "DyLoRA(LierLa)"
|
| 76 |
+
|
| 77 |
+
elif conv_dim > 0 or conv_alpha > 0:
|
| 78 |
+
return "LoRA(C3Lier)"
|
| 79 |
+
|
| 80 |
+
else:
|
| 81 |
+
return "LoRA(LierLa)"
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
def get_blocks(lora_on_disk, force):
|
| 85 |
+
baseKeys = __get_lora_state_keys(lora_on_disk.filename, force)
|
| 86 |
+
|
| 87 |
+
def formatForDownMidUp(key):
|
| 88 |
+
blocks = ["BASE"]
|
| 89 |
+
for key in keys:
|
| 90 |
+
k, v = key.split("_", 1)
|
| 91 |
+
if k == "down":
|
| 92 |
+
k = "IN"
|
| 93 |
+
v1, v2 = v.split("_")
|
| 94 |
+
val = int(v1) * 3 + int(v2) + 1
|
| 95 |
+
elif k == "mid":
|
| 96 |
+
blocks.append("M00")
|
| 97 |
+
continue
|
| 98 |
+
elif k == "up":
|
| 99 |
+
k = "OUT"
|
| 100 |
+
v1, v2 = v.split("_")
|
| 101 |
+
val = int(v1) * 3 + int(v2)
|
| 102 |
+
blocks.append(f'{k}{int(val):02}')
|
| 103 |
+
return sorted(blocks)
|
| 104 |
+
|
| 105 |
+
def formatForInputMiddleOutput(key):
|
| 106 |
+
blocks = ["BASE"]
|
| 107 |
+
for key in keys:
|
| 108 |
+
k, v = key.split("_")
|
| 109 |
+
if k == "input":
|
| 110 |
+
k = "IN"
|
| 111 |
+
elif k == "middle":
|
| 112 |
+
blocks.append("M00")
|
| 113 |
+
continue
|
| 114 |
+
elif k == "output":
|
| 115 |
+
k = "OUT"
|
| 116 |
+
blocks.append(f'{k}{int(v):02}')
|
| 117 |
+
return sorted(blocks)
|
| 118 |
+
|
| 119 |
+
def formatForFlux(key):
|
| 120 |
+
blocks = ["CLIP", "T5", "IN", "OUT"]
|
| 121 |
+
for key in keys:
|
| 122 |
+
k, v = key.split("_")
|
| 123 |
+
v = int(v)
|
| 124 |
+
if k == "double":
|
| 125 |
+
k = "D"
|
| 126 |
+
if k == "single":
|
| 127 |
+
k = "S"
|
| 128 |
+
blocks.append(f'{k}{v:02}')
|
| 129 |
+
return sorted(blocks)
|
| 130 |
+
|
| 131 |
+
keys = [k for k in baseKeys if k.find("lora_unet") == 0]
|
| 132 |
+
if len(keys) > 0:
|
| 133 |
+
keys_tmp = [k for k in keys if re.match("^lora_unet_(down|mid|up)_", k)]
|
| 134 |
+
if len(keys_tmp) > 0:
|
| 135 |
+
keys = set(["_".join([k.split("_")[2], k.split("_")[4] + "_" + k.split("_")[6]]) for k in keys_tmp if "transformer_blocks" in k])
|
| 136 |
+
return formatForDownMidUp(keys)
|
| 137 |
+
|
| 138 |
+
keys_tmp = [k for k in keys if re.match("^lora_unet_(input|middle|output)_", k)]
|
| 139 |
+
if len(keys_tmp) > 0:
|
| 140 |
+
keys = set(["_".join([k.split("_")[2], k.split("_")[4]]) for k in keys_tmp if "transformer_blocks" in k])
|
| 141 |
+
return formatForInputMiddleOutput(keys)
|
| 142 |
+
|
| 143 |
+
keys_tmp = [k for k in keys if re.match("^lora_unet_(single|double)_", k)]
|
| 144 |
+
if len(keys_tmp) > 0:
|
| 145 |
+
keys = set(["_".join([k.split("_")[2], k.split("_")[4]]) for k in keys_tmp])
|
| 146 |
+
return formatForFlux(keys)
|
| 147 |
+
|
| 148 |
+
keys_tmp = [k for k in keys if re.match("^lora_unet_joint_blocks_", k)]
|
| 149 |
+
if len(keys_tmp) > 0:
|
| 150 |
+
# TODO SD3? 38 blocks
|
| 151 |
+
return None
|
| 152 |
+
|
| 153 |
+
keys = [k for k in baseKeys if "transformer_blocks" in k and "attentions" in k]
|
| 154 |
+
if len(keys) > 0:
|
| 155 |
+
# TODO unknown
|
| 156 |
+
keys = set([".".join(k.split(".")[2:6]) for k in keys])
|
| 157 |
+
in_blocks = set([f"{k.split('.')[1]}_{k.split('.')[3]}" for k in keys if "down_block" in k])
|
| 158 |
+
mid_block = set([k.split(".")[2] for k in keys if "mid_block" in k])
|
| 159 |
+
out_blocks = set([f"{k.split('.')[1]}_{k.split('.')[3]}" for k in keys if "up_block" in k])
|
| 160 |
+
keys = list(in_blocks) + list(mid_block) + list(out_blocks)
|
| 161 |
+
return None
|
| 162 |
+
|
| 163 |
+
keys = [k for k in baseKeys if "transformer_blocks" in k and k.find("transformer") == 0]
|
| 164 |
+
if len(keys) > 0:
|
| 165 |
+
keys = set([".".join(k.split(".")[1:3]) for k in keys])
|
| 166 |
+
keys = [k.replace("single_transformer_blocks.", "single_") for k in keys]
|
| 167 |
+
keys = [k.replace("transformer_blocks.", "double_") for k in keys]
|
| 168 |
+
return formatForFlux(keys)
|
| 169 |
+
|
| 170 |
+
return None
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
def __get_lora_state_keys(filename, force):
|
| 174 |
+
cache_path = f"{os.path.splitext(filename)[0]}.whcache"
|
| 175 |
+
if not force and os.path.exists(cache_path):
|
| 176 |
+
try:
|
| 177 |
+
with open(cache_path, "rb") as f:
|
| 178 |
+
return pickle.load(f)
|
| 179 |
+
except Exception:
|
| 180 |
+
pass
|
| 181 |
+
|
| 182 |
+
lora_sd = env.network_lora.load_lora_state_dict(filename)
|
| 183 |
+
keys = list(lora_sd.keys())
|
| 184 |
+
try:
|
| 185 |
+
with open(cache_path, "wb") as f:
|
| 186 |
+
pickle.dump(keys, f)
|
| 187 |
+
except Exception:
|
| 188 |
+
pass
|
| 189 |
+
return keys
|
sd-webui-weight-helper-main/backup_before_patch/scripts/api.py
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
import ast
|
| 3 |
+
import json
|
| 4 |
+
import os
|
| 5 |
+
from typing import Any, Optional
|
| 6 |
+
from modules import shared
|
| 7 |
+
from scripts import analyzer, const, utils
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def get_metadata(key, force) -> dict[str, Optional[str]]:
|
| 11 |
+
ret: dict[str, Optional[str]] = {
|
| 12 |
+
"modelType": None,
|
| 13 |
+
"algorithm": None,
|
| 14 |
+
"baseModel": None,
|
| 15 |
+
"usingBlocks": None
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
lora_on_disk = utils.get_lora_on_disk(key)
|
| 19 |
+
if not lora_on_disk:
|
| 20 |
+
return ret
|
| 21 |
+
|
| 22 |
+
ret["modelType"] = analyzer.get_model_type(lora_on_disk)
|
| 23 |
+
|
| 24 |
+
metadata = lora_on_disk.metadata
|
| 25 |
+
ss_network_args = __get_network_args(lora_on_disk)
|
| 26 |
+
ret["algorithm"] = analyzer.get_algorithm(metadata, ss_network_args)
|
| 27 |
+
|
| 28 |
+
model_path, _ = os.path.splitext(lora_on_disk.filename)
|
| 29 |
+
civitai_info = __find_civitai_info(model_path)
|
| 30 |
+
ret["baseModel"] = civitai_info.get("baseModel", None)
|
| 31 |
+
|
| 32 |
+
if shared.opts.weight_helper_parse_lora_blocks:
|
| 33 |
+
try:
|
| 34 |
+
ret["usingBlocks"] = analyzer.get_blocks(lora_on_disk, force)
|
| 35 |
+
except Exception:
|
| 36 |
+
pass
|
| 37 |
+
return ret
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def get_preview_info(key):
|
| 41 |
+
ret: dict[str, Optional[bool | str | list[str]]] = {
|
| 42 |
+
"modelId": None,
|
| 43 |
+
"triggerWords": [],
|
| 44 |
+
"negativeTriggerWords": [],
|
| 45 |
+
"modelName": None,
|
| 46 |
+
"thumbUrl": None,
|
| 47 |
+
"hasMetadata": False,
|
| 48 |
+
"description": None,
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
lora_on_disk = utils.get_lora_on_disk(key)
|
| 52 |
+
if lora_on_disk:
|
| 53 |
+
model_path, _ = os.path.splitext(lora_on_disk.filename)
|
| 54 |
+
ret["modelName"] = lora_on_disk.name
|
| 55 |
+
ret["thumbUrl"] = __find_preview(model_path)
|
| 56 |
+
ret["hasMetadata"] = __find_metadata(lora_on_disk)
|
| 57 |
+
ret["description"] = __find_description(model_path)
|
| 58 |
+
|
| 59 |
+
trigger_words = []
|
| 60 |
+
civitai_info = __find_civitai_info(model_path)
|
| 61 |
+
ret["modelId"] = civitai_info.get("modelId", None)
|
| 62 |
+
trigger_words = civitai_info.get("trainedWords", [])
|
| 63 |
+
trigger_words = ",".join(trigger_words).split(",")
|
| 64 |
+
ret["triggerWords"] = [w.strip() for w in trigger_words if w]
|
| 65 |
+
|
| 66 |
+
lora_json = __get_lora_json(model_path)
|
| 67 |
+
|
| 68 |
+
activation_text = lora_json.get("activation text", "")
|
| 69 |
+
if activation_text:
|
| 70 |
+
activation_text = activation_text.split(",")
|
| 71 |
+
activation_text = [w.strip() for w in activation_text if w]
|
| 72 |
+
ret["triggerWords"] = activation_text
|
| 73 |
+
|
| 74 |
+
negative_text = lora_json.get("negative text", "")
|
| 75 |
+
if negative_text:
|
| 76 |
+
negative_text = negative_text.split(",")
|
| 77 |
+
negative_text = [w.strip() for w in negative_text if w]
|
| 78 |
+
ret["negativeTriggerWords"] = negative_text
|
| 79 |
+
|
| 80 |
+
json_description = lora_json.get("description", None)
|
| 81 |
+
if json_description:
|
| 82 |
+
ret["description"] = json_description
|
| 83 |
+
|
| 84 |
+
return ret
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
def __get_network_args(lora) -> dict[str, Any]:
|
| 88 |
+
metadata = lora.metadata
|
| 89 |
+
ss_network_args = metadata.get("ss_network_args", {})
|
| 90 |
+
if type(ss_network_args) is str:
|
| 91 |
+
try:
|
| 92 |
+
ss_network_args = ast.literal_eval(ss_network_args)
|
| 93 |
+
except Exception:
|
| 94 |
+
ss_network_args = {}
|
| 95 |
+
return ss_network_args
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
def __get_lora_json(path) -> dict[str, Any]:
|
| 99 |
+
if path:
|
| 100 |
+
lora_json = f"{path}.json"
|
| 101 |
+
if os.path.exists(lora_json):
|
| 102 |
+
try:
|
| 103 |
+
with open(lora_json, "r", encoding="utf-8", errors="replace") as f:
|
| 104 |
+
return json.load(f)
|
| 105 |
+
except OSError:
|
| 106 |
+
pass
|
| 107 |
+
return {}
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
def __find_preview(path) -> str:
|
| 111 |
+
if path:
|
| 112 |
+
potential_files = sum([[f"{path}.{ext}", f"{path}.preview.{ext}"] for ext in const.ALLOWED_PREVIEW_EXTENSIONS], [])
|
| 113 |
+
for file in potential_files:
|
| 114 |
+
if os.path.exists(file):
|
| 115 |
+
dpi_scale = 1.5
|
| 116 |
+
return utils.resize_to_base64(file, int(shared.opts.weight_helper_preview_height * dpi_scale))
|
| 117 |
+
return "./file=html/card-no-preview.png"
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
def __find_metadata(lora) -> bool:
|
| 121 |
+
return len(lora.metadata) > 0 if lora else False
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
def __find_description(path) -> Optional[str]:
|
| 125 |
+
if path:
|
| 126 |
+
for file in [f"{path}.txt", f"{path}.description.txt"]:
|
| 127 |
+
if os.path.exists(file):
|
| 128 |
+
try:
|
| 129 |
+
with open(file, "r", encoding="utf-8", errors="replace") as f:
|
| 130 |
+
return f.read()
|
| 131 |
+
except OSError:
|
| 132 |
+
pass
|
| 133 |
+
return None
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
def __find_civitai_info(path) -> dict[str, Any]:
|
| 137 |
+
if path:
|
| 138 |
+
civitai_info = f"{path}.civitai.info"
|
| 139 |
+
if os.path.exists(civitai_info):
|
| 140 |
+
try:
|
| 141 |
+
with open(civitai_info, "r", encoding="utf-8", errors="replace") as f:
|
| 142 |
+
return json.load(f)
|
| 143 |
+
except OSError:
|
| 144 |
+
pass
|
| 145 |
+
return {}
|
sd-webui-weight-helper-main/backup_before_patch/scripts/const.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import enum
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
API_PREFIX = "/whapi/v1"
|
| 5 |
+
ALLOWED_PREVIEW_EXTENSIONS = ["png", "jpg", "jpeg", "webp", "gif"]
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class UI_TYPE(enum.Enum):
|
| 9 |
+
Unknown = 1
|
| 10 |
+
A1111 = 2
|
| 11 |
+
NEW_FORGE = 3
|
sd-webui-weight-helper-main/backup_before_patch/scripts/env.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
import importlib
|
| 3 |
+
from scripts import const
|
| 4 |
+
|
| 5 |
+
network = None
|
| 6 |
+
network_lora = None
|
| 7 |
+
ui_type = None
|
| 8 |
+
|
| 9 |
+
try:
|
| 10 |
+
from modules_forge import forge_version # noqa: F401
|
| 11 |
+
ui_type = const.UI_TYPE.NEW_FORGE
|
| 12 |
+
except ImportError:
|
| 13 |
+
ui_type = const.UI_TYPE.A1111
|
| 14 |
+
|
| 15 |
+
try:
|
| 16 |
+
network = importlib.import_module("extensions-builtin.sd_forge_lora.network")
|
| 17 |
+
network_lora = importlib.import_module("extensions-builtin.sd_forge_lora.ui_extra_networks_lora").networks
|
| 18 |
+
except Exception:
|
| 19 |
+
pass
|
| 20 |
+
|
| 21 |
+
if network_lora is None:
|
| 22 |
+
try:
|
| 23 |
+
network = importlib.import_module("extensions-builtin.Lora.network")
|
| 24 |
+
network_lora = importlib.import_module("extensions-builtin.Lora.ui_extra_networks_lora").networks
|
| 25 |
+
except Exception:
|
| 26 |
+
pass
|
| 27 |
+
|
| 28 |
+
if network_lora is None:
|
| 29 |
+
ui_type = const.UI_TYPE.Unknown
|
sd-webui-weight-helper-main/backup_before_patch/scripts/utils.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import base64
|
| 2 |
+
import cv2
|
| 3 |
+
import urllib
|
| 4 |
+
|
| 5 |
+
import numpy as np
|
| 6 |
+
from scripts import env
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def get_lora_on_disk(key):
|
| 10 |
+
if env.network_lora:
|
| 11 |
+
lora_on_disk = env.network_lora.available_network_aliases.get(key)
|
| 12 |
+
if not lora_on_disk:
|
| 13 |
+
# sdnext
|
| 14 |
+
lora_on_disk = next((v for v in env.network_lora.available_network_aliases.values() if v.alias == key), None)
|
| 15 |
+
return lora_on_disk
|
| 16 |
+
return None
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def imread_unicode(path):
|
| 20 |
+
try:
|
| 21 |
+
with open(path, 'rb') as f:
|
| 22 |
+
data = np.frombuffer(f.read(), np.uint8)
|
| 23 |
+
img = cv2.imdecode(data, cv2.IMREAD_UNCHANGED)
|
| 24 |
+
return img
|
| 25 |
+
except Exception as e:
|
| 26 |
+
print(f"imread_unicode error: {e}")
|
| 27 |
+
return None
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def resize_to_base64(input_path, target_height):
|
| 31 |
+
output_format = '.webp'
|
| 32 |
+
quality = 85
|
| 33 |
+
|
| 34 |
+
img = imread_unicode(input_path)
|
| 35 |
+
|
| 36 |
+
h, w = img.shape[:2]
|
| 37 |
+
if h < target_height:
|
| 38 |
+
quoted_filename = urllib.parse.quote(input_path.replace('\\', '/'))
|
| 39 |
+
return f"./sd_extra_networks/thumb?filename={quoted_filename}"
|
| 40 |
+
|
| 41 |
+
scale = target_height / h
|
| 42 |
+
target_size = (int(w * scale), target_height)
|
| 43 |
+
|
| 44 |
+
resized = cv2.resize(img, target_size, interpolation=cv2.INTER_AREA)
|
| 45 |
+
|
| 46 |
+
sharpen_kernel = np.array([
|
| 47 |
+
[0, -0.2, 0],
|
| 48 |
+
[-0.2, 1.8, -0.2],
|
| 49 |
+
[0, -0.2, 0]
|
| 50 |
+
])
|
| 51 |
+
sharpened = cv2.filter2D(resized, -1, sharpen_kernel)
|
| 52 |
+
success, buffer = cv2.imencode(output_format, sharpened, [cv2.IMWRITE_WEBP_QUALITY, quality])
|
| 53 |
+
if not success:
|
| 54 |
+
quoted_filename = urllib.parse.quote(input_path.replace('\\', '/'))
|
| 55 |
+
return f"./sd_extra_networks/thumb?filename={quoted_filename}"
|
| 56 |
+
|
| 57 |
+
base64_str = base64.b64encode(buffer).decode('utf-8')
|
| 58 |
+
return f'data:image/webp;base64,{base64_str}'
|
sd-webui-weight-helper-main/backup_before_patch/scripts/weight_helper.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
from fastapi import FastAPI
|
| 3 |
+
from modules import script_callbacks, shared
|
| 4 |
+
from scripts import api, const
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def on_app_started(_: gr.Blocks, app: FastAPI):
|
| 8 |
+
@app.post(const.API_PREFIX + "/get_metadata")
|
| 9 |
+
async def _(key: str, force: bool = False):
|
| 10 |
+
return api.get_metadata(key, force)
|
| 11 |
+
|
| 12 |
+
@app.post(const.API_PREFIX + "/get_preview_info")
|
| 13 |
+
async def _(key: str):
|
| 14 |
+
return api.get_preview_info(key)
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
def on_ui_settings():
|
| 18 |
+
"""
|
| 19 |
+
Set up the UI settings for the weight helper by adding options to the shared configuration.
|
| 20 |
+
"""
|
| 21 |
+
section = ('weight_helper', 'Weight Helper')
|
| 22 |
+
|
| 23 |
+
shared.options_templates.update(shared.options_section(section, {
|
| 24 |
+
'weight_helper_enabled': shared.OptionInfo(True, 'Enabled'),
|
| 25 |
+
'weight_helper_context_menu_scale': shared.OptionInfo(0.8, "Context Menu Scale", gr.Number),
|
| 26 |
+
'weight_helper_using_execCommand': shared.OptionInfo(True, "Use the deprecated execCommand function to replace text.").info(
|
| 27 |
+
"You can use 'undo' to revert the text to its previous state, "
|
| 28 |
+
"but it will no longer be updated in real-time."),
|
| 29 |
+
|
| 30 |
+
"weight_helper_slider_length": shared.OptionInfo(160, "Slider Length (px)", gr.Number),
|
| 31 |
+
|
| 32 |
+
"weight_helper_TEnc_min": shared.OptionInfo(0, "TEnc Min Value", gr.Number),
|
| 33 |
+
"weight_helper_TEnc_max": shared.OptionInfo(1, "TEnc Max Value", gr.Number),
|
| 34 |
+
"weight_helper_TEnc_step": shared.OptionInfo(0.05, "TEnc Step", gr.Number),
|
| 35 |
+
|
| 36 |
+
"weight_helper_UNet_min": shared.OptionInfo(0, "UNet Min Value", gr.Number),
|
| 37 |
+
"weight_helper_UNet_max": shared.OptionInfo(1, "UNet Max Value", gr.Number),
|
| 38 |
+
"weight_helper_UNet_step": shared.OptionInfo(0.05, "UNet Step", gr.Number),
|
| 39 |
+
|
| 40 |
+
"weight_helper_LBW_min": shared.OptionInfo(0, "LBW (LoRA Block Weight) Min Value", gr.Number),
|
| 41 |
+
"weight_helper_LBW_max": shared.OptionInfo(1, "LBW (LoRA Block Weight) Max Value", gr.Number),
|
| 42 |
+
"weight_helper_LBW_step": shared.OptionInfo(0.05, "LBW (LoRA Block Weight) Step", gr.Number),
|
| 43 |
+
|
| 44 |
+
'weight_helper_show_preview': shared.OptionInfo(True, 'Show Preview'),
|
| 45 |
+
"weight_helper_preview_height": shared.OptionInfo(400, "Preview Height (px)", gr.Number),
|
| 46 |
+
"weight_helper_preview_position": shared.OptionInfo("Top Right", "Preview Position", gr.Radio, {
|
| 47 |
+
"choices": ["Top Right", "Bottom Right", "Top Left", "Bottom Left"]
|
| 48 |
+
}),
|
| 49 |
+
|
| 50 |
+
'weight_helper_parse_lora_blocks': shared.OptionInfo(True, '[experimental] Parse LoRA file to get block information'),
|
| 51 |
+
|
| 52 |
+
"weight_helper_LBW_SD_lora_block_points": shared.OptionInfo(
|
| 53 |
+
"BASE, IN01-IN04, IN05-IN08, M00, OUT03-OUT06, OUT07-OUT11",
|
| 54 |
+
"Advanced option - LoRA-LierLa block points")
|
| 55 |
+
.info("default: BASE, IN01-IN04, IN05-IN08, M00, OUT03-OUT06, OUT07-OUT11"),
|
| 56 |
+
"weight_helper_LBW_SD_lycoris_block_points": shared.OptionInfo(
|
| 57 |
+
"BASE, IN00-IN05, IN06-IN11, M00, OUT00-OUT05, OUT06-OUT11",
|
| 58 |
+
"Advanced option - LyCORIS or LoRA-C3Lier block points")
|
| 59 |
+
.info("default: BASE, IN00-IN05, IN06-IN11, M00, OUT00-OUT05, OUT06-OUT11"),
|
| 60 |
+
|
| 61 |
+
"weight_helper_LBW_SDXL_lora_block_points": shared.OptionInfo(
|
| 62 |
+
"BASE, IN04-IN08, M00, OUT00-OUT05",
|
| 63 |
+
"Advanced option - SDXL LoRA-LierLa block points")
|
| 64 |
+
.info("default: BASE, IN04-IN08, M00, OUT00-OUT05"),
|
| 65 |
+
"weight_helper_LBW_SDXL_lycoris_block_points": shared.OptionInfo(
|
| 66 |
+
"BASE, IN00-IN03, IN04-IN08, M00, OUT00-OUT03, OUT04-OUT08",
|
| 67 |
+
"Advanced option - SDXL LyCORIS or LoRA-C3Lier block points")
|
| 68 |
+
.info("default: BASE, IN00-IN03, IN04-IN08, M00, OUT00-OUT03, OUT04-OUT08"),
|
| 69 |
+
|
| 70 |
+
"weight_helper_LBW_Flux_lora_block_points": shared.OptionInfo(
|
| 71 |
+
"CLIP, T5, IN, OUT, D00-D18, S00-S18, S19-S37",
|
| 72 |
+
"Advanced option - Flux LoRA-LierLa block points")
|
| 73 |
+
.info("default: CLIP, T5, IN, OUT, D00-D18, S00-S18, S19-S37"),
|
| 74 |
+
"weight_helper_LBW_Flux_lycoris_block_points": shared.OptionInfo(
|
| 75 |
+
"CLIP, T5, IN, OUT, D00-D18, S00-S18, S19-S37",
|
| 76 |
+
"Advanced option - Flux LyCORIS or LoRA-C3Lier block points")
|
| 77 |
+
.info("default: CLIP, T5, IN, OUT, D00-D18, S00-S18, S19-S37"),
|
| 78 |
+
}))
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
script_callbacks.on_ui_settings(on_ui_settings)
|
| 82 |
+
script_callbacks.on_app_started(on_app_started)
|
sd-webui-weight-helper-main/esbuild.config.mjs
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { build } from 'esbuild';
|
| 2 |
+
|
| 3 |
+
const baseOptions = {
|
| 4 |
+
entryPoints: ['src/index.ts'],
|
| 5 |
+
bundle: true,
|
| 6 |
+
outfile: 'javascript/weight_helper.js',
|
| 7 |
+
target: 'es2022',
|
| 8 |
+
format: 'iife',
|
| 9 |
+
platform: 'browser',
|
| 10 |
+
};
|
| 11 |
+
|
| 12 |
+
build({
|
| 13 |
+
...baseOptions,
|
| 14 |
+
minify: process.argv.includes('--minify'),
|
| 15 |
+
sourcemap: process.argv.includes('--sourcemap'),
|
| 16 |
+
}).catch(() => process.exit(1));
|
sd-webui-weight-helper-main/eslint.config.mjs
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { defineConfig } from "eslint/config";
|
| 2 |
+
import globals from "globals";
|
| 3 |
+
import tseslint from "typescript-eslint";
|
| 4 |
+
import prettier from 'eslint-config-prettier';
|
| 5 |
+
|
| 6 |
+
export default defineConfig([
|
| 7 |
+
...tseslint.configs.recommended,
|
| 8 |
+
{
|
| 9 |
+
files: ['**/*.ts'],
|
| 10 |
+
languageOptions: {
|
| 11 |
+
globals: globals.browser,
|
| 12 |
+
},
|
| 13 |
+
rules: {
|
| 14 |
+
semi: ['error', 'always'],
|
| 15 |
+
quotes: ['error', 'single'],
|
| 16 |
+
},
|
| 17 |
+
},
|
| 18 |
+
prettier,
|
| 19 |
+
]);
|
sd-webui-weight-helper-main/javascript/weight_helper.js
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use strict";(()=>{var S={lora:"lora",lycoris:"lycoris",Unknown:"Unknown"},y={SD:"SD",SDXL:"SDXL",Flux:"Flux",Unknown:"Unknown"},P={te:"te",unet:"unet",start:"start",stop:"stop",step:"step",lbw:"lbw",lbwe:"lbwe"},m={TENC:"TEnc",UNET:"UNet",START:"Start",STOP:"Stop",LBW:"LBW"};var De={STABLE_DIFFUSION:["BASE","IN00","IN01","IN02","IN03","IN04","IN05","IN06","IN07","IN08","IN09","IN10","IN11","M00","OUT00","OUT01","OUT02","OUT03","OUT04","OUT05","OUT06","OUT07","OUT08","OUT09","OUT10","OUT11"],BLACK_FOREST_LABS:["CLIP","T5","IN","D00","D01","D02","D03","D04","D05","D06","D07","D08","D09","D10","D11","D12","D13","D14","D15","D16","D17","D18","S00","S01","S02","S03","S04","S05","S06","S07","S08","S09","S10","S11","S12","S13","S14","S15","S16","S17","S18","S19","S20","S21","S22","S23","S24","S25","S26","S27","S28","S29","S30","S31","S32","S33","S34","S35","S36","S37","OUT"]},ne={[y.SD]:De.STABLE_DIFFUSION,[y.SDXL]:De.STABLE_DIFFUSION,[y.Flux]:De.BLACK_FOREST_LABS,[y.Unknown]:[]},rt={[y.SD]:{[S.lora]:[1,0,1,1,0,1,1,0,1,1,0,0,0,1,0,0,0,1,1,1,1,1,1,1,1,1],[S.lycoris]:[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[S.Unknown]:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},[y.SDXL]:{[S.lora]:[1,0,0,0,0,1,1,0,1,1,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0],[S.lycoris]:[1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0],[S.Unknown]:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},[y.Flux]:{[S.lora]:[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[S.lycoris]:[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[S.Unknown]:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},[y.Unknown]:{[S.lora]:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[S.lycoris]:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[S.Unknown]:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},nt={[y.SD]:{[S.lora]:"XYZ(17)",[S.lycoris]:"XYZ(26)",[S.Unknown]:"XYZ(26)"},[y.SDXL]:{[S.lora]:"XYZ(12)",[S.lycoris]:"XYZ(20)",[S.Unknown]:"XYZ(26)"},[y.Flux]:{[S.lora]:"XYZ(19)",[S.lycoris]:"XYZ(19)",[S.Unknown]:"XYZ(19)"},[y.Unknown]:{[S.lora]:"XYZ(17)",[S.lycoris]:"XYZ(26)",[S.Unknown]:"XYZ(26)"}},K={"":y.Unknown,SD:y.SD,SDXL:y.SDXL,Flux:y.Flux},J={"":S.Unknown,"LoRA(LierLa)":S.lora,"LyCORIS,etc":S.lycoris},be="./file=html/card-no-preview.png";var ye={[m.TENC]:{min:0,max:0,default:1,step:.5},[m.UNET]:{min:0,max:0,default:0,step:.5},[m.START]:{min:0,max:0,default:0,step:1},[m.STOP]:{min:0,max:0,default:0,step:1},[m.LBW]:{min:0,max:0,default:1,step:.5}},st={[y.SD]:{[S.lora]:[["BASE","IN01-IN04","IN05-IN08","M00","OUT03-OUT06","OUT07-OUT11"]],[S.lycoris]:[["BASE","IN00-IN05","IN06-IN11","M00","OUT00-OUT05","OUT06-OUT11"]],[S.Unknown]:[[]]},[y.SDXL]:{[S.lora]:[["BASE","IN04-IN08","M00","OUT00-OUT05"]],[S.lycoris]:[["BASE","IN00-IN03","IN04-IN08","M00","OUT00-OUT03","OUT04-OUT08"]],[S.Unknown]:[[]]},[y.Flux]:{[S.lora]:[["CLIP","T5","IN","OUT"],["D00-D18"],["S00-S18"],["S19-S37"]],[S.lycoris]:[["CLIP","T5","IN","OUT"],["D00-D18"],["S00-S18"],["S19-S37"]],[S.Unknown]:[[]]},[y.Unknown]:{[S.lora]:[[]],[S.lycoris]:[[]],[S.Unknown]:[[]]}};function at(){let e=/((BASE|MID|M00|CLIP|T5|(IN|OUT|D|S)[0-9]{2}(-(IN|OUT|D|S)[0-9]{2})?) *(, *|$))+/;for(let t of Object.values(K))if(!(t===y.Unknown||t===y.Flux)){for(let o of Object.values(J))if(o!==S.Unknown)try{let r=opts[`weight_helper_LBW_${t}_${o}_block_points`];if(r=r.replace("MID","M00"),e.exec(r)){let n=r.split(",").map(a=>a.trim().replace(/\d+/g,s=>s.length===1?`0${s}`:s));st[t][o]=[n]}}catch(r){console.warn(`${t}_${o} block definition format is invalid.`,r)}}for(let t of[m.TENC,m.UNET,m.LBW])ye[t].min=+opts[`weight_helper_${t}_min`],ye[t].max=+opts[`weight_helper_${t}_max`],ye[t].step=+opts[`weight_helper_${t}_step`]}function T(e){return ye[e]}function we(e){return e in ne?ne[e]:ne[y.Unknown]}function Q(e,t){let o=V(e,t);return ne[e||y.Unknown].filter((r,n)=>o[n]===1)}function V(e,t){return rt[e||y.Unknown][t||S.Unknown]}function N(e,t){return st[e||y.Unknown][t||S.Unknown]}function it(e,t){return nt[e||y.Unknown][t||S.Unknown]}var A={},E={};function O(e){return A[e]??[]}function ee(e,t){t={loraParams:t.loraParams,selectedLoraBlockType:t.selectedLoraBlockType,selectedModelType:t.selectedModelType},e in A?(A[e]=A[e].filter(o=>o.loraParams!==t.loraParams),A[e].push(t)):A[e]=[t]}function lt(e){if(e in A){let t=E[e];A[e]=A[e].filter(o=>t&&t.has(o.loraParams))}}function ct(e,t){e in E?E[e].add(t):E[e]=new Set([t])}function gt(e,t){e in E&&E[e].delete(t)}function U(e,t){return e in E?E[e].has(t):!1}function dt(){localStorage.setItem("wh://histories",JSON.stringify(A));let e={};for(let t in E)e[t]=Array.from(E[t]);localStorage.setItem("wh://locks",JSON.stringify(e))}function pt(){let e=localStorage.getItem("wh://histories");e&&(A=JSON.parse(e));let t=localStorage.getItem("wh://locks");if(t){let o=JSON.parse(t);for(let r in o)E[r]=new Set(o[r])}}function G(e,t,o,r){let n=new Set(Q(e,t)),a=Object.entries(r).filter(([l])=>n.has(l)).map(l=>l[1].value).join(","),s=Object.entries(o).find(([,l])=>l===a);return s?s[0]:""}function Te(e){let t,o=typeof window.TAC_CFG<"u"&&window.TAC_CFG,r,n=typeof window.pilotIsActive<"u"&&window.pilotIsActive;try{o&&(t=window.TAC_CFG.activeIn.global,window.TAC_CFG.activeIn.global=!1),n&&(r=window.pilotIsActive,window.pilotIsActive=!1),e()}finally{o&&(window.TAC_CFG.activeIn.global=t),n&&(window.pilotIsActive=r)}}var ht={},ut={};function ft(e){return ht[e]}function mt(e,t){ht[e]={metadataState:t.metadataState,selectedLoraBlockType:t.weightState.selectedLoraBlockType,selectedModelType:t.weightState.selectedModelType,usingBlocks:t.usingBlocks}}function St(e){return ut[e]}function bt(e,t){ut[e]=t}var yt,wt,Tt,Mt,kt,xt={},vt=0;function se(){return yt}function Lt(e){yt=e}function ae(){return wt}function Ct(e){wt=e}function He(){return Tt}function $t(e){Tt=e}function Re(){return Mt}function Me(e){Mt=e}function _t(){return kt}function Bt(e){kt=e}function ke(){return vt||0}function At(e){vt=+gradioApp().querySelector(`div:is([id^='tab_${e}'][class*='tabitem'])`).querySelector('div:is([id$="_steps"]) input[type=number]').value}function $(e,t){return xt[e||y.Unknown][t||S.Unknown]}function Et(e){let n=(gradioApp().querySelector(`div:is([id^='tab_${e}'][class*='tabitem'])`).querySelector("#lbw_ratiospreset textarea").value??"").split(`
|
| 2 |
+
`).filter(s=>s.trim()!==""),a={};for(let s of Object.values(y)){a[s]={};for(let l of Object.values(S)){let i={},g={};a[s][l]=i;let u=V(s,l).filter(c=>c==1).length;for(let c of n){let h=c.split(":");h.length==2&&h[1].split(",").length==u&&(i[h[0]]=h[1],g[h[1]]=h[0])}}}xt=a}var Pt=e=>e.toLowerCase(),z=e=>e?"":"display: none",D=e=>e?"":"visibility: hidden",I=(e,t=void 0)=>{if(e.uiState.isWaiting)return!0;switch(t){case m.TENC:case m.UNET:case m.START:case m.STOP:case void 0:return!1}return e.usingBlocks!==void 0&&!e.usingBlocks.has(t)};function xe(e){let t=[];return e.split(",").map(o=>o.trim()).forEach(o=>{let r=o.match(/^([A-Z]+)(\d+)-\1(\d+)$/);if(!r){t.push(o);return}let[,n,a,s]=r,l=parseInt(a),i=parseInt(s),g=l;for(;t.push(`${n}${g.toString().padStart(2,"0")}`),g!=i;)g+=l<i?1:-1}),t}var wo=/<(lora|lyco):([^:]+):([^>]+)>/;function It(e){let t=e.target;if(!opts.weight_helper_enabled)return;let o=window.getSelection()?.toString();if(o)return;let r=t.value,n=t.selectionStart,a=r.lastIndexOf("<",n-1),s=r.indexOf(">",n);if(a<0||s<0||(o=r.substring(a,s+1),(o.match(/</g)||[]).length!=1||(o.match(/>/g)||[]).length!=1))return;n=a;let l=wo.exec(o);if(l){e.preventDefault();let i=l[1].toLowerCase(),g=l[2],u=l[3],c=t.closest("[id^='tab_'][class*='tabitem']").id.split("_")[1],h=n+l.index,p=h+l.input.trim().length;return{tabId:c,textarea:t,selectionStart:h,selectionEnd:p,namespace:i,loraName:g,loraParams:u,top:e.pageY+15,left:e.pageX}}}function X(e){let t=ae(),o=He(),r=Re();t.value=t.value.substring(0,o)+e+t.value.substring(r),Me(o+e.length)}function To(e){Te(()=>{let t=ae(),o=He(),r=Re();t.focus(),t.setSelectionRange(o,r),document.execCommand("insertText",!1,e)})}function _(e,t){let o=String(t.weights[m.TENC].value),r=0,n=0;for(let p of[m.UNET]){let w=t.weights[p],b=T(p).default,f=+w.value;(w.checkState||w.checkState===void 0&&f!=b)&&(n===r?o+=`:${f}`:o+=`:${Pt(p)}=${f}`,r++),n++}let a=T(m.START).default,s=t.weights[m.START].value,l=T(m.STOP).default,i=t.weights[m.STOP].value;i<0&&(i=T(m.STOP).default),s!=a&&i!=l?o+=`:step=${s}-${i}`:s!=a?o+=`:start=${s}`:i!=l&&(o+=`:stop=${i}`);let{selectedModelType:g,selectedLoraBlockType:u}=t,c=t.xyzMode,h=o;if(c)o+=":lbw=XYZ",h+=":lbw=XYZ";else if(g!==y.Unknown){let p=V(g,u).map((b,f)=>{if(b===1)return t.weights[we(g)[f]]}).filter(b=>b!==void 0),w=T(m.LBW).default;if(!p.every(b=>b.value===w)){let b=p.map(C=>C.value).join(",");o+=`:lbw=${b}`;let f=$(g,u),M=Object.entries(f).find(([,C])=>b===C);M?h+=`:lbw=${M[0]}`:h+=`:lbw=${b}`}}return t.lbwe&&(o+=`:lbwe=${t.lbwe}`,h+=`:lbwe=${t.lbwe}`),{loraParams:o,loraDefine:`<lora:${e}:${h}>`}}function le(e,t=!1){let o=_(e.loraName,e.weightState);opts.weight_helper_using_execCommand?e.srcLoraParams!==o.loraParams&&To(o.loraDefine):t&&X(_t()),mt(e.loraName,e),e.weightState.xyzMode||ee(e.loraName,{loraParams:o.loraParams,...e.weightState}),dt()}var d,ve=[],Le=[];function v(){ve.forEach(e=>e(d))}function Mo(e){Le.forEach(t=>t(e))}function Wt(e){return ve.push(e),()=>{let t=ve.indexOf(e);t>-1&&ve.splice(t,1)}}function Nt(e){return Le.push(e),()=>{let t=Le.indexOf(e);t>-1&&Le.splice(t,1)}}function L(){return d}function Ut(e){d=e,v()}function Dt(e){d=e,v()}function Ot(e){d=e,v()}function Ht(e,t){Mo({top:e,left:t})}function Ce(e){let t={...d,metadataState:{...d.metadataState,algorithm:e.algorithm||"Unknown",baseModel:e.baseModel||"Unknown",modelType:e.modelType||"Unknown"},weightState:{...d.weightState,selectedModelType:e.selectedModelType,weights:e.weights},blockGroups:e.blockGroups,lbwPresets:e.lbwPresets,uiState:{...d.uiState,isWaiting:!1}};e.usingBlocks===null?t.usingBlocks=void 0:e.usingBlocks&&(t.usingBlocks=new Set(e.usingBlocks)),d=t,v()}function ce(e){d={...d,uiState:{...d.uiState,isWaiting:e}},v()}function Ve(e){let t={...d,weightState:{...d.weightState,selectedLoraBlockType:e.selectedLoraBlockType,selectedModelType:e.selectedModelType,weights:e.weights},blockGroups:e.blockGroups,lbwPresets:e.lbwPresets};opts.weight_helper_using_execCommand||X(_(t.loraName,t.weightState).loraDefine),d=t,v()}function Rt(){let e={...d,weightState:{...d.weightState,xyzMode:!d.weightState.xyzMode}};opts.weight_helper_using_execCommand||X(_(e.loraName,e.weightState).loraDefine),d=e,v()}function Vt(e){let t={...d.weightState,weights:{...d.weightState.weights,...e.weights}},o=_(d.loraName,t),r=U(d.loraName,o.loraParams),n={...d,weightState:t,preset:e.preset,lock:r};opts.weight_helper_using_execCommand||X(o.loraDefine),d=n,v()}function Gt(){let e=_(d.loraName,d.weightState).loraParams,t=U(d.loraName,e);t?gt(d.loraName,e):ct(d.loraName,e),d={...d,lock:!t},v()}function Ge(e){let{locked:t,historyIndex:o,preset:r}=e,{selectedLoraBlockType:n,selectedModelType:a,weights:s,lbwe:l,xyzMode:i}=e.weightState,g={...d.weightState,weights:{...d.weightState.weights,...s},selectedLoraBlockType:n,selectedModelType:a,lbwe:l,xyzMode:i},u={...d,historyIndex:o,preset:r,weightState:g,lock:t};opts.weight_helper_using_execCommand||X(_(u.loraName,u.weightState).loraDefine),d=u,v()}function zt(e){d={...d,historyIndex:e},v()}function $e(e){d.weightState.xyzMode=!1;let t={...d.weightState.weights,[e.block]:{...d.weightState.weights[e.block],value:e.value,sliderMin:Math.min(e.value,d.weightState.weights[e.block].sliderMin),sliderMax:Math.max(e.value,d.weightState.weights[e.block].sliderMax),checkState:e.checkState}},o={...d.weightState,weights:t,xyzMode:!1},r=_(d.loraName,o),n=U(d.loraName,r.loraParams),a={...d,weightState:o,preset:G(d.weightState.selectedModelType,d.weightState.selectedLoraBlockType,d.lbwPresets,t),lock:n};opts.weight_helper_using_execCommand||X(r.loraDefine),d=a,v()}function Xt(){d={...d,uiState:{...d.uiState,isMoreButtonVisible:!1}},v()}function Ft(){lt(d.loraName),d.weightState.xyzMode||ee(d.loraName,{loraParams:_(d.loraName,d.weightState).loraParams,...d.weightState});let e=O(d.loraName).length-1;d={...d,historyIndex:e<0?0:e},v()}function Yt(e){d={...d,previewState:e},v()}function ze(e){d={...d,previewState:{...d.previewState,isDescriptionVisible:e}},v()}function jt(){d={...d,previewState:{...d.previewState,isTagInsertButtonVisible:!1}},v()}function _e(){return{loraName:"",metadataState:void 0,srcLoraParams:"",weightState:{selectedLoraBlockType:S.lora,selectedModelType:y.SD,weights:{},lbwe:"",xyzMode:!1},blockGroups:[],usingBlocks:void 0,preset:"",lbwPresets:{},uiState:{isVisible:!1,scale:1,isMoreButtonVisible:!0,isWaiting:!1},lock:!1,historyIndex:0,previewState:{modelId:"",triggerWords:[],negativeTriggerWords:[],modelName:"",thumbUrl:"",hasMetadata:!1,description:"",isDescriptionVisible:!1,isTagInsertButtonVisible:!1}}}function Zt(e,t,o){let r=y.Unknown,n=S.Unknown,a=O(t);if(a&&a.length>0){let p=a[a.length-1];r=p.selectedModelType??y.Unknown,n=p.selectedLoraBlockType??S.Unknown}let s,l,i=ft(t);i&&(s=i.metadataState,r=i.selectedModelType??y.Unknown,n=i.selectedLoraBlockType??S.Unknown,l=i.usingBlocks);let g=ko(e,o,r,n),u=$(g.selectedModelType,g.selectedLoraBlockType),c=_(t,g).loraParams,h=!1;for(let p of[m.UNET,m.START,m.STOP]){let w=g.weights[p],b=T(p).default,f=+w.value;if(!(w.checkState||w.checkState===void 0&&f!=b)){h=!0;break}}return{loraName:t,metadataState:s,srcLoraParams:c,weightState:g,blockGroups:N(g.selectedModelType,g.selectedLoraBlockType),usingBlocks:l,uiState:{isVisible:!0,scale:opts.weight_helper_context_menu_scale,isMoreButtonVisible:h,isWaiting:!s},previewState:xo(t),preset:G(g.selectedModelType,g.selectedLoraBlockType,u,g.weights),lbwPresets:u,lock:U(t,c),historyIndex:a.length-1}}function ko(e,t,o,r){let n=Be(t,o,r),{weights:a,lbwe:s,xyzMode:l}=n;return r===S.Unknown&&(r=e==="lora"?S.lora:S.lycoris),{selectedLoraBlockType:r,selectedModelType:o,weights:a,lbwe:s,xyzMode:l}}function Be(e,t,o){let r=e.split(":"),n={};for(let b=0;b<r.length;b++){let f,M;if(r[b].indexOf("=")>=0){let C=r[b].split("=");f=C[0].toLowerCase(),M=C[1]}else f=[P.te,P.unet][b],M=r[b];n[f]=M}let a=[];for(let b of Object.values(K))for(let f of Object.values(J))a.push({modelType:b,loraBlockType:f,presets:$(b,f),masks:V(b,f)});let s=T(m.TENC).default,l,i=T(m.START).default,g=T(m.STOP).default,u=[],c="",h=!1;Object.entries(n).forEach(([b,f])=>{switch(b){case P.lbw:if(f==="XYZ"){h=!0;break}let M=f.split(",");for(let W of a){if(M.length===1)if(f in W.presets)M=W.presets[f].split(",");else continue;if(M.length===W.masks.filter(q=>q==1).length){t=W.modelType,o=W.loraBlockType;let q=0;for(let Ue of W.masks)Ue?(u.push(+M[q]),q++):u.push(0);break}}break;case P.step:let C=f.split("-");i=Math.round(+C[0]),g=Math.round(+C[1]);break;case P.lbwe:c=f;break;case P.te:s=+f;break;case P.unet:l=+f;break;case P.start:i=Math.round(+f);break;case P.stop:g=Math.round(+f);break}});let p=!0;l===void 0&&(l=T(m.UNET).default,p=!1);let w={};if(t!==y.Unknown){let b=we(t);if(u.length===0)for(let f=0;f<b.length;f++)u.push(T(m.LBW).default);u.forEach((f,M)=>{w[b[M]]={initValue:f,value:f,sliderMin:Math.min(f,T(m.LBW).min),sliderMax:Math.max(f,T(m.LBW).max)}})}return{selectedLoraBlockType:o,selectedModelType:t,weights:{[m.TENC]:{initValue:s,value:s,sliderMin:Math.min(s,T(m.TENC).min),sliderMax:Math.max(s,T(m.TENC).max)},[m.UNET]:{initValue:l,value:l,sliderMin:Math.min(l,T(m.UNET).min),sliderMax:Math.max(l,T(m.UNET).max),initCheckState:p,checkState:p},[m.START]:{initValue:i,value:i,sliderMin:Math.min(i,T(m.START).min),sliderMax:Math.max(i,T(m.START).max)},[m.STOP]:{initValue:g,value:g,sliderMin:Math.min(g,T(m.STOP).min),sliderMax:Math.max(g,T(m.STOP).max)},...w},lbwe:c,xyzMode:h}}function xo(e){let t=St(e);return t||{modelId:"",triggerWords:[""],negativeTriggerWords:[""],modelName:"",thumbUrl:be,hasMetadata:!1,description:"",isDescriptionVisible:!1,isTagInsertButtonVisible:!1}}var Ae=null,Ee=null;function Pe(){return Ae&&Ae.abort(),Ae=new AbortController,Ae}function qt(){return Ee&&Ee.abort(),Ee=new AbortController,Ee}async function Ie(e,t,o){let r=await fetch(`/whapi/v1/get_metadata?key=${encodeURIComponent(e)}&force=${t}`,{method:"POST",signal:o});if(!r.ok)throw new Error(`Failed to set up API endpoints. Please reload the page.: ${r.status}`);return await r.json()}async function Kt(e,t){let o=await fetch(`/whapi/v1/get_preview_info?key=${encodeURIComponent(e)}`,{method:"POST",signal:t});if(!o.ok)throw new Error(`Failed to set up API endpoints. Please reload the page.: ${o.status}`);return{...await o.json(),isDescriptionVisible:!1,isTagInsertButtonVisible:!0}}function F(e,t){let o={...e},r=[];return t.forEach(n=>{n.forEach(a=>{xe(a).forEach(l=>{r.includes(l)||r.push(l)})})}),r.forEach(n=>{o[n]||(o[n]={initValue:T(m.LBW).default,value:T(m.LBW).default,sliderMin:T(m.LBW).min,sliderMax:T(m.LBW).max})}),o}var Ke=globalThis,We=Ke.trustedTypes,Jt=We?We.createPolicy("lit-html",{createHTML:e=>e}):void 0,no="$lit$",R=`lit$${Math.random().toFixed(9).slice(2)}$`,so="?"+R,vo=`<${so}>`,Z=document,de=()=>Z.createComment(""),pe=e=>e===null||typeof e!="object"&&typeof e!="function",Je=Array.isArray,Lo=e=>Je(e)||typeof e?.[Symbol.iterator]=="function",Xe=`[
|
| 3 |
+
\f\r]`,ge=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,Qt=/-->/g,eo=/>/g,Y=RegExp(`>|${Xe}(?:([^\\s"'>=/]+)(${Xe}*=${Xe}*(?:[^
|
| 4 |
+
\f\r"'\`<>=]|("|')|))|$)`,"g"),to=/'/g,oo=/"/g,ao=/^(?:script|style|textarea|title)$/i,Qe=e=>(t,...o)=>({_$litType$:e,strings:t,values:o}),k=Qe(1),rr=Qe(2),nr=Qe(3),he=Symbol.for("lit-noChange"),x=Symbol.for("lit-nothing"),ro=new WeakMap,j=Z.createTreeWalker(Z,129);function io(e,t){if(!Je(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return Jt!==void 0?Jt.createHTML(t):t}var Co=(e,t)=>{let o=e.length-1,r=[],n,a=t===2?"<svg>":t===3?"<math>":"",s=ge;for(let l=0;l<o;l++){let i=e[l],g,u,c=-1,h=0;for(;h<i.length&&(s.lastIndex=h,u=s.exec(i),u!==null);)h=s.lastIndex,s===ge?u[1]==="!--"?s=Qt:u[1]!==void 0?s=eo:u[2]!==void 0?(ao.test(u[2])&&(n=RegExp("</"+u[2],"g")),s=Y):u[3]!==void 0&&(s=Y):s===Y?u[0]===">"?(s=n??ge,c=-1):u[1]===void 0?c=-2:(c=s.lastIndex-u[2].length,g=u[1],s=u[3]===void 0?Y:u[3]==='"'?oo:to):s===oo||s===to?s=Y:s===Qt||s===eo?s=ge:(s=Y,n=void 0);let p=s===Y&&e[l+1].startsWith("/>")?" ":"";a+=s===ge?i+vo:c>=0?(r.push(g),i.slice(0,c)+no+i.slice(c)+R+p):i+R+(c===-2?l:p)}return[io(e,a+(e[o]||"<?>")+(t===2?"</svg>":t===3?"</math>":"")),r]},ue=class e{constructor({strings:t,_$litType$:o},r){let n;this.parts=[];let a=0,s=0,l=t.length-1,i=this.parts,[g,u]=Co(t,o);if(this.el=e.createElement(g,r),j.currentNode=this.el.content,o===2||o===3){let c=this.el.content.firstChild;c.replaceWith(...c.childNodes)}for(;(n=j.nextNode())!==null&&i.length<l;){if(n.nodeType===1){if(n.hasAttributes())for(let c of n.getAttributeNames())if(c.endsWith(no)){let h=u[s++],p=n.getAttribute(c).split(R),w=/([.?@])?(.*)/.exec(h);i.push({type:1,index:a,name:w[2],strings:p,ctor:w[1]==="."?Ye:w[1]==="?"?je:w[1]==="@"?Ze:re}),n.removeAttribute(c)}else c.startsWith(R)&&(i.push({type:6,index:a}),n.removeAttribute(c));if(ao.test(n.tagName)){let c=n.textContent.split(R),h=c.length-1;if(h>0){n.textContent=We?We.emptyScript:"";for(let p=0;p<h;p++)n.append(c[p],de()),j.nextNode(),i.push({type:2,index:++a});n.append(c[h],de())}}}else if(n.nodeType===8)if(n.data===so)i.push({type:2,index:a});else{let c=-1;for(;(c=n.data.indexOf(R,c+1))!==-1;)i.push({type:7,index:a}),c+=R.length-1}a++}}static createElement(t,o){let r=Z.createElement("template");return r.innerHTML=t,r}};function oe(e,t,o=e,r){if(t===he)return t;let n=r!==void 0?o._$Co?.[r]:o._$Cl,a=pe(t)?void 0:t._$litDirective$;return n?.constructor!==a&&(n?._$AO?.(!1),a===void 0?n=void 0:(n=new a(e),n._$AT(e,o,r)),r!==void 0?(o._$Co??=[])[r]=n:o._$Cl=n),n!==void 0&&(t=oe(e,n._$AS(e,t.values),n,r)),t}var Fe=class{constructor(t,o){this._$AV=[],this._$AN=void 0,this._$AD=t,this._$AM=o}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(t){let{el:{content:o},parts:r}=this._$AD,n=(t?.creationScope??Z).importNode(o,!0);j.currentNode=n;let a=j.nextNode(),s=0,l=0,i=r[0];for(;i!==void 0;){if(s===i.index){let g;i.type===2?g=new fe(a,a.nextSibling,this,t):i.type===1?g=new i.ctor(a,i.name,i.strings,this,t):i.type===6&&(g=new qe(a,this,t)),this._$AV.push(g),i=r[++l]}s!==i?.index&&(a=j.nextNode(),s++)}return j.currentNode=Z,n}p(t){let o=0;for(let r of this._$AV)r!==void 0&&(r.strings!==void 0?(r._$AI(t,r,o),o+=r.strings.length-2):r._$AI(t[o])),o++}},fe=class e{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(t,o,r,n){this.type=2,this._$AH=x,this._$AN=void 0,this._$AA=t,this._$AB=o,this._$AM=r,this.options=n,this._$Cv=n?.isConnected??!0}get parentNode(){let t=this._$AA.parentNode,o=this._$AM;return o!==void 0&&t?.nodeType===11&&(t=o.parentNode),t}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(t,o=this){t=oe(this,t,o),pe(t)?t===x||t==null||t===""?(this._$AH!==x&&this._$AR(),this._$AH=x):t!==this._$AH&&t!==he&&this._(t):t._$litType$!==void 0?this.$(t):t.nodeType!==void 0?this.T(t):Lo(t)?this.k(t):this._(t)}O(t){return this._$AA.parentNode.insertBefore(t,this._$AB)}T(t){this._$AH!==t&&(this._$AR(),this._$AH=this.O(t))}_(t){this._$AH!==x&&pe(this._$AH)?this._$AA.nextSibling.data=t:this.T(Z.createTextNode(t)),this._$AH=t}$(t){let{values:o,_$litType$:r}=t,n=typeof r=="number"?this._$AC(t):(r.el===void 0&&(r.el=ue.createElement(io(r.h,r.h[0]),this.options)),r);if(this._$AH?._$AD===n)this._$AH.p(o);else{let a=new Fe(n,this),s=a.u(this.options);a.p(o),this.T(s),this._$AH=a}}_$AC(t){let o=ro.get(t.strings);return o===void 0&&ro.set(t.strings,o=new ue(t)),o}k(t){Je(this._$AH)||(this._$AH=[],this._$AR());let o=this._$AH,r,n=0;for(let a of t)n===o.length?o.push(r=new e(this.O(de()),this.O(de()),this,this.options)):r=o[n],r._$AI(a),n++;n<o.length&&(this._$AR(r&&r._$AB.nextSibling,n),o.length=n)}_$AR(t=this._$AA.nextSibling,o){for(this._$AP?.(!1,!0,o);t!==this._$AB;){let r=t.nextSibling;t.remove(),t=r}}setConnected(t){this._$AM===void 0&&(this._$Cv=t,this._$AP?.(t))}},re=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(t,o,r,n,a){this.type=1,this._$AH=x,this._$AN=void 0,this.element=t,this.name=o,this._$AM=n,this.options=a,r.length>2||r[0]!==""||r[1]!==""?(this._$AH=Array(r.length-1).fill(new String),this.strings=r):this._$AH=x}_$AI(t,o=this,r,n){let a=this.strings,s=!1;if(a===void 0)t=oe(this,t,o,0),s=!pe(t)||t!==this._$AH&&t!==he,s&&(this._$AH=t);else{let l=t,i,g;for(t=a[0],i=0;i<a.length-1;i++)g=oe(this,l[r+i],o,i),g===he&&(g=this._$AH[i]),s||=!pe(g)||g!==this._$AH[i],g===x?t=x:t!==x&&(t+=(g??"")+a[i+1]),this._$AH[i]=g}s&&!n&&this.j(t)}j(t){t===x?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,t??"")}},Ye=class extends re{constructor(){super(...arguments),this.type=3}j(t){this.element[this.name]=t===x?void 0:t}},je=class extends re{constructor(){super(...arguments),this.type=4}j(t){this.element.toggleAttribute(this.name,!!t&&t!==x)}},Ze=class extends re{constructor(t,o,r,n,a){super(t,o,r,n,a),this.type=5}_$AI(t,o=this){if((t=oe(this,t,o,0)??x)===he)return;let r=this._$AH,n=t===x&&r!==x||t.capture!==r.capture||t.once!==r.once||t.passive!==r.passive,a=t!==x&&(r===x||n);n&&this.element.removeEventListener(this.name,this,r),a&&this.element.addEventListener(this.name,this,t),this._$AH=t}handleEvent(t){typeof this._$AH=="function"?this._$AH.call(this.options?.host??this.element,t):this._$AH.handleEvent(t)}},qe=class{constructor(t,o,r){this.element=t,this.type=6,this._$AN=void 0,this._$AM=o,this.options=r}get _$AU(){return this._$AM._$AU}_$AI(t){oe(this,t)}};var $o=Ke.litHtmlPolyfillSupport;$o?.(ue,fe),(Ke.litHtmlVersions??=[]).push("3.3.1");var et=(e,t,o)=>{let r=o?.renderBefore??t,n=r._$litPart$;if(n===void 0){let a=o?.renderBefore??null;r._$litPart$=n=new fe(t.insertBefore(de(),a),a,void 0,o??{})}return n._$AI(e),n};function me(e,t){let o=L(),r=T(e)??T(m.LBW),n=u=>{let c=u.target;$e({block:e,value:o.weightState.weights[e].value,checkState:c.checked})},a=u=>{let h=+u.target.value/100,p=o.weightState.weights[e].checkState;p!==void 0&&(p=!0),$e({block:e,value:h,checkState:p})},s=u=>{let h=+u.target.value,p=o.weightState.weights[e].checkState;p!==void 0&&(p=!0),$e({block:e,value:h,checkState:p})},l=t[e],i=u=>{let c=u.target,h=+c.value/100,w=c.parentElement.querySelector("input.value");w&&(w.value=h.toString())},g=u=>{let c=u.target,p=c.parentElement.querySelector("input.slider");if(!p)return;let w=+c.value;if(isNaN(w))return;let b=+p.min,f=+p.max,M=Math.round(w*100);M<b&&(b=M),M>f&&(f=M),b!==+p.min&&(p.min=String(b)),f!==+p.max&&(p.max=String(f)),p.value=String(M)};return k`
|
| 5 |
+
<span>
|
| 6 |
+
<label>${e}</label>
|
| 7 |
+
${o.weightState.weights[e].checkState!==void 0?k`<input type="checkbox" .checked=${o.weightState.weights[e].checkState} @input=${n} />`:""}
|
| 8 |
+
</span>
|
| 9 |
+
<div class="f f-c g-4">
|
| 10 |
+
<input
|
| 11 |
+
class="slider"
|
| 12 |
+
type="range"
|
| 13 |
+
.min=${Math.round(l.sliderMin*100)}
|
| 14 |
+
.max=${Math.round(l.sliderMax*100)}
|
| 15 |
+
.step=${Math.round(r.step*100)}
|
| 16 |
+
.value=${Math.round(l.value*100)}
|
| 17 |
+
?disabled=${I(o,e)}
|
| 18 |
+
@input=${i}
|
| 19 |
+
@change=${a}
|
| 20 |
+
/>
|
| 21 |
+
<input
|
| 22 |
+
class="value"
|
| 23 |
+
type="number"
|
| 24 |
+
.value=${+l.value}
|
| 25 |
+
.step=${r.step}
|
| 26 |
+
?disabled=${I(o,e)}
|
| 27 |
+
@input=${g}
|
| 28 |
+
@change=${s}
|
| 29 |
+
/>
|
| 30 |
+
</div>
|
| 31 |
+
`}var tt=!1,ot={x:0,y:0};function lo(e,t){let o=L(),r=O(o.loraName),n=c=>{tt=!0;let h=document.getElementById("weight-helper");if(!h)return;let p=h.getBoundingClientRect();ot={x:c.clientX-p.left,y:c.clientY-p.top},document.addEventListener("mousemove",a),document.addEventListener("mouseup",s)},a=c=>{if(!tt)return;let h=c.clientX-ot.x+window.scrollX,p=c.clientY-ot.y+window.scrollY;Ht(p,h)},s=()=>{tt=!1,document.removeEventListener("mousemove",a),document.removeEventListener("mouseup",s)},l=()=>{Ft()},i=()=>{Gt()},g=()=>{let c=Math.max(0,o.historyIndex-1),h=r[c],p=Be(h.loraParams,h.selectedModelType,h.selectedLoraBlockType),w=U(o.loraName,h.loraParams),b=G(h.selectedModelType,h.selectedLoraBlockType,o.lbwPresets,p.weights);Ge({historyIndex:c,weightState:p,locked:w,preset:b})},u=()=>{let c=Math.min(r.length-1,o.historyIndex+1),h=r[c],p=Be(h.loraParams,h.selectedModelType,h.selectedLoraBlockType),w=U(o.loraName,h.loraParams),b=G(h.selectedModelType,h.selectedLoraBlockType,o.lbwPresets,p.weights);Ge({historyIndex:c,weightState:p,locked:w,preset:b})};return k`
|
| 32 |
+
<header @mousedown=${n}>
|
| 33 |
+
<span>
|
| 34 |
+
<span class="lock ${t?"like":"unlike"}" style="${D(!o.weightState.xyzMode)}" @click=${i}>
|
| 35 |
+
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
| 36 |
+
<path
|
| 37 |
+
d="M21,10H19V7A7,7,0,0,0,5,7v3H3a1,1,0,0,0-1,1v9a4,4,0,0,0,4,4H18a4,4,0,0,0,4-4V11A1,1,0,0,0,21,10Zm-9,9.5A2.5,2.5,0,1,1,14.5,17,2.5,2.5,0,0,1,12,19.5ZM15,10H9V7a3,3,0,0,1,6,0v3Z"
|
| 38 |
+
></path>
|
| 39 |
+
</svg>
|
| 40 |
+
</span>
|
| 41 |
+
<label class="name">${e}</label>
|
| 42 |
+
</span>
|
| 43 |
+
<div class="history" style="${z(r.length>1)}">
|
| 44 |
+
<a class="icon" @click=${l}>clear</a>
|
| 45 |
+
<div class="page">
|
| 46 |
+
<a class="icon" @click=${g} style="${D(o.historyIndex>0)}"><</a>
|
| 47 |
+
<label class="page-label">${o.historyIndex+1}/${r.length}</label>
|
| 48 |
+
<a class="icon" @click=${u} style="${D(o.historyIndex<r.length-1)}">></a>
|
| 49 |
+
</div>
|
| 50 |
+
</div>
|
| 51 |
+
</header>
|
| 52 |
+
`}function co(){let e=L(),{blockGroups:t,weightState:o}=e,{selectedModelType:r,selectedLoraBlockType:n}=o,a=new Set(Q(r,n));return k`
|
| 53 |
+
<div class="lbw-column">
|
| 54 |
+
${t.map(s=>k`
|
| 55 |
+
<div class="f col g-2" style="display: flex">
|
| 56 |
+
${s.map(l=>k`
|
| 57 |
+
<div class="border p f g-2 col">
|
| 58 |
+
${xe(l).map(i=>a.has(i)&&o.weights[i]?k` <div class="f g-2">${me(i,o.weights)}</div> `:"")}
|
| 59 |
+
</div>
|
| 60 |
+
`)}
|
| 61 |
+
</div>
|
| 62 |
+
`)}
|
| 63 |
+
</div>
|
| 64 |
+
`}function go(){let e=L(),t=a=>{let l=a.target.value,i=N(e.weightState.selectedModelType,l),g=$(e.weightState.selectedModelType,l),u=F(e.weightState.weights,i);Ve({selectedLoraBlockType:l,selectedModelType:e.weightState.selectedModelType,blockGroups:i,lbwPresets:g,weights:u})},o=a=>{let l=a.target.value,i=N(l,e.weightState.selectedLoraBlockType),g=$(l,e.weightState.selectedLoraBlockType),u=F(e.weightState.weights,i);Ve({selectedModelType:l,selectedLoraBlockType:e.weightState.selectedLoraBlockType,blockGroups:i,lbwPresets:g,weights:u})},r=()=>{Rt()},n=a=>{let s=a.target,l=s.value;if(l===""&&(l=e.preset,l===""))return;let i=$(e.weightState.selectedModelType,e.weightState.selectedLoraBlockType)[l].split(",").map(c=>+c),g={};Q(e.weightState.selectedModelType,e.weightState.selectedLoraBlockType).forEach((c,h)=>{g[c]={initValue:e.weightState.weights[c].initValue,value:i[h],sliderMin:Math.min(i[h],e.weightState.weights[c].sliderMin),sliderMax:Math.max(i[h],e.weightState.weights[c].sliderMax)}}),Vt({weights:g,preset:s.value})};return k`
|
| 65 |
+
<div class="f g-2 f-end">
|
| 66 |
+
<select .value="${e.weightState.selectedModelType}" style="flex-grow: 1" ?disabled="${I(e)}" @change="${o}">
|
| 67 |
+
${Object.entries(K).map(([a,s])=>k` <option value="${s}">${a}</option> `)}
|
| 68 |
+
</select>
|
| 69 |
+
<select
|
| 70 |
+
.value="${e.weightState.selectedLoraBlockType}"
|
| 71 |
+
style="flex-grow: 1"
|
| 72 |
+
?disabled="${I(e)}"
|
| 73 |
+
@change="${t}"
|
| 74 |
+
>
|
| 75 |
+
${Object.entries(J).map(([a,s])=>k` <option value="${s}">${a}</option> `)}
|
| 76 |
+
</select>
|
| 77 |
+
</div>
|
| 78 |
+
<div class="f g-2 f-end">
|
| 79 |
+
<select .value="${e.preset}" style="flex-grow: 1" ?disabled="${I(e)}" @change="${n}">
|
| 80 |
+
<option value=""></option>
|
| 81 |
+
${Object.keys(e.lbwPresets).map(a=>k` <option value="${a}">${a}</option> `)}
|
| 82 |
+
</select>
|
| 83 |
+
<div class="p f g-2 f-end">
|
| 84 |
+
<div class="f g-2 f-end">
|
| 85 |
+
<input
|
| 86 |
+
id="wh:xyz"
|
| 87 |
+
value="XYZ"
|
| 88 |
+
type="checkbox"
|
| 89 |
+
.checked="${e.weightState.xyzMode}"
|
| 90 |
+
?disabled="${I(e)}"
|
| 91 |
+
@change="${r}"
|
| 92 |
+
/>
|
| 93 |
+
<label class="radio-label" for="wh:xyz">
|
| 94 |
+
${it(e.weightState.selectedModelType,e.weightState.selectedLoraBlockType)}
|
| 95 |
+
</label>
|
| 96 |
+
</div>
|
| 97 |
+
</div>
|
| 98 |
+
</div>
|
| 99 |
+
`}function po(){let e=L(),t=()=>{if(e.uiState.isWaiting)return;let o=Pe();ce(!0),Ie(e.loraName,!0,o.signal).then(r=>{let n=e.weightState.selectedModelType;(!n||n===y.Unknown)&&(n=r.modelType??y.Unknown);let a=N(n,e.weightState.selectedLoraBlockType),s=F(e.weightState.weights,a);Ce({algorithm:r.algorithm||"Unknown",modelType:r.modelType||"Unknown",baseModel:r.baseModel||"Unknown",selectedModelType:n,usingBlocks:r.usingBlocks,blockGroups:a,lbwPresets:$(n,e.weightState.selectedLoraBlockType),weights:s})}).catch(r=>{r.name!=="AbortError"&&(console.error("Error fetching metadata:",r),ce(!1))})};return k`
|
| 100 |
+
<span class="metadata">
|
| 101 |
+
<span>
|
| 102 |
+
<span>Model</span>
|
| 103 |
+
<span>${e.metadataState?.modelType||"Unknown"}</span>
|
| 104 |
+
</span>
|
| 105 |
+
<span>
|
| 106 |
+
<span>Base</span>
|
| 107 |
+
<span>${e.metadataState?.baseModel||"Unknown"}</span>
|
| 108 |
+
</span>
|
| 109 |
+
<a class="icon mini svg" @click=${t}>
|
| 110 |
+
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 492 492">
|
| 111 |
+
<g>
|
| 112 |
+
<path
|
| 113 |
+
d="M484.08,296.216c-5.1-5.128-11.848-7.936-19.032-7.936H330.516c-14.828,0-26.86,12.036-26.86,26.868v22.796c0,7.168,2.784,14.064,7.884,19.16c5.092,5.088,11.82,8.052,18.976,8.052H366.1c-31.544,30.752-74.928,50.08-120.388,50.08c-71.832,0-136.028-45.596-159.744-113.344c-5.392-15.404-19.972-25.784-36.28-25.784c-4.316,0-8.592,0.708-12.7,2.144c-9.692,3.396-17.48,10.352-21.932,19.596c-4.456,9.248-5.04,19.684-1.648,29.368c34.496,98.54,127.692,164.74,232.144,164.74c64.132,0,123.448-23.948,169.572-67.656v25.22c0,14.836,12.384,27.108,27.224,27.108h22.792c14.84,0,26.86-12.272,26.86-27.108V315.24C492,308.056,489.2,301.304,484.08,296.216z"
|
| 114 |
+
></path>
|
| 115 |
+
</g>
|
| 116 |
+
<g>
|
| 117 |
+
<path
|
| 118 |
+
d="M478.628,164.78C444.132,66.244,350.916,0.044,246.464,0.044c-64.136,0-123.464,23.952-169.588,67.66v-25.22c0-14.832-12.344-27.112-27.184-27.112H26.896C12.06,15.372,0,27.652,0,42.484V176.76c0,7.18,2.824,13.868,7.944,18.964c5.096,5.128,11.86,7.932,19.044,7.932l-0.08,0.06h134.604c14.84,0,26.832-12.028,26.832-26.86v-22.8c0-14.836-11.992-27.216-26.832-27.216h-35.576c31.544-30.752,74.932-50.076,120.392-50.076c71.832,0,136.024,45.596,159.74,113.348c5.392,15.404,19.968,25.78,36.28,25.78c4.32,0,8.588-0.704,12.7-2.144c9.696-3.396,17.48-10.348,21.932-19.596C481.432,184.9,482.02,174.472,478.628,164.78z"
|
| 119 |
+
></path>
|
| 120 |
+
</g>
|
| 121 |
+
</svg>
|
| 122 |
+
</a>
|
| 123 |
+
</span>
|
| 124 |
+
`}function ho(e){let t=i=>{extraNetworksRequestMetadata(i,"lora",e.modelName)},o=i=>{extraNetworksEditUserMetadata(i,se(),"lora",e.modelName)},r=()=>{window.open(`https://civitai.com/models/${e.modelId}`,"_blank")},n=()=>{ze(!0)},a=()=>{ze(!1)},s=()=>{let i=se(),g=document.querySelector(`#${i}_prompt textarea`),u=document.querySelector(`#${i}_neg_prompt textarea`),c=ae();if(c===u||c!==g&&(g=c,u=void 0),!opts.weight_helper_using_execCommand)(()=>{let p=[{triggerWords:e.triggerWords,textarea:g},{triggerWords:e.negativeTriggerWords,textarea:u}];for(let{triggerWords:w,textarea:b}of p)if(w.length>0&&b){let f=w.join(", ");b.value&&(f=", "+f),b.value+=f}})();else{let h=()=>{let p=[{triggerWords:e.triggerWords,textarea:g},{triggerWords:e.negativeTriggerWords,textarea:u}];for(let{triggerWords:w,textarea:b}of p)if(w.length>0&&b){let f=w.join(", ");b.value&&(f=", "+f),b.focus();let M=b.value.length;b.setSelectionRange(M,M),document.execCommand("insertText",!1,f)}};Te(()=>{h()})}jt()},l=["preview-pane","card"];switch(opts.weight_helper_preview_position){case"Bottom Right":l.push("preview-bottom-right");break;case"Top Left":l.push("preview-top-left");break;case"Bottom Left":l.push("preview-bottom-left");break;default:l.push("preview-top-right");break}return k`
|
| 125 |
+
<div class="${l.join(" ")}" data-name="${e.modelName}">
|
| 126 |
+
<img class="preview" src="${e.thumbUrl}" style="height: ${opts.weight_helper_preview_height}px" />
|
| 127 |
+
<div class="action-row button-top" style="${D(!e.isDescriptionVisible)}">
|
| 128 |
+
${e.modelName&&e.hasMetadata&&typeof extraNetworksRequestMetadata=="function"?k` <div class="metadata-btn card-btn" title="Show internal metadata" @click="${t}"></div> `:""}
|
| 129 |
+
${e.modelName&&typeof extraNetworksEditUserMetadata=="function"?k` <div class="edit-btn card-btn" title="Edit metadata" @click="${o}"></div> `:""}
|
| 130 |
+
${e.modelId?k` <div class="civitai-btn card-btn" title="Open civitai" @click="${r}"></div> `:""}
|
| 131 |
+
${e.triggerWords.length>0||e.negativeTriggerWords.length>0?k`
|
| 132 |
+
<div
|
| 133 |
+
class="add-trigger-btn card-btn"
|
| 134 |
+
title="Add trigger words"
|
| 135 |
+
@click="${s}"
|
| 136 |
+
style="${z(e.isTagInsertButtonVisible)}"
|
| 137 |
+
></div>
|
| 138 |
+
`:""}
|
| 139 |
+
</div>
|
| 140 |
+
|
| 141 |
+
${e.description?k`
|
| 142 |
+
<div class="action-row button-bottom" style="${D(!e.isDescriptionVisible)}">
|
| 143 |
+
<div class="card-btn note-btn" @click="${n}"></div>
|
| 144 |
+
</div>
|
| 145 |
+
<textarea class="description" style="${D(e.isDescriptionVisible)}">
|
| 146 |
+
${e.description}
|
| 147 |
+
</textarea
|
| 148 |
+
>
|
| 149 |
+
<div
|
| 150 |
+
class="card-btn description-close-btn"
|
| 151 |
+
style="${D(e.isDescriptionVisible)}"
|
| 152 |
+
@click="${a}"
|
| 153 |
+
></div>
|
| 154 |
+
`:""}
|
| 155 |
+
</div>
|
| 156 |
+
`}var uo=!1;function fo(){let e=L(),{uiState:t,weightState:o,lock:r}=e;uo||(_o(),uo=!0);let n=`transform: scale(${t.scale}); ${z(t.isVisible)}`;return k`
|
| 157 |
+
<div id="weight-helper" class="${e.uiState.isWaiting?"waiting":""}" style="${n}">
|
| 158 |
+
${lo(e.loraName,r)} ${po()}
|
| 159 |
+
${o.weights[m.TENC]&&k`<section class="border p">${me(m.TENC,o.weights)}</section>`}
|
| 160 |
+
${[m.UNET,m.START,m.STOP].filter(a=>!!o.weights[a]).map(a=>k`<section
|
| 161 |
+
class="border p"
|
| 162 |
+
style="${z(!t.isMoreButtonVisible||o.weights[a].initCheckState||o.weights[a].initValue!==T(a).default)}"
|
| 163 |
+
>
|
| 164 |
+
${me(a,o.weights)}
|
| 165 |
+
</section>`)}
|
| 166 |
+
|
| 167 |
+
<button style="${t.isMoreButtonVisible?"":"display: none"}" ?disabled="${I(e)}" @click="${()=>Xt()}">
|
| 168 |
+
show more options
|
| 169 |
+
</button>
|
| 170 |
+
|
| 171 |
+
<section class="border p">
|
| 172 |
+
<label>LBW</label>
|
| 173 |
+
<div class="f col g-4 w-fill">${go()} ${co()}</div>
|
| 174 |
+
</section>
|
| 175 |
+
|
| 176 |
+
${e.previewState.modelName?ho(e.previewState):""}
|
| 177 |
+
</div>
|
| 178 |
+
`}function _o(){let e=()=>{let s=L();s.uiState.isVisible&&(Se(),le(s))},t=s=>{let l=L();if(l.uiState.isVisible){s.preventDefault(),Se(),le(l);return}let i=It(s);i&&(s.preventDefault(),Bo(i))},o=s=>{let l=L();if(l.uiState.isVisible){let i=document.getElementById("weight-helper");if(!i)return;let g=se();if(s){let u=s.target;if(i.contains(u)||u.id===`${g}_token_button`||u.id===`${g}_lora_edit_user_metadata_button`||u.className==="global-popup-close")return;if(u.id.indexOf("_interrupt")>0){Se();return}}Se(),le(l)}},r=s=>{if(s.key==="Escape"){let l=L();Ao(l)}};gradioApp().querySelectorAll("button:is([id*='_generate'])").forEach(s=>{s.addEventListener("click",e,!0)}),gradioApp().querySelectorAll("*:is([id*='_toprow'] [id*='_prompt'], .prompt) textarea").forEach(s=>{s.addEventListener("contextmenu",t)}),document.addEventListener("click",o),document.addEventListener("keyup",r)}var mo=!1;function So(e){et(fo(),e),mo||(Wt(()=>{et(fo(),e)}),Nt(t=>{let o=e.querySelector("#weight-helper");o&&(o.style.top=t.top+"px",o.style.left=t.left+"px")}),mo=!0)}function Bo(e){let{tabId:t,textarea:o,selectionStart:r,selectionEnd:n,namespace:a,loraName:s,loraParams:l,top:i,left:g}=e;Lt(t),Ct(o),$t(r),Me(n),Bt(o.value.substring(r,n)),At(t),Et(t),T(m.START).max=ke(),T(m.STOP).max=ke(),T(m.STOP).default=ke();let u=document.getElementById("weight-helper").getBoundingClientRect(),c=window.innerHeight-u.bottom,h=i;c<0&&(u.top<0?h=window.scrollY:h+=c);let p=Zt(a,s,l);Dt(p);let w=document.getElementById("weight-helper");if(w&&(w.style.top=h+"px",w.style.left=g+"px"),!p.metadataState){let b=Pe();Ie(s,!1,b.signal).then(f=>{let M=p.weightState.selectedModelType;(!M||M===y.Unknown)&&(M=f.modelType??y.Unknown);let C=p.weightState.selectedLoraBlockType,W=N(M,C),q=F(p.weightState.weights,W),Ue={...p.weightState,selectedModelType:M,selectedLoraBlockType:C},bo=_(p.loraName,Ue).loraParams;p.weightState.xyzMode||(ee(s,{loraParams:bo,selectedLoraBlockType:C,selectedModelType:M}),zt(O(s).length-1)),Ce({algorithm:f.algorithm||"Unknown",modelType:f.modelType||"Unknown",baseModel:f.baseModel||"Unknown",selectedModelType:M,usingBlocks:f.usingBlocks,blockGroups:W,lbwPresets:$(M,p.weightState.selectedLoraBlockType),weights:q})}).catch(f=>{f.name!=="AbortError"&&(console.error("Error fetching metadata:",f),ce(!1))})}if(!p.previewState.modelId){let b=qt();Kt(s,b.signal).then(async f=>{f.thumbUrl!==be&&(f.thumbUrl=f.thumbUrl),bt(s,f),Yt(f)}).catch(f=>{f.name!=="AbortError"&&console.error("Error fetching metadata:",f)})}}function Se(){let e=_e();Ot(e)}function Ao(e){opts.weight_helper_using_execCommand||le(e,!0),Se()}var Ne,Eo=new Promise(e=>{Ne=e});pt();onUiLoaded(()=>{if(!gradioApp().querySelector("#lbw_ratiospreset"))return;let o=[...getComputedStyle(document.documentElement).getPropertyValue("--body-text-color").trim().slice(1).match(/.{1,2}/g).map(r=>parseInt(r,16)),.3];document.documentElement.style.setProperty("--weight-helper-shadow",`rgba(${o.join(",")})`),document.documentElement.style.setProperty("--weight-helper-slider_size",String(opts.weight_helper_slider_length)),Eo.then(()=>{let r=document.createElement("div");r.id="weight-helper-container",gradioApp().appendChild(r),at(),Ut(_e()),So(r)})});onOptionsChanged(()=>{Ne&&(Ne(!0),Ne=null)});})();
|
| 179 |
+
/*! Bundled license information:
|
| 180 |
+
|
| 181 |
+
lit-html/lit-html.js:
|
| 182 |
+
(**
|
| 183 |
+
* @license
|
| 184 |
+
* Copyright 2017 Google LLC
|
| 185 |
+
* SPDX-License-Identifier: BSD-3-Clause
|
| 186 |
+
*)
|
| 187 |
+
*/
|
| 188 |
+
//# sourceMappingURL=weight_helper.js.map
|
sd-webui-weight-helper-main/javascript/weight_helper.js.map
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
sd-webui-weight-helper-main/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "sd-webui-weight-helper",
|
| 3 |
+
"version": "1.3.3",
|
| 4 |
+
"description": "",
|
| 5 |
+
"scripts": {
|
| 6 |
+
"type-check": "tsc --noEmit",
|
| 7 |
+
"lint": "eslint src/**/*.ts",
|
| 8 |
+
"lint-fix": "eslint src/**/*.ts --fix",
|
| 9 |
+
"format": "prettier --write 'src/**/*.{ts,js,json,css,md}'",
|
| 10 |
+
"build": "node esbuild.config.mjs",
|
| 11 |
+
"build-min-map": "node esbuild.config.mjs --minify --sourcemap"
|
| 12 |
+
},
|
| 13 |
+
"keywords": [],
|
| 14 |
+
"author": "",
|
| 15 |
+
"devDependencies": {
|
| 16 |
+
"@eslint/js": "^9.34.0",
|
| 17 |
+
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
| 18 |
+
"@typescript-eslint/eslint-plugin": "^8.41.0",
|
| 19 |
+
"@typescript-eslint/parser": "^8.41.0",
|
| 20 |
+
"esbuild": "^0.25.9",
|
| 21 |
+
"eslint": "^9.34.0",
|
| 22 |
+
"eslint-config-prettier": "^10.1.8",
|
| 23 |
+
"eslint-plugin-prettier": "^5.5.4",
|
| 24 |
+
"globals": "^16.3.0",
|
| 25 |
+
"prettier": "^3.6.2",
|
| 26 |
+
"typescript": "^5.9.2",
|
| 27 |
+
"typescript-eslint": "^8.41.0"
|
| 28 |
+
},
|
| 29 |
+
"dependencies": {
|
| 30 |
+
"lit-html": "^3.3.1"
|
| 31 |
+
}
|
| 32 |
+
}
|
sd-webui-weight-helper-main/scripts/__pycache__/weight_helper.cpython-310.pyc
ADDED
|
Binary file (4.17 kB). View file
|
|
|
sd-webui-weight-helper-main/scripts/__pycache__/weight_helper.cpython-313.pyc
ADDED
|
Binary file (6.87 kB). View file
|
|
|
sd-webui-weight-helper-main/scripts/__pycache__/wh_analyzer.cpython-310.pyc
ADDED
|
Binary file (6.53 kB). View file
|
|
|
sd-webui-weight-helper-main/scripts/__pycache__/wh_analyzer.cpython-313.pyc
ADDED
|
Binary file (11.3 kB). View file
|
|
|
sd-webui-weight-helper-main/scripts/__pycache__/wh_api.cpython-310.pyc
ADDED
|
Binary file (4.23 kB). View file
|
|
|
sd-webui-weight-helper-main/scripts/__pycache__/wh_api.cpython-313.pyc
ADDED
|
Binary file (7.43 kB). View file
|
|
|
sd-webui-weight-helper-main/scripts/__pycache__/wh_const.cpython-310.pyc
ADDED
|
Binary file (502 Bytes). View file
|
|
|
sd-webui-weight-helper-main/scripts/__pycache__/wh_const.cpython-313.pyc
ADDED
|
Binary file (570 Bytes). View file
|
|
|
sd-webui-weight-helper-main/scripts/__pycache__/wh_env.cpython-310.pyc
ADDED
|
Binary file (912 Bytes). View file
|
|
|
sd-webui-weight-helper-main/scripts/__pycache__/wh_env.cpython-313.pyc
ADDED
|
Binary file (1.56 kB). View file
|
|
|
sd-webui-weight-helper-main/scripts/__pycache__/wh_utils.cpython-310.pyc
ADDED
|
Binary file (2.05 kB). View file
|
|
|
sd-webui-weight-helper-main/scripts/__pycache__/wh_utils.cpython-313.pyc
ADDED
|
Binary file (3.64 kB). View file
|
|
|
sd-webui-weight-helper-main/scripts/weight_helper.py
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
import gradio as gr
|
| 5 |
+
from fastapi import FastAPI
|
| 6 |
+
from modules import script_callbacks, shared
|
| 7 |
+
|
| 8 |
+
_THIS_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 9 |
+
if _THIS_DIR not in sys.path:
|
| 10 |
+
sys.path.insert(0, _THIS_DIR)
|
| 11 |
+
|
| 12 |
+
import wh_api as api
|
| 13 |
+
import wh_const as const
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def on_app_started(_: gr.Blocks, app: FastAPI):
|
| 17 |
+
@app.post(const.API_PREFIX + "/get_metadata")
|
| 18 |
+
async def _(key: str, force: bool = False):
|
| 19 |
+
return api.get_metadata(key, force)
|
| 20 |
+
|
| 21 |
+
@app.post(const.API_PREFIX + "/get_preview_info")
|
| 22 |
+
async def _(key: str):
|
| 23 |
+
return api.get_preview_info(key)
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def on_ui_settings():
|
| 27 |
+
"""
|
| 28 |
+
Set up the UI settings for the weight helper by adding options to the shared configuration.
|
| 29 |
+
"""
|
| 30 |
+
section = ('weight_helper', 'Weight Helper')
|
| 31 |
+
|
| 32 |
+
shared.options_templates.update(shared.options_section(section, {
|
| 33 |
+
'weight_helper_enabled': shared.OptionInfo(True, 'Enabled'),
|
| 34 |
+
'weight_helper_context_menu_scale': shared.OptionInfo(0.8, "Context Menu Scale", gr.Number),
|
| 35 |
+
'weight_helper_using_execCommand': shared.OptionInfo(True, "Use the deprecated execCommand function to replace text.").info(
|
| 36 |
+
"You can use 'undo' to revert the text to its previous state, "
|
| 37 |
+
"but it will no longer be updated in real-time."),
|
| 38 |
+
|
| 39 |
+
"weight_helper_slider_length": shared.OptionInfo(160, "Slider Length (px)", gr.Number),
|
| 40 |
+
|
| 41 |
+
"weight_helper_TEnc_min": shared.OptionInfo(0, "TEnc Min Value", gr.Number),
|
| 42 |
+
"weight_helper_TEnc_max": shared.OptionInfo(1, "TEnc Max Value", gr.Number),
|
| 43 |
+
"weight_helper_TEnc_step": shared.OptionInfo(0.05, "TEnc Step", gr.Number),
|
| 44 |
+
|
| 45 |
+
"weight_helper_UNet_min": shared.OptionInfo(0, "UNet Min Value", gr.Number),
|
| 46 |
+
"weight_helper_UNet_max": shared.OptionInfo(1, "UNet Max Value", gr.Number),
|
| 47 |
+
"weight_helper_UNet_step": shared.OptionInfo(0.05, "UNet Step", gr.Number),
|
| 48 |
+
|
| 49 |
+
"weight_helper_LBW_min": shared.OptionInfo(0, "LBW (LoRA Block Weight) Min Value", gr.Number),
|
| 50 |
+
"weight_helper_LBW_max": shared.OptionInfo(1, "LBW (LoRA Block Weight) Max Value", gr.Number),
|
| 51 |
+
"weight_helper_LBW_step": shared.OptionInfo(0.05, "LBW (LoRA Block Weight) Step", gr.Number),
|
| 52 |
+
|
| 53 |
+
'weight_helper_show_preview': shared.OptionInfo(True, 'Show Preview'),
|
| 54 |
+
"weight_helper_preview_height": shared.OptionInfo(400, "Preview Height (px)", gr.Number),
|
| 55 |
+
"weight_helper_preview_position": shared.OptionInfo("Top Right", "Preview Position", gr.Radio, {
|
| 56 |
+
"choices": ["Top Right", "Bottom Right", "Top Left", "Bottom Left"]
|
| 57 |
+
}),
|
| 58 |
+
|
| 59 |
+
'weight_helper_parse_lora_blocks': shared.OptionInfo(True, '[experimental] Parse LoRA file to get block information'),
|
| 60 |
+
|
| 61 |
+
"weight_helper_LBW_SD_lora_block_points": shared.OptionInfo(
|
| 62 |
+
"BASE, IN01-IN04, IN05-IN08, M00, OUT03-OUT06, OUT07-OUT11",
|
| 63 |
+
"Advanced option - LoRA-LierLa block points")
|
| 64 |
+
.info("default: BASE, IN01-IN04, IN05-IN08, M00, OUT03-OUT06, OUT07-OUT11"),
|
| 65 |
+
"weight_helper_LBW_SD_lycoris_block_points": shared.OptionInfo(
|
| 66 |
+
"BASE, IN00-IN05, IN06-IN11, M00, OUT00-OUT05, OUT06-OUT11",
|
| 67 |
+
"Advanced option - LyCORIS or LoRA-C3Lier block points")
|
| 68 |
+
.info("default: BASE, IN00-IN05, IN06-IN11, M00, OUT00-OUT05, OUT06-OUT11"),
|
| 69 |
+
|
| 70 |
+
"weight_helper_LBW_SDXL_lora_block_points": shared.OptionInfo(
|
| 71 |
+
"BASE, IN04-IN08, M00, OUT00-OUT05",
|
| 72 |
+
"Advanced option - SDXL LoRA-LierLa block points")
|
| 73 |
+
.info("default: BASE, IN04-IN08, M00, OUT00-OUT05"),
|
| 74 |
+
"weight_helper_LBW_SDXL_lycoris_block_points": shared.OptionInfo(
|
| 75 |
+
"BASE, IN00-IN03, IN04-IN08, M00, OUT00-OUT03, OUT04-OUT08",
|
| 76 |
+
"Advanced option - SDXL LyCORIS or LoRA-C3Lier block points")
|
| 77 |
+
.info("default: BASE, IN00-IN03, IN04-IN08, M00, OUT00-OUT03, OUT04-OUT08"),
|
| 78 |
+
|
| 79 |
+
"weight_helper_LBW_Flux_lora_block_points": shared.OptionInfo(
|
| 80 |
+
"CLIP, T5, IN, OUT, D00-D18, S00-S18, S19-S37",
|
| 81 |
+
"Advanced option - Flux LoRA-LierLa block points")
|
| 82 |
+
.info("default: CLIP, T5, IN, OUT, D00-D18, S00-S18, S19-S37"),
|
| 83 |
+
"weight_helper_LBW_Flux_lycoris_block_points": shared.OptionInfo(
|
| 84 |
+
"CLIP, T5, IN, OUT, D00-D18, S00-S18, S19-S37",
|
| 85 |
+
"Advanced option - Flux LyCORIS or LoRA-C3Lier block points")
|
| 86 |
+
.info("default: CLIP, T5, IN, OUT, D00-D18, S00-S18, S19-S37"),
|
| 87 |
+
}))
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
script_callbacks.on_ui_settings(on_ui_settings)
|
| 91 |
+
script_callbacks.on_app_started(on_app_started)
|
sd-webui-weight-helper-main/scripts/wh_analyzer.py
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import pickle
|
| 3 |
+
import re
|
| 4 |
+
import sys
|
| 5 |
+
from typing import Optional
|
| 6 |
+
|
| 7 |
+
_THIS_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 8 |
+
if _THIS_DIR not in sys.path:
|
| 9 |
+
sys.path.insert(0, _THIS_DIR)
|
| 10 |
+
|
| 11 |
+
import wh_const as const
|
| 12 |
+
import wh_env as env
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def get_model_type(lora) -> Optional[str]:
|
| 16 |
+
if env.ui_type == const.UI_TYPE.A1111:
|
| 17 |
+
sd_version: Optional[str] = lora.sd_version.name
|
| 18 |
+
if sd_version and env.network:
|
| 19 |
+
if sd_version == env.network.SdVersion.SD1.name or sd_version == env.network.SdVersion.SD2.name:
|
| 20 |
+
return "SD"
|
| 21 |
+
elif sd_version == env.network.SdVersion.SDXL.name:
|
| 22 |
+
return "SDXL"
|
| 23 |
+
return sd_version
|
| 24 |
+
elif env.ui_type == const.UI_TYPE.NEW_FORGE:
|
| 25 |
+
base_model_version: Optional[str] = lora.metadata.get("ss_base_model_version")
|
| 26 |
+
if base_model_version:
|
| 27 |
+
base_model_version = base_model_version.lower()
|
| 28 |
+
if "sd_" in base_model_version:
|
| 29 |
+
return "SD"
|
| 30 |
+
if "sd3" in base_model_version:
|
| 31 |
+
return "SD"
|
| 32 |
+
elif "sdxl" in base_model_version:
|
| 33 |
+
return "SDXL"
|
| 34 |
+
elif "flux" in base_model_version:
|
| 35 |
+
return "Flux"
|
| 36 |
+
return None
|
| 37 |
+
return None
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def get_algorithm(metadata, ss_network_args) -> Optional[str]:
|
| 41 |
+
ss_network_module = metadata.get("ss_network_module")
|
| 42 |
+
if not ss_network_module or ss_network_module == "Unknown":
|
| 43 |
+
return None
|
| 44 |
+
|
| 45 |
+
conv_dim = float(ss_network_args.get("conv_dim", "-1"))
|
| 46 |
+
conv_alpha = float(ss_network_args.get("conv_alpha", "-1"))
|
| 47 |
+
algo = ss_network_args.get("algo", "").lower()
|
| 48 |
+
unit = ss_network_args.get("unit", "").lower()
|
| 49 |
+
dora_wd = ss_network_args.get("dora_wd", False)
|
| 50 |
+
|
| 51 |
+
if ss_network_module.find("locon.locon_kohya") >= 0:
|
| 52 |
+
return "LoCon"
|
| 53 |
+
|
| 54 |
+
elif ss_network_module.find("lycoris.kohya") >= 0:
|
| 55 |
+
algoName = ""
|
| 56 |
+
if dora_wd:
|
| 57 |
+
algoName = "(DoRA)"
|
| 58 |
+
elif algo == "lora":
|
| 59 |
+
algoName += "(LoCon)"
|
| 60 |
+
elif algo == "locon":
|
| 61 |
+
if unit:
|
| 62 |
+
algoName += "(DyLoRA)"
|
| 63 |
+
else:
|
| 64 |
+
algoName += "(LoCon)"
|
| 65 |
+
elif algo == "loha":
|
| 66 |
+
algoName += "(LoHa)"
|
| 67 |
+
elif algo == "lokr":
|
| 68 |
+
algoName += "(Lokr)"
|
| 69 |
+
elif algo == "ia3":
|
| 70 |
+
algoName += "(IA3)"
|
| 71 |
+
elif algo == "full":
|
| 72 |
+
algoName += "(Full)"
|
| 73 |
+
elif algo == "glora":
|
| 74 |
+
algoName += "(GLoRA)"
|
| 75 |
+
|
| 76 |
+
return f"LyCORIS{algoName}"
|
| 77 |
+
|
| 78 |
+
elif ss_network_module.find("networks.dylora") >= 0:
|
| 79 |
+
if algo == "dylora" and unit:
|
| 80 |
+
if conv_dim > 0 or conv_alpha > 0:
|
| 81 |
+
return "DyLoRA(C3Lier)"
|
| 82 |
+
return "DyLoRA(LierLa)"
|
| 83 |
+
|
| 84 |
+
elif conv_dim > 0 or conv_alpha > 0:
|
| 85 |
+
return "LoRA(C3Lier)"
|
| 86 |
+
|
| 87 |
+
else:
|
| 88 |
+
return "LoRA(LierLa)"
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
def get_blocks(lora_on_disk, force):
|
| 92 |
+
baseKeys = __get_lora_state_keys(lora_on_disk.filename, force)
|
| 93 |
+
|
| 94 |
+
def formatForDownMidUp(key):
|
| 95 |
+
blocks = ["BASE"]
|
| 96 |
+
for key in keys:
|
| 97 |
+
k, v = key.split("_", 1)
|
| 98 |
+
if k == "down":
|
| 99 |
+
k = "IN"
|
| 100 |
+
v1, v2 = v.split("_")
|
| 101 |
+
val = int(v1) * 3 + int(v2) + 1
|
| 102 |
+
elif k == "mid":
|
| 103 |
+
blocks.append("M00")
|
| 104 |
+
continue
|
| 105 |
+
elif k == "up":
|
| 106 |
+
k = "OUT"
|
| 107 |
+
v1, v2 = v.split("_")
|
| 108 |
+
val = int(v1) * 3 + int(v2)
|
| 109 |
+
blocks.append(f'{k}{int(val):02}')
|
| 110 |
+
return sorted(blocks)
|
| 111 |
+
|
| 112 |
+
def formatForInputMiddleOutput(key):
|
| 113 |
+
blocks = ["BASE"]
|
| 114 |
+
for key in keys:
|
| 115 |
+
k, v = key.split("_")
|
| 116 |
+
if k == "input":
|
| 117 |
+
k = "IN"
|
| 118 |
+
elif k == "middle":
|
| 119 |
+
blocks.append("M00")
|
| 120 |
+
continue
|
| 121 |
+
elif k == "output":
|
| 122 |
+
k = "OUT"
|
| 123 |
+
blocks.append(f'{k}{int(v):02}')
|
| 124 |
+
return sorted(blocks)
|
| 125 |
+
|
| 126 |
+
def formatForFlux(key):
|
| 127 |
+
blocks = ["CLIP", "T5", "IN", "OUT"]
|
| 128 |
+
for key in keys:
|
| 129 |
+
k, v = key.split("_")
|
| 130 |
+
v = int(v)
|
| 131 |
+
if k == "double":
|
| 132 |
+
k = "D"
|
| 133 |
+
if k == "single":
|
| 134 |
+
k = "S"
|
| 135 |
+
blocks.append(f'{k}{v:02}')
|
| 136 |
+
return sorted(blocks)
|
| 137 |
+
|
| 138 |
+
keys = [k for k in baseKeys if k.find("lora_unet") == 0]
|
| 139 |
+
if len(keys) > 0:
|
| 140 |
+
keys_tmp = [k for k in keys if re.match("^lora_unet_(down|mid|up)_", k)]
|
| 141 |
+
if len(keys_tmp) > 0:
|
| 142 |
+
keys = set(["_".join([k.split("_")[2], k.split("_")[4] + "_" + k.split("_")[6]]) for k in keys_tmp if "transformer_blocks" in k])
|
| 143 |
+
return formatForDownMidUp(keys)
|
| 144 |
+
|
| 145 |
+
keys_tmp = [k for k in keys if re.match("^lora_unet_(input|middle|output)_", k)]
|
| 146 |
+
if len(keys_tmp) > 0:
|
| 147 |
+
keys = set(["_".join([k.split("_")[2], k.split("_")[4]]) for k in keys_tmp if "transformer_blocks" in k])
|
| 148 |
+
return formatForInputMiddleOutput(keys)
|
| 149 |
+
|
| 150 |
+
keys_tmp = [k for k in keys if re.match("^lora_unet_(single|double)_", k)]
|
| 151 |
+
if len(keys_tmp) > 0:
|
| 152 |
+
keys = set(["_".join([k.split("_")[2], k.split("_")[4]]) for k in keys_tmp])
|
| 153 |
+
return formatForFlux(keys)
|
| 154 |
+
|
| 155 |
+
keys_tmp = [k for k in keys if re.match("^lora_unet_joint_blocks_", k)]
|
| 156 |
+
if len(keys_tmp) > 0:
|
| 157 |
+
# TODO SD3? 38 blocks
|
| 158 |
+
return None
|
| 159 |
+
|
| 160 |
+
keys = [k for k in baseKeys if "transformer_blocks" in k and "attentions" in k]
|
| 161 |
+
if len(keys) > 0:
|
| 162 |
+
# TODO unknown
|
| 163 |
+
keys = set([".".join(k.split(".")[2:6]) for k in keys])
|
| 164 |
+
in_blocks = set([f"{k.split('.')[1]}_{k.split('.')[3]}" for k in keys if "down_block" in k])
|
| 165 |
+
mid_block = set([k.split(".")[2] for k in keys if "mid_block" in k])
|
| 166 |
+
out_blocks = set([f"{k.split('.')[1]}_{k.split('.')[3]}" for k in keys if "up_block" in k])
|
| 167 |
+
keys = list(in_blocks) + list(mid_block) + list(out_blocks)
|
| 168 |
+
return None
|
| 169 |
+
|
| 170 |
+
keys = [k for k in baseKeys if "transformer_blocks" in k and k.find("transformer") == 0]
|
| 171 |
+
if len(keys) > 0:
|
| 172 |
+
keys = set([".".join(k.split(".")[1:3]) for k in keys])
|
| 173 |
+
keys = [k.replace("single_transformer_blocks.", "single_") for k in keys]
|
| 174 |
+
keys = [k.replace("transformer_blocks.", "double_") for k in keys]
|
| 175 |
+
return formatForFlux(keys)
|
| 176 |
+
|
| 177 |
+
return None
|
| 178 |
+
|
| 179 |
+
|
| 180 |
+
def __get_lora_state_keys(filename, force):
|
| 181 |
+
cache_path = f"{os.path.splitext(filename)[0]}.whcache"
|
| 182 |
+
if not force and os.path.exists(cache_path):
|
| 183 |
+
try:
|
| 184 |
+
with open(cache_path, "rb") as f:
|
| 185 |
+
return pickle.load(f)
|
| 186 |
+
except Exception:
|
| 187 |
+
pass
|
| 188 |
+
|
| 189 |
+
lora_sd = env.network_lora.load_lora_state_dict(filename)
|
| 190 |
+
keys = list(lora_sd.keys())
|
| 191 |
+
try:
|
| 192 |
+
with open(cache_path, "wb") as f:
|
| 193 |
+
pickle.dump(keys, f)
|
| 194 |
+
except Exception:
|
| 195 |
+
pass
|
| 196 |
+
return keys
|
sd-webui-weight-helper-main/scripts/wh_api.py
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
import ast
|
| 3 |
+
import json
|
| 4 |
+
import os
|
| 5 |
+
import sys
|
| 6 |
+
from typing import Any, Optional
|
| 7 |
+
|
| 8 |
+
from modules import shared
|
| 9 |
+
|
| 10 |
+
_THIS_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 11 |
+
if _THIS_DIR not in sys.path:
|
| 12 |
+
sys.path.insert(0, _THIS_DIR)
|
| 13 |
+
|
| 14 |
+
import wh_analyzer as analyzer
|
| 15 |
+
import wh_const as const
|
| 16 |
+
import wh_utils as utils
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def get_metadata(key, force) -> dict[str, Optional[str]]:
|
| 20 |
+
ret: dict[str, Optional[str]] = {
|
| 21 |
+
"modelType": None,
|
| 22 |
+
"algorithm": None,
|
| 23 |
+
"baseModel": None,
|
| 24 |
+
"usingBlocks": None
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
lora_on_disk = utils.get_lora_on_disk(key)
|
| 28 |
+
if not lora_on_disk:
|
| 29 |
+
return ret
|
| 30 |
+
|
| 31 |
+
ret["modelType"] = analyzer.get_model_type(lora_on_disk)
|
| 32 |
+
|
| 33 |
+
metadata = lora_on_disk.metadata
|
| 34 |
+
ss_network_args = __get_network_args(lora_on_disk)
|
| 35 |
+
ret["algorithm"] = analyzer.get_algorithm(metadata, ss_network_args)
|
| 36 |
+
|
| 37 |
+
model_path, _ = os.path.splitext(lora_on_disk.filename)
|
| 38 |
+
civitai_info = __find_civitai_info(model_path)
|
| 39 |
+
ret["baseModel"] = civitai_info.get("baseModel", None)
|
| 40 |
+
|
| 41 |
+
if shared.opts.weight_helper_parse_lora_blocks:
|
| 42 |
+
try:
|
| 43 |
+
ret["usingBlocks"] = analyzer.get_blocks(lora_on_disk, force)
|
| 44 |
+
except Exception:
|
| 45 |
+
pass
|
| 46 |
+
return ret
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
def get_preview_info(key):
|
| 50 |
+
ret: dict[str, Optional[bool | str | list[str]]] = {
|
| 51 |
+
"modelId": None,
|
| 52 |
+
"triggerWords": [],
|
| 53 |
+
"negativeTriggerWords": [],
|
| 54 |
+
"modelName": None,
|
| 55 |
+
"thumbUrl": None,
|
| 56 |
+
"hasMetadata": False,
|
| 57 |
+
"description": None,
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
lora_on_disk = utils.get_lora_on_disk(key)
|
| 61 |
+
if lora_on_disk:
|
| 62 |
+
model_path, _ = os.path.splitext(lora_on_disk.filename)
|
| 63 |
+
ret["modelName"] = lora_on_disk.name
|
| 64 |
+
ret["thumbUrl"] = __find_preview(model_path)
|
| 65 |
+
ret["hasMetadata"] = __find_metadata(lora_on_disk)
|
| 66 |
+
ret["description"] = __find_description(model_path)
|
| 67 |
+
|
| 68 |
+
trigger_words = []
|
| 69 |
+
civitai_info = __find_civitai_info(model_path)
|
| 70 |
+
ret["modelId"] = civitai_info.get("modelId", None)
|
| 71 |
+
trigger_words = civitai_info.get("trainedWords", [])
|
| 72 |
+
trigger_words = ",".join(trigger_words).split(",")
|
| 73 |
+
ret["triggerWords"] = [w.strip() for w in trigger_words if w]
|
| 74 |
+
|
| 75 |
+
lora_json = __get_lora_json(model_path)
|
| 76 |
+
|
| 77 |
+
activation_text = lora_json.get("activation text", "")
|
| 78 |
+
if activation_text:
|
| 79 |
+
activation_text = activation_text.split(",")
|
| 80 |
+
activation_text = [w.strip() for w in activation_text if w]
|
| 81 |
+
ret["triggerWords"] = activation_text
|
| 82 |
+
|
| 83 |
+
negative_text = lora_json.get("negative text", "")
|
| 84 |
+
if negative_text:
|
| 85 |
+
negative_text = negative_text.split(",")
|
| 86 |
+
negative_text = [w.strip() for w in negative_text if w]
|
| 87 |
+
ret["negativeTriggerWords"] = negative_text
|
| 88 |
+
|
| 89 |
+
json_description = lora_json.get("description", None)
|
| 90 |
+
if json_description:
|
| 91 |
+
ret["description"] = json_description
|
| 92 |
+
|
| 93 |
+
return ret
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
def __get_network_args(lora) -> dict[str, Any]:
|
| 97 |
+
metadata = lora.metadata
|
| 98 |
+
ss_network_args = metadata.get("ss_network_args", {})
|
| 99 |
+
if type(ss_network_args) is str:
|
| 100 |
+
try:
|
| 101 |
+
ss_network_args = ast.literal_eval(ss_network_args)
|
| 102 |
+
except Exception:
|
| 103 |
+
ss_network_args = {}
|
| 104 |
+
return ss_network_args
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
def __get_lora_json(path) -> dict[str, Any]:
|
| 108 |
+
if path:
|
| 109 |
+
lora_json = f"{path}.json"
|
| 110 |
+
if os.path.exists(lora_json):
|
| 111 |
+
try:
|
| 112 |
+
with open(lora_json, "r", encoding="utf-8", errors="replace") as f:
|
| 113 |
+
return json.load(f)
|
| 114 |
+
except OSError:
|
| 115 |
+
pass
|
| 116 |
+
return {}
|
| 117 |
+
|
| 118 |
+
|
| 119 |
+
def __find_preview(path) -> str:
|
| 120 |
+
if path:
|
| 121 |
+
potential_files = sum([[f"{path}.{ext}", f"{path}.preview.{ext}"] for ext in const.ALLOWED_PREVIEW_EXTENSIONS], [])
|
| 122 |
+
for file in potential_files:
|
| 123 |
+
if os.path.exists(file):
|
| 124 |
+
dpi_scale = 1.5
|
| 125 |
+
return utils.resize_to_base64(file, int(shared.opts.weight_helper_preview_height * dpi_scale))
|
| 126 |
+
return "./file=html/card-no-preview.png"
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
def __find_metadata(lora) -> bool:
|
| 130 |
+
return len(lora.metadata) > 0 if lora else False
|
| 131 |
+
|
| 132 |
+
|
| 133 |
+
def __find_description(path) -> Optional[str]:
|
| 134 |
+
if path:
|
| 135 |
+
for file in [f"{path}.txt", f"{path}.description.txt"]:
|
| 136 |
+
if os.path.exists(file):
|
| 137 |
+
try:
|
| 138 |
+
with open(file, "r", encoding="utf-8", errors="replace") as f:
|
| 139 |
+
return f.read()
|
| 140 |
+
except OSError:
|
| 141 |
+
pass
|
| 142 |
+
return None
|
| 143 |
+
|
| 144 |
+
|
| 145 |
+
def __find_civitai_info(path) -> dict[str, Any]:
|
| 146 |
+
if path:
|
| 147 |
+
civitai_info = f"{path}.civitai.info"
|
| 148 |
+
if os.path.exists(civitai_info):
|
| 149 |
+
try:
|
| 150 |
+
with open(civitai_info, "r", encoding="utf-8", errors="replace") as f:
|
| 151 |
+
return json.load(f)
|
| 152 |
+
except OSError:
|
| 153 |
+
pass
|
| 154 |
+
return {}
|
sd-webui-weight-helper-main/scripts/wh_const.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import enum
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
API_PREFIX = "/whapi/v1"
|
| 5 |
+
ALLOWED_PREVIEW_EXTENSIONS = ["png", "jpg", "jpeg", "webp", "gif"]
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class UI_TYPE(enum.Enum):
|
| 9 |
+
Unknown = 1
|
| 10 |
+
A1111 = 2
|
| 11 |
+
NEW_FORGE = 3
|
sd-webui-weight-helper-main/scripts/wh_env.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
import importlib
|
| 3 |
+
import os
|
| 4 |
+
import sys
|
| 5 |
+
|
| 6 |
+
_THIS_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 7 |
+
if _THIS_DIR not in sys.path:
|
| 8 |
+
sys.path.insert(0, _THIS_DIR)
|
| 9 |
+
|
| 10 |
+
import wh_const as const
|
| 11 |
+
|
| 12 |
+
network = None
|
| 13 |
+
network_lora = None
|
| 14 |
+
ui_type = None
|
| 15 |
+
|
| 16 |
+
try:
|
| 17 |
+
from modules_forge import forge_version # noqa: F401
|
| 18 |
+
ui_type = const.UI_TYPE.NEW_FORGE
|
| 19 |
+
except ImportError:
|
| 20 |
+
ui_type = const.UI_TYPE.A1111
|
| 21 |
+
|
| 22 |
+
try:
|
| 23 |
+
network = importlib.import_module("extensions-builtin.sd_forge_lora.network")
|
| 24 |
+
network_lora = importlib.import_module("extensions-builtin.sd_forge_lora.ui_extra_networks_lora").networks
|
| 25 |
+
except Exception:
|
| 26 |
+
pass
|
| 27 |
+
|
| 28 |
+
if network_lora is None:
|
| 29 |
+
try:
|
| 30 |
+
network = importlib.import_module("extensions-builtin.Lora.network")
|
| 31 |
+
network_lora = importlib.import_module("extensions-builtin.Lora.ui_extra_networks_lora").networks
|
| 32 |
+
except Exception:
|
| 33 |
+
pass
|
| 34 |
+
|
| 35 |
+
if network_lora is None:
|
| 36 |
+
ui_type = const.UI_TYPE.Unknown
|
sd-webui-weight-helper-main/scripts/wh_utils.py
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import base64
|
| 2 |
+
import os
|
| 3 |
+
import sys
|
| 4 |
+
import urllib
|
| 5 |
+
|
| 6 |
+
import cv2
|
| 7 |
+
import numpy as np
|
| 8 |
+
|
| 9 |
+
_THIS_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 10 |
+
if _THIS_DIR not in sys.path:
|
| 11 |
+
sys.path.insert(0, _THIS_DIR)
|
| 12 |
+
|
| 13 |
+
import wh_env as env
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def get_lora_on_disk(key):
|
| 17 |
+
if env.network_lora:
|
| 18 |
+
lora_on_disk = env.network_lora.available_network_aliases.get(key)
|
| 19 |
+
if not lora_on_disk:
|
| 20 |
+
# sdnext
|
| 21 |
+
lora_on_disk = next((v for v in env.network_lora.available_network_aliases.values() if v.alias == key), None)
|
| 22 |
+
return lora_on_disk
|
| 23 |
+
return None
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def imread_unicode(path):
|
| 27 |
+
try:
|
| 28 |
+
with open(path, 'rb') as f:
|
| 29 |
+
data = np.frombuffer(f.read(), np.uint8)
|
| 30 |
+
img = cv2.imdecode(data, cv2.IMREAD_UNCHANGED)
|
| 31 |
+
return img
|
| 32 |
+
except Exception as e:
|
| 33 |
+
print(f"imread_unicode error: {e}")
|
| 34 |
+
return None
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def resize_to_base64(input_path, target_height):
|
| 38 |
+
output_format = '.webp'
|
| 39 |
+
quality = 85
|
| 40 |
+
|
| 41 |
+
img = imread_unicode(input_path)
|
| 42 |
+
|
| 43 |
+
h, w = img.shape[:2]
|
| 44 |
+
if h < target_height:
|
| 45 |
+
quoted_filename = urllib.parse.quote(input_path.replace('\\', '/'))
|
| 46 |
+
return f"./sd_extra_networks/thumb?filename={quoted_filename}"
|
| 47 |
+
|
| 48 |
+
scale = target_height / h
|
| 49 |
+
target_size = (int(w * scale), target_height)
|
| 50 |
+
|
| 51 |
+
resized = cv2.resize(img, target_size, interpolation=cv2.INTER_AREA)
|
| 52 |
+
|
| 53 |
+
sharpen_kernel = np.array([
|
| 54 |
+
[0, -0.2, 0],
|
| 55 |
+
[-0.2, 1.8, -0.2],
|
| 56 |
+
[0, -0.2, 0]
|
| 57 |
+
])
|
| 58 |
+
sharpened = cv2.filter2D(resized, -1, sharpen_kernel)
|
| 59 |
+
success, buffer = cv2.imencode(output_format, sharpened, [cv2.IMWRITE_WEBP_QUALITY, quality])
|
| 60 |
+
if not success:
|
| 61 |
+
quoted_filename = urllib.parse.quote(input_path.replace('\\', '/'))
|
| 62 |
+
return f"./sd_extra_networks/thumb?filename={quoted_filename}"
|
| 63 |
+
|
| 64 |
+
base64_str = base64.b64encode(buffer).decode('utf-8')
|
| 65 |
+
return f'data:image/webp;base64,{base64_str}'
|
sd-webui-weight-helper-main/src/components/sections/common-section.ts
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import * as configManager from '@/shared/manager/config-manager';
|
| 2 |
+
import * as globalState from '@/shared/state/global-weight-helper-state';
|
| 3 |
+
import { WeightControllerTypes } from '@/shared/types/lora-types';
|
| 4 |
+
import { disabled } from '@/shared/utils/helper-utils';
|
| 5 |
+
|
| 6 |
+
import { TemplateResult, html } from 'lit-html';
|
| 7 |
+
|
| 8 |
+
/**
|
| 9 |
+
* WeightController component provides UI controls for adjusting weight values.
|
| 10 |
+
* Displays a label, optional checkbox, slider, and number input for a weight parameter.
|
| 11 |
+
* @param label - The identifier for the weight block.
|
| 12 |
+
* @param values - The record of all weight values.
|
| 13 |
+
* @returns The WeightController template.
|
| 14 |
+
*/
|
| 15 |
+
export function createWeightController(label: string, values: Record<string, globalState.WeightControlState>): TemplateResult {
|
| 16 |
+
const state = globalState.getGlobalState();
|
| 17 |
+
const config = configManager.getWeightControllerConfig(label) ?? configManager.getWeightControllerConfig(WeightControllerTypes.LBW);
|
| 18 |
+
|
| 19 |
+
/**
|
| 20 |
+
* Handles the change event for the weight checkbox.
|
| 21 |
+
* Updates the check state for the weight block.
|
| 22 |
+
* @param e - The input change event.
|
| 23 |
+
*/
|
| 24 |
+
const handleChangeWeightCheck = (e: Event) => {
|
| 25 |
+
const target = e.target as HTMLInputElement;
|
| 26 |
+
globalState.setWeight({
|
| 27 |
+
block: label,
|
| 28 |
+
value: state.weightState.weights[label].value,
|
| 29 |
+
checkState: target.checked,
|
| 30 |
+
});
|
| 31 |
+
};
|
| 32 |
+
|
| 33 |
+
/**
|
| 34 |
+
* Handles the change event for the weight slider.
|
| 35 |
+
* Updates the value and check state for the weight block.
|
| 36 |
+
* @param e - The input change event.
|
| 37 |
+
*/
|
| 38 |
+
const handleChangeWeightSlider = (e: Event) => {
|
| 39 |
+
const target = e.target as HTMLInputElement;
|
| 40 |
+
const value = +target.value / 100;
|
| 41 |
+
let checkState = state.weightState.weights[label].checkState;
|
| 42 |
+
if (checkState !== undefined) {
|
| 43 |
+
checkState = true;
|
| 44 |
+
}
|
| 45 |
+
globalState.setWeight({
|
| 46 |
+
block: label,
|
| 47 |
+
value: value,
|
| 48 |
+
checkState: checkState,
|
| 49 |
+
});
|
| 50 |
+
};
|
| 51 |
+
|
| 52 |
+
/**
|
| 53 |
+
* Handles the change event for the weight number input.
|
| 54 |
+
* Updates the value and check state for the weight block.
|
| 55 |
+
* @param e - The input change event.
|
| 56 |
+
*/
|
| 57 |
+
const handleChangeWeightNumber = (e: Event) => {
|
| 58 |
+
const target = e.target as HTMLInputElement;
|
| 59 |
+
const value = +target.value;
|
| 60 |
+
let checkState = state.weightState.weights[label].checkState;
|
| 61 |
+
if (checkState !== undefined) {
|
| 62 |
+
checkState = true;
|
| 63 |
+
}
|
| 64 |
+
globalState.setWeight({
|
| 65 |
+
block: label,
|
| 66 |
+
value: value,
|
| 67 |
+
checkState: checkState,
|
| 68 |
+
});
|
| 69 |
+
};
|
| 70 |
+
|
| 71 |
+
const weightController = values[label];
|
| 72 |
+
|
| 73 |
+
/**
|
| 74 |
+
* Live-sync handler for slider @input (does not commit state yet).
|
| 75 |
+
* Mirrors the slider value (scaled back to original 0-? range) into the numeric input
|
| 76 |
+
* so the user sees real-time feedback while dragging before the @change event fires.
|
| 77 |
+
*/
|
| 78 |
+
const immediateSliderInput = (e: Event) => {
|
| 79 |
+
const target = e.target as HTMLInputElement;
|
| 80 |
+
const raw = +target.value / 100;
|
| 81 |
+
const wrapper = target.parentElement as HTMLElement;
|
| 82 |
+
const numberInput = wrapper.querySelector('input.value') as HTMLInputElement | null;
|
| 83 |
+
if (numberInput) numberInput.value = raw.toString();
|
| 84 |
+
};
|
| 85 |
+
/**
|
| 86 |
+
* Live-sync handler for number @input.
|
| 87 |
+
* Expands the slider range first when user enters a value outside current min/max
|
| 88 |
+
* (matching the logic used in setWeight) and then updates the slider thumb position.
|
| 89 |
+
* State commit is deferred to the @change handler.
|
| 90 |
+
*/
|
| 91 |
+
const immediateNumberInput = (e: Event) => {
|
| 92 |
+
const target = e.target as HTMLInputElement;
|
| 93 |
+
const wrapper = target.parentElement as HTMLElement;
|
| 94 |
+
const slider = wrapper.querySelector('input.slider') as HTMLInputElement | null;
|
| 95 |
+
if (!slider) return;
|
| 96 |
+
const raw = +target.value;
|
| 97 |
+
if (isNaN(raw)) return; // Unconfirmed / empty input etc.
|
| 98 |
+
let sliderMin = +slider.min; // Scaled (0-100x) current min
|
| 99 |
+
let sliderMax = +slider.max;
|
| 100 |
+
const scaled = Math.round(raw * 100);
|
| 101 |
+
// Expand range first if the input value is outside (same policy as setWeight)
|
| 102 |
+
if (scaled < sliderMin) sliderMin = scaled;
|
| 103 |
+
if (scaled > sliderMax) sliderMax = scaled;
|
| 104 |
+
if (sliderMin !== +slider.min) slider.min = String(sliderMin);
|
| 105 |
+
if (sliderMax !== +slider.max) slider.max = String(sliderMax);
|
| 106 |
+
// Finally assign the value (no clamp needed after expansion)
|
| 107 |
+
slider.value = String(scaled);
|
| 108 |
+
};
|
| 109 |
+
return html`
|
| 110 |
+
<span>
|
| 111 |
+
<label>${label}</label>
|
| 112 |
+
${state.weightState.weights[label].checkState !== undefined
|
| 113 |
+
? html`<input type="checkbox" .checked=${state.weightState.weights[label].checkState} @input=${handleChangeWeightCheck} />`
|
| 114 |
+
: ''}
|
| 115 |
+
</span>
|
| 116 |
+
<div class="f f-c g-4">
|
| 117 |
+
<input
|
| 118 |
+
class="slider"
|
| 119 |
+
type="range"
|
| 120 |
+
.min=${Math.round(weightController.sliderMin * 100)}
|
| 121 |
+
.max=${Math.round(weightController.sliderMax * 100)}
|
| 122 |
+
.step=${Math.round(config.step * 100)}
|
| 123 |
+
.value=${Math.round(weightController.value * 100)}
|
| 124 |
+
?disabled=${disabled(state, label)}
|
| 125 |
+
@input=${immediateSliderInput}
|
| 126 |
+
@change=${handleChangeWeightSlider}
|
| 127 |
+
/>
|
| 128 |
+
<input
|
| 129 |
+
class="value"
|
| 130 |
+
type="number"
|
| 131 |
+
.value=${+weightController.value}
|
| 132 |
+
.step=${config.step}
|
| 133 |
+
?disabled=${disabled(state, label)}
|
| 134 |
+
@input=${immediateNumberInput}
|
| 135 |
+
@change=${handleChangeWeightNumber}
|
| 136 |
+
/>
|
| 137 |
+
</div>
|
| 138 |
+
`;
|
| 139 |
+
}
|
sd-webui-weight-helper-main/src/components/sections/header-section.ts
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import * as historyManager from '@/shared/manager/history-manager';
|
| 2 |
+
import * as globalState from '@/shared/state/global-weight-helper-state';
|
| 3 |
+
import { getPreset } from '@/shared/utils/common-utils';
|
| 4 |
+
import { getDisplayStyle, getVisibilityStyle } from '@/shared/utils/helper-utils';
|
| 5 |
+
import { createLoraParamsState } from '@/shared/utils/state-utils';
|
| 6 |
+
|
| 7 |
+
import { TemplateResult, html } from 'lit-html';
|
| 8 |
+
|
| 9 |
+
// ドラッグ状態を管理するグローバル変数
|
| 10 |
+
let isDragging = false;
|
| 11 |
+
let offset = { x: 0, y: 0 };
|
| 12 |
+
|
| 13 |
+
/**
|
| 14 |
+
* HeaderSection component displays the title bar of the Weight Helper.
|
| 15 |
+
* Provides LoRA name display, lock toggle, and history navigation controls.
|
| 16 |
+
* @param loraName - The name of the LoRA model.
|
| 17 |
+
* @param lock - The current lock status.
|
| 18 |
+
* @returns The HeaderSection template.
|
| 19 |
+
*/
|
| 20 |
+
export function createHeaderSection(loraName: string, lock: boolean): TemplateResult {
|
| 21 |
+
const state = globalState.getGlobalState();
|
| 22 |
+
const histories = historyManager.getHistories(state.loraName);
|
| 23 |
+
|
| 24 |
+
/**
|
| 25 |
+
* Handles the mouse down event for dragging the header.
|
| 26 |
+
* @param e - The mouse event.
|
| 27 |
+
*/
|
| 28 |
+
const handleMouseDown = (e: MouseEvent) => {
|
| 29 |
+
isDragging = true;
|
| 30 |
+
const el = document.getElementById('weight-helper');
|
| 31 |
+
if (!el) return;
|
| 32 |
+
const rect = el.getBoundingClientRect();
|
| 33 |
+
offset = {
|
| 34 |
+
x: e.clientX - rect.left,
|
| 35 |
+
y: e.clientY - rect.top,
|
| 36 |
+
};
|
| 37 |
+
document.addEventListener('mousemove', handleMouseMove);
|
| 38 |
+
document.addEventListener('mouseup', handleMouseUp);
|
| 39 |
+
};
|
| 40 |
+
|
| 41 |
+
/**
|
| 42 |
+
* Handles the mouse move event for dragging the header.
|
| 43 |
+
* Updates the position of the header based on mouse movement.
|
| 44 |
+
* @param e - The mouse event.
|
| 45 |
+
*/
|
| 46 |
+
const handleMouseMove = (e: MouseEvent) => {
|
| 47 |
+
if (!isDragging) return;
|
| 48 |
+
|
| 49 |
+
const x = e.clientX - offset.x + window.scrollX;
|
| 50 |
+
const y = e.clientY - offset.y + window.scrollY;
|
| 51 |
+
|
| 52 |
+
globalState.setPosition(y, x);
|
| 53 |
+
};
|
| 54 |
+
|
| 55 |
+
/**
|
| 56 |
+
* Handles the mouse up event to stop dragging the header.
|
| 57 |
+
* Removes the event listeners for mouse move and mouse up.
|
| 58 |
+
*/
|
| 59 |
+
const handleMouseUp = () => {
|
| 60 |
+
isDragging = false;
|
| 61 |
+
document.removeEventListener('mousemove', handleMouseMove);
|
| 62 |
+
document.removeEventListener('mouseup', handleMouseUp);
|
| 63 |
+
};
|
| 64 |
+
|
| 65 |
+
/**
|
| 66 |
+
* Handles the clear history button click event.
|
| 67 |
+
* Clears the history of the Weight Helper.
|
| 68 |
+
*/
|
| 69 |
+
const handleClearHistory = () => {
|
| 70 |
+
globalState.clearHistory();
|
| 71 |
+
};
|
| 72 |
+
|
| 73 |
+
/**
|
| 74 |
+
* Handles the lock toggle button click event.
|
| 75 |
+
* Toggles the lock status for the current LoRA and loraParams.
|
| 76 |
+
*/
|
| 77 |
+
const handleToggleLockStatus = () => {
|
| 78 |
+
globalState.toggleLockStatus();
|
| 79 |
+
};
|
| 80 |
+
|
| 81 |
+
/**
|
| 82 |
+
* Handles the previous history button click event.
|
| 83 |
+
* Navigates to the previous history state.
|
| 84 |
+
*/
|
| 85 |
+
const handlePrevHistory = () => {
|
| 86 |
+
const newIndex = Math.max(0, state.historyIndex - 1);
|
| 87 |
+
const history = histories[newIndex];
|
| 88 |
+
const loraParams = createLoraParamsState(history.loraParams, history.selectedModelType, history.selectedLoraBlockType);
|
| 89 |
+
const locked = historyManager.isLocked(state.loraName, history.loraParams);
|
| 90 |
+
const preset = getPreset(history.selectedModelType, history.selectedLoraBlockType, state.lbwPresets, loraParams.weights);
|
| 91 |
+
globalState.setHistory({ historyIndex: newIndex, weightState: loraParams, locked: locked, preset: preset });
|
| 92 |
+
};
|
| 93 |
+
|
| 94 |
+
/**
|
| 95 |
+
* Handles the next history button click event.
|
| 96 |
+
* Navigates to the next history state.
|
| 97 |
+
*/
|
| 98 |
+
const handleNextHistory = () => {
|
| 99 |
+
const newIndex = Math.min(histories.length - 1, state.historyIndex + 1);
|
| 100 |
+
const history = histories[newIndex];
|
| 101 |
+
const loraParams = createLoraParamsState(history.loraParams, history.selectedModelType, history.selectedLoraBlockType);
|
| 102 |
+
const locked = historyManager.isLocked(state.loraName, history.loraParams);
|
| 103 |
+
const preset = getPreset(history.selectedModelType, history.selectedLoraBlockType, state.lbwPresets, loraParams.weights);
|
| 104 |
+
globalState.setHistory({ historyIndex: newIndex, weightState: loraParams, locked: locked, preset: preset });
|
| 105 |
+
};
|
| 106 |
+
|
| 107 |
+
return html`
|
| 108 |
+
<header @mousedown=${handleMouseDown}>
|
| 109 |
+
<span>
|
| 110 |
+
<span class="lock ${lock ? 'like' : 'unlike'}" style="${getVisibilityStyle(!state.weightState.xyzMode)}" @click=${handleToggleLockStatus}>
|
| 111 |
+
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
| 112 |
+
<path
|
| 113 |
+
d="M21,10H19V7A7,7,0,0,0,5,7v3H3a1,1,0,0,0-1,1v9a4,4,0,0,0,4,4H18a4,4,0,0,0,4-4V11A1,1,0,0,0,21,10Zm-9,9.5A2.5,2.5,0,1,1,14.5,17,2.5,2.5,0,0,1,12,19.5ZM15,10H9V7a3,3,0,0,1,6,0v3Z"
|
| 114 |
+
></path>
|
| 115 |
+
</svg>
|
| 116 |
+
</span>
|
| 117 |
+
<label class="name">${loraName}</label>
|
| 118 |
+
</span>
|
| 119 |
+
<div class="history" style="${getDisplayStyle(histories.length > 1)}">
|
| 120 |
+
<a class="icon" @click=${handleClearHistory}>clear</a>
|
| 121 |
+
<div class="page">
|
| 122 |
+
<a class="icon" @click=${handlePrevHistory} style="${getVisibilityStyle(state.historyIndex > 0)}"><</a>
|
| 123 |
+
<label class="page-label">${state.historyIndex + 1}/${histories.length}</label>
|
| 124 |
+
<a class="icon" @click=${handleNextHistory} style="${getVisibilityStyle(state.historyIndex < histories.length - 1)}">></a>
|
| 125 |
+
</div>
|
| 126 |
+
</div>
|
| 127 |
+
</header>
|
| 128 |
+
`;
|
| 129 |
+
}
|
sd-webui-weight-helper-main/src/components/sections/lbw-section.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import * as configManager from '@/shared/manager/config-manager';
|
| 2 |
+
import * as globalState from '@/shared/state/global-weight-helper-state';
|
| 3 |
+
import { expandRange } from '@/shared/utils/helper-utils';
|
| 4 |
+
|
| 5 |
+
import { createWeightController } from '@/components/sections/common-section';
|
| 6 |
+
|
| 7 |
+
import { TemplateResult, html } from 'lit-html';
|
| 8 |
+
|
| 9 |
+
/**
|
| 10 |
+
* LbwSection creates weight controllers for LoRA block weights.
|
| 11 |
+
* Shows groups of blocks based on the current model and block type configuration.
|
| 12 |
+
* @returns The LbwSection template.
|
| 13 |
+
*/
|
| 14 |
+
export function createLbwSection(): TemplateResult {
|
| 15 |
+
const state = globalState.getGlobalState();
|
| 16 |
+
const { blockGroups, weightState } = state;
|
| 17 |
+
const { selectedModelType, selectedLoraBlockType } = weightState;
|
| 18 |
+
|
| 19 |
+
const maskedBlockSet = new Set(configManager.getMaskedLbwBlocks(selectedModelType, selectedLoraBlockType));
|
| 20 |
+
|
| 21 |
+
return html`
|
| 22 |
+
<div class="lbw-column">
|
| 23 |
+
${blockGroups.map(
|
| 24 |
+
(cols) => html`
|
| 25 |
+
<div class="f col g-2" style="display: flex">
|
| 26 |
+
${cols.map(
|
| 27 |
+
(group) => html`
|
| 28 |
+
<div class="border p f g-2 col">
|
| 29 |
+
${expandRange(group).map((blockLabel) =>
|
| 30 |
+
maskedBlockSet.has(blockLabel) && weightState.weights[blockLabel]
|
| 31 |
+
? html` <div class="f g-2">${createWeightController(blockLabel, weightState.weights)}</div> `
|
| 32 |
+
: '',
|
| 33 |
+
)}
|
| 34 |
+
</div>
|
| 35 |
+
`,
|
| 36 |
+
)}
|
| 37 |
+
</div>
|
| 38 |
+
`,
|
| 39 |
+
)}
|
| 40 |
+
</div>
|
| 41 |
+
`;
|
| 42 |
+
}
|
sd-webui-weight-helper-main/src/components/sections/lora-settings-section.ts
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { SELECTABLE_LORA_BLOCK_TYPES, SELECTABLE_MODEL_TYPES } from '@/shared/constants/common-const';
|
| 2 |
+
import * as configManager from '@/shared/manager/config-manager';
|
| 3 |
+
import * as currentState from '@/shared/state/current-state';
|
| 4 |
+
import * as globalState from '@/shared/state/global-weight-helper-state';
|
| 5 |
+
import { LoraBlockTypes, ModelTypes } from '@/shared/types/lora-types';
|
| 6 |
+
import { disabled } from '@/shared/utils/helper-utils';
|
| 7 |
+
import { mergeWeightsWithGroups } from '@/shared/utils/weight-utils';
|
| 8 |
+
|
| 9 |
+
import { TemplateResult, html } from 'lit-html';
|
| 10 |
+
|
| 11 |
+
/**
|
| 12 |
+
* LoraSettingsSection creates controls for model settings.
|
| 13 |
+
* Allows selection of model type, LoRA block type, presets, and XYZ mode.
|
| 14 |
+
* @returns The LoraSettingsSection template.
|
| 15 |
+
*/
|
| 16 |
+
export function createLoraSettingsSection(): TemplateResult {
|
| 17 |
+
const state = globalState.getGlobalState();
|
| 18 |
+
|
| 19 |
+
/**
|
| 20 |
+
* Handles the change event for the LoRA block type select box.
|
| 21 |
+
* Updates the block groups, presets, and weights for the selected block type.
|
| 22 |
+
* @param e - The select change event.
|
| 23 |
+
*/
|
| 24 |
+
const handleChangeLoraBlockType = (e: Event) => {
|
| 25 |
+
const target = e.target as HTMLSelectElement;
|
| 26 |
+
const selectedLoraBlockType = target.value as LoraBlockTypes;
|
| 27 |
+
|
| 28 |
+
const blockGroups = configManager.getLbwBlockGroups(state.weightState.selectedModelType, selectedLoraBlockType);
|
| 29 |
+
const lbwPresets = currentState.getLbwPresets(state.weightState.selectedModelType, selectedLoraBlockType);
|
| 30 |
+
const weights = mergeWeightsWithGroups(state.weightState.weights, blockGroups);
|
| 31 |
+
|
| 32 |
+
globalState.setModelInfo({
|
| 33 |
+
selectedLoraBlockType: selectedLoraBlockType,
|
| 34 |
+
selectedModelType: state.weightState.selectedModelType,
|
| 35 |
+
blockGroups: blockGroups,
|
| 36 |
+
lbwPresets: lbwPresets,
|
| 37 |
+
weights: weights,
|
| 38 |
+
});
|
| 39 |
+
};
|
| 40 |
+
|
| 41 |
+
/**
|
| 42 |
+
* Handles the change event for the model type select box.
|
| 43 |
+
* Updates the block groups, presets, and weights for the selected model type.
|
| 44 |
+
* @param e - The select change event.
|
| 45 |
+
*/
|
| 46 |
+
const handleChangeModelType = (e: Event) => {
|
| 47 |
+
const target = e.target as HTMLSelectElement;
|
| 48 |
+
const selectedModelType = target.value as ModelTypes;
|
| 49 |
+
|
| 50 |
+
const blockGroups = configManager.getLbwBlockGroups(selectedModelType, state.weightState.selectedLoraBlockType);
|
| 51 |
+
const lbwPresets = currentState.getLbwPresets(selectedModelType, state.weightState.selectedLoraBlockType);
|
| 52 |
+
const weights = mergeWeightsWithGroups(state.weightState.weights, blockGroups);
|
| 53 |
+
|
| 54 |
+
globalState.setModelInfo({
|
| 55 |
+
selectedModelType: selectedModelType,
|
| 56 |
+
selectedLoraBlockType: state.weightState.selectedLoraBlockType,
|
| 57 |
+
blockGroups: blockGroups,
|
| 58 |
+
lbwPresets: lbwPresets,
|
| 59 |
+
weights: weights,
|
| 60 |
+
});
|
| 61 |
+
};
|
| 62 |
+
|
| 63 |
+
/**
|
| 64 |
+
* Handles the toggle event for the XYZ mode checkbox.
|
| 65 |
+
* Dispatches an action to toggle the XYZ mode state.
|
| 66 |
+
*/
|
| 67 |
+
const handleToggleXyzMode = () => {
|
| 68 |
+
globalState.toggleXyzMode();
|
| 69 |
+
};
|
| 70 |
+
|
| 71 |
+
/**
|
| 72 |
+
* Handles the change event for the preset select box.
|
| 73 |
+
* Applies the selected preset weights to the state.
|
| 74 |
+
* @param e - The select change event.
|
| 75 |
+
*/
|
| 76 |
+
const handleApplyPresetWeights = (e: Event) => {
|
| 77 |
+
const target = e.target as HTMLSelectElement;
|
| 78 |
+
let preset = target.value as string;
|
| 79 |
+
if (preset === '') {
|
| 80 |
+
preset = state.preset;
|
| 81 |
+
if (preset === '') {
|
| 82 |
+
return;
|
| 83 |
+
}
|
| 84 |
+
}
|
| 85 |
+
const presetValues = currentState
|
| 86 |
+
.getLbwPresets(state.weightState.selectedModelType, state.weightState.selectedLoraBlockType)
|
| 87 |
+
[preset].split(',')
|
| 88 |
+
.map((v) => +v);
|
| 89 |
+
|
| 90 |
+
const weights: Record<string, globalState.WeightControlState> = {};
|
| 91 |
+
const maskedLbwBlocks = configManager.getMaskedLbwBlocks(state.weightState.selectedModelType, state.weightState.selectedLoraBlockType);
|
| 92 |
+
maskedLbwBlocks.forEach((block, i) => {
|
| 93 |
+
weights[block] = {
|
| 94 |
+
initValue: state.weightState.weights[block].initValue,
|
| 95 |
+
value: presetValues[i],
|
| 96 |
+
sliderMin: Math.min(presetValues[i], state.weightState.weights[block].sliderMin),
|
| 97 |
+
sliderMax: Math.max(presetValues[i], state.weightState.weights[block].sliderMax),
|
| 98 |
+
};
|
| 99 |
+
});
|
| 100 |
+
|
| 101 |
+
globalState.setPreset({
|
| 102 |
+
weights: weights,
|
| 103 |
+
preset: target.value,
|
| 104 |
+
});
|
| 105 |
+
};
|
| 106 |
+
|
| 107 |
+
return html`
|
| 108 |
+
<div class="f g-2 f-end">
|
| 109 |
+
<select .value="${state.weightState.selectedModelType}" style="flex-grow: 1" ?disabled="${disabled(state)}" @change="${handleChangeModelType}">
|
| 110 |
+
${Object.entries(SELECTABLE_MODEL_TYPES).map(([name, modelType]) => html` <option value="${modelType}">${name}</option> `)}
|
| 111 |
+
</select>
|
| 112 |
+
<select
|
| 113 |
+
.value="${state.weightState.selectedLoraBlockType}"
|
| 114 |
+
style="flex-grow: 1"
|
| 115 |
+
?disabled="${disabled(state)}"
|
| 116 |
+
@change="${handleChangeLoraBlockType}"
|
| 117 |
+
>
|
| 118 |
+
${Object.entries(SELECTABLE_LORA_BLOCK_TYPES).map(([name, loraBlockType]) => html` <option value="${loraBlockType}">${name}</option> `)}
|
| 119 |
+
</select>
|
| 120 |
+
</div>
|
| 121 |
+
<div class="f g-2 f-end">
|
| 122 |
+
<select .value="${state.preset}" style="flex-grow: 1" ?disabled="${disabled(state)}" @change="${handleApplyPresetWeights}">
|
| 123 |
+
<option value=""></option>
|
| 124 |
+
${Object.keys(state.lbwPresets).map((presetName) => html` <option value="${presetName}">${presetName}</option> `)}
|
| 125 |
+
</select>
|
| 126 |
+
<div class="p f g-2 f-end">
|
| 127 |
+
<div class="f g-2 f-end">
|
| 128 |
+
<input
|
| 129 |
+
id="wh:xyz"
|
| 130 |
+
value="XYZ"
|
| 131 |
+
type="checkbox"
|
| 132 |
+
.checked="${state.weightState.xyzMode}"
|
| 133 |
+
?disabled="${disabled(state)}"
|
| 134 |
+
@change="${handleToggleXyzMode}"
|
| 135 |
+
/>
|
| 136 |
+
<label class="radio-label" for="wh:xyz">
|
| 137 |
+
${configManager.getXyzLabel(state.weightState.selectedModelType, state.weightState.selectedLoraBlockType)}
|
| 138 |
+
</label>
|
| 139 |
+
</div>
|
| 140 |
+
</div>
|
| 141 |
+
</div>
|
| 142 |
+
`;
|
| 143 |
+
}
|
sd-webui-weight-helper-main/src/components/sections/metadata-section.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { resetMetadataAbortController } from '@/shared/manager/api-manager';
|
| 2 |
+
import * as configManager from '@/shared/manager/config-manager';
|
| 3 |
+
import * as currentState from '@/shared/state/current-state';
|
| 4 |
+
import * as globalState from '@/shared/state/global-weight-helper-state';
|
| 5 |
+
import { ModelTypes } from '@/shared/types/lora-types';
|
| 6 |
+
import { fetchMetadata } from '@/shared/utils/api-utils';
|
| 7 |
+
import { mergeWeightsWithGroups } from '@/shared/utils/weight-utils';
|
| 8 |
+
|
| 9 |
+
import { TemplateResult, html } from 'lit-html';
|
| 10 |
+
|
| 11 |
+
/**
|
| 12 |
+
* MetadataSection component displays model and base information.
|
| 13 |
+
* Provides a button to fetch and analyze detailed metadata for the current LoRA model.
|
| 14 |
+
* @returns The MetadataSection template.
|
| 15 |
+
*/
|
| 16 |
+
export function createMetadataSection(): TemplateResult {
|
| 17 |
+
const state = globalState.getGlobalState();
|
| 18 |
+
|
| 19 |
+
/**
|
| 20 |
+
* Handles the click event for the analyze full metadata button.
|
| 21 |
+
* Initiates fetching and loading of full metadata for the current LoRA model.
|
| 22 |
+
*/
|
| 23 |
+
const handleAnalyzeFull = () => {
|
| 24 |
+
if (state.uiState.isWaiting) {
|
| 25 |
+
return;
|
| 26 |
+
}
|
| 27 |
+
const metadataAbortController = resetMetadataAbortController();
|
| 28 |
+
|
| 29 |
+
globalState.setWaiting(true);
|
| 30 |
+
|
| 31 |
+
fetchMetadata(state.loraName, true, metadataAbortController.signal)
|
| 32 |
+
.then((result) => {
|
| 33 |
+
let selectedModelType = state.weightState.selectedModelType;
|
| 34 |
+
if (!selectedModelType || selectedModelType === ModelTypes.Unknown) {
|
| 35 |
+
selectedModelType = result.modelType ?? ModelTypes.Unknown;
|
| 36 |
+
}
|
| 37 |
+
const blockGroups = configManager.getLbwBlockGroups(selectedModelType, state.weightState.selectedLoraBlockType);
|
| 38 |
+
const weights = mergeWeightsWithGroups(state.weightState.weights, blockGroups);
|
| 39 |
+
globalState.loadMetadata({
|
| 40 |
+
algorithm: result.algorithm || 'Unknown',
|
| 41 |
+
modelType: result.modelType || 'Unknown',
|
| 42 |
+
baseModel: result.baseModel || 'Unknown',
|
| 43 |
+
selectedModelType: selectedModelType,
|
| 44 |
+
usingBlocks: result.usingBlocks,
|
| 45 |
+
blockGroups: blockGroups,
|
| 46 |
+
lbwPresets: currentState.getLbwPresets(selectedModelType, state.weightState.selectedLoraBlockType),
|
| 47 |
+
weights: weights,
|
| 48 |
+
});
|
| 49 |
+
})
|
| 50 |
+
.catch((error) => {
|
| 51 |
+
if (error.name !== 'AbortError') {
|
| 52 |
+
console.error('Error fetching metadata:', error);
|
| 53 |
+
globalState.setWaiting(false);
|
| 54 |
+
}
|
| 55 |
+
});
|
| 56 |
+
};
|
| 57 |
+
|
| 58 |
+
return html`
|
| 59 |
+
<span class="metadata">
|
| 60 |
+
<span>
|
| 61 |
+
<span>Model</span>
|
| 62 |
+
<span>${state.metadataState?.modelType || 'Unknown'}</span>
|
| 63 |
+
</span>
|
| 64 |
+
<span>
|
| 65 |
+
<span>Base</span>
|
| 66 |
+
<span>${state.metadataState?.baseModel || 'Unknown'}</span>
|
| 67 |
+
</span>
|
| 68 |
+
<a class="icon mini svg" @click=${handleAnalyzeFull}>
|
| 69 |
+
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 492 492">
|
| 70 |
+
<g>
|
| 71 |
+
<path
|
| 72 |
+
d="M484.08,296.216c-5.1-5.128-11.848-7.936-19.032-7.936H330.516c-14.828,0-26.86,12.036-26.86,26.868v22.796c0,7.168,2.784,14.064,7.884,19.16c5.092,5.088,11.82,8.052,18.976,8.052H366.1c-31.544,30.752-74.928,50.08-120.388,50.08c-71.832,0-136.028-45.596-159.744-113.344c-5.392-15.404-19.972-25.784-36.28-25.784c-4.316,0-8.592,0.708-12.7,2.144c-9.692,3.396-17.48,10.352-21.932,19.596c-4.456,9.248-5.04,19.684-1.648,29.368c34.496,98.54,127.692,164.74,232.144,164.74c64.132,0,123.448-23.948,169.572-67.656v25.22c0,14.836,12.384,27.108,27.224,27.108h22.792c14.84,0,26.86-12.272,26.86-27.108V315.24C492,308.056,489.2,301.304,484.08,296.216z"
|
| 73 |
+
></path>
|
| 74 |
+
</g>
|
| 75 |
+
<g>
|
| 76 |
+
<path
|
| 77 |
+
d="M478.628,164.78C444.132,66.244,350.916,0.044,246.464,0.044c-64.136,0-123.464,23.952-169.588,67.66v-25.22c0-14.832-12.344-27.112-27.184-27.112H26.896C12.06,15.372,0,27.652,0,42.484V176.76c0,7.18,2.824,13.868,7.944,18.964c5.096,5.128,11.86,7.932,19.044,7.932l-0.08,0.06h134.604c14.84,0,26.832-12.028,26.832-26.86v-22.8c0-14.836-11.992-27.216-26.832-27.216h-35.576c31.544-30.752,74.932-50.076,120.392-50.076c71.832,0,136.024,45.596,159.74,113.348c5.392,15.404,19.968,25.78,36.28,25.78c4.32,0,8.588-0.704,12.7-2.144c9.696-3.396,17.48-10.348,21.932-19.596C481.432,184.9,482.02,174.472,478.628,164.78z"
|
| 78 |
+
></path>
|
| 79 |
+
</g>
|
| 80 |
+
</svg>
|
| 81 |
+
</a>
|
| 82 |
+
</span>
|
| 83 |
+
`;
|
| 84 |
+
}
|
sd-webui-weight-helper-main/src/components/sections/preview-section.ts
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { getEditor, getTabId } from '@/shared/state/current-state';
|
| 2 |
+
import * as globalState from '@/shared/state/global-weight-helper-state';
|
| 3 |
+
import { withoutPromptAssist } from '@/shared/utils/common-utils';
|
| 4 |
+
import { getDisplayStyle, getVisibilityStyle } from '@/shared/utils/helper-utils';
|
| 5 |
+
|
| 6 |
+
import { TemplateResult, html } from 'lit-html';
|
| 7 |
+
|
| 8 |
+
declare function extraNetworksRequestMetadata(e: Event, type: string, modelName: string): void;
|
| 9 |
+
declare function extraNetworksEditUserMetadata(e: Event, tabId: string, type: string, modelName: string): void;
|
| 10 |
+
|
| 11 |
+
/**
|
| 12 |
+
* PreviewSection creates information display about the selected model.
|
| 13 |
+
* Shows preview image, metadata actions, trigger word insertion buttons, and model description.
|
| 14 |
+
* @param preview - The preview state containing model information.
|
| 15 |
+
* @returns The PreviewSection template.
|
| 16 |
+
*/
|
| 17 |
+
export function createPreviewSection(preview: globalState.PreviewState): TemplateResult {
|
| 18 |
+
/**
|
| 19 |
+
* Handles the click event to show internal metadata for the model.
|
| 20 |
+
* @param e - The click event.
|
| 21 |
+
*/
|
| 22 |
+
const handleShowMetadata = (e: Event) => {
|
| 23 |
+
extraNetworksRequestMetadata(e, 'lora', preview.modelName);
|
| 24 |
+
};
|
| 25 |
+
|
| 26 |
+
/**
|
| 27 |
+
* Handles the click event to edit user metadata for the model.
|
| 28 |
+
* @param e - The click event.
|
| 29 |
+
*/
|
| 30 |
+
const handleEditMetadata = (e: Event) => {
|
| 31 |
+
extraNetworksEditUserMetadata(e, getTabId(), 'lora', preview.modelName);
|
| 32 |
+
};
|
| 33 |
+
|
| 34 |
+
/**
|
| 35 |
+
* Handles the click event to open the Civitai model page in a new tab.
|
| 36 |
+
*/
|
| 37 |
+
const handleOpenCivitai = () => {
|
| 38 |
+
window.open(`https://civitai.com/models/${preview.modelId}`, '_blank');
|
| 39 |
+
};
|
| 40 |
+
|
| 41 |
+
/**
|
| 42 |
+
* Handles the click event to show the preview description.
|
| 43 |
+
*/
|
| 44 |
+
const handleOpenPreviewDescription = () => {
|
| 45 |
+
globalState.setPreviewDescriptionVisible(true);
|
| 46 |
+
};
|
| 47 |
+
|
| 48 |
+
/**
|
| 49 |
+
* Handles the click event to close the preview description.
|
| 50 |
+
*/
|
| 51 |
+
const handleClosePreviewDescription = () => {
|
| 52 |
+
globalState.setPreviewDescriptionVisible(false);
|
| 53 |
+
};
|
| 54 |
+
|
| 55 |
+
/**
|
| 56 |
+
* Handles the click event to insert trigger words into the prompt or negative prompt textarea.
|
| 57 |
+
*/
|
| 58 |
+
const handleInsertTriggerWords = () => {
|
| 59 |
+
const tabId = getTabId();
|
| 60 |
+
let promptTextarea = document.querySelector(`#${tabId}_prompt textarea`) as HTMLTextAreaElement;
|
| 61 |
+
let negativeTextarea = document.querySelector(`#${tabId}_neg_prompt textarea`) as HTMLTextAreaElement | undefined;
|
| 62 |
+
|
| 63 |
+
const textarea = getEditor();
|
| 64 |
+
if (textarea === negativeTextarea) {
|
| 65 |
+
} else if (textarea !== promptTextarea) {
|
| 66 |
+
promptTextarea = textarea;
|
| 67 |
+
negativeTextarea = undefined;
|
| 68 |
+
}
|
| 69 |
+
if (!opts.weight_helper_using_execCommand) {
|
| 70 |
+
const insert = () => {
|
| 71 |
+
const zipped = [
|
| 72 |
+
{ triggerWords: preview.triggerWords, textarea: promptTextarea },
|
| 73 |
+
{ triggerWords: preview.negativeTriggerWords, textarea: negativeTextarea },
|
| 74 |
+
];
|
| 75 |
+
for (const { triggerWords, textarea } of zipped) {
|
| 76 |
+
if (triggerWords.length > 0 && textarea) {
|
| 77 |
+
let words = triggerWords.join(', ');
|
| 78 |
+
if (textarea.value) words = ', ' + words;
|
| 79 |
+
textarea.value += words;
|
| 80 |
+
}
|
| 81 |
+
}
|
| 82 |
+
};
|
| 83 |
+
insert();
|
| 84 |
+
} else {
|
| 85 |
+
const insert = () => {
|
| 86 |
+
const zipped = [
|
| 87 |
+
{ triggerWords: preview.triggerWords, textarea: promptTextarea },
|
| 88 |
+
{ triggerWords: preview.negativeTriggerWords, textarea: negativeTextarea },
|
| 89 |
+
];
|
| 90 |
+
for (const { triggerWords, textarea } of zipped) {
|
| 91 |
+
if (triggerWords.length > 0 && textarea) {
|
| 92 |
+
let words = triggerWords.join(', ');
|
| 93 |
+
if (textarea.value) words = ', ' + words;
|
| 94 |
+
textarea.focus();
|
| 95 |
+
const eolIndex = textarea.value.length;
|
| 96 |
+
textarea.setSelectionRange(eolIndex, eolIndex);
|
| 97 |
+
document.execCommand('insertText', false, words);
|
| 98 |
+
}
|
| 99 |
+
}
|
| 100 |
+
};
|
| 101 |
+
withoutPromptAssist(() => {
|
| 102 |
+
insert();
|
| 103 |
+
});
|
| 104 |
+
}
|
| 105 |
+
globalState.hideTagInsertButton();
|
| 106 |
+
};
|
| 107 |
+
|
| 108 |
+
const classNames = ['preview-pane', 'card'];
|
| 109 |
+
|
| 110 |
+
// position based on settings
|
| 111 |
+
switch (opts.weight_helper_preview_position) {
|
| 112 |
+
case 'Bottom Right':
|
| 113 |
+
classNames.push('preview-bottom-right');
|
| 114 |
+
break;
|
| 115 |
+
case 'Top Left':
|
| 116 |
+
classNames.push('preview-top-left');
|
| 117 |
+
break;
|
| 118 |
+
case 'Bottom Left':
|
| 119 |
+
classNames.push('preview-bottom-left');
|
| 120 |
+
break;
|
| 121 |
+
default:
|
| 122 |
+
classNames.push('preview-top-right');
|
| 123 |
+
break;
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
return html`
|
| 127 |
+
<div class="${classNames.join(' ')}" data-name="${preview.modelName}">
|
| 128 |
+
<img class="preview" src="${preview.thumbUrl}" style="height: ${opts.weight_helper_preview_height}px" />
|
| 129 |
+
<div class="action-row button-top" style="${getVisibilityStyle(!preview.isDescriptionVisible)}">
|
| 130 |
+
${preview.modelName && preview.hasMetadata && typeof extraNetworksRequestMetadata === 'function'
|
| 131 |
+
? html` <div class="metadata-btn card-btn" title="Show internal metadata" @click="${handleShowMetadata}"></div> `
|
| 132 |
+
: ''}
|
| 133 |
+
${preview.modelName && typeof extraNetworksEditUserMetadata === 'function'
|
| 134 |
+
? html` <div class="edit-btn card-btn" title="Edit metadata" @click="${handleEditMetadata}"></div> `
|
| 135 |
+
: ''}
|
| 136 |
+
${preview.modelId ? html` <div class="civitai-btn card-btn" title="Open civitai" @click="${handleOpenCivitai}"></div> ` : ''}
|
| 137 |
+
${preview.triggerWords.length > 0 || preview.negativeTriggerWords.length > 0
|
| 138 |
+
? html`
|
| 139 |
+
<div
|
| 140 |
+
class="add-trigger-btn card-btn"
|
| 141 |
+
title="Add trigger words"
|
| 142 |
+
@click="${handleInsertTriggerWords}"
|
| 143 |
+
style="${getDisplayStyle(preview.isTagInsertButtonVisible)}"
|
| 144 |
+
></div>
|
| 145 |
+
`
|
| 146 |
+
: ''}
|
| 147 |
+
</div>
|
| 148 |
+
|
| 149 |
+
${preview.description
|
| 150 |
+
? html`
|
| 151 |
+
<div class="action-row button-bottom" style="${getVisibilityStyle(!preview.isDescriptionVisible)}">
|
| 152 |
+
<div class="card-btn note-btn" @click="${handleOpenPreviewDescription}"></div>
|
| 153 |
+
</div>
|
| 154 |
+
<textarea class="description" style="${getVisibilityStyle(preview.isDescriptionVisible)}">
|
| 155 |
+
${preview.description}
|
| 156 |
+
</textarea
|
| 157 |
+
>
|
| 158 |
+
<div
|
| 159 |
+
class="card-btn description-close-btn"
|
| 160 |
+
style="${getVisibilityStyle(preview.isDescriptionVisible)}"
|
| 161 |
+
@click="${handleClosePreviewDescription}"
|
| 162 |
+
></div>
|
| 163 |
+
`
|
| 164 |
+
: ''}
|
| 165 |
+
</div>
|
| 166 |
+
`;
|
| 167 |
+
}
|
sd-webui-weight-helper-main/src/components/ui-template.ts
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { CARD_NO_IMAGE_PATH } from '@/shared/constants/common-const';
|
| 2 |
+
import { resetMetadataAbortController, resetPreviewAbortController } from '@/shared/manager/api-manager';
|
| 3 |
+
import * as cacheManager from '@/shared/manager/cache-manager';
|
| 4 |
+
import * as configManager from '@/shared/manager/config-manager';
|
| 5 |
+
import * as historyManager from '@/shared/manager/history-manager';
|
| 6 |
+
import * as currentState from '@/shared/state/current-state';
|
| 7 |
+
import * as globalState from '@/shared/state/global-weight-helper-state';
|
| 8 |
+
import { ModelTypes, WeightControllerTypes } from '@/shared/types/lora-types';
|
| 9 |
+
import { fetchMetadata, fetchPreviewData } from '@/shared/utils/api-utils';
|
| 10 |
+
import { getLoraDefineFromEditor, getOutputStrings, syncEditorWithState } from '@/shared/utils/editor-utils';
|
| 11 |
+
import { disabled, getDisplayStyle } from '@/shared/utils/helper-utils';
|
| 12 |
+
import { createWeightHelperInitState, createWeightHelperState } from '@/shared/utils/state-utils';
|
| 13 |
+
import { mergeWeightsWithGroups } from '@/shared/utils/weight-utils';
|
| 14 |
+
|
| 15 |
+
import { createWeightController } from '@/components/sections/common-section';
|
| 16 |
+
import { createHeaderSection } from '@/components/sections/header-section';
|
| 17 |
+
import { createLbwSection } from '@/components/sections/lbw-section';
|
| 18 |
+
import { createLoraSettingsSection } from '@/components/sections/lora-settings-section';
|
| 19 |
+
import { createMetadataSection } from '@/components/sections/metadata-section';
|
| 20 |
+
import { createPreviewSection } from '@/components/sections/preview-section';
|
| 21 |
+
|
| 22 |
+
import { TemplateResult, html, render } from 'lit-html';
|
| 23 |
+
|
| 24 |
+
declare function gradioApp(): HTMLElement;
|
| 25 |
+
|
| 26 |
+
// Track if global (one-time) event listeners were attached
|
| 27 |
+
let isEventListenersInitialized = false;
|
| 28 |
+
|
| 29 |
+
/**
|
| 30 |
+
* Build main Weight Helper UI template.
|
| 31 |
+
* Note: top/left positioning styles are applied imperatively (drag) and excluded from state to avoid re-renders.
|
| 32 |
+
* @returns The main Weight Helper UI template
|
| 33 |
+
*/
|
| 34 |
+
export function createUITemplate(): TemplateResult {
|
| 35 |
+
const state = globalState.getGlobalState();
|
| 36 |
+
const { uiState, weightState, lock } = state;
|
| 37 |
+
|
| 38 |
+
// Attach global listeners only once
|
| 39 |
+
if (!isEventListenersInitialized) {
|
| 40 |
+
setupEventListeners();
|
| 41 |
+
isEventListenersInitialized = true;
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
// top/left not included here (managed outside state for performance)
|
| 45 |
+
const containerStyle = `transform: scale(${uiState.scale}); ${getDisplayStyle(uiState.isVisible)}`;
|
| 46 |
+
|
| 47 |
+
return html`
|
| 48 |
+
<div id="weight-helper" class="${state.uiState.isWaiting ? 'waiting' : ''}" style="${containerStyle}">
|
| 49 |
+
${createHeaderSection(state.loraName, lock)} ${createMetadataSection()}
|
| 50 |
+
${weightState.weights[WeightControllerTypes.TENC] &&
|
| 51 |
+
html`<section class="border p">${createWeightController(WeightControllerTypes.TENC, weightState.weights)}</section>`}
|
| 52 |
+
${[WeightControllerTypes.UNET, WeightControllerTypes.START, WeightControllerTypes.STOP]
|
| 53 |
+
.filter((wt) => !!weightState.weights[wt])
|
| 54 |
+
.map(
|
| 55 |
+
(weightType) =>
|
| 56 |
+
html`<section
|
| 57 |
+
class="border p"
|
| 58 |
+
style="${getDisplayStyle(
|
| 59 |
+
!uiState.isMoreButtonVisible ||
|
| 60 |
+
weightState.weights[weightType].initCheckState ||
|
| 61 |
+
weightState.weights[weightType].initValue !== configManager.getWeightControllerConfig(weightType).default,
|
| 62 |
+
)}"
|
| 63 |
+
>
|
| 64 |
+
${createWeightController(weightType, weightState.weights)}
|
| 65 |
+
</section>`,
|
| 66 |
+
)}
|
| 67 |
+
|
| 68 |
+
<button style="${uiState.isMoreButtonVisible ? '' : 'display: none'}" ?disabled="${disabled(state)}" @click="${() => globalState.hideMoreButton()}">
|
| 69 |
+
show more options
|
| 70 |
+
</button>
|
| 71 |
+
|
| 72 |
+
<section class="border p">
|
| 73 |
+
<label>LBW</label>
|
| 74 |
+
<div class="f col g-4 w-fill">${createLoraSettingsSection()} ${createLbwSection()}</div>
|
| 75 |
+
</section>
|
| 76 |
+
|
| 77 |
+
${state.previewState.modelName ? createPreviewSection(state.previewState) : ''}
|
| 78 |
+
</div>
|
| 79 |
+
`;
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
/**
|
| 83 |
+
* Register global event listeners (context menu open/close lifecycle, outside click, ESC key, generate button etc.).
|
| 84 |
+
*/
|
| 85 |
+
function setupEventListeners(): void {
|
| 86 |
+
const handleClickGenButton = () => {
|
| 87 |
+
const state = globalState.getGlobalState();
|
| 88 |
+
if (state.uiState.isVisible) {
|
| 89 |
+
closeWeightHelperContext();
|
| 90 |
+
syncEditorWithState(state);
|
| 91 |
+
}
|
| 92 |
+
};
|
| 93 |
+
|
| 94 |
+
const handleRightClickTextarea = (e: MouseEvent) => {
|
| 95 |
+
const state = globalState.getGlobalState();
|
| 96 |
+
if (state.uiState.isVisible) {
|
| 97 |
+
e.preventDefault();
|
| 98 |
+
closeWeightHelperContext();
|
| 99 |
+
syncEditorWithState(state);
|
| 100 |
+
return;
|
| 101 |
+
}
|
| 102 |
+
const loraDefine = getLoraDefineFromEditor(e);
|
| 103 |
+
if (loraDefine) {
|
| 104 |
+
e.preventDefault();
|
| 105 |
+
openWeightHelperContext(loraDefine);
|
| 106 |
+
}
|
| 107 |
+
};
|
| 108 |
+
|
| 109 |
+
const handleClickAnyware = (e: MouseEvent) => {
|
| 110 |
+
const state = globalState.getGlobalState();
|
| 111 |
+
if (state.uiState.isVisible) {
|
| 112 |
+
const contextMenuElement = document.getElementById('weight-helper');
|
| 113 |
+
if (!contextMenuElement) return;
|
| 114 |
+
const tabId = currentState.getTabId();
|
| 115 |
+
if (e) {
|
| 116 |
+
const target = e.target as HTMLBodyElement;
|
| 117 |
+
if (contextMenuElement.contains(target)) return;
|
| 118 |
+
if (target.id === `${tabId}_token_button`) return;
|
| 119 |
+
if (target.id === `${tabId}_lora_edit_user_metadata_button`) return;
|
| 120 |
+
if (target.className === 'global-popup-close') return;
|
| 121 |
+
if (target.id.indexOf('_interrupt') > 0) {
|
| 122 |
+
closeWeightHelperContext();
|
| 123 |
+
return;
|
| 124 |
+
}
|
| 125 |
+
}
|
| 126 |
+
closeWeightHelperContext();
|
| 127 |
+
syncEditorWithState(state);
|
| 128 |
+
}
|
| 129 |
+
};
|
| 130 |
+
|
| 131 |
+
const handleKeyupAnyware = (e: KeyboardEvent) => {
|
| 132 |
+
if ((e as KeyboardEvent).key === 'Escape') {
|
| 133 |
+
const state = globalState.getGlobalState();
|
| 134 |
+
cancelWeightHelperContext(state);
|
| 135 |
+
}
|
| 136 |
+
};
|
| 137 |
+
|
| 138 |
+
// Attach listeners to generate buttons & prompt textareas
|
| 139 |
+
const genButtons = gradioApp().querySelectorAll("button:is([id*='_generate'])");
|
| 140 |
+
genButtons.forEach((genBtn) => {
|
| 141 |
+
genBtn.addEventListener('click', handleClickGenButton, true);
|
| 142 |
+
});
|
| 143 |
+
|
| 144 |
+
const textareas = gradioApp().querySelectorAll("*:is([id*='_toprow'] [id*='_prompt'], .prompt) textarea") as NodeListOf<HTMLTextAreaElement>;
|
| 145 |
+
textareas.forEach((textarea) => {
|
| 146 |
+
textarea.addEventListener('contextmenu', handleRightClickTextarea);
|
| 147 |
+
});
|
| 148 |
+
|
| 149 |
+
document.addEventListener('click', handleClickAnyware);
|
| 150 |
+
document.addEventListener('keyup', handleKeyupAnyware);
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
// One-time flag for state watching → subscribe only once
|
| 154 |
+
let isStateWatchingInitialized = false;
|
| 155 |
+
|
| 156 |
+
/**
|
| 157 |
+
* Render (and set up subscriptions) of the UI into container.
|
| 158 |
+
* Full state changes trigger template re-render; position changes only mutate style.
|
| 159 |
+
* @param container Target DOM element
|
| 160 |
+
*/
|
| 161 |
+
export function renderUI(container: HTMLElement): void {
|
| 162 |
+
// 初期レンダリング
|
| 163 |
+
render(createUITemplate(), container);
|
| 164 |
+
|
| 165 |
+
// 状態変化を監視して自動再レンダリング(一度だけ設定)
|
| 166 |
+
if (!isStateWatchingInitialized) {
|
| 167 |
+
// Subscribe to full state updates
|
| 168 |
+
globalState.subscribeToStateChanges(() => {
|
| 169 |
+
render(createUITemplate(), container);
|
| 170 |
+
});
|
| 171 |
+
|
| 172 |
+
// Subscribe to position-only updates (avoid re-render)
|
| 173 |
+
globalState.subscribeToPositionChanges((pos) => {
|
| 174 |
+
const el = container.querySelector('#weight-helper') as HTMLDivElement;
|
| 175 |
+
if (!el) return;
|
| 176 |
+
el.style.top = pos.top + 'px';
|
| 177 |
+
el.style.left = pos.left + 'px';
|
| 178 |
+
});
|
| 179 |
+
|
| 180 |
+
isStateWatchingInitialized = true;
|
| 181 |
+
}
|
| 182 |
+
}
|
| 183 |
+
|
| 184 |
+
/**
|
| 185 |
+
* Open Weight Helper context at given coordinates and load metadata / preview lazily.
|
| 186 |
+
*/
|
| 187 |
+
function openWeightHelperContext(loraDefine: {
|
| 188 |
+
tabId: string;
|
| 189 |
+
textarea: HTMLTextAreaElement;
|
| 190 |
+
selectionStart: number;
|
| 191 |
+
selectionEnd: number;
|
| 192 |
+
namespace: string;
|
| 193 |
+
loraName: string;
|
| 194 |
+
loraParams: string;
|
| 195 |
+
top: number;
|
| 196 |
+
left: number;
|
| 197 |
+
}) {
|
| 198 |
+
const { tabId, textarea, selectionStart, selectionEnd, namespace, loraName, loraParams, top, left } = loraDefine;
|
| 199 |
+
|
| 200 |
+
currentState.setTabId(tabId);
|
| 201 |
+
currentState.setEditor(textarea);
|
| 202 |
+
currentState.setSelectionStart(selectionStart);
|
| 203 |
+
currentState.setSelectionEnd(selectionEnd);
|
| 204 |
+
currentState.setLoraDefineString(textarea.value.substring(selectionStart, selectionEnd));
|
| 205 |
+
|
| 206 |
+
currentState.loadStep(tabId);
|
| 207 |
+
currentState.loadLbwPresets(tabId);
|
| 208 |
+
|
| 209 |
+
configManager.getWeightControllerConfig(WeightControllerTypes.START).max = currentState.getStep();
|
| 210 |
+
configManager.getWeightControllerConfig(WeightControllerTypes.STOP).max = currentState.getStep();
|
| 211 |
+
configManager.getWeightControllerConfig(WeightControllerTypes.STOP).default = currentState.getStep();
|
| 212 |
+
|
| 213 |
+
const rect = document.getElementById('weight-helper')!.getBoundingClientRect();
|
| 214 |
+
const diffBottom = window.innerHeight - rect.bottom;
|
| 215 |
+
let arrangedTop = top;
|
| 216 |
+
if (diffBottom < 0) {
|
| 217 |
+
if (rect.top < 0) {
|
| 218 |
+
arrangedTop = window.scrollY;
|
| 219 |
+
} else {
|
| 220 |
+
arrangedTop += diffBottom;
|
| 221 |
+
}
|
| 222 |
+
}
|
| 223 |
+
const props = createWeightHelperState(namespace, loraName, loraParams);
|
| 224 |
+
|
| 225 |
+
globalState.openContext(props);
|
| 226 |
+
// Apply position directly (not part of state)
|
| 227 |
+
const container = document.getElementById('weight-helper');
|
| 228 |
+
if (container) {
|
| 229 |
+
container.style.top = arrangedTop + 'px';
|
| 230 |
+
container.style.left = left + 'px';
|
| 231 |
+
}
|
| 232 |
+
|
| 233 |
+
if (!props.metadataState) {
|
| 234 |
+
const metadataAbortController = resetMetadataAbortController();
|
| 235 |
+
fetchMetadata(loraName, false, metadataAbortController.signal)
|
| 236 |
+
.then((result) => {
|
| 237 |
+
let selectedModelType = props.weightState.selectedModelType;
|
| 238 |
+
if (!selectedModelType || selectedModelType === ModelTypes.Unknown) {
|
| 239 |
+
selectedModelType = result.modelType ?? ModelTypes.Unknown;
|
| 240 |
+
}
|
| 241 |
+
const selectedLoraBlockType = props.weightState.selectedLoraBlockType;
|
| 242 |
+
const blockGroups = configManager.getLbwBlockGroups(selectedModelType, selectedLoraBlockType);
|
| 243 |
+
const weights = mergeWeightsWithGroups(props.weightState.weights, blockGroups);
|
| 244 |
+
|
| 245 |
+
const weightState = {
|
| 246 |
+
...props.weightState,
|
| 247 |
+
selectedModelType: selectedModelType,
|
| 248 |
+
selectedLoraBlockType: selectedLoraBlockType,
|
| 249 |
+
};
|
| 250 |
+
const loraParams = getOutputStrings(props.loraName, weightState).loraParams;
|
| 251 |
+
if (!props.weightState.xyzMode) {
|
| 252 |
+
historyManager.addHistory(loraName, {
|
| 253 |
+
loraParams: loraParams,
|
| 254 |
+
selectedLoraBlockType: selectedLoraBlockType,
|
| 255 |
+
selectedModelType: selectedModelType,
|
| 256 |
+
});
|
| 257 |
+
globalState.setHistoryIndex(historyManager.getHistories(loraName).length - 1);
|
| 258 |
+
}
|
| 259 |
+
|
| 260 |
+
globalState.loadMetadata({
|
| 261 |
+
algorithm: result.algorithm || 'Unknown',
|
| 262 |
+
modelType: result.modelType || 'Unknown',
|
| 263 |
+
baseModel: result.baseModel || 'Unknown',
|
| 264 |
+
selectedModelType: selectedModelType,
|
| 265 |
+
usingBlocks: result.usingBlocks,
|
| 266 |
+
blockGroups: blockGroups,
|
| 267 |
+
lbwPresets: currentState.getLbwPresets(selectedModelType, props.weightState.selectedLoraBlockType),
|
| 268 |
+
weights: weights,
|
| 269 |
+
});
|
| 270 |
+
})
|
| 271 |
+
.catch((error) => {
|
| 272 |
+
if (error.name !== 'AbortError') {
|
| 273 |
+
console.error('Error fetching metadata:', error);
|
| 274 |
+
globalState.setWaiting(false);
|
| 275 |
+
}
|
| 276 |
+
});
|
| 277 |
+
}
|
| 278 |
+
|
| 279 |
+
if (!props.previewState.modelId) {
|
| 280 |
+
const previewAbortController = resetPreviewAbortController();
|
| 281 |
+
fetchPreviewData(loraName, previewAbortController.signal)
|
| 282 |
+
.then(async (result) => {
|
| 283 |
+
if (result.thumbUrl !== CARD_NO_IMAGE_PATH) {
|
| 284 |
+
result.thumbUrl = result.thumbUrl;
|
| 285 |
+
}
|
| 286 |
+
cacheManager.setPreviewCache(loraName, result);
|
| 287 |
+
globalState.loadPreviewData(result);
|
| 288 |
+
})
|
| 289 |
+
.catch((error) => {
|
| 290 |
+
if (error.name !== 'AbortError') {
|
| 291 |
+
console.error('Error fetching metadata:', error);
|
| 292 |
+
}
|
| 293 |
+
});
|
| 294 |
+
}
|
| 295 |
+
}
|
| 296 |
+
|
| 297 |
+
/** Close context menu and reset to initial hidden state. */
|
| 298 |
+
function closeWeightHelperContext(): void {
|
| 299 |
+
const weightHelperState = createWeightHelperInitState();
|
| 300 |
+
globalState.closeContext(weightHelperState);
|
| 301 |
+
}
|
| 302 |
+
|
| 303 |
+
/** Cancel editing: revert editor text (if enabled) then close. */
|
| 304 |
+
function cancelWeightHelperContext(state: globalState.BasicState): void {
|
| 305 |
+
if (!opts.weight_helper_using_execCommand) {
|
| 306 |
+
syncEditorWithState(state, true);
|
| 307 |
+
}
|
| 308 |
+
closeWeightHelperContext();
|
| 309 |
+
}
|
sd-webui-weight-helper-main/src/index.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import * as configManager from '@/shared/manager/config-manager';
|
| 2 |
+
import * as historyManager from '@/shared/manager/history-manager';
|
| 3 |
+
import * as globalState from '@/shared/state/global-weight-helper-state';
|
| 4 |
+
import { createWeightHelperInitState } from '@/shared/utils/state-utils';
|
| 5 |
+
|
| 6 |
+
import { renderUI } from '@/components/ui-template';
|
| 7 |
+
|
| 8 |
+
declare function gradioApp(): HTMLElement;
|
| 9 |
+
declare function onUiLoaded(callback: VoidFunction): void;
|
| 10 |
+
declare function onOptionsChanged(callback: VoidFunction): void;
|
| 11 |
+
|
| 12 |
+
/**
|
| 13 |
+
* Promise resolver for the initialization process.
|
| 14 |
+
* Used to signal when options have been loaded and initialization can proceed.
|
| 15 |
+
*/
|
| 16 |
+
export let resolveInitialized: ((value: boolean) => void) | null;
|
| 17 |
+
|
| 18 |
+
/**
|
| 19 |
+
* Promise that resolves when the Weight Helper is ready to initialize.
|
| 20 |
+
* Used to defer initialization until options are loaded.
|
| 21 |
+
*/
|
| 22 |
+
const initializedPromise = new Promise<boolean>((resolve) => {
|
| 23 |
+
resolveInitialized = resolve;
|
| 24 |
+
});
|
| 25 |
+
|
| 26 |
+
/**
|
| 27 |
+
* Entry point for the Weight Helper React application.
|
| 28 |
+
* Handles initialization, theme adaptation, and state setup when the UI is loaded or options are changed.
|
| 29 |
+
*/
|
| 30 |
+
historyManager.loadLocalStorage();
|
| 31 |
+
|
| 32 |
+
onUiLoaded(() => {
|
| 33 |
+
if (!gradioApp().querySelector('#lbw_ratiospreset')) {
|
| 34 |
+
return;
|
| 35 |
+
}
|
| 36 |
+
const textColor = getComputedStyle(document.documentElement).getPropertyValue('--body-text-color').trim();
|
| 37 |
+
const textColorRgb = textColor
|
| 38 |
+
.slice(1)
|
| 39 |
+
.match(/.{1,2}/g)!
|
| 40 |
+
.map((hex) => parseInt(hex, 16));
|
| 41 |
+
const textColorRgba = [...textColorRgb, 0.3];
|
| 42 |
+
document.documentElement.style.setProperty('--weight-helper-shadow', `rgba(${textColorRgba.join(',')})`);
|
| 43 |
+
document.documentElement.style.setProperty('--weight-helper-slider_size', String(opts.weight_helper_slider_length));
|
| 44 |
+
|
| 45 |
+
initializedPromise.then(() => {
|
| 46 |
+
const weightHelperContainer = document.createElement('div');
|
| 47 |
+
weightHelperContainer.id = 'weight-helper-container';
|
| 48 |
+
gradioApp().appendChild(weightHelperContainer);
|
| 49 |
+
|
| 50 |
+
configManager.initialize();
|
| 51 |
+
globalState.initializeGlobalState(createWeightHelperInitState());
|
| 52 |
+
renderUI(weightHelperContainer);
|
| 53 |
+
});
|
| 54 |
+
});
|
| 55 |
+
|
| 56 |
+
onOptionsChanged(() => {
|
| 57 |
+
if (resolveInitialized) {
|
| 58 |
+
resolveInitialized(true);
|
| 59 |
+
resolveInitialized = null;
|
| 60 |
+
}
|
| 61 |
+
});
|
sd-webui-weight-helper-main/src/shared/constants/common-const.ts
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { LoraBlockTypes, ModelTypes } from '@/shared/types/lora-types';
|
| 2 |
+
|
| 3 |
+
const BASE_MODEL_TYPE = {
|
| 4 |
+
STABLE_DIFFUSION: [
|
| 5 |
+
'BASE',
|
| 6 |
+
'IN00',
|
| 7 |
+
'IN01',
|
| 8 |
+
'IN02',
|
| 9 |
+
'IN03',
|
| 10 |
+
'IN04',
|
| 11 |
+
'IN05',
|
| 12 |
+
'IN06',
|
| 13 |
+
'IN07',
|
| 14 |
+
'IN08',
|
| 15 |
+
'IN09',
|
| 16 |
+
'IN10',
|
| 17 |
+
'IN11',
|
| 18 |
+
'M00',
|
| 19 |
+
'OUT00',
|
| 20 |
+
'OUT01',
|
| 21 |
+
'OUT02',
|
| 22 |
+
'OUT03',
|
| 23 |
+
'OUT04',
|
| 24 |
+
'OUT05',
|
| 25 |
+
'OUT06',
|
| 26 |
+
'OUT07',
|
| 27 |
+
'OUT08',
|
| 28 |
+
'OUT09',
|
| 29 |
+
'OUT10',
|
| 30 |
+
'OUT11',
|
| 31 |
+
],
|
| 32 |
+
BLACK_FOREST_LABS: [
|
| 33 |
+
'CLIP',
|
| 34 |
+
'T5',
|
| 35 |
+
'IN',
|
| 36 |
+
'D00',
|
| 37 |
+
'D01',
|
| 38 |
+
'D02',
|
| 39 |
+
'D03',
|
| 40 |
+
'D04',
|
| 41 |
+
'D05',
|
| 42 |
+
'D06',
|
| 43 |
+
'D07',
|
| 44 |
+
'D08',
|
| 45 |
+
'D09',
|
| 46 |
+
'D10',
|
| 47 |
+
'D11',
|
| 48 |
+
'D12',
|
| 49 |
+
'D13',
|
| 50 |
+
'D14',
|
| 51 |
+
'D15',
|
| 52 |
+
'D16',
|
| 53 |
+
'D17',
|
| 54 |
+
'D18',
|
| 55 |
+
'S00',
|
| 56 |
+
'S01',
|
| 57 |
+
'S02',
|
| 58 |
+
'S03',
|
| 59 |
+
'S04',
|
| 60 |
+
'S05',
|
| 61 |
+
'S06',
|
| 62 |
+
'S07',
|
| 63 |
+
'S08',
|
| 64 |
+
'S09',
|
| 65 |
+
'S10',
|
| 66 |
+
'S11',
|
| 67 |
+
'S12',
|
| 68 |
+
'S13',
|
| 69 |
+
'S14',
|
| 70 |
+
'S15',
|
| 71 |
+
'S16',
|
| 72 |
+
'S17',
|
| 73 |
+
'S18',
|
| 74 |
+
'S19',
|
| 75 |
+
'S20',
|
| 76 |
+
'S21',
|
| 77 |
+
'S22',
|
| 78 |
+
'S23',
|
| 79 |
+
'S24',
|
| 80 |
+
'S25',
|
| 81 |
+
'S26',
|
| 82 |
+
'S27',
|
| 83 |
+
'S28',
|
| 84 |
+
'S29',
|
| 85 |
+
'S30',
|
| 86 |
+
'S31',
|
| 87 |
+
'S32',
|
| 88 |
+
'S33',
|
| 89 |
+
'S34',
|
| 90 |
+
'S35',
|
| 91 |
+
'S36',
|
| 92 |
+
'S37',
|
| 93 |
+
'OUT',
|
| 94 |
+
],
|
| 95 |
+
};
|
| 96 |
+
|
| 97 |
+
export const LBW_BLOCKS = {
|
| 98 |
+
[ModelTypes.SD]: BASE_MODEL_TYPE.STABLE_DIFFUSION,
|
| 99 |
+
[ModelTypes.SDXL]: BASE_MODEL_TYPE.STABLE_DIFFUSION,
|
| 100 |
+
[ModelTypes.Flux]: BASE_MODEL_TYPE.BLACK_FOREST_LABS,
|
| 101 |
+
[ModelTypes.Unknown]: [],
|
| 102 |
+
};
|
| 103 |
+
|
| 104 |
+
export const lbwMaskDefine = {
|
| 105 |
+
[ModelTypes.SD]: {
|
| 106 |
+
[LoraBlockTypes.lora]: [1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
| 107 |
+
[LoraBlockTypes.lycoris]: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
| 108 |
+
[LoraBlockTypes.Unknown]: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
| 109 |
+
},
|
| 110 |
+
[ModelTypes.SDXL]: {
|
| 111 |
+
[LoraBlockTypes.lora]: [1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
|
| 112 |
+
[LoraBlockTypes.lycoris]: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0],
|
| 113 |
+
[LoraBlockTypes.Unknown]: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
| 114 |
+
},
|
| 115 |
+
[ModelTypes.Flux]: {
|
| 116 |
+
[LoraBlockTypes.lora]: [
|
| 117 |
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
| 118 |
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
| 119 |
+
],
|
| 120 |
+
[LoraBlockTypes.lycoris]: [
|
| 121 |
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
| 122 |
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
| 123 |
+
],
|
| 124 |
+
[LoraBlockTypes.Unknown]: [
|
| 125 |
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
| 126 |
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
| 127 |
+
],
|
| 128 |
+
},
|
| 129 |
+
[ModelTypes.Unknown]: {
|
| 130 |
+
[LoraBlockTypes.lora]: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
| 131 |
+
[LoraBlockTypes.lycoris]: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
| 132 |
+
[LoraBlockTypes.Unknown]: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
| 133 |
+
},
|
| 134 |
+
};
|
| 135 |
+
|
| 136 |
+
export const XYZ_PRESETS = {
|
| 137 |
+
[ModelTypes.SD]: {
|
| 138 |
+
[LoraBlockTypes.lora]: 'XYZ(17)',
|
| 139 |
+
[LoraBlockTypes.lycoris]: 'XYZ(26)',
|
| 140 |
+
[LoraBlockTypes.Unknown]: 'XYZ(26)',
|
| 141 |
+
},
|
| 142 |
+
[ModelTypes.SDXL]: {
|
| 143 |
+
[LoraBlockTypes.lora]: 'XYZ(12)',
|
| 144 |
+
[LoraBlockTypes.lycoris]: 'XYZ(20)',
|
| 145 |
+
[LoraBlockTypes.Unknown]: 'XYZ(26)',
|
| 146 |
+
},
|
| 147 |
+
[ModelTypes.Flux]: {
|
| 148 |
+
[LoraBlockTypes.lora]: 'XYZ(19)',
|
| 149 |
+
[LoraBlockTypes.lycoris]: 'XYZ(19)',
|
| 150 |
+
[LoraBlockTypes.Unknown]: 'XYZ(19)',
|
| 151 |
+
},
|
| 152 |
+
[ModelTypes.Unknown]: {
|
| 153 |
+
[LoraBlockTypes.lora]: 'XYZ(17)',
|
| 154 |
+
[LoraBlockTypes.lycoris]: 'XYZ(26)',
|
| 155 |
+
[LoraBlockTypes.Unknown]: 'XYZ(26)',
|
| 156 |
+
},
|
| 157 |
+
};
|
| 158 |
+
|
| 159 |
+
export const SELECTABLE_MODEL_TYPES = {
|
| 160 |
+
'': ModelTypes.Unknown,
|
| 161 |
+
SD: ModelTypes.SD,
|
| 162 |
+
SDXL: ModelTypes.SDXL,
|
| 163 |
+
Flux: ModelTypes.Flux,
|
| 164 |
+
};
|
| 165 |
+
|
| 166 |
+
export const SELECTABLE_LORA_BLOCK_TYPES = {
|
| 167 |
+
'': LoraBlockTypes.Unknown,
|
| 168 |
+
'LoRA(LierLa)': LoraBlockTypes.lora,
|
| 169 |
+
'LyCORIS,etc': LoraBlockTypes.lycoris,
|
| 170 |
+
};
|
| 171 |
+
|
| 172 |
+
export const CARD_NO_IMAGE_PATH = './file=html/card-no-preview.png';
|
sd-webui-weight-helper-main/src/shared/hooks/use-global-state.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// このファイルはlit-html移行により不要になりました
|
| 2 |
+
// React/Preactのhooksは使用しないため、ダミーファイルとして残しています
|
| 3 |
+
import { BasicState, getGlobalState } from '@/shared/state/global-weight-helper-state';
|
| 4 |
+
|
| 5 |
+
/**
|
| 6 |
+
* 互換性のためのダミー関数
|
| 7 |
+
* lit-htmlベースではこの関数は使用されません
|
| 8 |
+
*/
|
| 9 |
+
export function useGlobalState(): BasicState {
|
| 10 |
+
return getGlobalState();
|
| 11 |
+
}
|
sd-webui-weight-helper-main/src/shared/manager/api-manager.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
let metadataAbortController: AbortController | null = null;
|
| 2 |
+
let previewAbortController: AbortController | null = null;
|
| 3 |
+
|
| 4 |
+
/**
|
| 5 |
+
* Returns the global AbortController for metadata fetch requests.
|
| 6 |
+
* Creates a new controller if one doesn't exist.
|
| 7 |
+
* @returns The AbortController instance for metadata requests.
|
| 8 |
+
*/
|
| 9 |
+
export function getMetadataAbortController(): AbortController {
|
| 10 |
+
if (!metadataAbortController) {
|
| 11 |
+
metadataAbortController = new AbortController();
|
| 12 |
+
}
|
| 13 |
+
return metadataAbortController;
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
/**
|
| 17 |
+
* Aborts any ongoing metadata fetch request and creates a new AbortController.
|
| 18 |
+
* @returns The new AbortController instance for metadata requests.
|
| 19 |
+
*/
|
| 20 |
+
export function resetMetadataAbortController(): AbortController {
|
| 21 |
+
if (metadataAbortController) {
|
| 22 |
+
metadataAbortController.abort();
|
| 23 |
+
}
|
| 24 |
+
metadataAbortController = new AbortController();
|
| 25 |
+
return metadataAbortController;
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
/**
|
| 29 |
+
* Returns the global AbortController for preview fetch requests.
|
| 30 |
+
* Creates a new controller if one doesn't exist.
|
| 31 |
+
* @returns The AbortController instance for preview requests.
|
| 32 |
+
*/
|
| 33 |
+
export function getPreviewAbortController(): AbortController {
|
| 34 |
+
if (!previewAbortController) {
|
| 35 |
+
previewAbortController = new AbortController();
|
| 36 |
+
}
|
| 37 |
+
return previewAbortController;
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
/**
|
| 41 |
+
* Aborts any ongoing preview fetch request and creates a new AbortController.
|
| 42 |
+
* @returns The new AbortController instance for preview requests.
|
| 43 |
+
*/
|
| 44 |
+
export function resetPreviewAbortController(): AbortController {
|
| 45 |
+
if (previewAbortController) {
|
| 46 |
+
previewAbortController.abort();
|
| 47 |
+
}
|
| 48 |
+
previewAbortController = new AbortController();
|
| 49 |
+
return previewAbortController;
|
| 50 |
+
}
|
sd-webui-weight-helper-main/src/shared/manager/cache-manager.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import * as globalState from '@/shared/state/global-weight-helper-state';
|
| 2 |
+
import { LoraBlockTypes, ModelTypes } from '@/shared/types/lora-types';
|
| 3 |
+
|
| 4 |
+
const _metadataCacheStore: Record<
|
| 5 |
+
string,
|
| 6 |
+
{
|
| 7 |
+
metadataState: globalState.MetadataState | undefined;
|
| 8 |
+
selectedLoraBlockType: LoraBlockTypes;
|
| 9 |
+
selectedModelType: ModelTypes;
|
| 10 |
+
usingBlocks: Set<string> | undefined;
|
| 11 |
+
}
|
| 12 |
+
> = {};
|
| 13 |
+
|
| 14 |
+
const _previewCacheStore: Record<string, globalState.PreviewState> = {};
|
| 15 |
+
|
| 16 |
+
/**
|
| 17 |
+
* Retrieves the metadata cache for the given LoRA name.
|
| 18 |
+
* @param loraName - The name of the LoRA model.
|
| 19 |
+
* @returns The cached metadata state, selected block type, model type, and used blocks, or undefined if not cached.
|
| 20 |
+
*/
|
| 21 |
+
export function getMetadataCache(loraName: string):
|
| 22 |
+
| {
|
| 23 |
+
metadataState: globalState.MetadataState | undefined;
|
| 24 |
+
selectedLoraBlockType: LoraBlockTypes;
|
| 25 |
+
selectedModelType: ModelTypes;
|
| 26 |
+
usingBlocks: Set<string> | undefined;
|
| 27 |
+
}
|
| 28 |
+
| undefined {
|
| 29 |
+
return _metadataCacheStore[loraName];
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
/**
|
| 33 |
+
* Sets the metadata cache for the given LoRA name.
|
| 34 |
+
* @param loraName - The name of the LoRA model.
|
| 35 |
+
* @param cache - The BasicState containing metadata and related info to cache.
|
| 36 |
+
*/
|
| 37 |
+
export function setMetadataCache(loraName: string, cache: globalState.BasicState) {
|
| 38 |
+
_metadataCacheStore[loraName] = {
|
| 39 |
+
metadataState: cache.metadataState,
|
| 40 |
+
selectedLoraBlockType: cache.weightState.selectedLoraBlockType,
|
| 41 |
+
selectedModelType: cache.weightState.selectedModelType,
|
| 42 |
+
usingBlocks: cache.usingBlocks,
|
| 43 |
+
};
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
/**
|
| 47 |
+
* Retrieves the preview cache for the given LoRA name.
|
| 48 |
+
* @param loraName - The name of the LoRA model.
|
| 49 |
+
* @returns The cached PreviewState, or undefined if not cached.
|
| 50 |
+
*/
|
| 51 |
+
export function getPreviewCache(loraName: string): globalState.PreviewState | undefined {
|
| 52 |
+
return _previewCacheStore[loraName];
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
/**
|
| 56 |
+
* Sets the preview cache for the given LoRA name.
|
| 57 |
+
* @param loraName - The name of the LoRA model.
|
| 58 |
+
* @param cache - The PreviewState to cache.
|
| 59 |
+
*/
|
| 60 |
+
export function setPreviewCache(loraName: string, cache: globalState.PreviewState) {
|
| 61 |
+
_previewCacheStore[loraName] = cache;
|
| 62 |
+
}
|
sd-webui-weight-helper-main/src/shared/manager/config-manager.ts
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import {
|
| 2 |
+
LBW_BLOCKS,
|
| 3 |
+
lbwMaskDefine as LBW_MASK_DEFINE,
|
| 4 |
+
SELECTABLE_LORA_BLOCK_TYPES,
|
| 5 |
+
SELECTABLE_MODEL_TYPES,
|
| 6 |
+
XYZ_PRESETS,
|
| 7 |
+
} from '@/shared/constants/common-const';
|
| 8 |
+
import { LoraBlockTypes, ModelTypes, WeightControllerTypes } from '@/shared/types/lora-types';
|
| 9 |
+
|
| 10 |
+
interface WeightControllerInterface {
|
| 11 |
+
min: number;
|
| 12 |
+
max: number;
|
| 13 |
+
default: number;
|
| 14 |
+
step: number;
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
const WeightControllerConfig: Record<string, WeightControllerInterface> = {
|
| 18 |
+
[WeightControllerTypes.TENC]: {
|
| 19 |
+
min: 0,
|
| 20 |
+
max: 0,
|
| 21 |
+
default: 1,
|
| 22 |
+
step: 0.5,
|
| 23 |
+
},
|
| 24 |
+
[WeightControllerTypes.UNET]: {
|
| 25 |
+
min: 0,
|
| 26 |
+
max: 0,
|
| 27 |
+
default: 0,
|
| 28 |
+
step: 0.5,
|
| 29 |
+
},
|
| 30 |
+
[WeightControllerTypes.START]: {
|
| 31 |
+
min: 0,
|
| 32 |
+
max: 0,
|
| 33 |
+
default: 0,
|
| 34 |
+
step: 1,
|
| 35 |
+
},
|
| 36 |
+
[WeightControllerTypes.STOP]: {
|
| 37 |
+
min: 0,
|
| 38 |
+
max: 0,
|
| 39 |
+
default: 0,
|
| 40 |
+
step: 1,
|
| 41 |
+
},
|
| 42 |
+
[WeightControllerTypes.LBW]: {
|
| 43 |
+
min: 0,
|
| 44 |
+
max: 0,
|
| 45 |
+
default: 1,
|
| 46 |
+
step: 0.5,
|
| 47 |
+
},
|
| 48 |
+
};
|
| 49 |
+
|
| 50 |
+
const lbwGroupConfig = {
|
| 51 |
+
[ModelTypes.SD]: {
|
| 52 |
+
[LoraBlockTypes.lora]: [['BASE', 'IN01-IN04', 'IN05-IN08', 'M00', 'OUT03-OUT06', 'OUT07-OUT11']],
|
| 53 |
+
[LoraBlockTypes.lycoris]: [['BASE', 'IN00-IN05', 'IN06-IN11', 'M00', 'OUT00-OUT05', 'OUT06-OUT11']],
|
| 54 |
+
[LoraBlockTypes.Unknown]: [[]] as string[][],
|
| 55 |
+
},
|
| 56 |
+
[ModelTypes.SDXL]: {
|
| 57 |
+
[LoraBlockTypes.lora]: [['BASE', 'IN04-IN08', 'M00', 'OUT00-OUT05']],
|
| 58 |
+
[LoraBlockTypes.lycoris]: [['BASE', 'IN00-IN03', 'IN04-IN08', 'M00', 'OUT00-OUT03', 'OUT04-OUT08']],
|
| 59 |
+
[LoraBlockTypes.Unknown]: [[]] as string[][],
|
| 60 |
+
},
|
| 61 |
+
[ModelTypes.Flux]: {
|
| 62 |
+
[LoraBlockTypes.lora]: [['CLIP', 'T5', 'IN', 'OUT'], ['D00-D18'], ['S00-S18'], ['S19-S37']],
|
| 63 |
+
[LoraBlockTypes.lycoris]: [['CLIP', 'T5', 'IN', 'OUT'], ['D00-D18'], ['S00-S18'], ['S19-S37']],
|
| 64 |
+
[LoraBlockTypes.Unknown]: [[]] as string[][],
|
| 65 |
+
},
|
| 66 |
+
[ModelTypes.Unknown]: {
|
| 67 |
+
[LoraBlockTypes.lora]: [[]] as string[][],
|
| 68 |
+
[LoraBlockTypes.lycoris]: [[]] as string[][],
|
| 69 |
+
[LoraBlockTypes.Unknown]: [[]] as string[][],
|
| 70 |
+
},
|
| 71 |
+
};
|
| 72 |
+
|
| 73 |
+
/**
|
| 74 |
+
* Initializes the configuration for block groups and weight controllers.
|
| 75 |
+
* Updates configuration values with settings from opts.
|
| 76 |
+
*/
|
| 77 |
+
export function initialize() {
|
| 78 |
+
const optBlockPattern = /((BASE|MID|M00|CLIP|T5|(IN|OUT|D|S)[0-9]{2}(-(IN|OUT|D|S)[0-9]{2})?) *(, *|$))+/;
|
| 79 |
+
for (const modelType of Object.values(SELECTABLE_MODEL_TYPES)) {
|
| 80 |
+
if (modelType === ModelTypes.Unknown || modelType === ModelTypes.Flux) continue;
|
| 81 |
+
for (const loraBlockType of Object.values(SELECTABLE_LORA_BLOCK_TYPES)) {
|
| 82 |
+
if (loraBlockType === LoraBlockTypes.Unknown) continue;
|
| 83 |
+
try {
|
| 84 |
+
let optBlockPoints = opts[`weight_helper_LBW_${modelType}_${loraBlockType}_block_points`] as string;
|
| 85 |
+
optBlockPoints = optBlockPoints.replace('MID', 'M00');
|
| 86 |
+
if (optBlockPattern.exec(optBlockPoints)) {
|
| 87 |
+
const blockPoints = optBlockPoints.split(',').map((v) => {
|
| 88 |
+
return v.trim().replace(/\d+/g, (match) => (match.length === 1 ? `0${match}` : match));
|
| 89 |
+
});
|
| 90 |
+
lbwGroupConfig[modelType][loraBlockType] = [blockPoints];
|
| 91 |
+
}
|
| 92 |
+
} catch (e) {
|
| 93 |
+
console.warn(`${modelType}_${loraBlockType} block definition format is invalid.`, e);
|
| 94 |
+
}
|
| 95 |
+
}
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
for (const k of [WeightControllerTypes.TENC, WeightControllerTypes.UNET, WeightControllerTypes.LBW]) {
|
| 99 |
+
WeightControllerConfig[k].min = +opts[`weight_helper_${k}_min`];
|
| 100 |
+
WeightControllerConfig[k].max = +opts[`weight_helper_${k}_max`];
|
| 101 |
+
WeightControllerConfig[k].step = +opts[`weight_helper_${k}_step`];
|
| 102 |
+
}
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
/**
|
| 106 |
+
* Retrieves the configuration for a specific weight controller type.
|
| 107 |
+
* @param type - The weight controller type.
|
| 108 |
+
* @returns The configuration object for the specified controller type.
|
| 109 |
+
*/
|
| 110 |
+
export function getWeightControllerConfig(type: string): WeightControllerInterface {
|
| 111 |
+
return WeightControllerConfig[type];
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
/**
|
| 115 |
+
* Returns the list of LBW blocks for the selected model type.
|
| 116 |
+
* @param selectedModelType - The selected model type.
|
| 117 |
+
* @returns An array of block labels for the given model type.
|
| 118 |
+
*/
|
| 119 |
+
export function getLbwBlocks(selectedModelType: ModelTypes): string[] {
|
| 120 |
+
if (selectedModelType in LBW_BLOCKS) {
|
| 121 |
+
return LBW_BLOCKS[selectedModelType];
|
| 122 |
+
}
|
| 123 |
+
return LBW_BLOCKS[ModelTypes.Unknown];
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
/**
|
| 127 |
+
* Returns an array of enabled LBW block labels for the selected model and LoRA block type.
|
| 128 |
+
* Only blocks with a mask value of 1 are included.
|
| 129 |
+
* @param selectedModelType - The selected model type.
|
| 130 |
+
* @param selectedLoraBlockType - The selected LoRA block type.
|
| 131 |
+
* @returns An array of enabled block labels.
|
| 132 |
+
*/
|
| 133 |
+
export function getMaskedLbwBlocks(selectedModelType: ModelTypes, selectedLoraBlockType: LoraBlockTypes): string[] {
|
| 134 |
+
const masks = getLbwMasks(selectedModelType, selectedLoraBlockType);
|
| 135 |
+
return LBW_BLOCKS[selectedModelType || ModelTypes.Unknown].filter((_, i) => masks[i] === 1);
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
/**
|
| 139 |
+
* Returns the mask array for LBW blocks for the selected model and block type.
|
| 140 |
+
* Each value in the array (1 or 0) indicates whether the corresponding block is enabled.
|
| 141 |
+
* @param selectedModelType - The selected model type.
|
| 142 |
+
* @param selectedLoraBlockType - The selected LoRA block type.
|
| 143 |
+
* @returns An array of binary values (1=enabled, 0=disabled).
|
| 144 |
+
*/
|
| 145 |
+
export function getLbwMasks(selectedModelType: ModelTypes, selectedLoraBlockType: LoraBlockTypes): number[] {
|
| 146 |
+
return LBW_MASK_DEFINE[selectedModelType || ModelTypes.Unknown][selectedLoraBlockType || LoraBlockTypes.Unknown];
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
/**
|
| 150 |
+
* Returns the block groups configuration for the selected model and block type.
|
| 151 |
+
* @param selectedModelType - The selected model type.
|
| 152 |
+
* @param selectedLoraBlockType - The selected LoRA block type.
|
| 153 |
+
* @returns An array of block group identifiers.
|
| 154 |
+
*/
|
| 155 |
+
export function getLbwBlockGroups(selectedModelType: ModelTypes, selectedLoraBlockType: LoraBlockTypes): string[][] {
|
| 156 |
+
return lbwGroupConfig[selectedModelType || ModelTypes.Unknown][selectedLoraBlockType || LoraBlockTypes.Unknown];
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
/**
|
| 160 |
+
* Returns the XYZ label for the selected model and block type.
|
| 161 |
+
* @param selectedModelType - The selected model type.
|
| 162 |
+
* @param selectedLoraBlockType - The selected LoRA block type.
|
| 163 |
+
* @returns The XYZ identifier string.
|
| 164 |
+
*/
|
| 165 |
+
export function getXyzLabel(selectedModelType: ModelTypes, selectedLoraBlockType: LoraBlockTypes): string {
|
| 166 |
+
return XYZ_PRESETS[selectedModelType || ModelTypes.Unknown][selectedLoraBlockType || LoraBlockTypes.Unknown];
|
| 167 |
+
}
|