Spaces:
Runtime error
Runtime error
Commit ·
424f388
1
Parent(s): 5cc7bed
AutoExpress Docker version 1.0
Browse files- .gitattributes +2 -35
- .gitignore +156 -0
- .hintrc +25 -0
- Changelog.md +26 -0
- Dockerfile +25 -0
- LICENSE +21 -0
- README.md +158 -10
- autoexpress/__init__.py +13 -0
- autoexpress/create_grid.py +55 -0
- autoexpress/modules/__init__.py +0 -0
- autoexpress/modules/a1111_client.py +248 -0
- autoexpress/modules/background_remover.py +64 -0
- autoexpress/modules/expression_generator.py +100 -0
- autoexpress/modules/image_parser.py +76 -0
- autoexpress/modules/json_handler.py +95 -0
- autoexpress/modules/utils.py +41 -0
- autoexpress/resources/clip_expressions.json +30 -0
- autoexpress/resources/empty_bg.json +49 -0
- autoexpress/resources/expressions.json +30 -0
- autoexpress/resources/illu_expressions.json +30 -0
- autoexpress/resources/images/AutoExpressUI_2024_11_13.png +0 -0
- autoexpress/resources/images/AutoExpressUI_Revamped.png +0 -0
- autoexpress/resources/images/UI.png +0 -0
- autoexpress/resources/images/anime_grid.png +0 -0
- autoexpress/resources/images/anime_input.png +0 -0
- autoexpress/resources/images/realistic_grid.png +0 -0
- autoexpress/resources/images/realistic_input.png +0 -0
- autoexpress/resources/payload.json +99 -0
- autoexpress/static/ico/favicon-rounded.png +0 -0
- autoexpress/static/ico/favicon.png +0 -0
- autoexpress/static/js/anime_toggle.js +37 -0
- autoexpress/static/js/connect.js +93 -0
- autoexpress/static/js/frontend_settings.js +12 -0
- autoexpress/static/js/generate.js +39 -0
- autoexpress/static/js/image_drag_and_drop.js +160 -0
- autoexpress/static/js/image_viewer.js +89 -0
- autoexpress/static/js/main.js +15 -0
- autoexpress/static/js/modal.js +7 -0
- autoexpress/static/stylesheet/frontend_settings.css +7 -0
- autoexpress/static/stylesheet/image_and_prompt.css +152 -0
- autoexpress/static/stylesheet/image_viewer.css +102 -0
- autoexpress/static/stylesheet/main.css +442 -0
- autoexpress/static/stylesheet/modal.css +40 -0
- autoexpress/static/stylesheet/sidebar.css +71 -0
- autoexpress/static/stylesheet/slider_object.css +77 -0
- autoexpress/templates/index.html +260 -0
- autoexpress/views.py +210 -0
- requirements.txt +6 -0
- startup.bat +2 -0
- startupDebug.bat +2 -0
.gitattributes
CHANGED
|
@@ -1,35 +1,2 @@
|
|
| 1 |
-
|
| 2 |
-
*
|
| 3 |
-
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
-
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
-
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
-
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
-
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
-
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
-
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
-
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
-
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
-
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
-
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
-
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
-
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
-
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
-
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
-
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
-
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
-
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
-
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
-
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
-
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
-
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
-
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
-
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
-
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
-
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
-
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
-
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
-
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
-
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
-
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
-
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
-
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
| 1 |
+
# Auto detect text files and perform LF normalization
|
| 2 |
+
* text=auto
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.gitignore
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
| 105 |
+
__pypackages__/
|
| 106 |
+
|
| 107 |
+
# Celery stuff
|
| 108 |
+
celerybeat-schedule
|
| 109 |
+
celerybeat.pid
|
| 110 |
+
|
| 111 |
+
# SageMath parsed files
|
| 112 |
+
*.sage.py
|
| 113 |
+
|
| 114 |
+
# Environments
|
| 115 |
+
.env
|
| 116 |
+
.venv
|
| 117 |
+
env/
|
| 118 |
+
venv/
|
| 119 |
+
ENV/
|
| 120 |
+
env.bak/
|
| 121 |
+
venv.bak/
|
| 122 |
+
|
| 123 |
+
# Spyder project settings
|
| 124 |
+
.spyderproject
|
| 125 |
+
.spyproject
|
| 126 |
+
|
| 127 |
+
# Rope project settings
|
| 128 |
+
.ropeproject
|
| 129 |
+
|
| 130 |
+
# mkdocs documentation
|
| 131 |
+
/site
|
| 132 |
+
|
| 133 |
+
# mypy
|
| 134 |
+
.mypy_cache/
|
| 135 |
+
.dmypy.json
|
| 136 |
+
dmypy.json
|
| 137 |
+
|
| 138 |
+
# Pyre type checker
|
| 139 |
+
.pyre/
|
| 140 |
+
|
| 141 |
+
# pytype static type analyzer
|
| 142 |
+
.pytype/
|
| 143 |
+
|
| 144 |
+
# Cython debug symbols
|
| 145 |
+
cython_debug/
|
| 146 |
+
|
| 147 |
+
# PyCharm
|
| 148 |
+
# JetBrains specific template is maintainted in a separate JetBrains.gitignore that can
|
| 149 |
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
| 150 |
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
| 151 |
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
| 152 |
+
#.idea/
|
| 153 |
+
Output/
|
| 154 |
+
uploads/
|
| 155 |
+
.vscode/
|
| 156 |
+
QOL CHANGES.txt
|
.hintrc
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"extends": [
|
| 3 |
+
"development"
|
| 4 |
+
],
|
| 5 |
+
"hints": {
|
| 6 |
+
"axe/name-role-value": [
|
| 7 |
+
"default",
|
| 8 |
+
{
|
| 9 |
+
"button-name": "off"
|
| 10 |
+
}
|
| 11 |
+
],
|
| 12 |
+
"axe/forms": [
|
| 13 |
+
"default",
|
| 14 |
+
{
|
| 15 |
+
"label": "off"
|
| 16 |
+
}
|
| 17 |
+
]
|
| 18 |
+
},
|
| 19 |
+
"browserslist": [
|
| 20 |
+
"defaults",
|
| 21 |
+
"not ie 11",
|
| 22 |
+
"not ios_saf <= 18",
|
| 23 |
+
"not safari <= 18"
|
| 24 |
+
]
|
| 25 |
+
}
|
Changelog.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
## 2024-11-13
|
| 2 |
+
- Docker image available here: [AutoExpress on DockerHub](https://hub.docker.com/r/deepratna/autoexpress)
|
| 3 |
+
- Added Logo to UI
|
| 4 |
+
- Added Scheduler dropdown
|
| 5 |
+
- Added info icon to UI
|
| 6 |
+
- Whenever you hover on the image or the info icon, it will show the raw generation data for convienience.
|
| 7 |
+
- Added Settings cog to have a modal for infrequently used settings.
|
| 8 |
+
- If element does not exist in dropdown (Model, Sampler, Scheduler, Lora), a new dropdown element is created.
|
| 9 |
+
|
| 10 |
+
**Avery Contributions**
|
| 11 |
+
- Boiler plate Theming Support by modifying [main.css](autoexpress/static/stylesheet/main.css)
|
| 12 |
+
- Implemented Gradient pause feature for performace increase.
|
| 13 |
+
- Expression jsons are now in different flavours instead of only being Anime/Realistic.
|
| 14 |
+
-
|
| 15 |
+

|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
## 2024-09-26
|
| 19 |
+
- Tested on Ububtu (22.04.3 | jammy)
|
| 20 |
+
|
| 21 |
+
## 2024-06-23
|
| 22 |
+
- Added revamped UI
|
| 23 |
+

|
| 24 |
+
|
| 25 |
+
- Removed my custom logger and added loguru library.
|
| 26 |
+
|
Dockerfile
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Use the official Python image and set it to support multiple architectures
|
| 2 |
+
FROM python:3
|
| 3 |
+
|
| 4 |
+
# Set working directory
|
| 5 |
+
WORKDIR /AutoExpress/
|
| 6 |
+
|
| 7 |
+
# Copy the requirements file and install dependencies
|
| 8 |
+
COPY requirements.txt ./
|
| 9 |
+
RUN pip install --upgrade pip
|
| 10 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
| 11 |
+
|
| 12 |
+
# Copy the entire project into the container
|
| 13 |
+
COPY . .
|
| 14 |
+
|
| 15 |
+
# Expose the port that Flask will run on
|
| 16 |
+
EXPOSE 5000
|
| 17 |
+
|
| 18 |
+
# Set environment variable for Flask
|
| 19 |
+
ENV FLASK_APP=autoexpress
|
| 20 |
+
ENV FLASK_RUN_HOST=0.0.0.0
|
| 21 |
+
ENV FLASK_RUN_PORT=5000
|
| 22 |
+
|
| 23 |
+
# Command to run the Flask app
|
| 24 |
+
CMD ["flask", "run"]
|
| 25 |
+
|
LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2023 Deepratna Awale
|
| 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 all
|
| 13 |
+
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 THE
|
| 21 |
+
SOFTWARE.
|
README.md
CHANGED
|
@@ -1,12 +1,160 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
-
title: AutoExpress
|
| 3 |
-
emoji: 👀
|
| 4 |
-
colorFrom: purple
|
| 5 |
-
colorTo: green
|
| 6 |
-
sdk: docker
|
| 7 |
-
pinned: false
|
| 8 |
-
license: mit
|
| 9 |
-
short_description: Launch AutoExpress to create expressions for chatbots.
|
| 10 |
-
---
|
| 11 |
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<h1> <img src="autoexpress\static\ico\favicon-rounded.png" alt="Favicon" width="25px"> AutoExpress</h1>
|
| 2 |
+
|
| 3 |
+
# Introduction
|
| 4 |
+
Automatically creates 28 different expressions from a given image using [Automatic1111 Stable Diffusion WebUI API](https://github.com/AUTOMATIC1111/stable-diffusion-webui). The application uses Inpainting with [After Detailer Extension](https://github.com/Bing-su/adetailer) to inpaint the following expressions on the face:
|
| 5 |
+
|
| 6 |
+
### For the latest changes, goto: [Change Log](Changelog.md)
|
| 7 |
+
|
| 8 |
+
<p align="center">
|
| 9 |
+
|
| 10 |
+
| Emotion | Emotion | Emotion | Emotion |
|
| 11 |
+
| ------------- | -------------- | ----------- | ----------- |
|
| 12 |
+
| Admiration | Amusement | Anger | Annoyance |
|
| 13 |
+
| Approval | Caring | Confusion | Curiosity |
|
| 14 |
+
| Desire | Disappointment | Disapproval | Disgust |
|
| 15 |
+
| Embarrassment | Excitement | Fear | Gratitude |
|
| 16 |
+
| Grief | Joy | Love | Nervousness |
|
| 17 |
+
| Neutral | Optimism | Pride | Realization |
|
| 18 |
+
| Relief | Remorse | Sadness | Surprise |
|
| 19 |
+
|
| 20 |
+
</p>
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
# Examples
|
| 24 |
+
|
| 25 |
+
### Anime
|
| 26 |
+
|
| 27 |
+
<div style="text-align:center">
|
| 28 |
+
<figure>
|
| 29 |
+
<img src ="autoexpress/resources/images/anime_grid.png" alt="Anime Image Grid" width="100%">
|
| 30 |
+
<figcaption>Anime Image Emotion Grid</figcaption>
|
| 31 |
+
</figure>
|
| 32 |
+
</div>
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
The above is an example anime expressions on the following image without cherry picking results.
|
| 36 |
+
|
| 37 |
+
<div style="text-align:center">
|
| 38 |
+
<figure>
|
| 39 |
+
<img src="autoexpress\resources\images\anime_input.png" alt="Realistic Input Image" width="100%">
|
| 40 |
+
<figcaption>Anime input image</figcaption>
|
| 41 |
+
</figure>
|
| 42 |
+
</div>
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
### Realistic
|
| 46 |
+
|
| 47 |
+
<div style="text-align:center">
|
| 48 |
+
<figure>
|
| 49 |
+
<img src ="autoexpress/resources/images/realistic_grid.png" alt="Realistic Image Grid" width="100%">
|
| 50 |
+
<figcaption>Realistic Image Emotion Grid</figcaption>
|
| 51 |
+
</figure>
|
| 52 |
+
</div>
|
| 53 |
+
|
| 54 |
+
The above is an example realistic expressions on the following image without cherry picking results.
|
| 55 |
+
|
| 56 |
+
<div style="text-align:center">
|
| 57 |
+
<figure>
|
| 58 |
+
<img src="autoexpress\resources\images\realistic_input.png" alt="Realistic Input Image" width="100%">
|
| 59 |
+
<figcaption>Realistic input image</figcaption>
|
| 60 |
+
</figure>
|
| 61 |
+
</div>
|
| 62 |
+
|
| 63 |
---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
|
| 65 |
+
# Requirements
|
| 66 |
+
- [Python3](https://www.python.org/downloads/) Prefer version 10
|
| 67 |
+
- [Automatic1111 Stable Diffusion WebUI API](https://github.com/AUTOMATIC1111/stable-diffusion-webui)
|
| 68 |
+
- [Online Services](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Online-Services)
|
| 69 |
+
- I'm currently working on integrating my [CivitAI-Model-Downloader](https://github.com/deepratna-awale/CivitAI-Model-Downloader) to automatically download LORAs.
|
| 70 |
+
- [After Detailer Extension](https://github.com/Bing-su/adetailer)
|
| 71 |
+
|
| 72 |
+
- ## Additional packages for Linux
|
| 73 |
+
- python3-pip
|
| 74 |
+
- python3-venv
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
## Run With Docker (Requires [Docker](https://www.docker.com/))
|
| 78 |
+
|
| 79 |
+
> Now AutoExpress is also available as a [Docker Image](https://hub.docker.com/r/deepratna/autoexpress)
|
| 80 |
+
|
| 81 |
+
Pull image from DockerHub
|
| 82 |
+
```bash
|
| 83 |
+
docker pull deepratna/autoexpress
|
| 84 |
+
```
|
| 85 |
+
Run
|
| 86 |
+
```bash
|
| 87 |
+
docker run -p 5000:5000 deepratna/autoexpress
|
| 88 |
+
```
|
| 89 |
+
### OR
|
| 90 |
+
Build (skip if you have pulled image)
|
| 91 |
+
```bash
|
| 92 |
+
git clone https://github.com/deepratnaawale/AutoExpress.git
|
| 93 |
+
cd AutoExpress
|
| 94 |
+
```
|
| 95 |
+
```bash
|
| 96 |
+
docker buildx build --tag ${your_dockerhub_username}/autoexpress .
|
| 97 |
+
```
|
| 98 |
+
Run
|
| 99 |
+
```bash
|
| 100 |
+
docker run -p 5000:5000 ${your_dockerhub_username}/autoexpress
|
| 101 |
+
```
|
| 102 |
+
|
| 103 |
+
## Clone Github Repo and cd into it
|
| 104 |
+
```bash
|
| 105 |
+
git clone https://github.com/deepratnaawale/AutoExpress.git
|
| 106 |
+
cd AutoExpress
|
| 107 |
+
```
|
| 108 |
+
|
| 109 |
+
- Create and activate virtual enviorenment
|
| 110 |
+
```bash
|
| 111 |
+
python3 -m venv .venv
|
| 112 |
+
```
|
| 113 |
+
- WINDOWS
|
| 114 |
+
```bash
|
| 115 |
+
.venv\Scripts\activate
|
| 116 |
+
```
|
| 117 |
+
- LINUX
|
| 118 |
+
```bash
|
| 119 |
+
source .venv/bin/activate
|
| 120 |
+
```
|
| 121 |
+
|
| 122 |
+
- Install Requirements
|
| 123 |
+
```bash
|
| 124 |
+
pip install -r requirements.txt
|
| 125 |
+
```
|
| 126 |
+
|
| 127 |
+
- Launch App
|
| 128 |
+
```bash
|
| 129 |
+
flask --app autoexpress run
|
| 130 |
+
```
|
| 131 |
+
|
| 132 |
+
- Connect to the AutoExpress UI at
|
| 133 |
+
[http://127.0.0.1:5000](http:127.0.0.1:5000)
|
| 134 |
+
|
| 135 |
+
## Launch Your A1111 Stable Diffusion WebUI Api
|
| 136 |
+
> You can check if the api is active by accessing the docs (if running locally)
|
| 137 |
+
[http://127.0.0.1:7860/docs#/default/](http://127.0.0.1:7860/docs#/default/)
|
| 138 |
+
|
| 139 |
+
|
| 140 |
+
# Usage
|
| 141 |
+

|
| 142 |
+
|
| 143 |
+
It's pretty Straight forward. Keep an eye on the logs in the console. Dropping an image will auto populate all attributes in the UI if the image has Stable Diffusion info text. Only supports A1111 WebUI API for now.
|
| 144 |
+
|
| 145 |
+
PS: This is a very handy tool to use with [Silly Tavern](https://github.com/SillyTavern/SillyTavern) to **generate character expressions sprites** for any bot.
|
| 146 |
+
|
| 147 |
+
# Latest UI
|
| 148 |
+

|
| 149 |
+
|
| 150 |
+
# Future Work
|
| 151 |
+
- Change pose along with expression keeping consistent clothes and background. (Probably via Controlnets and ADetailer)
|
| 152 |
+
- Better Expressions for Realistic Images.
|
| 153 |
+
- Tests to check each module.
|
| 154 |
+
|
| 155 |
+
# Special Thanks
|
| 156 |
+
[SD Parsers by d3x-at](https://github.com/d3x-at/sd-parsers)
|
| 157 |
+
|
| 158 |
+
[SD API Examples](https://github.com/AUTOMATIC1111/stable-diffusion-webui/discussions/3734)
|
| 159 |
+
|
| 160 |
+
[Avery Velfaire](https://github.com/AveryVeilfaire) for bug fixes, UI design, and prompt engineering.
|
autoexpress/__init__.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from flask import Flask
|
| 2 |
+
import sys
|
| 3 |
+
import os
|
| 4 |
+
|
| 5 |
+
parent_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir))
|
| 6 |
+
sys.path.insert(0, parent_dir)
|
| 7 |
+
|
| 8 |
+
autoexpress = Flask(__name__)
|
| 9 |
+
|
| 10 |
+
from autoexpress.views import autoexpress
|
| 11 |
+
|
| 12 |
+
if __name__ == "__main__":
|
| 13 |
+
autoexpress.run(debug=True)
|
autoexpress/create_grid.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import matplotlib.pyplot as plt
|
| 2 |
+
import glob
|
| 3 |
+
import matplotlib.image as mpimg
|
| 4 |
+
from modules.json_handler import get_expression_list
|
| 5 |
+
|
| 6 |
+
def plot_images(images, labels, rows, cols, output_file):
|
| 7 |
+
fig, axes = plt.subplots(rows, cols, figsize=(12, 12))
|
| 8 |
+
fig.patch.set_facecolor("#333333") # Set background color to dark grey
|
| 9 |
+
for ax in axes.flat:
|
| 10 |
+
ax.axis("off")
|
| 11 |
+
for i, ax in enumerate(axes.flat):
|
| 12 |
+
ax.imshow(images[i])
|
| 13 |
+
ax.set_title(labels[i], color="white") # Set title color to white
|
| 14 |
+
plt.tight_layout()
|
| 15 |
+
plt.savefig(output_file, facecolor=fig.get_facecolor()) # Save figure
|
| 16 |
+
plt.show()
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def create_sprites(images, rows, cols, output_file):
|
| 20 |
+
fig, axes = plt.subplots(rows, cols, figsize=(12, 12))
|
| 21 |
+
fig.patch.set_facecolor("#333333") # Set background color to dark grey
|
| 22 |
+
|
| 23 |
+
for ax in axes.flat:
|
| 24 |
+
ax.axis("off")
|
| 25 |
+
|
| 26 |
+
for i, ax in enumerate(axes.flat):
|
| 27 |
+
ax.imshow(images[i])
|
| 28 |
+
|
| 29 |
+
plt.subplots_adjust(left=0, right=1, top=1, bottom=0, wspace=0, hspace=0)
|
| 30 |
+
plt.savefig(output_file, facecolor=fig.get_facecolor()) # Save figure
|
| 31 |
+
plt.show()
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def load_images_from_directory(directory):
|
| 35 |
+
image_list = []
|
| 36 |
+
for filename in glob.glob(directory + "/*.png"):
|
| 37 |
+
image = mpimg.imread(filename)
|
| 38 |
+
image_list.append(image)
|
| 39 |
+
return image_list
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
def main():
|
| 43 |
+
character_name = "Hinata"
|
| 44 |
+
input_dir = r"Output\Hinata"
|
| 45 |
+
output_file = f"Output\\{character_name}_sprite.png"
|
| 46 |
+
rows,cols = 4, 7
|
| 47 |
+
|
| 48 |
+
labels = get_expression_list().keys()
|
| 49 |
+
images = load_images_from_directory(input_dir)
|
| 50 |
+
|
| 51 |
+
# plot_images(images, labels, rows, cols, output_file)
|
| 52 |
+
create_sprites(images, rows, cols, output_file)
|
| 53 |
+
|
| 54 |
+
if __name__ == "__main__":
|
| 55 |
+
main()
|
autoexpress/modules/__init__.py
ADDED
|
File without changes
|
autoexpress/modules/a1111_client.py
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import requests
|
| 2 |
+
import io
|
| 3 |
+
import base64
|
| 4 |
+
from PIL import Image, PngImagePlugin
|
| 5 |
+
from loguru import logger as log
|
| 6 |
+
import pathlib
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class A1111Client:
|
| 10 |
+
|
| 11 |
+
def __init__(self, ip="127.0.0.1", port="7860", use_https=False):
|
| 12 |
+
protocol = "https://" if use_https else "http://"
|
| 13 |
+
self._url = f"{protocol}{ip}:{port}"
|
| 14 |
+
self._endpoints = {
|
| 15 |
+
"img2img": "/sdapi/v1/img2img",
|
| 16 |
+
"samplers": "/sdapi/v1/samplers",
|
| 17 |
+
"models": "/sdapi/v1/sd-models",
|
| 18 |
+
"loras": "/sdapi/v1/loras",
|
| 19 |
+
"extensions": "/sdapi/v1/extensions",
|
| 20 |
+
"interrupt": "/sdapi/v1/interrupt",
|
| 21 |
+
"image_info": "/sdapi/v1/png-info",
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
@property
|
| 25 |
+
def extensions(self):
|
| 26 |
+
response = requests.get(
|
| 27 |
+
url=f"{self._url}{self._endpoints['extensions']}",
|
| 28 |
+
headers={"Content-Type": "application/json"},
|
| 29 |
+
)
|
| 30 |
+
|
| 31 |
+
if response.status_code == 200:
|
| 32 |
+
r = response.json()
|
| 33 |
+
extensions = {extension["name"]: extension["enabled"] for extension in r}
|
| 34 |
+
return extensions
|
| 35 |
+
else:
|
| 36 |
+
log.error(
|
| 37 |
+
f"Request failed with code: {response.status_code} {response.json()}"
|
| 38 |
+
)
|
| 39 |
+
return None
|
| 40 |
+
|
| 41 |
+
@property
|
| 42 |
+
def loras(self):
|
| 43 |
+
response = requests.get(
|
| 44 |
+
url=f"{self._url}{self._endpoints['loras']}",
|
| 45 |
+
headers={"Content-Type": "application/json"},
|
| 46 |
+
)
|
| 47 |
+
|
| 48 |
+
if response.status_code == 200:
|
| 49 |
+
r = response.json()
|
| 50 |
+
loras = [lora["name"] for lora in r]
|
| 51 |
+
return loras
|
| 52 |
+
else:
|
| 53 |
+
log.error(
|
| 54 |
+
f"Request failed with code: {response.status_code} {response.json()}"
|
| 55 |
+
)
|
| 56 |
+
return None
|
| 57 |
+
|
| 58 |
+
@property
|
| 59 |
+
def samplers(self):
|
| 60 |
+
response = requests.get(
|
| 61 |
+
url=f"{self._url}{self._endpoints['samplers']}",
|
| 62 |
+
headers={"Content-Type": "application/json"},
|
| 63 |
+
)
|
| 64 |
+
|
| 65 |
+
if response.status_code == 200:
|
| 66 |
+
r = response.json()
|
| 67 |
+
samplers = [sampler["name"] for sampler in r]
|
| 68 |
+
return samplers
|
| 69 |
+
else:
|
| 70 |
+
log.error(
|
| 71 |
+
f"Request failed with code: {response.status_code} {response.json()}"
|
| 72 |
+
)
|
| 73 |
+
return None
|
| 74 |
+
|
| 75 |
+
@property
|
| 76 |
+
def models(self):
|
| 77 |
+
response = requests.get(
|
| 78 |
+
url=f"{self._url}{self._endpoints['models']}",
|
| 79 |
+
headers={"Content-Type": "application/json"},
|
| 80 |
+
)
|
| 81 |
+
|
| 82 |
+
if response.status_code == 200:
|
| 83 |
+
r = response.json()
|
| 84 |
+
models = [model["model_name"] for model in r]
|
| 85 |
+
return models
|
| 86 |
+
else:
|
| 87 |
+
log.error(
|
| 88 |
+
f"Request failed with code: {response.status_code} {response.json()}"
|
| 89 |
+
)
|
| 90 |
+
return None
|
| 91 |
+
|
| 92 |
+
def img2img_api(self, json_payload):
|
| 93 |
+
response = requests.post(
|
| 94 |
+
url=f"{self._url}{self._endpoints['img2img']}",
|
| 95 |
+
data=json_payload,
|
| 96 |
+
headers={"Content-Type": "application/json"},
|
| 97 |
+
)
|
| 98 |
+
|
| 99 |
+
if response.status_code == 200:
|
| 100 |
+
return response
|
| 101 |
+
|
| 102 |
+
log.error(f"Request failed with code: {response.status_code} {response.json()}")
|
| 103 |
+
return False
|
| 104 |
+
|
| 105 |
+
def get_image_info(self, b64_image):
|
| 106 |
+
png_payload = "data:image/png;base64," + b64_image
|
| 107 |
+
|
| 108 |
+
response = requests.post(
|
| 109 |
+
url=f"{self._url}{self._endpoints['image_info']}",
|
| 110 |
+
json=png_payload,
|
| 111 |
+
headers={"Content-Type": "application/json"},
|
| 112 |
+
)
|
| 113 |
+
|
| 114 |
+
if response.status_code == 200:
|
| 115 |
+
return response
|
| 116 |
+
|
| 117 |
+
log.error(f"Request failed with code: {response.status_code} {response.json()}")
|
| 118 |
+
return False
|
| 119 |
+
|
| 120 |
+
def interrupt(self):
|
| 121 |
+
response = requests.post(
|
| 122 |
+
url=f"{self._url}{self._endpoints['interrupt']}",
|
| 123 |
+
headers={"Content-Type": "application/json"},
|
| 124 |
+
)
|
| 125 |
+
|
| 126 |
+
if response.status_code != 200:
|
| 127 |
+
log.error(
|
| 128 |
+
f"Request failed with code: {response.status_code} {response.json()}"
|
| 129 |
+
)
|
| 130 |
+
return False
|
| 131 |
+
|
| 132 |
+
r = response.json()
|
| 133 |
+
log.error(f"Interrupted by user.{r.text}")
|
| 134 |
+
return True
|
| 135 |
+
|
| 136 |
+
def is_extension(self, ext="adetailer"):
|
| 137 |
+
extensions = self.extensions
|
| 138 |
+
log.debug(f"Found following extensions: {extensions}")
|
| 139 |
+
|
| 140 |
+
if ext in extensions:
|
| 141 |
+
log.info(f"Found {ext} extension.")
|
| 142 |
+
|
| 143 |
+
if extensions[ext]:
|
| 144 |
+
log.info(f"{ext} extension is enabled.")
|
| 145 |
+
return True
|
| 146 |
+
else:
|
| 147 |
+
log.warning(f"Please enable the {ext} extension if you want to use it.")
|
| 148 |
+
return False
|
| 149 |
+
|
| 150 |
+
log.error(f"Could not find {ext} extension")
|
| 151 |
+
return False
|
| 152 |
+
|
| 153 |
+
def setURL(self, url: str):
|
| 154 |
+
self._url = url
|
| 155 |
+
|
| 156 |
+
def getURL(self):
|
| 157 |
+
return self._url
|
| 158 |
+
|
| 159 |
+
|
| 160 |
+
def main():
|
| 161 |
+
import utils
|
| 162 |
+
file_path = r"D:\Workspace\AI\stable-diffusion-webui\outputs\txt2img-images\2024-04-15\00018-4139222450.png"
|
| 163 |
+
file_path = pathlib.Path(file_path)
|
| 164 |
+
image_str = utils.raw_b64_img(file_path)
|
| 165 |
+
|
| 166 |
+
json_body = {
|
| 167 |
+
"prompt": "",
|
| 168 |
+
"negative_prompt": "",
|
| 169 |
+
"styles": [""],
|
| 170 |
+
"seed": -1,
|
| 171 |
+
"subseed": -1,
|
| 172 |
+
"subseed_strength": 0,
|
| 173 |
+
"seed_resize_from_h": -1,
|
| 174 |
+
"seed_resize_from_w": -1,
|
| 175 |
+
"sampler_name": "Euler",
|
| 176 |
+
"scheduler": "Automatic",
|
| 177 |
+
"batch_size": 1,
|
| 178 |
+
"n_iter": 1,
|
| 179 |
+
"steps": 50,
|
| 180 |
+
"cfg_scale": 7,
|
| 181 |
+
"width": 512,
|
| 182 |
+
"height": 768,
|
| 183 |
+
"restore_faces": False,
|
| 184 |
+
"tiling": True,
|
| 185 |
+
"do_not_save_samples": False,
|
| 186 |
+
"do_not_save_grid": False,
|
| 187 |
+
"eta": 0,
|
| 188 |
+
"denoising_strength": 0.75,
|
| 189 |
+
"s_min_uncond": 0,
|
| 190 |
+
"s_churn": 0,
|
| 191 |
+
"s_tmax": 0,
|
| 192 |
+
"s_tmin": 0,
|
| 193 |
+
"s_noise": 0,
|
| 194 |
+
"override_settings": {},
|
| 195 |
+
"override_settings_restore_afterwards": True,
|
| 196 |
+
"refiner_checkpoint": "",
|
| 197 |
+
"refiner_switch_at": 0,
|
| 198 |
+
"disable_extra_networks": False,
|
| 199 |
+
"firstpass_image": "",
|
| 200 |
+
"comments": {},
|
| 201 |
+
"init_images": [""],
|
| 202 |
+
"resize_mode": 0,
|
| 203 |
+
"image_cfg_scale": 7,
|
| 204 |
+
"mask": "string",
|
| 205 |
+
"mask_blur_x": 4,
|
| 206 |
+
"mask_blur_y": 4,
|
| 207 |
+
"mask_blur": 0,
|
| 208 |
+
"mask_round": True,
|
| 209 |
+
"inpainting_fill": 0,
|
| 210 |
+
"inpaint_full_res": True,
|
| 211 |
+
"inpaint_full_res_padding": 0,
|
| 212 |
+
"inpainting_mask_invert": 0,
|
| 213 |
+
"initial_noise_multiplier": 0,
|
| 214 |
+
"latent_mask": "string",
|
| 215 |
+
"force_task_id": "string",
|
| 216 |
+
"sampler_index": "Euler",
|
| 217 |
+
"include_init_images": False,
|
| 218 |
+
"script_name": "",
|
| 219 |
+
"script_args": [],
|
| 220 |
+
"send_images": True,
|
| 221 |
+
"save_images": False,
|
| 222 |
+
"alwayson_scripts": {},
|
| 223 |
+
"infotext": "string",
|
| 224 |
+
}
|
| 225 |
+
|
| 226 |
+
png_payload = "data:image/png;base64," + image_str
|
| 227 |
+
json_body["init_images"][0] = png_payload
|
| 228 |
+
|
| 229 |
+
sd = A1111Client()
|
| 230 |
+
response = sd.img2img_api(json_body)
|
| 231 |
+
|
| 232 |
+
if response == 200:
|
| 233 |
+
r = response.json()
|
| 234 |
+
for i in r['images']:
|
| 235 |
+
image = Image.open(io.BytesIO(base64.b64decode(i.split(",",1)[0])))
|
| 236 |
+
|
| 237 |
+
info_response = sd.get_image_info(i)
|
| 238 |
+
|
| 239 |
+
pnginfo = PngImagePlugin.PngInfo()
|
| 240 |
+
pnginfo.add_text("parameters", info_response.json().get("info"))
|
| 241 |
+
|
| 242 |
+
image.save(f"Output/{file_path.stem}.png", pnginfo=pnginfo)
|
| 243 |
+
else:
|
| 244 |
+
print(response.json())
|
| 245 |
+
|
| 246 |
+
|
| 247 |
+
if __name__ == "__main__":
|
| 248 |
+
main()
|
autoexpress/modules/background_remover.py
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from rembg import remove
|
| 2 |
+
from PIL import Image, ImageFilter
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
import io
|
| 5 |
+
from glob import glob
|
| 6 |
+
from loguru import logger as log
|
| 7 |
+
|
| 8 |
+
global files_processed
|
| 9 |
+
files_processed = None
|
| 10 |
+
|
| 11 |
+
def get_files_processed():
|
| 12 |
+
return files_processed
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def remove_background_and_feather(input_path, output_path, feather_radius=4):
|
| 16 |
+
# Read the image
|
| 17 |
+
with open(input_path, "rb") as file:
|
| 18 |
+
input_image = file.read()
|
| 19 |
+
|
| 20 |
+
# Remove the background
|
| 21 |
+
output_image = remove(input_image)
|
| 22 |
+
|
| 23 |
+
# Convert the result to a PIL image
|
| 24 |
+
img_with_transparency = Image.open(io.BytesIO(output_image))
|
| 25 |
+
|
| 26 |
+
# Apply feather (Gaussian Blur) to the alpha channel
|
| 27 |
+
alpha = img_with_transparency.getchannel("A")
|
| 28 |
+
alpha_feathered = alpha.filter(ImageFilter.GaussianBlur(feather_radius))
|
| 29 |
+
img_with_transparency.putalpha(alpha_feathered)
|
| 30 |
+
|
| 31 |
+
# Save the final image
|
| 32 |
+
img_with_transparency.save(output_path, "PNG")
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def batch_process_images(input_dir, output_dir):
|
| 36 |
+
input_dir_path = Path(input_dir)
|
| 37 |
+
output_dir_path = Path(output_dir)
|
| 38 |
+
output_dir_path.mkdir(exist_ok=True)
|
| 39 |
+
global files_processed
|
| 40 |
+
# Process each image in the input directory
|
| 41 |
+
images = list(input_dir_path.glob("*.png")) + list(input_dir_path.glob("*.jpg"))
|
| 42 |
+
if images:
|
| 43 |
+
log.info("Found the following images: ", [img.stem for img in images])
|
| 44 |
+
files_processed = len(images)
|
| 45 |
+
for image_path in images:
|
| 46 |
+
output_image_path = output_dir_path / image_path.name
|
| 47 |
+
log.info(f"Processing {image_path}...")
|
| 48 |
+
remove_background_and_feather(image_path, output_image_path)
|
| 49 |
+
log.info(f"Saved to {output_image_path}")
|
| 50 |
+
return files_processed
|
| 51 |
+
else:
|
| 52 |
+
log.info("No Images in this Directory")
|
| 53 |
+
return None
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
def main():
|
| 57 |
+
input_path = input("Enter the directory your images are in: ")
|
| 58 |
+
output_path = input("Output Directory: ")
|
| 59 |
+
|
| 60 |
+
batch_process_images(input_path, output_path)
|
| 61 |
+
|
| 62 |
+
# Usage: Specify your input and output directories
|
| 63 |
+
if __name__ == "__main__":
|
| 64 |
+
main()
|
autoexpress/modules/expression_generator.py
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from . import utils, json_handler
|
| 2 |
+
from . import a1111_client
|
| 3 |
+
from loguru import logger as log
|
| 4 |
+
|
| 5 |
+
import io
|
| 6 |
+
import base64
|
| 7 |
+
import pathlib
|
| 8 |
+
|
| 9 |
+
from PIL import Image, PngImagePlugin
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def generate_expressions(
|
| 13 |
+
sd: a1111_client.A1111Client,
|
| 14 |
+
output_path: str,
|
| 15 |
+
settings: dict,
|
| 16 |
+
image_str: str = None,
|
| 17 |
+
input_image_path: str = None,
|
| 18 |
+
is_realistic: bool = False,
|
| 19 |
+
):
|
| 20 |
+
|
| 21 |
+
image_str = utils.is_image_valid(input_image_path, image_str)
|
| 22 |
+
|
| 23 |
+
output_path = pathlib.Path(output_path)
|
| 24 |
+
pathlib.Path(output_path).mkdir(parents=True, exist_ok=True)
|
| 25 |
+
|
| 26 |
+
if is_realistic:
|
| 27 |
+
log.info("Using clip prompts since realistic is set to true.")
|
| 28 |
+
expressions = json_handler.get_clip_expression_list()
|
| 29 |
+
else:
|
| 30 |
+
expressions = json_handler.get_expression_list()
|
| 31 |
+
|
| 32 |
+
log.info(f"Output Directory: {output_path.absolute()}")
|
| 33 |
+
|
| 34 |
+
for expression_name, tags in expressions.items():
|
| 35 |
+
log.info(f"Generating image for {expression_name} expression.")
|
| 36 |
+
|
| 37 |
+
default_request_body = json_handler.get_img2img_payload()
|
| 38 |
+
|
| 39 |
+
json_payload = json_handler.edit_payload_body(
|
| 40 |
+
image_str, default_request_body, settings, tags
|
| 41 |
+
)
|
| 42 |
+
|
| 43 |
+
output_image_path = pathlib.Path(output_path, expression_name + ".png")
|
| 44 |
+
|
| 45 |
+
response = sd.img2img_api(json_payload)
|
| 46 |
+
|
| 47 |
+
if not response:
|
| 48 |
+
return
|
| 49 |
+
|
| 50 |
+
r = response.json()
|
| 51 |
+
image = Image.open(io.BytesIO(base64.b64decode(r["images"][0])))
|
| 52 |
+
image.save(output_image_path)
|
| 53 |
+
log.info("Done.")
|
| 54 |
+
|
| 55 |
+
log.info(f"Generated all Expressions in {output_path.absolute()}")
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def opaque(
|
| 59 |
+
sd: a1111_client.A1111Client,
|
| 60 |
+
input_image_path: str,
|
| 61 |
+
image_str: str,
|
| 62 |
+
output_path: str,
|
| 63 |
+
settings: dict = None,
|
| 64 |
+
):
|
| 65 |
+
gen_info = None
|
| 66 |
+
|
| 67 |
+
image_str = utils.is_image_valid(input_image_path, image_str)
|
| 68 |
+
|
| 69 |
+
output_path = pathlib.Path(output_path).absolute()
|
| 70 |
+
pathlib.Path(output_path).mkdir(parents=True, exist_ok=True)
|
| 71 |
+
|
| 72 |
+
default_request_body = json_handler.get_opaque_payload()
|
| 73 |
+
|
| 74 |
+
json_payload = json_handler.edit_payload_body(
|
| 75 |
+
image_str, default_request_body, settings, ""
|
| 76 |
+
)
|
| 77 |
+
|
| 78 |
+
output_image_path = pathlib.Path(output_path, "temp" + ".png")
|
| 79 |
+
|
| 80 |
+
response = sd.img2img_api(json_payload)
|
| 81 |
+
|
| 82 |
+
if not response:
|
| 83 |
+
return
|
| 84 |
+
|
| 85 |
+
r = response.json()
|
| 86 |
+
|
| 87 |
+
img_str = r["images"][0]
|
| 88 |
+
gen_info = r["info"]
|
| 89 |
+
|
| 90 |
+
image = Image.open(io.BytesIO(base64.b64decode(img_str)))
|
| 91 |
+
image.save(output_image_path)
|
| 92 |
+
|
| 93 |
+
log.info(f"Picture generated with info: {gen_info}")
|
| 94 |
+
log.info(f"Image Saved")
|
| 95 |
+
|
| 96 |
+
log.info(
|
| 97 |
+
f"Enforced an opaque background on image. Temp file at {output_image_path.absolute()}"
|
| 98 |
+
)
|
| 99 |
+
|
| 100 |
+
return (output_image_path, gen_info)
|
autoexpress/modules/image_parser.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Read Image Data using sd_parsers
|
| 2 |
+
from sd_parsers import ParserManager
|
| 3 |
+
from sd_parsers.data import Generators
|
| 4 |
+
from loguru import logger as log
|
| 5 |
+
import re
|
| 6 |
+
|
| 7 |
+
def get_lora_from_prompt(prompt):
|
| 8 |
+
# Regular expression pattern to find text and strength
|
| 9 |
+
pattern = r"<lora:(.*?):(.*?)>"
|
| 10 |
+
|
| 11 |
+
# Find all matches
|
| 12 |
+
matches = re.findall(pattern, prompt)
|
| 13 |
+
|
| 14 |
+
log.info(matches)
|
| 15 |
+
return matches
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def get_parsed_data(image_path):
|
| 19 |
+
parser_manager = ParserManager()
|
| 20 |
+
parsed_data = parser_manager.parse(image_path)
|
| 21 |
+
if not parsed_data: # return if no metadata found in image
|
| 22 |
+
return None
|
| 23 |
+
return parsed_data
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def generate_parameters(image_path):
|
| 27 |
+
parsed_data = get_parsed_data(image_path)
|
| 28 |
+
|
| 29 |
+
# get first sampler (there may be more than one (i.e., in upscaled comfy images)
|
| 30 |
+
sampler = next(iter(parsed_data.samplers), None)
|
| 31 |
+
if sampler is None: # return if no samplers found in image
|
| 32 |
+
return None
|
| 33 |
+
|
| 34 |
+
prompt = parsed_data.full_prompt
|
| 35 |
+
if prompt:
|
| 36 |
+
lora = get_lora_from_prompt(prompt)
|
| 37 |
+
|
| 38 |
+
width, height = "", ""
|
| 39 |
+
if parsed_data.generator == Generators.AUTOMATIC1111:
|
| 40 |
+
try:
|
| 41 |
+
# almost every SD image generator uses a different way to store image sizes
|
| 42 |
+
width, height = parsed_data.metadata["Size"].split("x")
|
| 43 |
+
except Exception:
|
| 44 |
+
pass
|
| 45 |
+
|
| 46 |
+
params = {
|
| 47 |
+
"checkpoint": sampler.model.name if sampler.model else None,
|
| 48 |
+
"sampler": sampler.name,
|
| 49 |
+
"lora": parsed_data.metadata.get("lora", None) or parsed_data.metadata.get("lora_name", None),
|
| 50 |
+
"scheduler": sampler.parameters.get("scheduler", None),
|
| 51 |
+
"clip_skip": "2",
|
| 52 |
+
"seed": sampler.parameters.get("seed", None),
|
| 53 |
+
"steps": sampler.parameters.get("steps", None),
|
| 54 |
+
"inpaint_width": width,
|
| 55 |
+
"inpaint_height": height,
|
| 56 |
+
"cfg_scale": sampler.parameters.get("cfg_scale", None),
|
| 57 |
+
"denoising_strength": "0.5",
|
| 58 |
+
"prompt": parsed_data.full_prompt,
|
| 59 |
+
"negative_prompt": parsed_data.full_negative_prompt,
|
| 60 |
+
}
|
| 61 |
+
return params
|
| 62 |
+
|
| 63 |
+
def generate_uncleaned_params(image_path):
|
| 64 |
+
return str(get_parsed_data(image_path))
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
def main():
|
| 68 |
+
|
| 69 |
+
image_path = r"D:\Workspace\AutoExpress\uploads\ComfyUI_00011_.png"
|
| 70 |
+
params = generate_parameters(image_path)
|
| 71 |
+
parsed_data = get_parsed_data(image_path)
|
| 72 |
+
log.info(params)
|
| 73 |
+
print(parsed_data)
|
| 74 |
+
|
| 75 |
+
if __name__ == "__main__":
|
| 76 |
+
main()
|
autoexpress/modules/json_handler.py
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
from loguru import logger as log
|
| 3 |
+
|
| 4 |
+
def get_opaque_payload():
|
| 5 |
+
with open(r"autoexpress\resources\empty_bg.json", "r") as payload_file:
|
| 6 |
+
return json.load(payload_file)
|
| 7 |
+
|
| 8 |
+
def get_expression_list():
|
| 9 |
+
with open(r"autoexpress\resources\expressions.json", "r") as exp_file:
|
| 10 |
+
return json.load(exp_file)
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def get_clip_expression_list():
|
| 14 |
+
with open(r"autoexpress\resources\clip_expressions.json", "r") as exp_file:
|
| 15 |
+
return json.load(exp_file)
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def get_img2img_payload():
|
| 19 |
+
with open(r"autoexpress\resources\payload.json", "r") as payload_file:
|
| 20 |
+
return json.load(payload_file)
|
| 21 |
+
|
| 22 |
+
def update_nested_key(data, key_to_update, new_value):
|
| 23 |
+
if isinstance(data, dict):
|
| 24 |
+
for key, value in data.items():
|
| 25 |
+
if key == key_to_update:
|
| 26 |
+
data[key] = new_value
|
| 27 |
+
update_nested_key(value, key_to_update, new_value)
|
| 28 |
+
elif isinstance(data, list):
|
| 29 |
+
for item in data:
|
| 30 |
+
update_nested_key(item, key_to_update, new_value)
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def find_nested_key(data, target_key):
|
| 34 |
+
"""Recursively search for a key in a nested structure (dictionary or list) and return its value."""
|
| 35 |
+
if isinstance(data, dict):
|
| 36 |
+
if target_key in data:
|
| 37 |
+
return data[target_key]
|
| 38 |
+
return next(
|
| 39 |
+
(
|
| 40 |
+
result
|
| 41 |
+
for key, value in data.items()
|
| 42 |
+
if (result := find_nested_key(value, target_key)) is not None
|
| 43 |
+
),
|
| 44 |
+
None,
|
| 45 |
+
)
|
| 46 |
+
|
| 47 |
+
elif isinstance(data, list):
|
| 48 |
+
return next(
|
| 49 |
+
(
|
| 50 |
+
result
|
| 51 |
+
for item in data
|
| 52 |
+
if isinstance(item, (dict, list))
|
| 53 |
+
and (result := find_nested_key(item, target_key)) is not None
|
| 54 |
+
),
|
| 55 |
+
None,
|
| 56 |
+
)
|
| 57 |
+
return None
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def edit_payload_body(b64_image_str: str, payload, settings=None, expression_tags=None):
|
| 61 |
+
|
| 62 |
+
if settings:
|
| 63 |
+
for key, value in settings.items():
|
| 64 |
+
update_nested_key(payload, key, value)
|
| 65 |
+
|
| 66 |
+
prompt = find_nested_key(payload, "ad_prompt")
|
| 67 |
+
|
| 68 |
+
if prompt:
|
| 69 |
+
if prompt[-1] not in [","]:
|
| 70 |
+
update_nested_key(payload, "ad_prompt", prompt + ", ")
|
| 71 |
+
|
| 72 |
+
if expression_tags:
|
| 73 |
+
update_nested_key(
|
| 74 |
+
payload,
|
| 75 |
+
"ad_prompt",
|
| 76 |
+
find_nested_key(payload, "ad_prompt") + str(expression_tags),
|
| 77 |
+
)
|
| 78 |
+
|
| 79 |
+
payload["prompt"] = payload["alwayson_scripts"]["ADetailer"]["args"][2]["ad_prompt"]
|
| 80 |
+
payload["negative_prompt"] = payload["alwayson_scripts"]["ADetailer"]["args"][2][
|
| 81 |
+
"ad_negative_prompt"
|
| 82 |
+
]
|
| 83 |
+
|
| 84 |
+
log.debug(f"{payload}")
|
| 85 |
+
|
| 86 |
+
payload["init_images"][0] = b64_image_str
|
| 87 |
+
|
| 88 |
+
json_payload = json.dumps(payload, indent=4)
|
| 89 |
+
|
| 90 |
+
return json_payload
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
if __name__ == "__main__":
|
| 94 |
+
expression = get_expression_list()
|
| 95 |
+
print(expression.keys())
|
autoexpress/modules/utils.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import io
|
| 2 |
+
import base64
|
| 3 |
+
from PIL import Image, PngImagePlugin
|
| 4 |
+
from loguru import logger as log
|
| 5 |
+
import pathlib
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def raw_b64_img(input_image):
|
| 10 |
+
# Convert the input image to base64 format (SD api accepts base64)
|
| 11 |
+
with Image.open(input_image) as image:
|
| 12 |
+
with io.BytesIO() as img_buffer:
|
| 13 |
+
# Save the image to a bytes buffer
|
| 14 |
+
image.save(
|
| 15 |
+
img_buffer, format=input_image.suffix[1:]
|
| 16 |
+
) # suffix returns .png -> remove . to get only png
|
| 17 |
+
|
| 18 |
+
# Encode the image to base64 and decode to a string in one step
|
| 19 |
+
input_img_base64_str = base64.b64encode(img_buffer.getvalue()).decode(
|
| 20 |
+
"utf-8"
|
| 21 |
+
)
|
| 22 |
+
# input_img_base64_str = Image.open(io.BytesIO(base64.b64decode(input_image.split(",", 1)[0])))
|
| 23 |
+
return input_img_base64_str
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def b64_img(image) -> str:
|
| 27 |
+
return "data:image/png;base64," + raw_b64_img(image)
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def is_image_valid(input_image_path, image_str):
|
| 31 |
+
|
| 32 |
+
if not input_image_path and not image_str:
|
| 33 |
+
log.error("Need atleast an image path/ base 64 string of image.")
|
| 34 |
+
return False
|
| 35 |
+
|
| 36 |
+
if not image_str:
|
| 37 |
+
input_image_path = pathlib.Path(input_image_path)
|
| 38 |
+
image_str = raw_b64_img(input_image_path)
|
| 39 |
+
return image_str
|
| 40 |
+
|
| 41 |
+
return image_str
|
autoexpress/resources/clip_expressions.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"admiration": "A look of respect and warm approval, characterized by slightly widened eyes that convey interest and esteem. The eyebrows are gently arched, enhancing the expression of intrigue and appreciation. The mouth is closed in a soft, tender smile, reflecting a deep sense of admiration and pleasure. The face overall holds a calm and composed demeanor, with a slight nod or tilt of the head towards the object of admiration, symbolizing respect and veneration.",
|
| 3 |
+
"amusement": "A joyful and slightly mischievous expression, featuring slightly raised eyebrows to indicate curiosity and interest. The eyes are bright and twinkling, reflecting a light-hearted enjoyment. The mouth is open in a subtle, relaxed smile, showing a hint of teeth. The overall demeanor is relaxed and cheerful, with a gentle, playful tilt of the head, suggesting a moment of genuine amusement and delight.",
|
| 4 |
+
"anger": "A fierce and intense expression, marked by furrowed brows that draw together sharply, creating deep lines on the forehead. The eyes are narrowed and piercing, conveying a strong sense of irritation or hostility. The lips are tightly pressed together or slightly parted in a snarl, revealing clenched teeth. The jaw is set firmly, and the overall facial muscles are tensed, reflecting the strong, forceful emotions associated with anger.",
|
| 5 |
+
"annoyance": "A mildly irritated expression characterized by a slight frown and a furrowed brow, showing subtle frustration. The eyes are slightly squinted or rolling, often looking away from the source of annoyance. The lips are pursed or slightly turned down at the corners, indicating displeasure. The overall demeanor may include a subtle shaking of the head or a dismissive gesture, such as a slight shrug, conveying a sense of impatience or minor irritation.",
|
| 6 |
+
"approval": "A warm and positive expression, highlighted by softly raised eyebrows and relaxed, open eyes that convey a sense of satisfaction and agreement. The mouth is gently curved into a subtle, reassuring smile, indicating a favorable response. The overall facial posture is open and inviting, with a slight nod or an affirmative tilt of the head, symbolizing acceptance and encouragement.",
|
| 7 |
+
"caring": "A tender and compassionate expression, characterized by slightly tilted head conveying empathy and concern. The eyes are soft and warm, with gentle, direct gaze that communicates understanding and kindness. The eyebrows are relaxed and slightly curved, enhancing the nurturing aspect of the expression. The mouth is curved in a soft, comforting smile, suggesting reassurance and support. The overall demeanor is calm and attentive, projecting a strong sense of care and protection.",
|
| 8 |
+
"confusion": "A puzzled and uncertain expression, characterized by a slightly furrowed brow and a tilted head, indicating a lack of understanding. The eyes are wide and searching, possibly darting around as if looking for clarity. The mouth is partly open, reflecting hesitation or questioning, and the lips might be slightly pursed. The overall demeanor suggests bewilderment, with possible gestures like a hand to the chin or cheek, symbolizing deep thought or perplexity.",
|
| 9 |
+
"curiosity": "An intrigued and attentive expression, marked by slightly raised eyebrows and wide, bright eyes that convey a keen interest. The head may be tilted forward slightly, symbolizing an eagerness to learn or discover more. The mouth is often closed with a hint of a smile, suggesting a pleasant and engaged demeanor. Occasionally, the lips may be parted as if about to ask a question. The overall posture is alert and forward-leaning, indicating active engagement and curiosity.",
|
| 10 |
+
"desire": "An intense and longing expression, characterized by slightly parted lips and a soft, focused gaze that conveys deep yearning. The eyebrows are relaxed, but the eyes are wide and expressive, reflecting a strong emotional pull towards the object of desire. The overall facial posture is subtly forward-leaning, suggesting anticipation and attraction. The mouth may show a tender smile or remain slightly open, enhancing the sensuality and emotional depth of the expression.",
|
| 11 |
+
"disappointment": "A downcast and subdued expression, characterized by a slight frown and downturned corners of the mouth, conveying a sense of sadness or letdown. The eyebrows are gently furrowed, adding to the overall sorrowful appearance. The eyes may appear slightly glossy or stare blankly, reflecting a sense of loss or unmet expectations. The overall demeanor is slumped, with a drooping posture that enhances the impression of being disheartened.",
|
| 12 |
+
"disapproval": "A stern and critical expression, characterized by narrowed eyes and a tight, thin-lipped frown. The eyebrows are drawn down and together, creating a strong look of judgment or censure. The mouth is often set in a firm line, and the overall facial tension suggests displeasure and objection. The head may be slightly shaken or tilted back, enhancing the sense of rejection or condemnation.",
|
| 13 |
+
"disgust": "A repelled and distasteful expression, characterized by a scrunched nose and raised upper lip, mimicking a grimace. The eyebrows are knitted together, and the eyes may be slightly squinted or turned away from the source of disgust. The mouth is often open in an expression of revulsion, possibly showing the teeth in a sneer. The overall demeanor conveys a strong sense of aversion and rejection, as if recoiling from an unpleasant smell or sight.",
|
| 14 |
+
"embarrassment": "A shy and awkward expression, characterized by flushed cheeks and averted eyes that shy away from direct contact. The eyebrows are slightly raised, and the mouth may be parted or twisted into a sheepish, uncomfortable smile. The overall facial posture often includes a downward tilt of the head, symbolizing a desire to avoid attention. There might also be a nervous gesture, such as touching the face or tugging at clothing, enhancing the sense of self-consciousness and unease.",
|
| 15 |
+
"excitement": "A vibrant and energetic expression, characterized by wide-open eyes and a broad, enthusiastic smile, showing teeth. The eyebrows are raised high, enhancing the openness and alertness of the eyes. The face may be slightly flushed with the rush of adrenaline, and the overall posture is often forward-leaning or dynamic, reflecting an eagerness and joy. There might also be visible signs of animation, such as hands raised in excitement or a bounce in posture, indicating a lively and spirited mood.",
|
| 16 |
+
"fear": "A tense and alarmed expression, characterized by wide-open eyes and dilated pupils, conveying a heightened state of alertness. The eyebrows are drawn upwards, accentuating the look of shock or fright. The mouth is open, often in a slight oval shape, as if gasping or breathing heavily. The overall facial muscles are tight, and the skin may appear paler than usual due to a rush of adrenaline. The posture might be recoiling or shrinking away, signifying an instinctive response to perceived danger.",
|
| 17 |
+
"gratitude": "A warm and heartfelt expression, featuring gently smiling eyes that convey a deep sense of thankfulness. The eyebrows are relaxed, and the eyes may be slightly moist, reflecting emotional depth. The mouth is curved into a sincere, soft smile, showing appreciation and contentment. The overall demeanor is open and humble, often accompanied by a slight nod or a gesture of the hands placed over the heart, symbolizing genuine gratitude and recognition.",
|
| 18 |
+
"grief": "A wounded and defeated expression, characterized by furrowed brows and drooping eyelids that convey a sense of sorrow. The eyes are or teary, reflecting grief. The mouth is downturned, open as if in pain, expressing pain and dejection. The overall facial features appear tensed and frozen in a rictus, that conveys pain and sorrow.",
|
| 19 |
+
"joy": "An exuberant and radiant expression, characterized by wide, sparkling eyes and a wide, beaming smile that shows teeth. The eyebrows are raised, enhancing the bright and lively appearance of the eyes. The cheeks are lifted and possibly flushed with a rosy color, adding to the vibrancy of the face. The overall demeanor is very animated, with possible laughter or cheerful gestures that convey a sense of uncontained happiness and delight.",
|
| 20 |
+
"love": "A tender and affectionate expression, characterized by soft, gentle eyes that convey deep warmth and caring. The eyebrows are relaxed, curving gently to reflect a sense of calm and contentment. The mouth is slightly upturned in a serene smile, exuding kindness and a deep connection. The overall demeanor is open and inviting, often accompanied by a slight tilt of the head or a soft gaze that lingers, symbolizing intimacy and emotional closeness.",
|
| 21 |
+
"nervousness": "A tense and apprehensive expression, characterized by slightly widened eyes and a furrowed brow, reflecting anxiety or worry. The mouth may be pressed into a thin line or slightly open, indicating unease. The lips might twitch or quiver slightly as part of an involuntary nervous reaction. The overall demeanor includes fidgety movements, such as wringing hands or shifting weight from foot to foot, portraying a state of restlessness and discomfort.",
|
| 22 |
+
"neutral": "A calm and composed expression, characterized by a relaxed brow and soft, even eyes that convey a sense of tranquility and impartiality. The mouth is closed in a straight line, showing neither a smile nor a frown, maintaining an even and reserved appearance. The overall facial muscles are relaxed, suggesting a state of neutrality and detachment. The posture is typically upright and poised, reflecting a balanced and impartial emotional state.",
|
| 23 |
+
"optimism": "A hopeful and positive expression, characterized by bright eyes and a wide, confident smile. The eyebrows are raised slightly, enhancing the open and inviting look of the eyes, which convey anticipation and a forward-looking attitude. The mouth is curved upward, showing a genuine and enthusiastic smile that radiates a sense of certainty and good expectations. The overall demeanor is upbeat and energetic, often accompanied by an upright and forward-leaning posture, symbolizing readiness and eagerness for the future.",
|
| 24 |
+
"pride": "A dignified and self-assured expression, characterized by a lifted chin and a slight smile that conveys confidence and satisfaction. The eyes are focused and bright, reflecting a sense of accomplishment and self-respect. The eyebrows are relaxed but held in a natural, composed position, enhancing the overall poised appearance. The mouth is often closed in a contented, subtle smile, or slightly parted in a proud, gratified expression. The posture is erect and composed, embodying a sense of stature and presence.",
|
| 25 |
+
"realization": "An insightful and sudden expression, marked by widened eyes and slightly raised eyebrows, indicating a moment of understanding or epiphany. The eyes are focused and perhaps reflecting a shift in thought, showcasing an 'aha' moment. The mouth is relaxed, possibly parting slightly in surprise or forming a subtle smile as the realization sinks in. The overall demeanor conveys a sense of clarity and comprehension, often accompanied by a nod or a slight tilt of the head, symbolizing acknowledgment and acceptance of the new insight.",
|
| 26 |
+
"relief": "A relaxed and comforted expression, characterized by a visible release of tension in the face. The eyebrows are lifted slightly, easing any previous furrows, and the eyes are soft, perhaps closing momentarily in a sigh of relief. The mouth curves into a gentle, relieved smile, indicating a significant alleviation of stress or worry. The overall posture may include a slight sagging of the shoulders, as if a burden has been lifted, conveying a profound sense of ease and reassurance.",
|
| 27 |
+
"remorse": "A sorrowful and repentant expression, characterized by downcast eyes and a furrowed brow, reflecting deep regret. The eyes are often moist, showing a hint of tears or a saddened gaze that avoids direct contact. The mouth is turned downward in a frown, and the lips may be slightly quivering as if struggling to maintain composure. The overall demeanor is subdued, with a lowered head and possibly clasped hands, symbolizing a desire for atonement and the weight of guilt.",
|
| 28 |
+
"sadness": "A somber and melancholic expression, characterized by downward eyebrows and drooping eyelids that convey a sense of sorrow. The eyes may appear glossy or teary, reflecting emotional pain or grief. The mouth is downturned, often in a slight frown, expressing unhappiness and dejection. The overall facial features appear softened and less animated, with a general downward pull that enhances the impression of being weighed down by sadness.",
|
| 29 |
+
"surprise": "An astonished and wide-eyed expression, characterized by eyebrows raised high, enlarging the eyes in a look of shock or unexpected wonder. The mouth is often open in a rounded shape, reflecting the suddenness of the surprise. The eyes are focused, possibly with dilated pupils, signifying intense attention to the surprising event. The overall demeanor is one of momentary pause and heightened alertness, as if the person is momentarily frozen in response to an unexpected occurrence."
|
| 30 |
+
}
|
autoexpress/resources/empty_bg.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"batch_size": 1,
|
| 3 |
+
"cfg_scale": 7,
|
| 4 |
+
"comments": {},
|
| 5 |
+
"denoising_strength": 0,
|
| 6 |
+
"disable_extra_networks": false,
|
| 7 |
+
"do_not_save_grid": false,
|
| 8 |
+
"do_not_save_samples": false,
|
| 9 |
+
"height": 768,
|
| 10 |
+
"image_cfg_scale": 1.5,
|
| 11 |
+
"init_images": [
|
| 12 |
+
"base64image placeholder"
|
| 13 |
+
],
|
| 14 |
+
"initial_noise_multiplier": 1.0,
|
| 15 |
+
"inpaint_full_res": 0,
|
| 16 |
+
"inpaint_full_res_padding": 32,
|
| 17 |
+
"inpainting_fill": 1,
|
| 18 |
+
"inpainting_mask_invert": 0,
|
| 19 |
+
"mask_blur": 4,
|
| 20 |
+
"mask_blur_x": 4,
|
| 21 |
+
"mask_blur_y": 4,
|
| 22 |
+
"mask_round": true,
|
| 23 |
+
"n_iter": 1,
|
| 24 |
+
"negative_prompt": "",
|
| 25 |
+
"override_settings": {},
|
| 26 |
+
"override_settings_restore_afterwards": true,
|
| 27 |
+
"prompt": "",
|
| 28 |
+
"resize_mode": 0,
|
| 29 |
+
"restore_faces": false,
|
| 30 |
+
"s_churn": 0.0,
|
| 31 |
+
"s_min_uncond": 0.0,
|
| 32 |
+
"s_noise": 1.0,
|
| 33 |
+
"s_tmax": null,
|
| 34 |
+
"s_tmin": 0.0,
|
| 35 |
+
"sampler_name": "Euler a",
|
| 36 |
+
"scheduler": "Automatic",
|
| 37 |
+
"script_args": [],
|
| 38 |
+
"script_name": null,
|
| 39 |
+
"seed": -1,
|
| 40 |
+
"seed_enable_extras": true,
|
| 41 |
+
"seed_resize_from_h": -1,
|
| 42 |
+
"seed_resize_from_w": -1,
|
| 43 |
+
"steps": 20,
|
| 44 |
+
"styles": [],
|
| 45 |
+
"subseed": -1,
|
| 46 |
+
"subseed_strength": 0,
|
| 47 |
+
"tiling": false,
|
| 48 |
+
"width": 512
|
| 49 |
+
}
|
autoexpress/resources/expressions.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"admiration": "raised eyebrow, upwards_gaze, blushing, smiling, sparkling eyes, relaxed posture",
|
| 3 |
+
"amusement": "smiling, relaxed eyes, slight blush, amused, happy",
|
| 4 |
+
"anger": "frowning, narrowed eyes, clenched teeth, angry, scowling",
|
| 5 |
+
"annoyance": "frowning, furrowed eyebrows, pouting, slight blush, irritated",
|
| 6 |
+
"approval": "smiling, nodding, content, relaxed eyes, pleased",
|
| 7 |
+
"caring": "soft smile, gentle eyes, tender, warm, caring gaze",
|
| 8 |
+
"confusion": "furrowed eyebrows, puzzled, open mouth, tilted head, confused",
|
| 9 |
+
"curiosity": "tilted head, wide eyes, intrigued, raised eyebrow, curious smile",
|
| 10 |
+
"desire": "half-lidded eyes, blushing, biting lip, longing gaze, seductive, horny",
|
| 11 |
+
"disappointment": "sad, downcast eyes, frowning, disappointed",
|
| 12 |
+
"disapproval": "stern, disapproving gaze, narrowed eyes",
|
| 13 |
+
"disgust": "scrunched nose, disgusted, averted eyes, grimacing",
|
| 14 |
+
"embarrassment": "blushing, averted eyes, embarrassed smile, flustered",
|
| 15 |
+
"excitement": "wide eyes, open mouth, smiling, energetic, excited",
|
| 16 |
+
"fear": "wide eyes, open mouth, sweating, trembling, fearful",
|
| 17 |
+
"gratitude": "smiling, bowing, thankful, touched, gentle eyes",
|
| 18 |
+
"grief": "tearful, downcast eyes, sobbing, distressed, grieving",
|
| 19 |
+
"joy": "beaming smile, sparkling eyes, joyful, laughing, delighted",
|
| 20 |
+
"love": "blushing, soft smile, loving gaze, heart eyes, affectionate",
|
| 21 |
+
"nervousness": "fidgeting, nervous smile, mouth slightly open, sweating, narrow eyes",
|
| 22 |
+
"neutral": "blank expression, calm, emotionless, neutral eyes, slight smile",
|
| 23 |
+
"optimism": "smiling, hopeful eyes, cheerful, confident, bright expression, puppy eyes",
|
| 24 |
+
"pride": "grinning, head held high, looking down, confident, proud stance",
|
| 25 |
+
"realization": "wide eyes, open mouth, surprised, enlightened, sudden clarity",
|
| 26 |
+
"relief": "relaxed smile, sighing, relieved, calm eyes, content",
|
| 27 |
+
"remorse": "downcast eyes, frowning, sad, regretful, tearful",
|
| 28 |
+
"sadness": "tearful, frowning, downcast eyes, sad, subdued smile",
|
| 29 |
+
"surprise": "@_@,surprised, wide-eyed, amazed"
|
| 30 |
+
}
|
autoexpress/resources/illu_expressions.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"admiration": "A look of respect and warm approval, characterized by slightly widened eyes that convey interest and esteem. The eyebrows are gently arched, enhancing the expression of intrigue and appreciation. The mouth is closed in a soft, tender smile, reflecting a deep sense of admiration and pleasure. The face overall holds a calm and composed demeanor, with a slight nod or tilt of the head towards the object of admiration, symbolizing respect and veneration.",
|
| 3 |
+
"amusement": "A joyful and slightly mischievous expression, featuring slightly raised eyebrows to indicate curiosity and interest. The eyes are bright and twinkling, reflecting a light-hearted enjoyment. The mouth is open in a subtle, relaxed smile, showing a hint of teeth. The overall demeanor is relaxed and cheerful, with a gentle, playful tilt of the head, suggesting a moment of genuine amusement and delight.",
|
| 4 |
+
"anger": "A fierce and intense expression, furrowed brows that are brought together to conveyed a sense of frustration or anger. The eyes are narrowed and piercing, conveying a strong sense of irritation or hostility. Lips scowling or slightly parted in a snarl revealing clenched teeth. The jaw is set firmly, and the overall look is tense, reflecting the strong, forceful emotions associated with anger.",
|
| 5 |
+
"annoyance": "A mildly irritated expression characterized by a slight frown and a furrowed brow, showing subtle frustration. The eyes are slightly squinted or rolling, often looking away from the source of annoyance. The lips are pursed or slightly turned down at the corners, indicating displeasure. The overall demeanor may include a subtle shaking of the head or a dismissive gesture, such as a slight shrug, conveying a sense of impatience or minor irritation.",
|
| 6 |
+
"approval": "A warm and positive expression, highlighted by softly raised eyebrows and relaxed, open eyes that convey a sense of satisfaction and agreement. The mouth is gently curved into a subtle, reassuring smile, indicating a favorable response. The overall facial posture is open and inviting, with a slight nod or an affirmative tilt of the head, symbolizing acceptance and encouragement.",
|
| 7 |
+
"caring": "A tender and compassionate expression, characterized by slightly tilted head conveying empathy and concern. The eyes are soft and warm, with gentle, direct gaze that communicates understanding and kindness. The eyebrows are relaxed and slightly curved, enhancing the nurturing aspect of the expression. The mouth is curved in a soft, comforting smile, suggesting reassurance and support. The overall demeanor is calm and attentive, projecting a strong sense of care and protection.",
|
| 8 |
+
"confusion": "A puzzled and uncertain expression, characterized by a slightly furrowed brow and a tilted head, indicating a lack of understanding. The eyes are wide and searching, possibly darting around as if looking for clarity. The mouth is partly open, reflecting hesitation or questioning, and the lips might be slightly pursed. The overall demeanor suggests bewilderment, with possible gestures like a hand to the chin or cheek, symbolizing deep thought or perplexity.",
|
| 9 |
+
"curiosity": "An intrigued and attentive expression, marked by a single raised eyebrows and wide, bright eyes that convey a keen interest. The head may be tilted forward slightly, symbolizing an eagerness to learn or discover more. The mouth is often closed with a hint of a smile, suggesting a pleasant and engaged demeanor. Occasionally, the lips may be parted as if about to ask a question. The overall posture is alert and forward-leaning, indicating active engagement and curiosity.",
|
| 10 |
+
"desire": "An intense and longing expression, characterized by slightly parted lips flushed cheeks and a soft, focused gaze that conveys deep yearning. The eyebrows are relaxed, but the eyes are wide and expressive, reflecting a strong emotional pull towards the object of desire. The overall facial posture is subtly forward-leaning, suggesting anticipation and attraction. The mouth may show a tender smile or remain slightly open, enhancing the sensuality and emotional depth of the expression.",
|
| 11 |
+
"disappointment": "A downcast and subdued expression, characterized by a slight frown and downturned corners of the mouth, conveying a sense of sadness or letdown. The eyebrows are gently furrowed, adding to the overall sorrowful appearance. The eyes may appear slightly glossy or stare blankly, reflecting a sense of loss or unmet expectations. The overall demeanor is slumped, with a drooping posture that enhances the impression of being disheartened.",
|
| 12 |
+
"disapproval": "A stern and critical expression, characterized by narrowed eyes and a tight, thin-lipped frown. The eyebrows are drawn down and together, creating a strong look of judgment or censure. The mouth is often set in a firm line, and the overall facial tension suggests displeasure and objection. The head may be slightly shaken or tilted back, enhancing the sense of rejection or condemnation.",
|
| 13 |
+
"disgust": "A repelled and distasteful expression, characterized by a scrunched nose and raised upper lip, mimicking a grimace. The eyebrows are knitted together, and the eyes may be slightly squinted or turned away from the source of disgust. The mouth is often open in an expression of revulsion, possibly showing the teeth in a sneer. The overall demeanor conveys a strong sense of aversion and rejection, as if recoiling from an unpleasant smell or sight.",
|
| 14 |
+
"embarrassment": "A shy and awkward expression, characterized by flushed cheeks and averted eyes that shy away from direct contact. The eyebrows are slightly raised, and the mouth may be parted or twisted into a sheepish, uncomfortable smile. The overall facial posture often includes a downward tilt of the head, symbolizing a desire to avoid attention. There might also be a nervous gesture, such as touching the face or tugging at clothing, enhancing the sense of self-consciousness and unease.",
|
| 15 |
+
"excitement": "A vibrant and energetic expression, characterized by wide-open eyes and a broad, enthusiastic smile, showing teeth. The eyebrows are raised high, enhancing the openness and alertness of the eyes. The face may be slightly flushed with the rush of adrenaline, and the overall posture is often forward-leaning or dynamic, reflecting an eagerness and joy. There might also be visible signs of animation, such as hands raised in excitement or a bounce in posture, indicating a lively and spirited mood.",
|
| 16 |
+
"fear": "A tense and alarmed expression, characterized by wide-open eyes and dilated pupils, conveying a heightened state of alertness. The eyebrows are drawn upwards, accentuating the look of fright. The mouth is open, often in a slight oval shape, as if gasping. The overall facial muscles are tight, and the skin may appear paler than usual due to a rush of adrenaline. The posture might be recoiling or shrinking away, signifying an instinctive response to perceived danger.",
|
| 17 |
+
"gratitude": "A heartfelt expression, featuring gently smiling eyes that convey a deep sense of thankfulness. The eyebrows are relaxed, and the eyes may be slightly moist, reflecting emotional depth. The mouth is curved into a sincere, soft smile, showing appreciation and contentment. The overall demeanor is open and humble, often accompanied by a slight nod or a gesture of the hands placed over the heart, symbolizing genuine gratitude and recognition.",
|
| 18 |
+
"grief": "A emotionally pained and hurt expression, a downward-turned open mouth forming a wail of suffering, grit teeth, raised eyebrows, tears streaming doen cheeks, thousand yard stare, and a clenched jaw.",
|
| 19 |
+
"joy": "An exuberant and radiant expression, characterized by wide, sparkling eyes and a wide, beaming smile that shows teeth. The eyebrows are raised, enhancing the bright and lively appearance of the eyes. The cheeks are lifted and possibly flushed with a rosy color, adding to the vibrancy of the face. The overall demeanor is very animated, with possible laughter or cheerful gestures that convey a sense of uncontained happiness and delight.",
|
| 20 |
+
"love": "A tender and affectionate expression, characterized by soft, gentle eyes that convey deep warmth and caring. The eyebrows are relaxed, curving gently to reflect a sense of calm and contentment. The mouth is slightly upturned in a serene smile, exuding kindness and a deep connection. The overall demeanor is open and inviting, often accompanied by a slight tilt of the head or a soft gaze that lingers, symbolizing intimacy and emotional closeness.",
|
| 21 |
+
"nervousness": "A tense and apprehensive expression, characterized by slightly widened eyes and a furrowed brow, reflecting anxiety or worry. The mouth may be pressed into a thin line or slightly open, indicating unease. The lips might twitch or quiver slightly as part of an involuntary nervous reaction. The overall demeanor includes fidgety movements, such as wringing hands or shifting weight from foot to foot, portraying a state of restlessness and discomfort.",
|
| 22 |
+
"neutral": "A calm and composed expression, characterized by a relaxed brow and soft, even eyes that convey a sense of tranquility and impartiality. The mouth is closed in a straight line, showing neither a smile nor a frown, maintaining an even and reserved appearance. The overall facial muscles are relaxed, suggesting a state of neutrality and detachment. The posture is typically upright and poised, reflecting a balanced and impartial emotional state.",
|
| 23 |
+
"optimism": "A hopeful and positive expression, characterized by bright eyes and a wide, confident smile. The eyebrows are raised slightly, enhancing the open and inviting look of the eyes, which convey anticipation and a forward-looking attitude. The mouth is curved upward, showing a genuine and enthusiastic smile that radiates a sense of certainty and good expectations. The overall demeanor is upbeat and energetic, often accompanied by an upright and forward-leaning posture, symbolizing readiness and eagerness for the future.",
|
| 24 |
+
"pride": "A dignified and self-assured expression, characterized by a lifted chin and a big smile that conveys confidence and satisfaction. The eyes are focused and bright, reflecting a sense of accomplishment and self-respect. The eyebrows are relaxed but held in a natural, composed position, enhancing the overall poised appearance. The mouth is often closed in a contented, subtle smile, or slightly parted in a proud, gratified expression. The posture is erect and composed, embodying a sense of stature and presence.",
|
| 25 |
+
"realization": "An insightful and sudden expression, marked by widened eyes and slightly raised eyebrows, indicating a moment of understanding or epiphany. The eyes are focused and perhaps reflecting a shift in thought, showcasing an 'aha' moment. The mouth is relaxed, possibly parting slightly in surprise or forming a subtle smile as the realization sinks in. The overall demeanor conveys a sense of clarity and comprehension, often accompanied by a nod or a slight tilt of the head, symbolizing acknowledgment and acceptance of the new insight.",
|
| 26 |
+
"relief": "A relaxed and comforted expression, characterized by a visible release of tension in the face. The eyebrows are lifted slightly, easing any previous furrows, and the eyes are soft, perhaps closing momentarily in a sigh of relief. The mouth curves into a gentle, relieved smile, indicating a significant alleviation of stress or worry. The overall posture may include a slight sagging of the shoulders, as if a burden has been lifted, conveying a profound sense of ease and reassurance.",
|
| 27 |
+
"remorse": "A sorrowful and repentant expression, characterized by downcast eyes and a furrowed brow, reflecting deep regret. The eyes are often moist, showing a hint of tears or a saddened gaze that avoids direct contact. The mouth is turned downward in a frown, and the lips may be slightly quivering as if struggling to maintain composure. The overall demeanor is subdued, with a lowered head and possibly clasped hands, symbolizing a desire for atonement and the weight of guilt.",
|
| 28 |
+
"sadness": "A somber and melancholic expression, characterized by downward eyebrows and drooping eyelids that convey a sense of sorrow. The eyes may appear glossy or teary, reflecting emotional pain or grief. The mouth is downturned, often in a slight frown, expressing unhappiness and dejection. The overall facial features appear softened and less animated, with a general downward pull that enhances the impression of being weighed down by sadness.",
|
| 29 |
+
"surprise": "An astonished and wide-eyed expression, characterized by eyebrows raised high, enlarging the eyes in a look of shock or unexpected wonder. The mouth is open wide in a rounded shape, reflecting the suddenness of the surprise. The eyes are focused, possibly with dilated pupils, signifying intense attention to the surprising event. The overall demeanor is one of momentary pause and heightened alertness, as if the person is momentarily frozen in response to an unexpected occurrence."
|
| 30 |
+
}
|
autoexpress/resources/images/AutoExpressUI_2024_11_13.png
ADDED
|
autoexpress/resources/images/AutoExpressUI_Revamped.png
ADDED
|
autoexpress/resources/images/UI.png
ADDED
|
autoexpress/resources/images/anime_grid.png
ADDED
|
autoexpress/resources/images/anime_input.png
ADDED
|
autoexpress/resources/images/realistic_grid.png
ADDED
|
autoexpress/resources/images/realistic_input.png
ADDED
|
autoexpress/resources/payload.json
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"alwayson_scripts": {
|
| 3 |
+
"ADetailer": {
|
| 4 |
+
"args": [
|
| 5 |
+
true,
|
| 6 |
+
true,
|
| 7 |
+
{
|
| 8 |
+
"ad_cfg_scale": 7,
|
| 9 |
+
"ad_checkpoint": "Use same checkpoint",
|
| 10 |
+
"ad_clip_skip": 1,
|
| 11 |
+
"ad_confidence": 0.3,
|
| 12 |
+
"ad_controlnet_guidance_end": 1,
|
| 13 |
+
"ad_controlnet_guidance_start": 0,
|
| 14 |
+
"ad_controlnet_model": "None",
|
| 15 |
+
"ad_controlnet_module": "None",
|
| 16 |
+
"ad_controlnet_weight": 1,
|
| 17 |
+
"ad_denoising_strength": 0.5,
|
| 18 |
+
"ad_dilate_erode": 4,
|
| 19 |
+
"ad_inpaint_height": 512,
|
| 20 |
+
"ad_inpaint_only_masked": true,
|
| 21 |
+
"ad_inpaint_only_masked_padding": 32,
|
| 22 |
+
"ad_inpaint_width": 512,
|
| 23 |
+
"ad_mask_blur": 4,
|
| 24 |
+
"ad_mask_k_largest": 0,
|
| 25 |
+
"ad_mask_max_ratio": 1,
|
| 26 |
+
"ad_mask_merge_invert": "None",
|
| 27 |
+
"ad_mask_min_ratio": 0,
|
| 28 |
+
"ad_model": "face_yolov8n.pt",
|
| 29 |
+
"ad_model_classes": "",
|
| 30 |
+
"ad_negative_prompt": "",
|
| 31 |
+
"ad_noise_multiplier": 1,
|
| 32 |
+
"ad_prompt": "",
|
| 33 |
+
"ad_restore_face": false,
|
| 34 |
+
"ad_sampler": "Euler a",
|
| 35 |
+
"ad_scheduler": "Automatic",
|
| 36 |
+
"ad_steps": 32,
|
| 37 |
+
"ad_use_cfg_scale": true,
|
| 38 |
+
"ad_use_checkpoint": true,
|
| 39 |
+
"ad_use_clip_skip": true,
|
| 40 |
+
"ad_use_inpaint_width_height": true,
|
| 41 |
+
"ad_use_noise_multiplier": false,
|
| 42 |
+
"ad_use_sampler": true,
|
| 43 |
+
"ad_use_steps": true,
|
| 44 |
+
"ad_use_vae": true,
|
| 45 |
+
"ad_vae": "Use same VAE",
|
| 46 |
+
"ad_x_offset": 0,
|
| 47 |
+
"ad_y_offset": 0,
|
| 48 |
+
"is_api": []
|
| 49 |
+
}
|
| 50 |
+
]
|
| 51 |
+
}
|
| 52 |
+
},
|
| 53 |
+
"batch_size": 1,
|
| 54 |
+
"cfg_scale": 7,
|
| 55 |
+
"comments": {},
|
| 56 |
+
"denoising_strength": 0.5,
|
| 57 |
+
"disable_extra_networks": false,
|
| 58 |
+
"do_not_save_grid": false,
|
| 59 |
+
"do_not_save_samples": false,
|
| 60 |
+
"height": 128,
|
| 61 |
+
"init_images": [
|
| 62 |
+
"base64image placeholder"
|
| 63 |
+
],
|
| 64 |
+
"initial_noise_multiplier": 1.0,
|
| 65 |
+
"inpaint_full_res": 0,
|
| 66 |
+
"inpaint_full_res_padding": 32,
|
| 67 |
+
"inpainting_fill": 1,
|
| 68 |
+
"inpainting_mask_invert": 0,
|
| 69 |
+
"mask_blur": 4,
|
| 70 |
+
"mask_blur_x": 4,
|
| 71 |
+
"mask_blur_y": 4,
|
| 72 |
+
"mask_round": true,
|
| 73 |
+
"n_iter": 1,
|
| 74 |
+
"negative_prompt": "",
|
| 75 |
+
"override_settings": {},
|
| 76 |
+
"override_settings_restore_afterwards": true,
|
| 77 |
+
"prompt": "",
|
| 78 |
+
"resize_mode": 0,
|
| 79 |
+
"restore_faces": false,
|
| 80 |
+
"s_churn": 0.0,
|
| 81 |
+
"s_min_uncond": 0.0,
|
| 82 |
+
"s_noise": 1.0,
|
| 83 |
+
"s_tmax": null,
|
| 84 |
+
"s_tmin": 0.0,
|
| 85 |
+
"sampler_name": "Euler",
|
| 86 |
+
"scheduler": "Automatic",
|
| 87 |
+
"script_args": [],
|
| 88 |
+
"script_name": null,
|
| 89 |
+
"seed": -1,
|
| 90 |
+
"seed_enable_extras": true,
|
| 91 |
+
"seed_resize_from_h": -1,
|
| 92 |
+
"seed_resize_from_w": -1,
|
| 93 |
+
"steps": 32,
|
| 94 |
+
"styles": [],
|
| 95 |
+
"subseed": -1,
|
| 96 |
+
"subseed_strength": 0,
|
| 97 |
+
"tiling": false,
|
| 98 |
+
"width": 128
|
| 99 |
+
}
|
autoexpress/static/ico/favicon-rounded.png
ADDED
|
|
autoexpress/static/ico/favicon.png
ADDED
|
|
autoexpress/static/js/anime_toggle.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const styleSelector = document.getElementById("styleSelector");
|
| 2 |
+
|
| 3 |
+
// Event listener for button state change
|
| 4 |
+
styleSelector.addEventListener("change", () => {
|
| 5 |
+
if (styleSelector.checked) {
|
| 6 |
+
// Button is toggled ON (Realistic)
|
| 7 |
+
sendDataToServer(true);
|
| 8 |
+
} else {
|
| 9 |
+
// Button is toggled OFF (Anime)
|
| 10 |
+
sendDataToServer(false);
|
| 11 |
+
}
|
| 12 |
+
});
|
| 13 |
+
|
| 14 |
+
// Function to send data to your Flask server
|
| 15 |
+
function sendDataToServer(isRealistic) {
|
| 16 |
+
// Make an HTTP request (e.g., using fetch or XMLHttpRequest)
|
| 17 |
+
// Replace the URL with your Flask server endpoint
|
| 18 |
+
const url = "/toggle"; // Example endpoint
|
| 19 |
+
|
| 20 |
+
fetch(url, {
|
| 21 |
+
method: "POST",
|
| 22 |
+
headers: {
|
| 23 |
+
"Content-Type": "application/json",
|
| 24 |
+
},
|
| 25 |
+
body: JSON.stringify({ isRealistic }), // Send data to server
|
| 26 |
+
})
|
| 27 |
+
.then((response) => {
|
| 28 |
+
if (response.ok) {
|
| 29 |
+
console.log("Data sent successfully!");
|
| 30 |
+
} else {
|
| 31 |
+
console.error("Error sending data to server.");
|
| 32 |
+
}
|
| 33 |
+
})
|
| 34 |
+
.catch((error) => {
|
| 35 |
+
console.error("Network error:", error);
|
| 36 |
+
});
|
| 37 |
+
}
|
autoexpress/static/js/connect.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
let image_data = null;
|
| 2 |
+
|
| 3 |
+
document.querySelector('.sd-connect').addEventListener('click', function () {
|
| 4 |
+
;
|
| 5 |
+
var inputText = document.querySelector('#ip-input').value; // Get the input value
|
| 6 |
+
var button = this;
|
| 7 |
+
|
| 8 |
+
// Create an XMLHttpRequest to send data
|
| 9 |
+
var xhr = new XMLHttpRequest();
|
| 10 |
+
xhr.open("POST", "/receive_data", true);
|
| 11 |
+
xhr.setRequestHeader("Content-Type", "application/json");
|
| 12 |
+
xhr.onreadystatechange = function () {
|
| 13 |
+
if (xhr.readyState === 4) {
|
| 14 |
+
if (xhr.status === 200) {
|
| 15 |
+
console.log('Data sent successfully');
|
| 16 |
+
button.style.backgroundColor = 'grey'; // Set button background to grey
|
| 17 |
+
} else {
|
| 18 |
+
console.log('Failed to send data');
|
| 19 |
+
button.style.backgroundColor = 'red'; // Set button background to red
|
| 20 |
+
}
|
| 21 |
+
}
|
| 22 |
+
};
|
| 23 |
+
|
| 24 |
+
var data = JSON.stringify({ text: inputText });
|
| 25 |
+
xhr.send(data);
|
| 26 |
+
|
| 27 |
+
// Function to handle empty dropdown data and clear previous options
|
| 28 |
+
function handleEmptyData(models, dropdownId) {
|
| 29 |
+
const dropdown = document.getElementById(dropdownId);
|
| 30 |
+
// Clear existing options first
|
| 31 |
+
while (dropdown.firstChild) {
|
| 32 |
+
dropdown.removeChild(dropdown.firstChild);
|
| 33 |
+
}
|
| 34 |
+
// Set the button to red if no models are fetched
|
| 35 |
+
if (models.length === 0) {
|
| 36 |
+
button.style.backgroundColor = 'red'; // Set button background to red
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
// Create 1 blank option
|
| 40 |
+
const option = document.createElement('option');
|
| 41 |
+
option.value = "";
|
| 42 |
+
option.textContent = "";
|
| 43 |
+
dropdown.appendChild(option);
|
| 44 |
+
|
| 45 |
+
// Populate dropdown with new data
|
| 46 |
+
models.forEach(model => {
|
| 47 |
+
const option = document.createElement('option');
|
| 48 |
+
option.value = model;
|
| 49 |
+
option.textContent = model;
|
| 50 |
+
dropdown.appendChild(option);
|
| 51 |
+
});
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
// Fetch models and populate dropdown
|
| 55 |
+
fetch('/get-models')
|
| 56 |
+
.then(response => response.json())
|
| 57 |
+
.then(models => {
|
| 58 |
+
handleEmptyData(models, 'model-input');
|
| 59 |
+
})
|
| 60 |
+
.catch(error => {
|
| 61 |
+
console.error('Error loading models:', error);
|
| 62 |
+
button.style.backgroundColor = 'red'; // Set button background to red
|
| 63 |
+
});
|
| 64 |
+
|
| 65 |
+
// Fetch samplers and populate dropdown
|
| 66 |
+
fetch('/get-samplers')
|
| 67 |
+
.then(response => response.json())
|
| 68 |
+
.then(models => {
|
| 69 |
+
handleEmptyData(models, 'sampler-input');
|
| 70 |
+
button.style.backgroundColor = 'green';
|
| 71 |
+
})
|
| 72 |
+
.catch(error => {
|
| 73 |
+
console.error('Error loading models:', error);
|
| 74 |
+
button.style.backgroundColor = 'red'; // Set button background to red
|
| 75 |
+
});
|
| 76 |
+
|
| 77 |
+
// Fetch LORAs and populate dropdown
|
| 78 |
+
fetch('/get-loras')
|
| 79 |
+
.then(response => response.json())
|
| 80 |
+
.then(models => {
|
| 81 |
+
handleEmptyData(models, 'lora-input');
|
| 82 |
+
if (image_data != null) {
|
| 83 |
+
document.getElementById('lora-input').value = image_data.lora;
|
| 84 |
+
document.getElementById('model-input').value = image_data.ad_checkpoint;
|
| 85 |
+
document.getElementById('sampler-input').value = image_data.ad_sampler;
|
| 86 |
+
}
|
| 87 |
+
})
|
| 88 |
+
.catch(error => {
|
| 89 |
+
console.error('Error loading models:', error);
|
| 90 |
+
button.style.backgroundColor = 'red'; // Set button background to red
|
| 91 |
+
});
|
| 92 |
+
|
| 93 |
+
});
|
autoexpress/static/js/frontend_settings.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
var gradientSelector = document.getElementById('gradient-animation-toggle');
|
| 3 |
+
const htmlElement = document.documentElement;
|
| 4 |
+
gradientSelector.addEventListener('change', () => {
|
| 5 |
+
if (gradientSelector.checked) {
|
| 6 |
+
htmlElement.style.animationPlayState = "running";
|
| 7 |
+
console.log('Gradient animation on');
|
| 8 |
+
} else {
|
| 9 |
+
htmlElement.style.animationPlayState = "paused";
|
| 10 |
+
console.log('Gradient animation off');
|
| 11 |
+
}
|
| 12 |
+
});
|
autoexpress/static/js/generate.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
document.querySelector('.generate-button').addEventListener('click', function () {
|
| 2 |
+
// Create an XMLHttpRequest to send data
|
| 3 |
+
var xhr = new XMLHttpRequest();
|
| 4 |
+
|
| 5 |
+
xhr.open("POST", "/generate", true);
|
| 6 |
+
xhr.setRequestHeader("Content-Type", "application/json");
|
| 7 |
+
xhr.onreadystatechange = function () {
|
| 8 |
+
|
| 9 |
+
if (xhr.readyState === 4 && xhr.status === 200) {
|
| 10 |
+
console.log('Data sent successfully');
|
| 11 |
+
} else if (xhr.readyState === 4) {
|
| 12 |
+
console.log('Failed to send data');
|
| 13 |
+
}
|
| 14 |
+
};
|
| 15 |
+
|
| 16 |
+
// Get the thumbnail element
|
| 17 |
+
var thumbnailElement = document.querySelector('#drop-zone-thumbnail-image');
|
| 18 |
+
// Get the base64 string of the image, or an empty string if no image uploaded
|
| 19 |
+
var thumbnailSrc = thumbnailElement ? thumbnailElement.src : "";
|
| 20 |
+
|
| 21 |
+
var data = JSON.stringify({
|
| 22 |
+
init_images: thumbnailSrc,
|
| 23 |
+
output_dir: document.getElementById('output-directory').value,
|
| 24 |
+
ad_inpaint_width: document.getElementById('width-input').value,
|
| 25 |
+
ad_inpaint_height: document.getElementById('height-input').value,
|
| 26 |
+
lora: document.getElementById('lora-input').value,
|
| 27 |
+
seed: document.getElementById('seed-input').value,
|
| 28 |
+
ad_prompt: document.getElementById('prompt-textfield').value,
|
| 29 |
+
ad_negative_prompt: document.getElementById('negative-prompt-textfield').value,
|
| 30 |
+
ad_steps: document.getElementById('steps-input').value,
|
| 31 |
+
ad_checkpoint: document.getElementById('model-input').value,
|
| 32 |
+
ad_sampler: document.getElementById('sampler-input').value,
|
| 33 |
+
ad_clip_skip: document.getElementById('clip-skip-input').value,
|
| 34 |
+
ad_cfg_scale: document.getElementById('cfg-scale-input').value,
|
| 35 |
+
ad_denoising_strength: document.getElementById('denoising-strength-input').value,
|
| 36 |
+
});
|
| 37 |
+
|
| 38 |
+
xhr.send(data);
|
| 39 |
+
});
|
autoexpress/static/js/image_drag_and_drop.js
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
document.querySelectorAll("#drop-zone-input-field").forEach((inputElement) => {
|
| 2 |
+
const dropZoneElement = inputElement.closest(".drop-zone");
|
| 3 |
+
|
| 4 |
+
dropZoneElement.addEventListener("click", (e) => {
|
| 5 |
+
inputElement.click();
|
| 6 |
+
});
|
| 7 |
+
|
| 8 |
+
inputElement.addEventListener("change", (e) => {
|
| 9 |
+
if (inputElement.files.length) {
|
| 10 |
+
updateThumbnail(dropZoneElement, inputElement.files[0]);
|
| 11 |
+
}
|
| 12 |
+
});
|
| 13 |
+
|
| 14 |
+
dropZoneElement.addEventListener("dragover", (e) => {
|
| 15 |
+
e.preventDefault();
|
| 16 |
+
dropZoneElement.classList.add("drop-zone--over");
|
| 17 |
+
});
|
| 18 |
+
|
| 19 |
+
["dragleave", "dragend"].forEach((type) => {
|
| 20 |
+
dropZoneElement.addEventListener(type, (e) => {
|
| 21 |
+
dropZoneElement.classList.remove("drop-zone--over");
|
| 22 |
+
});
|
| 23 |
+
});
|
| 24 |
+
|
| 25 |
+
dropZoneElement.addEventListener("drop", (e) => {
|
| 26 |
+
e.preventDefault();
|
| 27 |
+
|
| 28 |
+
if (e.dataTransfer.files.length) {
|
| 29 |
+
inputElement.files = e.dataTransfer.files;
|
| 30 |
+
updateThumbnail(dropZoneElement, e.dataTransfer.files[0]);
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
dropZoneElement.classList.remove("drop-zone--over");
|
| 34 |
+
});
|
| 35 |
+
});
|
| 36 |
+
|
| 37 |
+
function updateThumbnail(dropZoneElement, file) {
|
| 38 |
+
let thumbnailElement = dropZoneElement.querySelector("#drop-zone-thumbnail-image");
|
| 39 |
+
|
| 40 |
+
// First time - remove the prompt
|
| 41 |
+
if (dropZoneElement.querySelector("#upload-file-drop-zone")) {
|
| 42 |
+
dropZoneElement.querySelector(".drop-zone-prompt").remove();
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
// First time - there is no thumbnail element, so let's create it
|
| 46 |
+
if (!thumbnailElement) {
|
| 47 |
+
thumbnailElement = document.createElement("img");
|
| 48 |
+
thumbnailElement.id = "drop-zone-thumbnail-image";
|
| 49 |
+
dropZoneElement.appendChild(thumbnailElement);
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
thumbnailElement.dataset.label = file.name;
|
| 53 |
+
|
| 54 |
+
// Show thumbnail for image files
|
| 55 |
+
if (file.type.startsWith("image/")) {
|
| 56 |
+
const reader = new FileReader();
|
| 57 |
+
|
| 58 |
+
reader.readAsDataURL(file);
|
| 59 |
+
reader.onload = () => {
|
| 60 |
+
thumbnailElement.src = reader.result;
|
| 61 |
+
uploadImage(file); // Call upload function after setting the src
|
| 62 |
+
};
|
| 63 |
+
} else {
|
| 64 |
+
thumbnailElement.src = ""; // Clear the source if it's not an image
|
| 65 |
+
}
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
function uploadImage(file) {
|
| 69 |
+
const formData = new FormData();
|
| 70 |
+
formData.append('file', file);
|
| 71 |
+
|
| 72 |
+
fetch('/upload', {
|
| 73 |
+
method: 'POST',
|
| 74 |
+
body: formData,
|
| 75 |
+
})
|
| 76 |
+
.then(response => response.json())
|
| 77 |
+
.then(data => {
|
| 78 |
+
console.log('Upload successful. Recieved metadata for the image:', data)
|
| 79 |
+
const uncleaned_data = data.uncleaned_data;
|
| 80 |
+
const image_data = data.cleaned_data;
|
| 81 |
+
showRawData(uncleaned_data);
|
| 82 |
+
updateToolTip(uncleaned_data);
|
| 83 |
+
updateUI(image_data);
|
| 84 |
+
|
| 85 |
+
})
|
| 86 |
+
.catch(error => console.error('Error uploading file:', error));
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
function showRawData(uncleaned_data) {
|
| 91 |
+
const element = document.getElementById("info-icon");
|
| 92 |
+
|
| 93 |
+
// Show uncleaned data on hover
|
| 94 |
+
element.addEventListener('mouseenter', () => {
|
| 95 |
+
element.title = uncleaned_data; // Use title attribute to show data as tooltip
|
| 96 |
+
});
|
| 97 |
+
|
| 98 |
+
// Remove tooltip on mouse leave
|
| 99 |
+
element.addEventListener('mouseleave', () => {
|
| 100 |
+
element.removeAttribute('title');
|
| 101 |
+
});
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
function updateToolTip(data) {
|
| 105 |
+
const element = document.getElementById('drop-zone-thumbnail-image');
|
| 106 |
+
|
| 107 |
+
// Show uncleaned data on hover
|
| 108 |
+
element.addEventListener('mouseenter', () => {
|
| 109 |
+
element.title = data; // Use title attribute to show data as tooltip
|
| 110 |
+
});
|
| 111 |
+
|
| 112 |
+
// Remove tooltip on mouse leave
|
| 113 |
+
element.addEventListener('mouseleave', () => {
|
| 114 |
+
element.removeAttribute('title');
|
| 115 |
+
});
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
function updateUI(data) {
|
| 119 |
+
setDropdownValue('model-input', data.checkpoint);
|
| 120 |
+
setDropdownValue('sampler-input', data.sampler);
|
| 121 |
+
setDropdownValue('lora-input', data.lora);
|
| 122 |
+
setDropdownValue('scheduler-input', data.scheduler);
|
| 123 |
+
|
| 124 |
+
document.getElementById('clip-skip-input').value = data.clip_skip;
|
| 125 |
+
document.getElementById('seed-input').value = data.seed;
|
| 126 |
+
|
| 127 |
+
document.getElementById('steps-input').value = data.steps;
|
| 128 |
+
|
| 129 |
+
document.getElementById('width-input').value = data.inpaint_width;
|
| 130 |
+
document.getElementById('height-input').value = data.inpaint_height;
|
| 131 |
+
document.getElementById('cfg-scale-input').value = data.cfg_scale;
|
| 132 |
+
document.getElementById('denoising-strength-input').value = data.denoising_strength;
|
| 133 |
+
|
| 134 |
+
document.getElementById('prompt-textfield').value = data.prompt;
|
| 135 |
+
document.getElementById('negative-prompt-textfield').value = data.negative_prompt;
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
function setDropdownValue(elementId, dataValue) {
|
| 140 |
+
const dropdown = document.getElementById(elementId);
|
| 141 |
+
|
| 142 |
+
// Check if the dropdown exists
|
| 143 |
+
if (!dropdown) {
|
| 144 |
+
console.warn(`Dropdown with id "${elementId}" not found.`);
|
| 145 |
+
return;
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
// Check if the option already exists in the dropdown
|
| 149 |
+
let optionExists = Array.from(dropdown.options).some(option => option.value === dataValue);
|
| 150 |
+
|
| 151 |
+
// If the option doesn't exist, add it to the dropdown
|
| 152 |
+
if (!optionExists) {
|
| 153 |
+
let newOption = new Option(dataValue, dataValue);
|
| 154 |
+
dropdown.add(newOption);
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
// Set the dropdown value
|
| 158 |
+
dropdown.value = dataValue;
|
| 159 |
+
}
|
| 160 |
+
|
autoexpress/static/js/image_viewer.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
function loadImagesInput(event) {
|
| 2 |
+
if (event.key === 'Enter') {
|
| 3 |
+
loadImages();
|
| 4 |
+
}
|
| 5 |
+
}
|
| 6 |
+
|
| 7 |
+
function loadImages() {
|
| 8 |
+
const outputDir = document.getElementById('output-directory').value;
|
| 9 |
+
|
| 10 |
+
fetch(`/images/${outputDir}`)
|
| 11 |
+
.then(response => response.json())
|
| 12 |
+
.then(files => {
|
| 13 |
+
// Filter files to only include those with the .png extension
|
| 14 |
+
images = files.filter(file => file.endsWith('.png')).map(file => `/image/${outputDir}/${file}`);
|
| 15 |
+
fileNames = files.filter(file => file.endsWith('.png')); // Filter file names as well
|
| 16 |
+
currentIndex = 0; // Reset index when new images are loaded
|
| 17 |
+
|
| 18 |
+
if (images.length > 0) {
|
| 19 |
+
displayImage(currentIndex);
|
| 20 |
+
} else {
|
| 21 |
+
document.getElementsById('image-display').src = "";
|
| 22 |
+
document.getElementById('expression-image-name').textContent = "No PNG images found.";
|
| 23 |
+
}
|
| 24 |
+
})
|
| 25 |
+
.catch(error => {
|
| 26 |
+
console.error('Error loading images:', error);
|
| 27 |
+
alert('Failed to load images.');
|
| 28 |
+
});
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
function navigate(direction) {
|
| 32 |
+
if (images.length > 0) {
|
| 33 |
+
currentIndex += direction;
|
| 34 |
+
// Wrap around the navigation
|
| 35 |
+
if (currentIndex < 0) {
|
| 36 |
+
currentIndex = images.length - 1;
|
| 37 |
+
} else if (currentIndex >= images.length) {
|
| 38 |
+
currentIndex = 0;
|
| 39 |
+
}
|
| 40 |
+
displayImage(currentIndex);
|
| 41 |
+
}
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
function displayImage(index) {
|
| 45 |
+
document.getElementById('image-display').src = images[index];
|
| 46 |
+
//document.getElementById('image-name').textContent = "Expression: " + fileNames[index]);
|
| 47 |
+
//document.getElementById('image-name').textContent = "Expression: " + fileNames[index].substring(0, fileNames[index].lastIndexOf('.'));
|
| 48 |
+
document.getElementById('expression-image-name').textContent = fileNames[index].replace(/\.[^.]+$/, '').charAt(0).toUpperCase() + fileNames[index].replace(/\.[^.]+$/, '').slice(1).toLowerCase();
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
function calculateAspectRatio(image) {
|
| 54 |
+
const naturalWidth = image.naturalWidth;
|
| 55 |
+
const naturalHeight = image.naturalHeight;
|
| 56 |
+
if (naturalWidth && naturalHeight) {
|
| 57 |
+
return naturalWidth / naturalHeight;
|
| 58 |
+
} else {
|
| 59 |
+
console.error("Error: Image dimensions not available.");
|
| 60 |
+
return 1; // Default to 1:1 aspect ratio in case of errors
|
| 61 |
+
}
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
// Attach event listeners to navigation buttons
|
| 65 |
+
document.querySelector('.nav-left').addEventListener('click', function () {
|
| 66 |
+
navigate(-1); // Navigate left
|
| 67 |
+
});
|
| 68 |
+
|
| 69 |
+
document.querySelector('.nav-right').addEventListener('click', function () {
|
| 70 |
+
navigate(1); // Navigate right
|
| 71 |
+
});
|
| 72 |
+
|
| 73 |
+
document.querySelector('.load-images').addEventListener('click', function () {
|
| 74 |
+
loadImages(); // Initial load of images
|
| 75 |
+
});
|
| 76 |
+
|
| 77 |
+
document.querySelector('#output-directory').addEventListener('change', function () {
|
| 78 |
+
loadImages();
|
| 79 |
+
});
|
| 80 |
+
|
| 81 |
+
document.addEventListener('keydown', function (event) {
|
| 82 |
+
if (event.key === 'ArrowLeft') {
|
| 83 |
+
navigate(-1);
|
| 84 |
+
// Add your custom logic here
|
| 85 |
+
} else if (event.key === 'ArrowRight') {
|
| 86 |
+
navigate(1);
|
| 87 |
+
// Add your custom logic here
|
| 88 |
+
}
|
| 89 |
+
});
|
autoexpress/static/js/main.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Function to update input value when slider changes
|
| 2 |
+
function updateInput(inputId) {
|
| 3 |
+
const slider = document.getElementById(`${inputId}-slider`);
|
| 4 |
+
const input = document.getElementById(`${inputId}-input`);
|
| 5 |
+
input.value = slider.value;
|
| 6 |
+
}
|
| 7 |
+
|
| 8 |
+
// Function to update slider value when input changes
|
| 9 |
+
function updateSlider(inputId) {
|
| 10 |
+
const slider = document.getElementById(`${inputId}-slider`);
|
| 11 |
+
const input = document.getElementById(`${inputId}-input`);
|
| 12 |
+
slider.value = input.value;
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
|
autoexpress/static/js/modal.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
function openModal() {
|
| 2 |
+
document.getElementById('modalOverlay').style.display = 'flex';
|
| 3 |
+
}
|
| 4 |
+
|
| 5 |
+
function closeModal() {
|
| 6 |
+
document.getElementById('modalOverlay').style.display = 'none';
|
| 7 |
+
}
|
autoexpress/static/stylesheet/frontend_settings.css
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.frontend-settings {
|
| 2 |
+
margin: 0px;
|
| 3 |
+
padding: 0px;
|
| 4 |
+
border-radius: 20px;
|
| 5 |
+
width: 95%;
|
| 6 |
+
justify-content: center;
|
| 7 |
+
}
|
autoexpress/static/stylesheet/image_and_prompt.css
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.image-and-prompt-container {
|
| 2 |
+
margin: 0px 15px 0px 15px;
|
| 3 |
+
padding: 0px;
|
| 4 |
+
width: 100%;
|
| 5 |
+
}
|
| 6 |
+
|
| 7 |
+
.drop-zone {
|
| 8 |
+
justify-content: center;
|
| 9 |
+
text-align: center;
|
| 10 |
+
font-weight: 500;
|
| 11 |
+
font-size: smaller;
|
| 12 |
+
cursor: pointer;
|
| 13 |
+
color: var(--font-color);
|
| 14 |
+
background-color: var(--input-background-color);
|
| 15 |
+
box-shadow: inset 0 0 0px 1px var(--dark-accent), var(--box-shadow-inset-neg);
|
| 16 |
+
border-radius: 10px;
|
| 17 |
+
position: relative;
|
| 18 |
+
overflow: hidden;
|
| 19 |
+
transition: background-color 0.3s ease;
|
| 20 |
+
height: 40vh;
|
| 21 |
+
z-index:7;
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
.drop-zone-prompt {
|
| 25 |
+
display: flex;
|
| 26 |
+
flex-direction: column;
|
| 27 |
+
justify-content: center;
|
| 28 |
+
align-items: center;
|
| 29 |
+
z-index:7;
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
.drop-zone:hover {
|
| 33 |
+
.drop-zone-prompt {
|
| 34 |
+
transform: scale(1.2);
|
| 35 |
+
transition: 0.4s;
|
| 36 |
+
}
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
#drop-zone-input-field {
|
| 40 |
+
display: none;
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
#drop-zone-thumbnail-image {
|
| 44 |
+
width: auto;
|
| 45 |
+
max-width: 100%;
|
| 46 |
+
object-fit: contain;
|
| 47 |
+
height: 90%;
|
| 48 |
+
border-radius: 5px;
|
| 49 |
+
overflow: auto;
|
| 50 |
+
position: relative;
|
| 51 |
+
z-index:7;
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
#drop-zone-thumbnail-image::after {
|
| 55 |
+
content: attr(data-label);
|
| 56 |
+
position: absolute;
|
| 57 |
+
bottom: 0;
|
| 58 |
+
left: 0;
|
| 59 |
+
width: 100%;
|
| 60 |
+
padding: 2px 0;
|
| 61 |
+
font-size: small;
|
| 62 |
+
text-align: center;
|
| 63 |
+
z-index:7;
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
#upload-file-drop-zone {
|
| 67 |
+
color: var(--font-color);
|
| 68 |
+
font-weight: 400;
|
| 69 |
+
font-size: medium;
|
| 70 |
+
width: 80%;
|
| 71 |
+
z-index:7;
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
.generate-button {
|
| 75 |
+
cursor: pointer;
|
| 76 |
+
display: flex;
|
| 77 |
+
align-items: center;
|
| 78 |
+
justify-content: center;
|
| 79 |
+
position: relative;
|
| 80 |
+
background-color: var(--generate-button-color);
|
| 81 |
+
border-radius: 10px;
|
| 82 |
+
font-size: large;
|
| 83 |
+
color: var(--font-color);
|
| 84 |
+
width: 100%;
|
| 85 |
+
text-align: center;
|
| 86 |
+
height: 3rem;
|
| 87 |
+
margin-top: 5%;
|
| 88 |
+
margin-bottom: 5%;
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
.generate-icon {
|
| 92 |
+
margin-right: 20px;
|
| 93 |
+
/* Adjust the left position as needed */
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
.generate-button:hover {
|
| 97 |
+
background-color: var(--generate-button-hover-color);
|
| 98 |
+
transform: scale(1.02);
|
| 99 |
+
transition: 0.4s;
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
.generate-button:hover .generate-icon {
|
| 103 |
+
transform: rotateZ(-15deg);
|
| 104 |
+
transition: 0.4s;
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
#prompt-textfield {
|
| 108 |
+
width: 100%;
|
| 109 |
+
height: calc(var(--input-height) * 4);
|
| 110 |
+
color: var(--prompt-text-color);
|
| 111 |
+
background-color: var(--prompt-background-color);
|
| 112 |
+
border: 1px solid var(--prompt-border-color);
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
#negative-prompt-textfield {
|
| 116 |
+
width: 100%;
|
| 117 |
+
height: calc(var(--input-height) * 4);
|
| 118 |
+
color: var(--negative-prompt-text-color);
|
| 119 |
+
background-color: var(--negative-prompt-background-color);
|
| 120 |
+
border: 1px solid var(--negative-prompt-border-color);
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
/* Style for the info icon */
|
| 124 |
+
.info-icon {
|
| 125 |
+
position: absolute;
|
| 126 |
+
bottom: 10px;
|
| 127 |
+
right: 10px;
|
| 128 |
+
font-size: 18px;
|
| 129 |
+
cursor: pointer;
|
| 130 |
+
color: var(--icon-color);
|
| 131 |
+
z-index:9;
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
/* Tooltip styling (optional) */
|
| 135 |
+
.tooltip {
|
| 136 |
+
display: none;
|
| 137 |
+
position: absolute;
|
| 138 |
+
bottom: 40px;
|
| 139 |
+
right: 10px;
|
| 140 |
+
background-color: #333;
|
| 141 |
+
color: #fff;
|
| 142 |
+
padding: 5px 10px;
|
| 143 |
+
border-radius: 5px;
|
| 144 |
+
font-size: 14px;
|
| 145 |
+
z-index: 20;
|
| 146 |
+
max-width: 200px;
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
/* Show tooltip when info icon is clicked */
|
| 150 |
+
.input-container.drop-zone .tooltip.show {
|
| 151 |
+
display: block;
|
| 152 |
+
}
|
autoexpress/static/stylesheet/image_viewer.css
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.image-output-container {
|
| 2 |
+
display: flex;
|
| 3 |
+
flex-direction: column;
|
| 4 |
+
flex-grow: 1;
|
| 5 |
+
width: 100%;
|
| 6 |
+
height: 100%;
|
| 7 |
+
}
|
| 8 |
+
|
| 9 |
+
.directory-bar-container {
|
| 10 |
+
display: flex;
|
| 11 |
+
margin: 10px;
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
.display-container {
|
| 15 |
+
display: flex;
|
| 16 |
+
flex-direction: row;
|
| 17 |
+
justify-content: space-between;
|
| 18 |
+
flex: 1;
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
.image-name-column-container {
|
| 22 |
+
display: flex;
|
| 23 |
+
flex-direction: column;
|
| 24 |
+
flex: 1;
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
.image-container {
|
| 28 |
+
flex: 1;
|
| 29 |
+
display: flex;
|
| 30 |
+
align-self: center;
|
| 31 |
+
object-fit: scale-down;
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
#image-display {
|
| 35 |
+
display: flex;
|
| 36 |
+
object-fit: contain;
|
| 37 |
+
width: 95%;
|
| 38 |
+
height: 95%;
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
#image-display:empty {
|
| 42 |
+
background-color: transparent;
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
#expression-image-name {
|
| 46 |
+
background-color: var(--input-background-color);
|
| 47 |
+
outline: none;
|
| 48 |
+
border: none;
|
| 49 |
+
border-radius: 10px;
|
| 50 |
+
|
| 51 |
+
color: var(--expression-name-font-color);
|
| 52 |
+
font-size: larger;
|
| 53 |
+
width: 50%;
|
| 54 |
+
padding: 5px 5px 5px 5px;
|
| 55 |
+
margin-top: -2.5%;
|
| 56 |
+
z-index: 3;
|
| 57 |
+
align-self: center;
|
| 58 |
+
text-align: center;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
#expression-image-name:empty {
|
| 62 |
+
background-color: transparent;
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
.output-directory {
|
| 67 |
+
font-size: large;
|
| 68 |
+
color: var(--output-directory-font-color);
|
| 69 |
+
background-color: var(--input-background-color);
|
| 70 |
+
height: var(--input-height);
|
| 71 |
+
border: none;
|
| 72 |
+
padding-left: 10px;
|
| 73 |
+
padding-right: 10px;
|
| 74 |
+
margin-right: 10px;
|
| 75 |
+
border-radius: 10px;
|
| 76 |
+
|
| 77 |
+
transition: box-shadow 0.3s ease-in-out;
|
| 78 |
+
flex-grow: 1;
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
.nav-button {
|
| 82 |
+
margin: 10px;
|
| 83 |
+
display: flex;
|
| 84 |
+
color: var(--knob-color);
|
| 85 |
+
height: calc(var(--input-height) * 1.75);
|
| 86 |
+
width: calc(var(--input-height) * 1.75);
|
| 87 |
+
cursor: pointer;
|
| 88 |
+
border: none;
|
| 89 |
+
border-radius: 100%;
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
.nav-icon {
|
| 93 |
+
display: flex;
|
| 94 |
+
font-size: xx-large;
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
.load-images {
|
| 98 |
+
color: var(--knob-color);
|
| 99 |
+
height: calc(var(--input-height));
|
| 100 |
+
width: calc(var(--input-height));
|
| 101 |
+
|
| 102 |
+
}
|
autoexpress/static/stylesheet/main.css
ADDED
|
@@ -0,0 +1,442 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
@import url("https://fonts.googleapis.com/css2?family=Quicksand:wght@300..700&display=swap");
|
| 2 |
+
|
| 3 |
+
/*NOTES:*/
|
| 4 |
+
/*
|
| 5 |
+
Icons are now a font: lucide-icon-font
|
| 6 |
+
Usage: Add a class with the name of the icon
|
| 7 |
+
EXAMPLE:
|
| 8 |
+
<div class="icon-link-2"></div>
|
| 9 |
+
IMPORTANT, when getting the name of the icon add "icon-" in front of it.
|
| 10 |
+
circle-chevron-left = icon-circle-chevron-left
|
| 11 |
+
Icons can be looked up here: https://lucide.dev/icons/?focus
|
| 12 |
+
NOTE: [class^="icon-"], [class*=" icon-"] is part of the font and in main css to style all the icons
|
| 13 |
+
*/
|
| 14 |
+
|
| 15 |
+
:root {
|
| 16 |
+
--font-family: "Quicksand", sans-serif;
|
| 17 |
+
--font-size: 16px;
|
| 18 |
+
|
| 19 |
+
--input-height: 2rem;
|
| 20 |
+
|
| 21 |
+
/* COLORS */
|
| 22 |
+
--font-color: white;
|
| 23 |
+
--icon-color: white;
|
| 24 |
+
--knob-color: rgb(64, 210, 255);
|
| 25 |
+
|
| 26 |
+
/* 'Border' (shadows) Color */
|
| 27 |
+
--dark-accent: rgba(0, 0, 0, 0.007);
|
| 28 |
+
|
| 29 |
+
/* 'Border' (shadows) Color Light, (hovers)*/
|
| 30 |
+
--light-accent: rgb(0, 0, 0);
|
| 31 |
+
|
| 32 |
+
/* HEADER COLORS */
|
| 33 |
+
--header-font-color: #ffffff;
|
| 34 |
+
|
| 35 |
+
/* Labels Color */
|
| 36 |
+
--label-font-color: rgb(201, 201, 201);
|
| 37 |
+
|
| 38 |
+
/*input field font color*/
|
| 39 |
+
--input-font-color: rgb(201, 201, 201);
|
| 40 |
+
|
| 41 |
+
/*specific fields*/
|
| 42 |
+
--input-number-color: var(--input-font-color);
|
| 43 |
+
--input-select-color: var(--input-font-color);
|
| 44 |
+
--textarea-font-color: var(--input-font-color);
|
| 45 |
+
--prompt-text-color: var(--input-font-color);
|
| 46 |
+
--negative-prompt-text-color: var(--input-font-color);
|
| 47 |
+
--prompt-border-color: rgba(0, 128, 0, 0.8);
|
| 48 |
+
--negative-prompt-border-color: rgba(255, 0, 0, 0.8);
|
| 49 |
+
--expression-name-font-color: var(--input-font-color);
|
| 50 |
+
--output-directory-font-color: var(--input-font-color);
|
| 51 |
+
|
| 52 |
+
/* filter over the background */
|
| 53 |
+
--body-background-filter-color: rgba(0, 0, 0, 0.6);
|
| 54 |
+
/* the background of the fields*/
|
| 55 |
+
--input-background-color: rgba(65, 65, 65, 0.4);
|
| 56 |
+
|
| 57 |
+
/* button colors */
|
| 58 |
+
--button-color: rgba(0, 0, 0, 0.6);
|
| 59 |
+
|
| 60 |
+
/*main panels color*/
|
| 61 |
+
--panel-background-color: rgba(5, 5, 5, 0.5);
|
| 62 |
+
|
| 63 |
+
/*background color of positive prompts textareas*/
|
| 64 |
+
--prompt-background-color: rgba(0, 0, 0, 0.1);
|
| 65 |
+
/*background color of negative prompts textareas*/
|
| 66 |
+
--negative-prompt-background-color: rgba(0, 0, 0, 0.1);
|
| 67 |
+
|
| 68 |
+
/*generate button color*/
|
| 69 |
+
--generate-button-color: rgba(69, 142, 77, 1);
|
| 70 |
+
|
| 71 |
+
/*generate button hover color*/
|
| 72 |
+
--generate-button-hover-color: rgb(94, 201, 106);
|
| 73 |
+
|
| 74 |
+
--hover-outline-color: rgba(0, 153, 255, 0);
|
| 75 |
+
--hover-shadow-color: rgb(116, 188, 248);
|
| 76 |
+
--focus-outline-color: rgb(0, 0, 0);
|
| 77 |
+
--focus-shadow-color: rgb(116, 188, 248);
|
| 78 |
+
|
| 79 |
+
/* OBJECTS */
|
| 80 |
+
|
| 81 |
+
--box-shadow-panes: inset 0 0 8px 0px var(--dark-accent);
|
| 82 |
+
--box-shadow-inset-pos: inset 2px 2px 5px 0px var(--dark-accent);
|
| 83 |
+
/*bottom right inner shadow glow for textarea/button/ etc etc*/
|
| 84 |
+
--box-shadow-inset-neg: inset -2px -2px 5px 0px var(--dark-accent);
|
| 85 |
+
|
| 86 |
+
--hover-outline: 0px auto var(--hover-outline-color);
|
| 87 |
+
--hover-box-shadow: 0 0 1px 1px var(--hover-shadow-color);
|
| 88 |
+
/*outline width/style/color*/
|
| 89 |
+
--focus-outline: 1px auto var(--focus-outline-color);
|
| 90 |
+
--focus-box-shadow: 0 0 2px 2px var(--focus-shadow-color);
|
| 91 |
+
|
| 92 |
+
--realistic-switch-bg-color: #332f31;
|
| 93 |
+
--anime-switch-bg-color: #332f31;
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
html {
|
| 97 |
+
font-size: var(--font-size);
|
| 98 |
+
font-family: var(--font-family);
|
| 99 |
+
background: linear-gradient(-45deg, #5fe691, #f28e8e, #44c4f3, #814bff);
|
| 100 |
+
background-size: 200% 200%;
|
| 101 |
+
overflow: hidden;
|
| 102 |
+
animation: gradient 120s ease infinite;
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
@keyframes gradient {
|
| 106 |
+
0% {
|
| 107 |
+
background-position: 0% 50%;
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
50% {
|
| 111 |
+
background-position: 100% 50%;
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
100% {
|
| 115 |
+
background-position: 0% 50%;
|
| 116 |
+
}
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
body {
|
| 121 |
+
margin: 0;
|
| 122 |
+
border: none;
|
| 123 |
+
display: flex;
|
| 124 |
+
justify-content: center;
|
| 125 |
+
align-items: center;
|
| 126 |
+
background-color: var(--body-background-filter-color);
|
| 127 |
+
-webkit-backdrop-filter: blur(10px);
|
| 128 |
+
backdrop-filter: blur(10px);
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
.container {
|
| 132 |
+
display: flex;
|
| 133 |
+
flex-flow: row nowrap;
|
| 134 |
+
justify-content: center;
|
| 135 |
+
align-items: stretch;
|
| 136 |
+
padding: 0px;
|
| 137 |
+
height: 100vh;
|
| 138 |
+
width: 95vw;
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
.left-pane {
|
| 142 |
+
flex-grow: 1;
|
| 143 |
+
display: flex;
|
| 144 |
+
flex-direction: column;
|
| 145 |
+
justify-content: flex-start;
|
| 146 |
+
align-items: center;
|
| 147 |
+
width: 25%;
|
| 148 |
+
max-width: 350px;
|
| 149 |
+
min-width: max(350px, 25%);
|
| 150 |
+
background-color: var(--panel-background-color);
|
| 151 |
+
border-radius: 20px;
|
| 152 |
+
overflow-y: auto;
|
| 153 |
+
overflow-x: hidden;
|
| 154 |
+
margin: 20px;
|
| 155 |
+
padding: 15px;
|
| 156 |
+
/* border-right: 3rem; */
|
| 157 |
+
box-shadow: var(--box-shadow-panes);
|
| 158 |
+
}
|
| 159 |
+
|
| 160 |
+
|
| 161 |
+
.center-pane {
|
| 162 |
+
flex-grow: 1;
|
| 163 |
+
display: flex;
|
| 164 |
+
flex-direction: column;
|
| 165 |
+
justify-content: flex-start;
|
| 166 |
+
align-items: center;
|
| 167 |
+
max-width: 45%;
|
| 168 |
+
min-width: max(300px, 30%);
|
| 169 |
+
background-color: var(--panel-background-color);
|
| 170 |
+
border-radius: 20px;
|
| 171 |
+
overflow-y: auto;
|
| 172 |
+
overflow-x: hidden;
|
| 173 |
+
margin-top: 20px;
|
| 174 |
+
margin-bottom: 20px;
|
| 175 |
+
padding: 15px;
|
| 176 |
+
box-shadow: var(--box-shadow-panes);
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
.right-pane {
|
| 180 |
+
flex-grow: 2;
|
| 181 |
+
display: flex;
|
| 182 |
+
flex-direction: column;
|
| 183 |
+
justify-content: flex-start;
|
| 184 |
+
align-items: flex-start;
|
| 185 |
+
max-width: 40%;
|
| 186 |
+
min-width: max(350px, 40%);
|
| 187 |
+
background-color: var(--panel-background-color);
|
| 188 |
+
border-radius: 20px;
|
| 189 |
+
margin: 20px;
|
| 190 |
+
padding: 15px;
|
| 191 |
+
overflow: hidden;
|
| 192 |
+
box-shadow: var(--box-shadow-panes);
|
| 193 |
+
}
|
| 194 |
+
|
| 195 |
+
|
| 196 |
+
.input-container {
|
| 197 |
+
display: flex;
|
| 198 |
+
flex-direction: row;
|
| 199 |
+
justify-content: space-between;
|
| 200 |
+
align-items: center;
|
| 201 |
+
margin: 5px 5px 5px 0px;
|
| 202 |
+
padding: 5px 0px 0px 0px;
|
| 203 |
+
width: 100%;
|
| 204 |
+
}
|
| 205 |
+
|
| 206 |
+
.input-container.column {
|
| 207 |
+
display: flex;
|
| 208 |
+
flex-direction: column;
|
| 209 |
+
justify-content: flex-end;
|
| 210 |
+
height: 100%;
|
| 211 |
+
width: fit-content;
|
| 212 |
+
align-self: flex-end;
|
| 213 |
+
margin: 0px;
|
| 214 |
+
padding: 0px;
|
| 215 |
+
}
|
| 216 |
+
|
| 217 |
+
/*select container is two columns, and slider container is three*/
|
| 218 |
+
|
| 219 |
+
.input-container.select-container :first-child,
|
| 220 |
+
.input-container.slider-container :first-child {
|
| 221 |
+
width: 30%;
|
| 222 |
+
flex: 0 0 auto;
|
| 223 |
+
}
|
| 224 |
+
|
| 225 |
+
.input-container.slider-container :last-child {
|
| 226 |
+
width: 15%;
|
| 227 |
+
flex: 0 0 auto;
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
.input-container.grid-container {
|
| 231 |
+
justify-content: space-between;
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
h1,
|
| 235 |
+
h2,
|
| 236 |
+
h3,
|
| 237 |
+
h4,
|
| 238 |
+
h5,
|
| 239 |
+
h6 {
|
| 240 |
+
color: var(--header-font-color);
|
| 241 |
+
text-align: center;
|
| 242 |
+
margin: 0px;
|
| 243 |
+
padding: 10px;
|
| 244 |
+
}
|
| 245 |
+
|
| 246 |
+
select {
|
| 247 |
+
flex-grow: 1;
|
| 248 |
+
background-color: var(--input-background-color);
|
| 249 |
+
|
| 250 |
+
color: var(--input-select-color);
|
| 251 |
+
border: none;
|
| 252 |
+
|
| 253 |
+
font-size: small;
|
| 254 |
+
height: var(--input-height);
|
| 255 |
+
border-radius: 10px;
|
| 256 |
+
min-width: 25%;
|
| 257 |
+
width: 60%;
|
| 258 |
+
max-width: 75%;
|
| 259 |
+
}
|
| 260 |
+
|
| 261 |
+
[class^="icon-"],
|
| 262 |
+
[class*=" icon-"] {
|
| 263 |
+
display: flex;
|
| 264 |
+
align-self: center;
|
| 265 |
+
justify-content: center;
|
| 266 |
+
align-items: center;
|
| 267 |
+
font-size: x-large;
|
| 268 |
+
color: var(--icon-color);
|
| 269 |
+
}
|
| 270 |
+
|
| 271 |
+
select:hover,
|
| 272 |
+
input:hover,
|
| 273 |
+
textarea:hover,
|
| 274 |
+
button:hover,
|
| 275 |
+
.output-directory:hover,
|
| 276 |
+
.drop-zone:hover,
|
| 277 |
+
.drop-zone--over,
|
| 278 |
+
.slider:hover {
|
| 279 |
+
box-shadow: var(--hover-box-shadow),
|
| 280 |
+
var(--box-shadow-inset-neg);
|
| 281 |
+
outline: var(--hover-outline);
|
| 282 |
+
}
|
| 283 |
+
|
| 284 |
+
input:focus,
|
| 285 |
+
textarea:focus {
|
| 286 |
+
box-shadow: var(--focus-box-shadow);
|
| 287 |
+
outline: var(--focus-outline);
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
button {
|
| 291 |
+
display: flex;
|
| 292 |
+
align-self: center;
|
| 293 |
+
justify-content: center;
|
| 294 |
+
align-items: center;
|
| 295 |
+
border: none;
|
| 296 |
+
color: var(--input-font-color);
|
| 297 |
+
background-color: var(--button-color);
|
| 298 |
+
border-radius: 10px;
|
| 299 |
+
box-shadow: var(--box-shadow-inset-neg);
|
| 300 |
+
min-width: calc(var(--input-height)*1.5);
|
| 301 |
+
}
|
| 302 |
+
|
| 303 |
+
button:hover {
|
| 304 |
+
background-color: var(--icon-color);
|
| 305 |
+
|
| 306 |
+
[class^="icon-"],
|
| 307 |
+
[class*=" icon-"] {
|
| 308 |
+
color: var(--input-background-color);
|
| 309 |
+
}
|
| 310 |
+
}
|
| 311 |
+
|
| 312 |
+
input,
|
| 313 |
+
select {
|
| 314 |
+
height: var(--input-height);
|
| 315 |
+
border: none;
|
| 316 |
+
outline: none;
|
| 317 |
+
box-shadow: var(--box-shadow-inset-pos);
|
| 318 |
+
}
|
| 319 |
+
|
| 320 |
+
/********** Range Input Styles **********/
|
| 321 |
+
/*Range Reset*/
|
| 322 |
+
input[type="range"] {
|
| 323 |
+
-webkit-appearance: none;
|
| 324 |
+
appearance: none;
|
| 325 |
+
height: 0.5rem;
|
| 326 |
+
background: transparent;
|
| 327 |
+
cursor: pointer;
|
| 328 |
+
width: 15rem;
|
| 329 |
+
}
|
| 330 |
+
|
| 331 |
+
/* slider thumb */
|
| 332 |
+
input[type="range"]::-webkit-slider-thumb {
|
| 333 |
+
box-shadow: var(--box-shadow-inset-neg);
|
| 334 |
+
appearance: none;
|
| 335 |
+
background-color: var(--knob-color);
|
| 336 |
+
height: calc(var(--input-height) * 0.75);
|
| 337 |
+
width: calc(var(--input-height) * 0.75);
|
| 338 |
+
margin-top: calc(-1em * 0.75);
|
| 339 |
+
border-radius: 100%;
|
| 340 |
+
}
|
| 341 |
+
|
| 342 |
+
input[type="range"]::-webkit-slider-runnable-track {
|
| 343 |
+
box-shadow: var(--box-shadow-inset-pos);
|
| 344 |
+
background-color: var(--input-background-color);
|
| 345 |
+
border-radius: 15px;
|
| 346 |
+
height: 100%;
|
| 347 |
+
width: 100%;
|
| 348 |
+
}
|
| 349 |
+
|
| 350 |
+
|
| 351 |
+
/* Adjust input number appearance */
|
| 352 |
+
input[type="number"] {
|
| 353 |
+
text-align: center;
|
| 354 |
+
height: var(--input-height);
|
| 355 |
+
margin-left: 5px;
|
| 356 |
+
padding-right: 1.5rem;
|
| 357 |
+
padding-left: 5px;
|
| 358 |
+
color: var(--input-number-color);
|
| 359 |
+
border: none;
|
| 360 |
+
border-radius: 10px;
|
| 361 |
+
background-color: var(--input-background-color);
|
| 362 |
+
|
| 363 |
+
&::-webkit-inner-spin-button {
|
| 364 |
+
opacity: 0.5 !important;
|
| 365 |
+
background-color: var(--input-background-color);
|
| 366 |
+
color: var(--input-font-color);
|
| 367 |
+
height: 100%;
|
| 368 |
+
width: 1.2rem;
|
| 369 |
+
position: absolute;
|
| 370 |
+
top: 0;
|
| 371 |
+
bottom: 0;
|
| 372 |
+
right: 0;
|
| 373 |
+
cursor: pointer;
|
| 374 |
+
}
|
| 375 |
+
}
|
| 376 |
+
|
| 377 |
+
|
| 378 |
+
label {
|
| 379 |
+
color: var(--label-font-color);
|
| 380 |
+
font-size: medium;
|
| 381 |
+
font-weight: 600;
|
| 382 |
+
padding: 5px;
|
| 383 |
+
|
| 384 |
+
}
|
| 385 |
+
|
| 386 |
+
|
| 387 |
+
|
| 388 |
+
textarea {
|
| 389 |
+
background-color: var(--input-background-color);
|
| 390 |
+
color: var(--textarea-font-color);
|
| 391 |
+
border: 0px;
|
| 392 |
+
padding: 10px;
|
| 393 |
+
border-radius: 10px;
|
| 394 |
+
font-size: large;
|
| 395 |
+
resize: vertical;
|
| 396 |
+
transition: box-shadow 0.3s ease-in-out;
|
| 397 |
+
box-shadow: var(--box-shadow-inset-pos),
|
| 398 |
+
var(--box-shadow-inset-neg);
|
| 399 |
+
|
| 400 |
+
}
|
| 401 |
+
|
| 402 |
+
|
| 403 |
+
/*////////////////scrollbar////////////////*/
|
| 404 |
+
|
| 405 |
+
|
| 406 |
+
::-webkit-scrollbar {
|
| 407 |
+
display: none;
|
| 408 |
+
width: 0.5rem;
|
| 409 |
+
height: 0.5rem;
|
| 410 |
+
scrollbar-gutter: stable;
|
| 411 |
+
border: none;
|
| 412 |
+
padding: 0px;
|
| 413 |
+
margin: 0px;
|
| 414 |
+
}
|
| 415 |
+
|
| 416 |
+
::-webkit-scrollbar-track {
|
| 417 |
+
box-shadow: var(--box-shadow-inset-pos);
|
| 418 |
+
background-color: var(--input-background-color);
|
| 419 |
+
border-radius: 10px;
|
| 420 |
+
margin-top: 15px;
|
| 421 |
+
margin-bottom: 15px;
|
| 422 |
+
}
|
| 423 |
+
|
| 424 |
+
|
| 425 |
+
::-webkit-scrollbar-thumb {
|
| 426 |
+
border-radius: 10px;
|
| 427 |
+
background-clip: content-box;
|
| 428 |
+
box-shadow: var(--box-shadow-inset-neg);
|
| 429 |
+
background-color: var(--knob-color);
|
| 430 |
+
}
|
| 431 |
+
|
| 432 |
+
::-webkit-scrollbar-thumb:vertical {
|
| 433 |
+
min-height: 40px;
|
| 434 |
+
}
|
| 435 |
+
|
| 436 |
+
::-webkit-scrollbar-thumb:horizontal {
|
| 437 |
+
min-width: 40px;
|
| 438 |
+
}
|
| 439 |
+
|
| 440 |
+
::-webkit-scrollbar-corner {
|
| 441 |
+
appearance: none;
|
| 442 |
+
}
|
autoexpress/static/stylesheet/modal.css
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* Style for settings cog icon */
|
| 2 |
+
.settings-cog {
|
| 3 |
+
font-size: 24px;
|
| 4 |
+
cursor: pointer;
|
| 5 |
+
|
| 6 |
+
}
|
| 7 |
+
|
| 8 |
+
/* Modal background overlay */
|
| 9 |
+
.modal-overlay {
|
| 10 |
+
position: fixed;
|
| 11 |
+
top: 0;
|
| 12 |
+
left: 0;
|
| 13 |
+
width: 100%;
|
| 14 |
+
height: 100%;
|
| 15 |
+
background-color: rgba(0, 0, 0, 0.8);
|
| 16 |
+
display: none;
|
| 17 |
+
align-items: center;
|
| 18 |
+
justify-content: center;
|
| 19 |
+
z-index: 1000;
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
/* Modal content styling */
|
| 23 |
+
.modal-content {
|
| 24 |
+
background-color: var(--panel-background-color);
|
| 25 |
+
padding: 20px;
|
| 26 |
+
border-radius: 1.5rem;
|
| 27 |
+
box-shadow: 0 4px 8px rgba(64, 210, 255, 0.6);
|
| 28 |
+
width: 600px;
|
| 29 |
+
max-width: 80%;
|
| 30 |
+
color: #fff;
|
| 31 |
+
text-align: center;
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
/* Close button style */
|
| 35 |
+
.close-btn {
|
| 36 |
+
font-size: 30px;
|
| 37 |
+
color:red;
|
| 38 |
+
cursor: pointer;
|
| 39 |
+
float: right;
|
| 40 |
+
}
|
autoexpress/static/stylesheet/sidebar.css
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.sidebar {
|
| 2 |
+
margin: 0px 15px 0px 15px;
|
| 3 |
+
padding: 0px;
|
| 4 |
+
width: 100%;
|
| 5 |
+
}
|
| 6 |
+
|
| 7 |
+
.sidebar-title {
|
| 8 |
+
margin: 0px 0px 0px 0px;
|
| 9 |
+
padding: 0px;
|
| 10 |
+
color: var(--font-color);
|
| 11 |
+
font-size: large;
|
| 12 |
+
font-weight: bold;
|
| 13 |
+
display: flex;
|
| 14 |
+
justify-content: space-around;
|
| 15 |
+
align-items: center;
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
.sidebar-logo{
|
| 19 |
+
height: auto;
|
| 20 |
+
width: 12%;
|
| 21 |
+
position: relative;
|
| 22 |
+
right:5%
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
#ip-input {
|
| 26 |
+
display: flex;
|
| 27 |
+
flex: auto;
|
| 28 |
+
background-color: var(--input-background-color);
|
| 29 |
+
padding-left: 10px;
|
| 30 |
+
padding-right: 10px;
|
| 31 |
+
margin-right: 10px;
|
| 32 |
+
margin-right: 10px;
|
| 33 |
+
border-radius: 10px;
|
| 34 |
+
min-width: 1px;
|
| 35 |
+
color: var(--input-number-color);
|
| 36 |
+
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
.sidebar-add-space {
|
| 40 |
+
padding: 25px;
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
input:checked+.anime {
|
| 44 |
+
transition: .4s;
|
| 45 |
+
background-color: var(--realistic-switch-bg-color);
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
input:not(:checked)+.anime {
|
| 49 |
+
transition: .4s;
|
| 50 |
+
background-color: var(--anime-switch-bg-color);
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
#seed-input {
|
| 54 |
+
width: 7rem;
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
#clip-skip-input {
|
| 58 |
+
width: 3rem;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
#seed-input {
|
| 62 |
+
padding-right: 0.5rem;
|
| 63 |
+
|
| 64 |
+
&::-webkit-inner-spin-button {
|
| 65 |
+
appearance: none;
|
| 66 |
+
opacity: 0 !important;
|
| 67 |
+
cursor: auto;
|
| 68 |
+
width: 0px;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
}
|
autoexpress/static/stylesheet/slider_object.css
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* The switch - the box around the slider */
|
| 2 |
+
.switch {
|
| 3 |
+
position: relative;
|
| 4 |
+
text-align: center;
|
| 5 |
+
display: inline-block;
|
| 6 |
+
margin-right: 0px;
|
| 7 |
+
padding-right: 0px;
|
| 8 |
+
max-width: 60px;
|
| 9 |
+
min-width: 60px;
|
| 10 |
+
height: var(--input-height);
|
| 11 |
+
font-size: large;
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
.switch-container {
|
| 15 |
+
width: 100%;
|
| 16 |
+
display: flex;
|
| 17 |
+
flex-direction: row;
|
| 18 |
+
justify-content: space-evenly;
|
| 19 |
+
align-items: center;
|
| 20 |
+
margin: 5px 5px 5px 5px;
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
.switch-label {
|
| 24 |
+
text-align: center;
|
| 25 |
+
font-size: large;
|
| 26 |
+
margin: 0px 10px 0px 10px;
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
/* Hide default HTML checkbox */
|
| 30 |
+
.switch input {
|
| 31 |
+
opacity: 0;
|
| 32 |
+
width: 0;
|
| 33 |
+
height: 0;
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
/* The slider */
|
| 37 |
+
.slider {
|
| 38 |
+
position: absolute;
|
| 39 |
+
cursor: pointer;
|
| 40 |
+
height: var(--input-height);
|
| 41 |
+
width: calc(var(--input-height) * 2);
|
| 42 |
+
top: 0;
|
| 43 |
+
left: 0;
|
| 44 |
+
right: 0;
|
| 45 |
+
bottom: 0;
|
| 46 |
+
background-color: var(--input-background-color);
|
| 47 |
+
border: 2px solid var(--knob-color);
|
| 48 |
+
box-shadow: inset 0 0 0px 1px var(--light-accent),
|
| 49 |
+
var(--box-shadow-inset-neg);
|
| 50 |
+
outline: 1px var(--knob-color);
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
/*knob*/
|
| 54 |
+
.slider:before {
|
| 55 |
+
position: absolute;
|
| 56 |
+
content: "";
|
| 57 |
+
height: var(--input-height);
|
| 58 |
+
width: calc(var(--input-height));
|
| 59 |
+
left: 0px;
|
| 60 |
+
bottom: 0px;
|
| 61 |
+
background-color: var(--knob-color);
|
| 62 |
+
box-shadow: var(--box-shadow-inset-pos);
|
| 63 |
+
transition: .3s;
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
input:checked+.slider:before {
|
| 67 |
+
transform: translateX(100%);
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
/* Rounded sliders */
|
| 71 |
+
.slider.round {
|
| 72 |
+
border-radius: 66px;
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
.slider.round:before {
|
| 76 |
+
border-radius: 100%;
|
| 77 |
+
}
|
autoexpress/templates/index.html
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
|
| 3 |
+
<!--
|
| 4 |
+
/*NOTES:*/
|
| 5 |
+
/*
|
| 6 |
+
Icons are now a font: lucide-icon-font
|
| 7 |
+
Usage: Add a class with the name of the icon
|
| 8 |
+
EXAMPLE:
|
| 9 |
+
<div class="icon-link-2"></div>
|
| 10 |
+
IMPORTANT, when getting the name of the icon add "icon-" in front of it.
|
| 11 |
+
circle-chevron-left = icon-circle-chevron-left
|
| 12 |
+
Icons can be looked up here: https://lucide.dev/icons/?focus
|
| 13 |
+
NOTE: [class^="icon-"], [class*=" icon-"] is part of the font and in main css to style all the icons
|
| 14 |
+
|
| 15 |
+
Authors: Deepratna Awale, Avery Velfaire
|
| 16 |
+
*/
|
| 17 |
+
-->
|
| 18 |
+
|
| 19 |
+
<html id="bg" lang="en">
|
| 20 |
+
|
| 21 |
+
<head>
|
| 22 |
+
<meta charset="UTF-8" />
|
| 23 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 24 |
+
<title>Auto Express UI</title>
|
| 25 |
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/AveryVeilfaire/lucide-font@main/lucide.css">
|
| 26 |
+
<link rel="stylesheet" href="{{ url_for('static', filename='stylesheet/main.css') }}" />
|
| 27 |
+
<link rel="stylesheet" href="{{ url_for('static', filename='stylesheet/sidebar.css') }}" />
|
| 28 |
+
<link rel="stylesheet" href="{{ url_for('static', filename='stylesheet/modal.css') }}" />
|
| 29 |
+
<link rel="stylesheet" href="{{ url_for('static', filename='stylesheet/image_and_prompt.css') }}" />
|
| 30 |
+
<link rel="stylesheet" href="{{ url_for('static', filename='stylesheet/image_viewer.css') }}" />
|
| 31 |
+
<link rel="stylesheet" href="{{ url_for('static', filename='stylesheet/slider_object.css') }}" />
|
| 32 |
+
<link rel="stylesheet" href="{{ url_for('static', filename='stylesheet/frontend_settings.css') }}" />
|
| 33 |
+
<link rel="shortcut icon" href="{{ url_for('static', filename='ico/favicon-rounded.png') }}" />
|
| 34 |
+
<meta name="theme-color" content="#14151f">
|
| 35 |
+
<!-- Dark/Light mode support <meta name="color-scheme" content="dark light" /> -->
|
| 36 |
+
</head>
|
| 37 |
+
|
| 38 |
+
<body>
|
| 39 |
+
<div class="container">
|
| 40 |
+
<div class="left-pane">
|
| 41 |
+
<!-- Sidebar -->
|
| 42 |
+
<div class="sidebar">
|
| 43 |
+
<div class="sidebar-title">
|
| 44 |
+
<img class="sidebar-logo" src="{{ url_for('static', filename='ico/favicon-rounded.png') }}" alt="Logo"/>
|
| 45 |
+
<h1>Parameters</h1>
|
| 46 |
+
</div>
|
| 47 |
+
|
| 48 |
+
<!-- A1111 API Url -->
|
| 49 |
+
|
| 50 |
+
<div class="input-container slider-container">
|
| 51 |
+
<label for="ip-input">A1111 Api</label>
|
| 52 |
+
<input id="ip-input" name="ip-input" type="text" placeholder="127.0.0.1:7860" />
|
| 53 |
+
<button class="sd-connect">
|
| 54 |
+
<div class="icon-link-2"></div>
|
| 55 |
+
</button>
|
| 56 |
+
</div>
|
| 57 |
+
|
| 58 |
+
<!-- Model Dropdown -->
|
| 59 |
+
<div class="input-container select-container">
|
| 60 |
+
<label for="model-input">Model</label>
|
| 61 |
+
<select id="model-input" name="model">
|
| 62 |
+
<!-- Add more options as needed -->
|
| 63 |
+
</select>
|
| 64 |
+
</div>
|
| 65 |
+
|
| 66 |
+
<!-- Sampler Dropdown -->
|
| 67 |
+
<div class="input-container select-container">
|
| 68 |
+
<label for="sampler-input">Sampler</label>
|
| 69 |
+
<select id="sampler-input" name="sampler">
|
| 70 |
+
<!-- Add more options as needed -->
|
| 71 |
+
</select>
|
| 72 |
+
</div>
|
| 73 |
+
|
| 74 |
+
<!-- Scheduler Dropdown -->
|
| 75 |
+
<div class="input-container select-container">
|
| 76 |
+
<label for="scheduler-input">Scheduler</label>
|
| 77 |
+
<select id="scheduler-input" name="scheduler">
|
| 78 |
+
<!-- Add more options as needed -->
|
| 79 |
+
</select>
|
| 80 |
+
</div>
|
| 81 |
+
|
| 82 |
+
<!-- Lora Dropdown -->
|
| 83 |
+
<div class="input-container select-container">
|
| 84 |
+
<label for="lora-input">Lora</label>
|
| 85 |
+
<select id="lora-input" name="lora">
|
| 86 |
+
<!-- Add more options as needed -->
|
| 87 |
+
</select>
|
| 88 |
+
</div>
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
<div class="input-container grid-container">
|
| 92 |
+
<!-- Clip skip Input -->
|
| 93 |
+
<div class="input-container">
|
| 94 |
+
<label for="clip-skip-input">Clip Skip</label>
|
| 95 |
+
<input type="number" id="clip-skip-input" name="clip-skip" value="2" />
|
| 96 |
+
</div>
|
| 97 |
+
<!-- Seed Input -->
|
| 98 |
+
<div class="input-container">
|
| 99 |
+
<label id= "seed-label" for="seed-input">Seed</label>
|
| 100 |
+
<input type="number" id="seed-input" name="seed-input" value="-1" min="-1" />
|
| 101 |
+
</div>
|
| 102 |
+
</div>
|
| 103 |
+
|
| 104 |
+
<!-- Steps Slider + Input -->
|
| 105 |
+
<div class="input-container slider-container">
|
| 106 |
+
<label for="steps-slider">Steps</label>
|
| 107 |
+
<input type="range" id="steps-slider" name="steps-slider" value="32" min="0" max="40" step="1"
|
| 108 |
+
oninput="updateInput('steps')" />
|
| 109 |
+
<input type="number" id="steps-input" name="steps-input" value="32" min="0" max="40" step="1"
|
| 110 |
+
oninput="updateSlider('steps')" />
|
| 111 |
+
</div>
|
| 112 |
+
|
| 113 |
+
<!-- Width Slider + Input -->
|
| 114 |
+
<div class="input-container slider-container">
|
| 115 |
+
<label for="width-slider">Width</label>
|
| 116 |
+
<input type="range" id="width-slider" name="width-slider" value="512" min="0" max="2048" step="1"
|
| 117 |
+
oninput="updateInput('width')" />
|
| 118 |
+
<input type="number" id="width-input" name="width-input" value="512" min="0" max="2048" step="1"
|
| 119 |
+
oninput="updateSlider('width')" />
|
| 120 |
+
</div>
|
| 121 |
+
|
| 122 |
+
<!-- Height Slider + Input -->
|
| 123 |
+
<div class="input-container slider-container">
|
| 124 |
+
<label for="height-slider">Height</label>
|
| 125 |
+
<input type="range" id="height-slider" name="height-slider" value="768" min="0" max="2048" step="1"
|
| 126 |
+
oninput="updateInput('height')" />
|
| 127 |
+
<input type="number" id="height-input" name="height-input" value="768" min="0" max="2048" step="1"
|
| 128 |
+
oninput="updateSlider('height')" />
|
| 129 |
+
</div>
|
| 130 |
+
|
| 131 |
+
<!-- CFG Scale Slider + Input -->
|
| 132 |
+
<div class="input-container slider-container">
|
| 133 |
+
<label for="cfg-scale-slider">CFG Scale</label>
|
| 134 |
+
<input type="range" id="cfg-scale-slider" name="cfg-scale-slider" value="7" min="0" max="20" step="0.5"
|
| 135 |
+
oninput="updateInput('cfg-scale')" />
|
| 136 |
+
<input type="number" id="cfg-scale-input" name="cfg-scale-input" value="7" min="0" max="20" step="0.5"
|
| 137 |
+
oninput="updateSlider('cfg-scale')" />
|
| 138 |
+
</div>
|
| 139 |
+
|
| 140 |
+
<!-- Denoising Strength Slider + Input -->
|
| 141 |
+
<div class="input-container slider-container">
|
| 142 |
+
<label for="denoising-strength-slider">Denoising Strength</label>
|
| 143 |
+
<input type="range" id="denoising-strength-slider" name="denoising-strength-slider" min="0" max="1"
|
| 144 |
+
value="0.5" step="0.05" oninput="updateInput('denoising-strength')" />
|
| 145 |
+
<input type="number" id="denoising-strength-input" name="denoising-strength-input" min="0" max="1" value="0.5"
|
| 146 |
+
oninput="updateSlider('denoising-strength')" />
|
| 147 |
+
</div>
|
| 148 |
+
|
| 149 |
+
<div class="sidebar-add-space"></div>
|
| 150 |
+
|
| 151 |
+
<!-- Style Selector -->
|
| 152 |
+
<div class="switch-container">
|
| 153 |
+
<label class="switch-label">Anime</label>
|
| 154 |
+
<label class="switch">
|
| 155 |
+
<input type="checkbox" id="styleSelector" /> <!--checked-->
|
| 156 |
+
<span class="slider round anime"></span>
|
| 157 |
+
</label>
|
| 158 |
+
<label class="switch-label">Realistic</label>
|
| 159 |
+
</div>
|
| 160 |
+
|
| 161 |
+
|
| 162 |
+
<div class="sidebar-add-space"></div>
|
| 163 |
+
<!-- Settings cog icon -->
|
| 164 |
+
<span class="icon-settings settings-cog" onclick="openModal()"></span>
|
| 165 |
+
|
| 166 |
+
<!-- Modal overlay and content -->
|
| 167 |
+
<div id="modalOverlay" class="modal-overlay">
|
| 168 |
+
<div class="modal-content">
|
| 169 |
+
<span class="close-btn" onclick="closeModal()">×</span>
|
| 170 |
+
<!-- FrontEnd Settings (Modal Content) -->
|
| 171 |
+
<div class="frontend-settings">
|
| 172 |
+
<h1>GUI Settings</h1>
|
| 173 |
+
<h2>Background</h2>
|
| 174 |
+
<div class="input-container">
|
| 175 |
+
<label>BG Animation</label>
|
| 176 |
+
<div class="switch-container">
|
| 177 |
+
<label class="switch-label">Off</label>
|
| 178 |
+
<label class="switch">
|
| 179 |
+
<input type="checkbox" id="gradient-animation-toggle" checked />
|
| 180 |
+
<span class="slider round"></span>
|
| 181 |
+
</label>
|
| 182 |
+
<label class="switch-label">On</label>
|
| 183 |
+
</div>
|
| 184 |
+
</div>
|
| 185 |
+
</div>
|
| 186 |
+
<!-- End of FrontEnd Settings (Modal Content) -->
|
| 187 |
+
</div>
|
| 188 |
+
</div>
|
| 189 |
+
<!-- End of Modal overlay and content -->
|
| 190 |
+
</div>
|
| 191 |
+
</div>
|
| 192 |
+
<div class="center-pane">
|
| 193 |
+
<div class="image-and-prompt-container">
|
| 194 |
+
|
| 195 |
+
<div class="input-container drop-zone">
|
| 196 |
+
<div class="drop-zone-prompt">
|
| 197 |
+
<div class="icon-upload"></div>
|
| 198 |
+
<span id="upload-file-drop-zone">Drop file here or click to upload image</span>
|
| 199 |
+
</div>
|
| 200 |
+
<input type="file" name="image" id="drop-zone-input-field" />
|
| 201 |
+
<!-- Info icon at bottom right -->
|
| 202 |
+
<span class="icon-info info-icon" id="info-icon" title="Drop image and hover on this icon or the image to see the raw generation data. This can help you fill in the missing parameters manually if not autodetected."></span>
|
| 203 |
+
<div class="tooltip" id="tooltip"></div>
|
| 204 |
+
</div>
|
| 205 |
+
|
| 206 |
+
<button type="submit" class="generate-button" data-lucide="image-play">
|
| 207 |
+
<div class="generate-icon icon-image-play"></div>
|
| 208 |
+
Generate
|
| 209 |
+
</button>
|
| 210 |
+
<div class="input-container">
|
| 211 |
+
<textarea type="text" id="prompt-textfield" name="prompt-textfield"
|
| 212 |
+
placeholder="Prompt"></textarea>
|
| 213 |
+
</div>
|
| 214 |
+
<div class="input-container">
|
| 215 |
+
<textarea type="text" id="negative-prompt-textfield" name="negative-prompt-textfield"
|
| 216 |
+
placeholder="Negative prompt..."></textarea>
|
| 217 |
+
</div>
|
| 218 |
+
</div>
|
| 219 |
+
</div>
|
| 220 |
+
<div class="right-pane">
|
| 221 |
+
<div class="image-output-container">
|
| 222 |
+
<div class="input-container">
|
| 223 |
+
<input type="text" class="output-directory" id="output-directory" name="output-directory"
|
| 224 |
+
placeholder="Character_Name" onkeypress="loadImagesInput(event)" />
|
| 225 |
+
<button class="load-images" onclick="loadImages()">
|
| 226 |
+
<div class="icon-refresh-cw"></div>
|
| 227 |
+
</button>
|
| 228 |
+
</div>
|
| 229 |
+
<div class="display-container">
|
| 230 |
+
<button class="nav-left" onclick="navigate(-1)">
|
| 231 |
+
<div class="nav-icon icon-circle-chevron-left"></div>
|
| 232 |
+
</button>
|
| 233 |
+
<div class="image-name-column-container">
|
| 234 |
+
<div class="image-container">
|
| 235 |
+
<img id="image-display" src="" alt="" onload="this.style.display='flex'"
|
| 236 |
+
onerror="this.style.display='none'" />
|
| 237 |
+
</div>
|
| 238 |
+
<div id="expression-image-name"></div>
|
| 239 |
+
</div>
|
| 240 |
+
<button class="nav-right" onclick="navigate(1)">
|
| 241 |
+
<div class="nav-icon icon-circle-chevron-right"></div>
|
| 242 |
+
</button>
|
| 243 |
+
</div>
|
| 244 |
+
</div>
|
| 245 |
+
</div>
|
| 246 |
+
</div>
|
| 247 |
+
</div>
|
| 248 |
+
<!DOCTYPE html>
|
| 249 |
+
|
| 250 |
+
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
|
| 251 |
+
<script src="{{ url_for('static', filename='js/connect.js') }}"></script>
|
| 252 |
+
<script src="{{ url_for('static', filename='js/modal.js') }}"></script>
|
| 253 |
+
<script src="{{ url_for('static', filename='js/image_drag_and_drop.js') }}"></script>
|
| 254 |
+
<script src="{{ url_for('static', filename='js/generate.js') }}"></script>
|
| 255 |
+
<script src="{{ url_for('static', filename='js/image_viewer.js') }}"></script>
|
| 256 |
+
<script src="{{ url_for('static', filename='js/anime_toggle.js') }}"></script>
|
| 257 |
+
<script src="{{ url_for('static', filename='js/frontend_settings.js') }}"></script>
|
| 258 |
+
</body>
|
| 259 |
+
|
| 260 |
+
</html>
|
autoexpress/views.py
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from flask import Flask, request, jsonify, render_template, send_from_directory
|
| 2 |
+
from werkzeug.utils import secure_filename
|
| 3 |
+
|
| 4 |
+
import os
|
| 5 |
+
import pathlib
|
| 6 |
+
|
| 7 |
+
from autoexpress.modules import (
|
| 8 |
+
a1111_client,
|
| 9 |
+
image_parser,
|
| 10 |
+
expression_generator,
|
| 11 |
+
)
|
| 12 |
+
|
| 13 |
+
from loguru import logger as log
|
| 14 |
+
import requests
|
| 15 |
+
import re
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
autoexpress = Flask(__name__)
|
| 19 |
+
sd = a1111_client.A1111Client()
|
| 20 |
+
|
| 21 |
+
uploaded = False
|
| 22 |
+
filepath = None
|
| 23 |
+
is_realistic = False
|
| 24 |
+
|
| 25 |
+
# Assuming you want to save uploaded files in a folder called 'uploads'
|
| 26 |
+
UPLOAD_FOLDER = "uploads"
|
| 27 |
+
MAX_FILES = 10
|
| 28 |
+
autoexpress.config["UPLOAD_FOLDER"] = UPLOAD_FOLDER
|
| 29 |
+
|
| 30 |
+
if not os.path.exists(UPLOAD_FOLDER):
|
| 31 |
+
os.makedirs(UPLOAD_FOLDER)
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
# AutoExpress UI
|
| 35 |
+
@autoexpress.route("/", methods=["GET"])
|
| 36 |
+
def index():
|
| 37 |
+
return render_template("index.html")
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
# Stable diffusion API Calls
|
| 41 |
+
@autoexpress.route("/get-models")
|
| 42 |
+
def get_models():
|
| 43 |
+
# Simulate fetching models from an API
|
| 44 |
+
try:
|
| 45 |
+
models = sd.models
|
| 46 |
+
except requests.exceptions.ConnectionError:
|
| 47 |
+
models = []
|
| 48 |
+
return jsonify(models)
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
@autoexpress.route("/get-samplers")
|
| 52 |
+
def get_samplers():
|
| 53 |
+
# Simulate fetching models from an API
|
| 54 |
+
try:
|
| 55 |
+
samplers = sd.samplers
|
| 56 |
+
except requests.exceptions.ConnectionError:
|
| 57 |
+
samplers = []
|
| 58 |
+
return jsonify(samplers)
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
@autoexpress.route("/get-loras")
|
| 62 |
+
def get_loras():
|
| 63 |
+
# Simulate fetching models from an API
|
| 64 |
+
try:
|
| 65 |
+
loras = sd.loras
|
| 66 |
+
except requests.exceptions.ConnectionError:
|
| 67 |
+
loras = []
|
| 68 |
+
return jsonify(loras)
|
| 69 |
+
|
| 70 |
+
# End of Stable diffusion API Calls
|
| 71 |
+
|
| 72 |
+
# Image uploaded
|
| 73 |
+
@autoexpress.route("/upload", methods=["POST"])
|
| 74 |
+
def upload_file():
|
| 75 |
+
if "file" not in request.files:
|
| 76 |
+
return jsonify({"error": "No file part"}), 400
|
| 77 |
+
|
| 78 |
+
file = request.files["file"]
|
| 79 |
+
|
| 80 |
+
if file.filename == "":
|
| 81 |
+
return jsonify({"error": "No selected file"}), 400
|
| 82 |
+
|
| 83 |
+
if file and allowed_file(file.filename):
|
| 84 |
+
filename = secure_filename(file.filename)
|
| 85 |
+
filepath = os.path.join(autoexpress.config["UPLOAD_FOLDER"], filename)
|
| 86 |
+
file.save(filepath)
|
| 87 |
+
|
| 88 |
+
full_image_data = {"cleaned_data": None, "uncleaned_data": None}
|
| 89 |
+
full_image_data["cleaned_data"] = image_parser.generate_parameters(filepath)
|
| 90 |
+
full_image_data["uncleaned_data"] = image_parser.generate_uncleaned_params(filepath)
|
| 91 |
+
|
| 92 |
+
return (
|
| 93 |
+
jsonify(full_image_data),
|
| 94 |
+
200,
|
| 95 |
+
)
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
def allowed_file(filename):
|
| 99 |
+
return "." in filename and filename.rsplit(".", 1)[1].lower() in {
|
| 100 |
+
"png",
|
| 101 |
+
"jpg",
|
| 102 |
+
"jpeg",
|
| 103 |
+
"gif",
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
# Try connecting to SD
|
| 107 |
+
@autoexpress.route("/receive_data", methods=["POST"])
|
| 108 |
+
def receive_data():
|
| 109 |
+
|
| 110 |
+
data = request.json
|
| 111 |
+
|
| 112 |
+
url = data["text"]
|
| 113 |
+
|
| 114 |
+
if url in [""]:
|
| 115 |
+
sd.setURL("http://127.0.0.1:7860")
|
| 116 |
+
log.info(f"No url found.")
|
| 117 |
+
|
| 118 |
+
elif url[-1] in ["/"]:
|
| 119 |
+
sd.setURL(url[:-1])
|
| 120 |
+
|
| 121 |
+
elif "http" in url:
|
| 122 |
+
sd.setURL(url)
|
| 123 |
+
|
| 124 |
+
else:
|
| 125 |
+
sd.setURL("http://" + url)
|
| 126 |
+
|
| 127 |
+
log.info("SD URL set to: " + sd.getURL())
|
| 128 |
+
|
| 129 |
+
return jsonify({"status": "success"})
|
| 130 |
+
|
| 131 |
+
# Generate Images
|
| 132 |
+
@autoexpress.route("/generate", methods=["POST"])
|
| 133 |
+
def generate():
|
| 134 |
+
data = request.json
|
| 135 |
+
|
| 136 |
+
adetailer_exists = sd.is_extension()
|
| 137 |
+
|
| 138 |
+
if not adetailer_exists:
|
| 139 |
+
return jsonify({"status": "Failed", "message": "Could not find adetailer"})
|
| 140 |
+
|
| 141 |
+
matches = get_lora_from_prompt(data.get("ad_prompt"))
|
| 142 |
+
img_str = data.get("init_images")
|
| 143 |
+
|
| 144 |
+
output_dir = data.get("output_dir") or "New_Character"
|
| 145 |
+
|
| 146 |
+
if not matches and data.get("lora") not in [""]:
|
| 147 |
+
data["ad_prompt"] += f" <lora: {data.get('lora')}: 0.8>"
|
| 148 |
+
|
| 149 |
+
data.pop("output_dir")
|
| 150 |
+
data.pop("lora")
|
| 151 |
+
data.pop("init_images")
|
| 152 |
+
|
| 153 |
+
log.info("Using the following generation parameters:\n" + str(data))
|
| 154 |
+
|
| 155 |
+
try:
|
| 156 |
+
expression_generator.generate_expressions(
|
| 157 |
+
sd=sd,
|
| 158 |
+
image_str=img_str,
|
| 159 |
+
output_path=f"Output/{output_dir}",
|
| 160 |
+
settings=data,
|
| 161 |
+
is_realistic=is_realistic,
|
| 162 |
+
)
|
| 163 |
+
except KeyboardInterrupt:
|
| 164 |
+
sd.interrupt()
|
| 165 |
+
|
| 166 |
+
# Process data here, e.g., generate text based on the model and prompt
|
| 167 |
+
return jsonify({"status": "success", "message": "Data processed successfully"})
|
| 168 |
+
|
| 169 |
+
|
| 170 |
+
def get_lora_from_prompt(text):
|
| 171 |
+
if not text:
|
| 172 |
+
return []
|
| 173 |
+
# Regular expression pattern to find text and strength
|
| 174 |
+
pattern = r"<lora:(.*?):(.*?)>"
|
| 175 |
+
# Find all matches
|
| 176 |
+
matches = re.findall(pattern, text)
|
| 177 |
+
return matches
|
| 178 |
+
|
| 179 |
+
|
| 180 |
+
@autoexpress.route("/images/<path:subpath>")
|
| 181 |
+
def list_images(subpath):
|
| 182 |
+
root = pathlib.Path(autoexpress.root_path).parent
|
| 183 |
+
directory = os.path.join(root, "Output", subpath)
|
| 184 |
+
log.info("Attempting to list images from:", directory) # Debugging statement
|
| 185 |
+
try:
|
| 186 |
+
files = [
|
| 187 |
+
f
|
| 188 |
+
for f in os.listdir(directory)
|
| 189 |
+
if os.path.isfile(os.path.join(directory, f))
|
| 190 |
+
]
|
| 191 |
+
return jsonify(files)
|
| 192 |
+
except FileNotFoundError:
|
| 193 |
+
log.info("Directory not found:", directory) # Debugging statement
|
| 194 |
+
return jsonify({"error": "Directory not found"}), 404
|
| 195 |
+
|
| 196 |
+
|
| 197 |
+
@autoexpress.route("/image/<path:filename>")
|
| 198 |
+
def get_image(filename):
|
| 199 |
+
"""Endpoint to serve images from the entire 'Output' directory."""
|
| 200 |
+
root_path = pathlib.Path(autoexpress.root_path).parent
|
| 201 |
+
return send_from_directory(os.path.join(root_path, "Output"), filename)
|
| 202 |
+
|
| 203 |
+
|
| 204 |
+
@autoexpress.route("/toggle", methods=["POST"])
|
| 205 |
+
def handle_toggle():
|
| 206 |
+
global is_realistic
|
| 207 |
+
data = request.get_json()
|
| 208 |
+
is_realistic = data.get("isRealistic")
|
| 209 |
+
|
| 210 |
+
return jsonify({"message": f"Is realistic status set to {is_realistic}"})
|
requirements.txt
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
flask
|
| 2 |
+
sd-parsers==0.4
|
| 3 |
+
matplotlib
|
| 4 |
+
pillow
|
| 5 |
+
requests
|
| 6 |
+
loguru
|
startup.bat
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
REM .venv\Scripts\activate
|
| 2 |
+
flask --app autoexpress run
|
startupDebug.bat
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
REM .venv\Scripts\activate
|
| 2 |
+
flask --app autoexpress run --debug
|