damientheodore commited on
Commit
424f388
·
1 Parent(s): 5cc7bed

AutoExpress Docker version 1.0

Browse files
Files changed (50) hide show
  1. .gitattributes +2 -35
  2. .gitignore +156 -0
  3. .hintrc +25 -0
  4. Changelog.md +26 -0
  5. Dockerfile +25 -0
  6. LICENSE +21 -0
  7. README.md +158 -10
  8. autoexpress/__init__.py +13 -0
  9. autoexpress/create_grid.py +55 -0
  10. autoexpress/modules/__init__.py +0 -0
  11. autoexpress/modules/a1111_client.py +248 -0
  12. autoexpress/modules/background_remover.py +64 -0
  13. autoexpress/modules/expression_generator.py +100 -0
  14. autoexpress/modules/image_parser.py +76 -0
  15. autoexpress/modules/json_handler.py +95 -0
  16. autoexpress/modules/utils.py +41 -0
  17. autoexpress/resources/clip_expressions.json +30 -0
  18. autoexpress/resources/empty_bg.json +49 -0
  19. autoexpress/resources/expressions.json +30 -0
  20. autoexpress/resources/illu_expressions.json +30 -0
  21. autoexpress/resources/images/AutoExpressUI_2024_11_13.png +0 -0
  22. autoexpress/resources/images/AutoExpressUI_Revamped.png +0 -0
  23. autoexpress/resources/images/UI.png +0 -0
  24. autoexpress/resources/images/anime_grid.png +0 -0
  25. autoexpress/resources/images/anime_input.png +0 -0
  26. autoexpress/resources/images/realistic_grid.png +0 -0
  27. autoexpress/resources/images/realistic_input.png +0 -0
  28. autoexpress/resources/payload.json +99 -0
  29. autoexpress/static/ico/favicon-rounded.png +0 -0
  30. autoexpress/static/ico/favicon.png +0 -0
  31. autoexpress/static/js/anime_toggle.js +37 -0
  32. autoexpress/static/js/connect.js +93 -0
  33. autoexpress/static/js/frontend_settings.js +12 -0
  34. autoexpress/static/js/generate.js +39 -0
  35. autoexpress/static/js/image_drag_and_drop.js +160 -0
  36. autoexpress/static/js/image_viewer.js +89 -0
  37. autoexpress/static/js/main.js +15 -0
  38. autoexpress/static/js/modal.js +7 -0
  39. autoexpress/static/stylesheet/frontend_settings.css +7 -0
  40. autoexpress/static/stylesheet/image_and_prompt.css +152 -0
  41. autoexpress/static/stylesheet/image_viewer.css +102 -0
  42. autoexpress/static/stylesheet/main.css +442 -0
  43. autoexpress/static/stylesheet/modal.css +40 -0
  44. autoexpress/static/stylesheet/sidebar.css +71 -0
  45. autoexpress/static/stylesheet/slider_object.css +77 -0
  46. autoexpress/templates/index.html +260 -0
  47. autoexpress/views.py +210 -0
  48. requirements.txt +6 -0
  49. startup.bat +2 -0
  50. startupDebug.bat +2 -0
.gitattributes CHANGED
@@ -1,35 +1,2 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
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
+ ![Latest UI](autoexpress/resources/images/AutoExpressUI_2024_11_13.png)
16
+
17
+
18
+ ## 2024-09-26
19
+ - Tested on Ububtu (22.04.3 | jammy)
20
+
21
+ ## 2024-06-23
22
+ - Added revamped UI
23
+ ![AutoExpress Reskinned](autoexpress/resources/images/AutoExpressUI_Revamped.png)
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
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ ![UI Description](autoexpress/resources/images/UI.png)
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
+ ![LatestUI](autoexpress/resources/images/AutoExpressUI_2024_11_13.png)
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