mirror of
https://github.com/easydiffusion/easydiffusion.git
synced 2025-06-20 18:08:00 +02:00
Merge Improvements from JeLuF:gallery
added Options
This commit is contained in:
commit
d50ef991ad
@ -22,6 +22,14 @@
|
|||||||
Our focus continues to remain on an easy installation experience, and an easy user-interface. While still remaining pretty powerful, in terms of features and speed.
|
Our focus continues to remain on an easy installation experience, and an easy user-interface. While still remaining pretty powerful, in terms of features and speed.
|
||||||
|
|
||||||
### Detailed changelog
|
### Detailed changelog
|
||||||
|
* 3.0.1 - 17 Aug 2023 - Fix broken embeddings with SDXL.
|
||||||
|
* 3.0.1 - 16 Aug 2023 - Fix broken LoRA with SDXL.
|
||||||
|
* 3.0.1 - 15 Aug 2023 - Fix broken seamless tiling.
|
||||||
|
* 3.0.1 - 15 Aug 2023 - Fix textual inversion embeddings not working in `low` VRAM usage mode.
|
||||||
|
* 3.0.1 - 15 Aug 2023 - Fix for custom VAEs not working in `low` VRAM usage mode.
|
||||||
|
* 3.0.1 - 14 Aug 2023 - Slider to change the image dimensions proportionally (in Image Settings). Thanks @JeLuf.
|
||||||
|
* 3.0.1 - 14 Aug 2023 - Show an error to the user if an embedding isn't compatible with the model, instead of failing silently without informing the user. Thanks @JeLuf.
|
||||||
|
* 3.0.1 - 14 Aug 2023 - Disable watermarking for SDXL img2img. Thanks @AvidGameFan.
|
||||||
* 3.0.0 - 3 Aug 2023 - Enabled diffusers for everyone by default. The old v2 engine can be used by disabling the "Use v3 engine" option in the Settings tab.
|
* 3.0.0 - 3 Aug 2023 - Enabled diffusers for everyone by default. The old v2 engine can be used by disabling the "Use v3 engine" option in the Settings tab.
|
||||||
* 2.5.48 - 1 Aug 2023 - (beta-only) Full support for ControlNets. You can select a control image to guide the AI. You can pick a filter to pre-process the image, and one of the known (or custom) controlnet models. Supports `OpenPose`, `Canny`, `Straight Lines`, `Depth`, `Line Art`, `Scribble`, `Soft Edge`, `Shuffle` and `Segment`.
|
* 2.5.48 - 1 Aug 2023 - (beta-only) Full support for ControlNets. You can select a control image to guide the AI. You can pick a filter to pre-process the image, and one of the known (or custom) controlnet models. Supports `OpenPose`, `Canny`, `Straight Lines`, `Depth`, `Line Art`, `Scribble`, `Soft Edge`, `Shuffle` and `Segment`.
|
||||||
* 2.5.47 - 30 Jul 2023 - An option to use `Strict Mask Border` while inpainting, to avoid touching areas outside the mask. But this might show a slight outline of the mask, which you will have to touch up separately.
|
* 2.5.47 - 30 Jul 2023 - An option to use `Strict Mask Border` while inpainting, to avoid touching areas outside the mask. But this might show a slight outline of the mask, which you will have to touch up separately.
|
||||||
|
@ -18,7 +18,7 @@ os_name = platform.system()
|
|||||||
modules_to_check = {
|
modules_to_check = {
|
||||||
"torch": ("1.11.0", "1.13.1", "2.0.0"),
|
"torch": ("1.11.0", "1.13.1", "2.0.0"),
|
||||||
"torchvision": ("0.12.0", "0.14.1", "0.15.1"),
|
"torchvision": ("0.12.0", "0.14.1", "0.15.1"),
|
||||||
"sdkit": "1.0.167",
|
"sdkit": "1.0.174",
|
||||||
"stable-diffusion-sdkit": "2.1.4",
|
"stable-diffusion-sdkit": "2.1.4",
|
||||||
"rich": "12.6.0",
|
"rich": "12.6.0",
|
||||||
"uvicorn": "0.19.0",
|
"uvicorn": "0.19.0",
|
||||||
|
@ -46,6 +46,8 @@ if "%update_branch%"=="" (
|
|||||||
|
|
||||||
@cd sd-ui-files
|
@cd sd-ui-files
|
||||||
|
|
||||||
|
@call git add -A .
|
||||||
|
@call git stash
|
||||||
@call git reset --hard
|
@call git reset --hard
|
||||||
@call git -c advice.detachedHead=false checkout "%update_branch%"
|
@call git -c advice.detachedHead=false checkout "%update_branch%"
|
||||||
@call git pull
|
@call git pull
|
||||||
|
@ -29,6 +29,8 @@ if [ -f "scripts/install_status.txt" ] && [ `grep -c sd_ui_git_cloned scripts/in
|
|||||||
|
|
||||||
cd sd-ui-files
|
cd sd-ui-files
|
||||||
|
|
||||||
|
git add -A .
|
||||||
|
git stash
|
||||||
git reset --hard
|
git reset --hard
|
||||||
git -c advice.detachedHead=false checkout "$update_branch"
|
git -c advice.detachedHead=false checkout "$update_branch"
|
||||||
git pull
|
git pull
|
||||||
|
@ -100,9 +100,9 @@ def init():
|
|||||||
raise HTTPException(status_code=404, detail="Image not found")
|
raise HTTPException(status_code=404, detail="Image not found")
|
||||||
|
|
||||||
@server_api.get("/all_images")
|
@server_api.get("/all_images")
|
||||||
def get_all_images(prompt: str = "", model: str = "", page: int = 0, images_per_page: int = 50, db: Session = Depends(get_db)):
|
def get_all_images(prompt: str = "", model: str = "", page: int = 0, images_per_page: int = 50, workspace : str = "default", db: Session = Depends(get_db)):
|
||||||
from easydiffusion.easydb.mappings import GalleryImage
|
from easydiffusion.easydb.mappings import GalleryImage
|
||||||
images = db.query(GalleryImage).order_by(GalleryImage.time_created.desc())
|
images = db.query(GalleryImage).filter(GalleryImage.workspace == workspace).order_by(GalleryImage.time_created.desc())
|
||||||
if prompt != "":
|
if prompt != "":
|
||||||
images = images.filter(GalleryImage.prompt.like("%"+prompt+"%"))
|
images = images.filter(GalleryImage.prompt.like("%"+prompt+"%"))
|
||||||
if model != "":
|
if model != "":
|
||||||
@ -110,6 +110,7 @@ def init():
|
|||||||
images = images.offset(page*images_per_page).limit(images_per_page)
|
images = images.offset(page*images_per_page).limit(images_per_page)
|
||||||
return images.all()
|
return images.all()
|
||||||
|
|
||||||
|
|
||||||
def get_filename_from_url(url):
|
def get_filename_from_url(url):
|
||||||
path = urlparse(url).path
|
path = urlparse(url).path
|
||||||
name = path[path.rfind('/')+1:]
|
name = path[path.rfind('/')+1:]
|
||||||
|
@ -65,9 +65,6 @@ def load_default_models(context: Context):
|
|||||||
|
|
||||||
runtime.set_vram_optimizations(context)
|
runtime.set_vram_optimizations(context)
|
||||||
|
|
||||||
config = app.getConfig()
|
|
||||||
context.embeddings_path = os.path.join(app.MODELS_DIR, "embeddings")
|
|
||||||
|
|
||||||
# init default model paths
|
# init default model paths
|
||||||
for model_type in MODELS_TO_LOAD_ON_START:
|
for model_type in MODELS_TO_LOAD_ON_START:
|
||||||
context.model_paths[model_type] = resolve_model_to_use(model_type=model_type, fail_if_not_found=False)
|
context.model_paths[model_type] = resolve_model_to_use(model_type=model_type, fail_if_not_found=False)
|
||||||
|
@ -12,9 +12,9 @@ from easydiffusion import app
|
|||||||
manifest = {
|
manifest = {
|
||||||
"tensorrt": {
|
"tensorrt": {
|
||||||
"install": [
|
"install": [
|
||||||
"nvidia-cudnn --pre --extra-index-url=https://pypi.ngc.nvidia.com --trusted-host pypi.ngc.nvidia.com",
|
"nvidia-cudnn --pre --extra-index-url=https://pypi.nvidia.com --trusted-host pypi.nvidia.com",
|
||||||
"tensorrt-libs --pre --extra-index-url=https://pypi.ngc.nvidia.com --trusted-host pypi.ngc.nvidia.com",
|
"tensorrt-libs --pre --extra-index-url=https://pypi.nvidia.com --trusted-host pypi.nvidia.com",
|
||||||
"tensorrt --pre --extra-index-url=https://pypi.ngc.nvidia.com --trusted-host pypi.ngc.nvidia.com",
|
"tensorrt --pre --extra-index-url=https://pypi.nvidia.com --trusted-host pypi.nvidia.com",
|
||||||
],
|
],
|
||||||
"uninstall": ["tensorrt"],
|
"uninstall": ["tensorrt"],
|
||||||
# TODO also uninstall tensorrt-libs and nvidia-cudnn, but do it upon restarting (avoid 'file in use' error)
|
# TODO also uninstall tensorrt-libs and nvidia-cudnn, but do it upon restarting (avoid 'file in use' error)
|
||||||
|
@ -73,6 +73,7 @@ class TaskData(BaseModel):
|
|||||||
use_hypernetwork_model: Union[str, List[str]] = None
|
use_hypernetwork_model: Union[str, List[str]] = None
|
||||||
use_lora_model: Union[str, List[str]] = None
|
use_lora_model: Union[str, List[str]] = None
|
||||||
use_controlnet_model: Union[str, List[str]] = None
|
use_controlnet_model: Union[str, List[str]] = None
|
||||||
|
use_embeddings_model: Union[str, List[str]] = None
|
||||||
filters: List[str] = []
|
filters: List[str] = []
|
||||||
filter_params: Dict[str, Dict[str, Any]] = {}
|
filter_params: Dict[str, Dict[str, Any]] = {}
|
||||||
control_filter_to_apply: Union[str, List[str]] = None
|
control_filter_to_apply: Union[str, List[str]] = None
|
||||||
@ -85,6 +86,7 @@ class TaskData(BaseModel):
|
|||||||
clip_skip: bool = False
|
clip_skip: bool = False
|
||||||
codeformer_upscale_faces: bool = False
|
codeformer_upscale_faces: bool = False
|
||||||
codeformer_fidelity: float = 0.5
|
codeformer_fidelity: float = 0.5
|
||||||
|
use_gallery: str = None
|
||||||
|
|
||||||
|
|
||||||
class MergeRequest(BaseModel):
|
class MergeRequest(BaseModel):
|
||||||
@ -200,6 +202,7 @@ def convert_legacy_render_req_to_new(old_req: dict):
|
|||||||
model_paths["hypernetwork"] = old_req.get("use_hypernetwork_model")
|
model_paths["hypernetwork"] = old_req.get("use_hypernetwork_model")
|
||||||
model_paths["lora"] = old_req.get("use_lora_model")
|
model_paths["lora"] = old_req.get("use_lora_model")
|
||||||
model_paths["controlnet"] = old_req.get("use_controlnet_model")
|
model_paths["controlnet"] = old_req.get("use_controlnet_model")
|
||||||
|
model_paths["embeddings"] = old_req.get("use_embeddings_model")
|
||||||
|
|
||||||
model_paths["gfpgan"] = old_req.get("use_face_correction", "")
|
model_paths["gfpgan"] = old_req.get("use_face_correction", "")
|
||||||
model_paths["gfpgan"] = model_paths["gfpgan"] if "gfpgan" in model_paths["gfpgan"].lower() else None
|
model_paths["gfpgan"] = model_paths["gfpgan"] if "gfpgan" in model_paths["gfpgan"].lower() else None
|
||||||
|
@ -160,28 +160,30 @@ def save_images_to_disk(
|
|||||||
from easydiffusion.easydb.mappings import GalleryImage
|
from easydiffusion.easydb.mappings import GalleryImage
|
||||||
from easydiffusion.easydb.database import SessionLocal
|
from easydiffusion.easydb.database import SessionLocal
|
||||||
|
|
||||||
session = SessionLocal()
|
if task_data.use_gallery != None:
|
||||||
session.add(GalleryImage(
|
session = SessionLocal()
|
||||||
path = path_i,
|
session.add(GalleryImage(
|
||||||
seed = metadata_entries[i]["seed"],
|
path = path_i,
|
||||||
use_stable_diffusion_model = metadata_entries[i]["use_stable_diffusion_model"],
|
seed = metadata_entries[i]["seed"],
|
||||||
clip_skip = metadata_entries[i]["clip_skip"],
|
use_stable_diffusion_model = metadata_entries[i]["use_stable_diffusion_model"],
|
||||||
use_vae_model = metadata_entries[i]["use_vae_model"],
|
clip_skip = metadata_entries[i]["clip_skip"],
|
||||||
sampler_name = metadata_entries[i]["sampler_name"],
|
use_vae_model = metadata_entries[i]["use_vae_model"],
|
||||||
width = metadata_entries[i]["width"],
|
sampler_name = metadata_entries[i]["sampler_name"],
|
||||||
height = metadata_entries[i]["height"],
|
width = metadata_entries[i]["width"],
|
||||||
num_inference_steps = metadata_entries[i]["num_inference_steps"],
|
height = metadata_entries[i]["height"],
|
||||||
guidance_scale = metadata_entries[i]["guidance_scale"],
|
num_inference_steps = metadata_entries[i]["num_inference_steps"],
|
||||||
lora = createLoraString(metadata_entries, i),
|
guidance_scale = metadata_entries[i]["guidance_scale"],
|
||||||
use_hypernetwork_model = metadata_entries[i]["use_hypernetwork_model"],
|
lora = createLoraString(metadata_entries, i),
|
||||||
tiling = metadata_entries[i]["tiling"],
|
use_hypernetwork_model = metadata_entries[i]["use_hypernetwork_model"],
|
||||||
use_face_correction = metadata_entries[i]["use_face_correction"],
|
tiling = metadata_entries[i]["tiling"],
|
||||||
use_upscale = metadata_entries[i]["use_upscale"],
|
use_face_correction = metadata_entries[i]["use_face_correction"],
|
||||||
prompt = metadata_entries[i]["prompt"],
|
use_upscale = metadata_entries[i]["use_upscale"],
|
||||||
negative_prompt = metadata_entries[i]["negative_prompt"]
|
prompt = metadata_entries[i]["prompt"],
|
||||||
))
|
negative_prompt = metadata_entries[i]["negative_prompt"],
|
||||||
session.commit()
|
workspace = task_data.use_gallery
|
||||||
session.close()
|
))
|
||||||
|
session.commit()
|
||||||
|
session.close()
|
||||||
|
|
||||||
if task_data.metadata_output_format:
|
if task_data.metadata_output_format:
|
||||||
for metadata_output_format in task_data.metadata_output_format.split(","):
|
for metadata_output_format in task_data.metadata_output_format.split(","):
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
<h1>
|
<h1>
|
||||||
<img id="logo_img" src="/media/images/icon-512x512.png" >
|
<img id="logo_img" src="/media/images/icon-512x512.png" >
|
||||||
Easy Diffusion
|
Easy Diffusion
|
||||||
<small><span id="version">v3.0.0</span> <span id="updateBranchLabel"></span></small>
|
<small><span id="version">v3.0.1</span> <span id="updateBranchLabel"></span></small>
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
<div id="server-status">
|
<div id="server-status">
|
||||||
@ -307,12 +307,22 @@
|
|||||||
<input id="custom-width" name="custom-width" type="number" min="128" value="512" onkeypress="preventNonNumericalInput(event)">
|
<input id="custom-width" name="custom-width" type="number" min="128" value="512" onkeypress="preventNonNumericalInput(event)">
|
||||||
×
|
×
|
||||||
<input id="custom-height" name="custom-height" type="number" min="128" value="512" onkeypress="preventNonNumericalInput(event)"><br>
|
<input id="custom-height" name="custom-height" type="number" min="128" value="512" onkeypress="preventNonNumericalInput(event)"><br>
|
||||||
|
<small>Resize:</small><br>
|
||||||
|
<input id="resize-slider" name="resize-slider" class="editor-slider" value="1" type="range" min="0.4" max="2" step="0.005" style="width:100%;"><br>
|
||||||
|
<div id="enlarge-buttons"><button data-factor="0.5" class="tertiaryButton smallButton">×0.5</button> <button data-factor="1.2" class="tertiaryButton smallButton">×1.2</button> <button data-factor="1.5" class="tertiaryButton smallButton">×1.5</button> <button data-factor="2" class="tertiaryButton smallButton">×2</button> <button data-factor="3" class="tertiaryButton smallButton">×3</button></div>
|
||||||
|
|
||||||
<small>Enlarge:</small><br>
|
<div class="two-column">
|
||||||
<div id="enlarge-buttons"><button id="enlarge15" class="tertiaryButton smallButton">×1.5</button> <button id="enlarge2" class="tertiaryButton smallButton">×2</button> <button id="enlarge3" class="tertiaryButton smallButton">×3</button></div>
|
<div class="left-column">
|
||||||
|
<small>Recently used:</small><br>
|
||||||
|
<div id="recent-resolution-list">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="right-column">
|
||||||
|
<small>Common sizes:</small><br>
|
||||||
|
<div id="common-resolution-list">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<small>Recently used:</small><br>
|
|
||||||
<div id="recent-resolution-list">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -34,6 +34,7 @@ code {
|
|||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
transform: translateY(4px);
|
transform: translateY(4px);
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
#prompt {
|
#prompt {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -1031,6 +1032,9 @@ input::file-selector-button {
|
|||||||
.input-toggle > input:checked + label {
|
.input-toggle > input:checked + label {
|
||||||
background: var(--accent-color);
|
background: var(--accent-color);
|
||||||
}
|
}
|
||||||
|
.input-toggle > input:disabled + label {
|
||||||
|
background: var(--background-color1);
|
||||||
|
}
|
||||||
.input-toggle > input:checked + label:before {
|
.input-toggle > input:checked + label:before {
|
||||||
right: calc(var(--input-border-size) + var(--input-switch-padding));
|
right: calc(var(--input-border-size) + var(--input-switch-padding));
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
@ -1418,6 +1422,10 @@ div.task-fs-initimage {
|
|||||||
display: none;
|
display: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
div.task-fs-initimage img {
|
||||||
|
max-height: 70vH;
|
||||||
|
max-width: 70vW;
|
||||||
|
}
|
||||||
div.task-initimg:hover div.task-fs-initimage {
|
div.task-initimg:hover div.task-fs-initimage {
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -1433,9 +1441,13 @@ div.top-right {
|
|||||||
right: 8px;
|
right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button.useForControlnetBtn {
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
#small_image_warning {
|
#small_image_warning {
|
||||||
font-size: smaller;
|
font-size: smaller;
|
||||||
color: var(--status-orange);
|
color: var(--status-orange);
|
||||||
}
|
}
|
||||||
|
|
||||||
button#save-system-settings-btn {
|
button#save-system-settings-btn {
|
||||||
@ -1460,6 +1472,9 @@ button#save-system-settings-btn {
|
|||||||
cursor: pointer;;
|
cursor: pointer;;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.validation-failed {
|
||||||
|
border: solid 2px red;
|
||||||
|
}
|
||||||
/* SCROLLBARS */
|
/* SCROLLBARS */
|
||||||
:root {
|
:root {
|
||||||
--scrollbar-width: 14px;
|
--scrollbar-width: 14px;
|
||||||
@ -1833,6 +1848,10 @@ div#recent-resolutions-popup small {
|
|||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div#common-resolution-list button {
|
||||||
|
background: var(--background-color1);
|
||||||
|
}
|
||||||
|
|
||||||
td#image-size-options small {
|
td#image-size-options small {
|
||||||
margin-right: 0px !important;
|
margin-right: 0px !important;
|
||||||
}
|
}
|
||||||
@ -1849,6 +1868,27 @@ div#enlarge-buttons {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.two-column { display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
gap: 0px 0.5em;
|
||||||
|
grid-auto-flow: row;
|
||||||
|
grid-template-areas:
|
||||||
|
"left-column right-column";
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-column {
|
||||||
|
justify-self: center;
|
||||||
|
align-self: center;
|
||||||
|
grid-area: left-column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-column {
|
||||||
|
justify-self: center;
|
||||||
|
align-self: center;
|
||||||
|
grid-area: right-column;
|
||||||
|
}
|
||||||
|
|
||||||
.clickable {
|
.clickable {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
@ -1890,15 +1930,6 @@ div#enlarge-buttons {
|
|||||||
|
|
||||||
/* Gallery CSS */
|
/* Gallery CSS */
|
||||||
|
|
||||||
/*
|
|
||||||
.gallery {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
flex-direction: column;
|
|
||||||
font-family: sans-serif;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
button:disabled {
|
button:disabled {
|
||||||
background-color: var(--secondary-button-background);
|
background-color: var(--secondary-button-background);
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ const SETTINGS_IDS_LIST = [
|
|||||||
"num_outputs_parallel",
|
"num_outputs_parallel",
|
||||||
"stable_diffusion_model",
|
"stable_diffusion_model",
|
||||||
"clip_skip",
|
"clip_skip",
|
||||||
|
"use_gallery",
|
||||||
"vae_model",
|
"vae_model",
|
||||||
"hypernetwork_model",
|
"hypernetwork_model",
|
||||||
"sampler_name",
|
"sampler_name",
|
||||||
|
@ -83,9 +83,9 @@ let customHeightField = document.querySelector("#custom-height")
|
|||||||
let recentResolutionsButton = document.querySelector("#recent-resolutions-button")
|
let recentResolutionsButton = document.querySelector("#recent-resolutions-button")
|
||||||
let recentResolutionsPopup = document.querySelector("#recent-resolutions-popup")
|
let recentResolutionsPopup = document.querySelector("#recent-resolutions-popup")
|
||||||
let recentResolutionList = document.querySelector("#recent-resolution-list")
|
let recentResolutionList = document.querySelector("#recent-resolution-list")
|
||||||
let enlarge15Button = document.querySelector("#enlarge15")
|
let commonResolutionList = document.querySelector("#common-resolution-list")
|
||||||
let enlarge2Button = document.querySelector("#enlarge2")
|
let resizeSlider = document.querySelector("#resize-slider")
|
||||||
let enlarge3Button = document.querySelector("#enlarge3")
|
let enlargeButtons = document.querySelector("#enlarge-buttons")
|
||||||
let swapWidthHeightButton = document.querySelector("#swap-width-height")
|
let swapWidthHeightButton = document.querySelector("#swap-width-height")
|
||||||
let smallImageWarning = document.querySelector("#small_image_warning")
|
let smallImageWarning = document.querySelector("#small_image_warning")
|
||||||
let initImageSelector = document.querySelector("#init_image")
|
let initImageSelector = document.querySelector("#init_image")
|
||||||
@ -152,7 +152,6 @@ let galleryPromptSearchField = document.querySelector("#gallery-prompt-search")
|
|||||||
let galleryModelSearchField = document.querySelector("#gallery-model-search")
|
let galleryModelSearchField = document.querySelector("#gallery-model-search")
|
||||||
let galleryImageContainer = document.querySelector("#imagecontainer")
|
let galleryImageContainer = document.querySelector("#imagecontainer")
|
||||||
|
|
||||||
|
|
||||||
let positiveEmbeddingText = document.querySelector("#positive-embedding-text")
|
let positiveEmbeddingText = document.querySelector("#positive-embedding-text")
|
||||||
let negativeEmbeddingText = document.querySelector("#negative-embedding-text")
|
let negativeEmbeddingText = document.querySelector("#negative-embedding-text")
|
||||||
let embeddingsCollapsiblesBtn = document.querySelector("#embeddings-action-collapsibles-btn")
|
let embeddingsCollapsiblesBtn = document.querySelector("#embeddings-action-collapsibles-btn")
|
||||||
@ -199,6 +198,7 @@ let undoButton = document.querySelector("#undo")
|
|||||||
let undoBuffer = []
|
let undoBuffer = []
|
||||||
const UNDO_LIMIT = 20
|
const UNDO_LIMIT = 20
|
||||||
const MAX_IMG_UNDO_ENTRIES = 5
|
const MAX_IMG_UNDO_ENTRIES = 5
|
||||||
|
var GALLERY_NAME="default"
|
||||||
|
|
||||||
let IMAGE_STEP_SIZE = 64
|
let IMAGE_STEP_SIZE = 64
|
||||||
|
|
||||||
@ -534,6 +534,7 @@ function showImages(reqBody, res, outputContainer, livePreview) {
|
|||||||
const imageRedoBuffer = []
|
const imageRedoBuffer = []
|
||||||
let buttons = [
|
let buttons = [
|
||||||
{ text: "Use as Input", on_click: onUseAsInputClick },
|
{ text: "Use as Input", on_click: onUseAsInputClick },
|
||||||
|
{ text: "Use for Controlnet", on_click: onUseForControlnetClick },
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
html: '<i class="fa-solid fa-download"></i> Download Image',
|
html: '<i class="fa-solid fa-download"></i> Download Image',
|
||||||
@ -645,6 +646,10 @@ function onUseAsInputClick(req, img) {
|
|||||||
maskSetting.checked = false
|
maskSetting.checked = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onUseForControlnetClick(req, img) {
|
||||||
|
controlImagePreview.src = img.src
|
||||||
|
}
|
||||||
|
|
||||||
function getDownloadFilename(img, suffix) {
|
function getDownloadFilename(img, suffix) {
|
||||||
const imageSeed = img.getAttribute("data-seed")
|
const imageSeed = img.getAttribute("data-seed")
|
||||||
const imagePrompt = img.getAttribute("data-prompt")
|
const imagePrompt = img.getAttribute("data-prompt")
|
||||||
@ -955,12 +960,25 @@ function makeImage() {
|
|||||||
}
|
}
|
||||||
if (!randomSeedField.checked && seedField.value == "") {
|
if (!randomSeedField.checked && seedField.value == "") {
|
||||||
alert('The "Seed" field must not be empty.')
|
alert('The "Seed" field must not be empty.')
|
||||||
|
seedField.classList.add("validation-failed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
seedField.classList.remove("validation-failed")
|
||||||
|
|
||||||
if (numInferenceStepsField.value == "") {
|
if (numInferenceStepsField.value == "") {
|
||||||
alert('The "Inference Steps" field must not be empty.')
|
alert('The "Inference Steps" field must not be empty.')
|
||||||
|
numInferenceStepsField.classList.add("validation-failed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
numInferenceStepsField.classList.remove("validation-failed")
|
||||||
|
|
||||||
|
if (controlnetModelField.value === "" && IMAGE_REGEX.test(controlImagePreview.src)) {
|
||||||
|
alert("Please choose a ControlNet model, to use the ControlNet image.")
|
||||||
|
document.getElementById("controlnet_model").classList.add("validation-failed")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
document.getElementById("controlnet_model").classList.remove("validation-failed")
|
||||||
|
|
||||||
if (numOutputsTotalField.value == "" || numOutputsTotalField.value == 0) {
|
if (numOutputsTotalField.value == "" || numOutputsTotalField.value == 0) {
|
||||||
numOutputsTotalField.value = 1
|
numOutputsTotalField.value = 1
|
||||||
}
|
}
|
||||||
@ -979,6 +997,7 @@ function makeImage() {
|
|||||||
reqBody: Object.assign({ prompt: prompt }, taskTemplate.reqBody),
|
reqBody: Object.assign({ prompt: prompt }, taskTemplate.reqBody),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
newTaskRequests.forEach(setEmbeddings)
|
||||||
newTaskRequests.forEach(createTask)
|
newTaskRequests.forEach(createTask)
|
||||||
|
|
||||||
updateInitialText()
|
updateInitialText()
|
||||||
@ -1172,15 +1191,18 @@ function onTaskCompleted(task, reqBody, instance, outputContainer, stepUpdate) {
|
|||||||
<b>Suggestions</b>:
|
<b>Suggestions</b>:
|
||||||
<br/>
|
<br/>
|
||||||
Try to use a different model or a different LORA.`
|
Try to use a different model or a different LORA.`
|
||||||
} else if (msg.includes("Tensor on device cuda:0 is not on the expected device meta")) {
|
} else if (msg.includes("'ModuleList' object has no attribute '1'")) {
|
||||||
msg += `<br/><br/>
|
msg += `<br/><br/>
|
||||||
<b>Reason</b>: Due to some software issues, embeddings currently don't work with the "Low" memory profile.
|
<b>Reason</b>: SDXL models need a yaml config file.
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
<b>Suggestions</b>:
|
<b>Suggestions</b>:
|
||||||
<br/>
|
<br/>
|
||||||
1. Set the memory profile to "Balanced"<br/>
|
<ol>
|
||||||
2. Remove the embeddings from the prompt and the negative prompt<br/>
|
<li>Download the <a href="https://gist.githubusercontent.com/JeLuF/5dc56e7a3a6988265c423f464d3cbdd3/raw/4ba4c39b1c7329877ad7a39c8c8a077ea4b53d11/dreamshaperXL10_alpha2Xl10.yaml" target="_blank">config file</a></li>
|
||||||
3. Check whether the plugins you're using change the memory profile automatically.`
|
<li>Save it in the same directory as the SDXL model file</li>
|
||||||
|
<li>Rename the config file so that it matches the filename of the model, with the extension of the model file replaced by <tt>yaml</tt>.
|
||||||
|
For example, if the model file is called <tt>FantasySDXL_v2.safetensors</tt>, the config file must be called <tt>FantasySDXL_v2.yaml</tt>.
|
||||||
|
</ol>`
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
msg = `Unexpected Read Error:<br/><pre>StepUpdate: ${JSON.stringify(stepUpdate, undefined, 4)}</pre>`
|
msg = `Unexpected Read Error:<br/><pre>StepUpdate: ${JSON.stringify(stepUpdate, undefined, 4)}</pre>`
|
||||||
@ -1334,6 +1356,27 @@ async function onTaskStart(task) {
|
|||||||
|
|
||||||
/* Hover effect for the init image in the task list */
|
/* Hover effect for the init image in the task list */
|
||||||
function createInitImageHover(taskEntry) {
|
function createInitImageHover(taskEntry) {
|
||||||
|
taskEntry.querySelectorAll(".task-initimg").forEach( thumb => {
|
||||||
|
let thumbimg = thumb.querySelector("img")
|
||||||
|
let img = createElement("img", {src: thumbimg.src})
|
||||||
|
thumb.querySelector(".task-fs-initimage").appendChild(img)
|
||||||
|
let div = createElement("div", undefined, ["top-right"])
|
||||||
|
div.innerHTML = `
|
||||||
|
<button class="useAsInputBtn">Use as Input</button>
|
||||||
|
<br>
|
||||||
|
<button class="useForControlnetBtn">Use for Controlnet</button>`
|
||||||
|
div.querySelector(".useAsInputBtn").addEventListener("click", e => {
|
||||||
|
e.preventDefault()
|
||||||
|
onUseAsInputClick(null, img)
|
||||||
|
})
|
||||||
|
div.querySelector(".useForControlnetBtn").addEventListener("click", e => {
|
||||||
|
e.preventDefault()
|
||||||
|
controlImagePreview.src = img.src
|
||||||
|
})
|
||||||
|
thumb.querySelector(".task-fs-initimage").appendChild(div)
|
||||||
|
})
|
||||||
|
return
|
||||||
|
|
||||||
var $tooltip = $(taskEntry.querySelector(".task-fs-initimage"))
|
var $tooltip = $(taskEntry.querySelector(".task-fs-initimage"))
|
||||||
var img = document.createElement("img")
|
var img = document.createElement("img")
|
||||||
img.src = taskEntry.querySelector("div.task-initimg > img").src
|
img.src = taskEntry.querySelector("div.task-initimg > img").src
|
||||||
@ -1398,6 +1441,11 @@ function createTask(task) {
|
|||||||
let w = ((task.reqBody.width * h) / task.reqBody.height) >> 0
|
let w = ((task.reqBody.width * h) / task.reqBody.height) >> 0
|
||||||
taskConfig += `<div class="task-initimg" style="float:left;"><img style="width:${w}px;height:${h}px;" src="${task.reqBody.init_image}"><div class="task-fs-initimage"></div></div>`
|
taskConfig += `<div class="task-initimg" style="float:left;"><img style="width:${w}px;height:${h}px;" src="${task.reqBody.init_image}"><div class="task-fs-initimage"></div></div>`
|
||||||
}
|
}
|
||||||
|
if (task.reqBody.control_image !== undefined) {
|
||||||
|
let h = 80
|
||||||
|
let w = ((task.reqBody.width * h) / task.reqBody.height) >> 0
|
||||||
|
taskConfig += `<div class="task-initimg" style="float:left;"><img style="width:${w}px;height:${h}px;" src="${task.reqBody.control_image}"><div class="task-fs-initimage"></div></div>`
|
||||||
|
}
|
||||||
|
|
||||||
taskConfig += `<div class="taskConfigData">${createTaskConfig(task)}</span></div></div>`
|
taskConfig += `<div class="taskConfigData">${createTaskConfig(task)}</span></div></div>`
|
||||||
|
|
||||||
@ -1448,7 +1496,7 @@ function createTask(task) {
|
|||||||
startY = e.target.closest(".imageTaskContainer").offsetTop
|
startY = e.target.closest(".imageTaskContainer").offsetTop
|
||||||
})
|
})
|
||||||
|
|
||||||
if (task.reqBody.init_image !== undefined) {
|
if (task.reqBody.init_image !== undefined || task.reqBody.control_image !== undefined) {
|
||||||
createInitImageHover(taskEntry)
|
createInitImageHover(taskEntry)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1542,6 +1590,7 @@ function getCurrentUserRequest() {
|
|||||||
output_quality: parseInt(outputQualityField.value),
|
output_quality: parseInt(outputQualityField.value),
|
||||||
output_lossless: outputLosslessField.checked,
|
output_lossless: outputLosslessField.checked,
|
||||||
metadata_output_format: metadataOutputFormatField.value,
|
metadata_output_format: metadataOutputFormatField.value,
|
||||||
|
use_gallery: useGalleryField.checked?GALLERY_NAME:null,
|
||||||
original_prompt: promptField.value,
|
original_prompt: promptField.value,
|
||||||
active_tags: activeTags.map((x) => x.name),
|
active_tags: activeTags.map((x) => x.name),
|
||||||
inactive_tags: activeTags.filter((tag) => tag.inactive === true).map((x) => x.name),
|
inactive_tags: activeTags.filter((tag) => tag.inactive === true).map((x) => x.name),
|
||||||
@ -1627,6 +1676,42 @@ function getCurrentUserRequest() {
|
|||||||
return newTask
|
return newTask
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setEmbeddings(task) {
|
||||||
|
let prompt = task.reqBody.prompt.toLowerCase()
|
||||||
|
let negativePrompt = task.reqBody.negative_prompt.toLowerCase()
|
||||||
|
let overallPrompt = (prompt + " " + negativePrompt).split(" ")
|
||||||
|
|
||||||
|
let embeddingsTree = modelsOptions["embeddings"]
|
||||||
|
let embeddings = []
|
||||||
|
function extract(entries, basePath = "") {
|
||||||
|
entries.forEach((e) => {
|
||||||
|
if (Array.isArray(e)) {
|
||||||
|
let path = basePath === "" ? basePath + e[0] : basePath + "/" + e[0]
|
||||||
|
extract(e[1], path)
|
||||||
|
} else {
|
||||||
|
let path = basePath === "" ? basePath + e : basePath + "/" + e
|
||||||
|
embeddings.push([e.toLowerCase().replace(" ", "_"), path])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
extract(embeddingsTree)
|
||||||
|
|
||||||
|
let embeddingPaths = []
|
||||||
|
|
||||||
|
embeddings.forEach((e) => {
|
||||||
|
let token = e[0]
|
||||||
|
let path = e[1]
|
||||||
|
|
||||||
|
if (overallPrompt.includes(token)) {
|
||||||
|
embeddingPaths.push(path)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (embeddingPaths.length > 0) {
|
||||||
|
task.reqBody.use_embeddings_model = embeddingPaths
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getModelInfo(models) {
|
function getModelInfo(models) {
|
||||||
let modelInfo = models.map((e) => [e[0].value, e[1].value])
|
let modelInfo = models.map((e) => [e[0].value, e[1].value])
|
||||||
modelInfo = modelInfo.filter((e) => e[0].trim() !== "")
|
modelInfo = modelInfo.filter((e) => e[0].trim() !== "")
|
||||||
@ -2008,6 +2093,7 @@ function onDimensionChange() {
|
|||||||
|
|
||||||
diskPathField.disabled = !saveToDiskField.checked
|
diskPathField.disabled = !saveToDiskField.checked
|
||||||
metadataOutputFormatField.disabled = !saveToDiskField.checked
|
metadataOutputFormatField.disabled = !saveToDiskField.checked
|
||||||
|
useGalleryField.disabled = !saveToDiskField.checked
|
||||||
|
|
||||||
gfpganModelField.disabled = !useFaceCorrectionField.checked
|
gfpganModelField.disabled = !useFaceCorrectionField.checked
|
||||||
useFaceCorrectionField.addEventListener("change", function(e) {
|
useFaceCorrectionField.addEventListener("change", function(e) {
|
||||||
@ -2663,7 +2749,7 @@ function updateEmbeddingsList(filter = "") {
|
|||||||
let button
|
let button
|
||||||
if (iconlist.length==0) {
|
if (iconlist.length==0) {
|
||||||
button = document.createElement("button")
|
button = document.createElement("button")
|
||||||
button.innerText="m"
|
button.innerText = m
|
||||||
} else {
|
} else {
|
||||||
let img = '/media/images/noimg.png'
|
let img = '/media/images/noimg.png'
|
||||||
if (token in embIcon) {
|
if (token in embIcon) {
|
||||||
@ -2976,38 +3062,27 @@ let recentResolutionsValues = []
|
|||||||
|
|
||||||
;(function() {
|
;(function() {
|
||||||
///// Init resolutions dropdown
|
///// Init resolutions dropdown
|
||||||
function makeResolutionButtons() {
|
|
||||||
recentResolutionList.innerHTML = ""
|
function makeResolutionButtons(listElement, resolutionList) {
|
||||||
recentResolutionsValues.forEach((el) => {
|
listElement.innerHTML = ""
|
||||||
let button = document.createElement("button")
|
resolutionList.forEach((el) => {
|
||||||
button.classList.add("tertiaryButton")
|
let button = createElement("button", { style: "width: 8em;" }, "tertiaryButton", `${el.w}×${el.h}`)
|
||||||
button.style.width = "8em"
|
|
||||||
button.innerHTML = `${el.w}×${el.h}`
|
|
||||||
button.addEventListener("click", () => {
|
button.addEventListener("click", () => {
|
||||||
customWidthField.value = el.w
|
customWidthField.value = el.w
|
||||||
customHeightField.value = el.h
|
customHeightField.value = el.h
|
||||||
hidePopup()
|
hidePopup()
|
||||||
})
|
})
|
||||||
recentResolutionList.appendChild(button)
|
listElement.appendChild(button)
|
||||||
recentResolutionList.appendChild(document.createElement("br"))
|
listElement.appendChild(document.createElement("br"))
|
||||||
})
|
})
|
||||||
localStorage.recentResolutionsValues = JSON.stringify(recentResolutionsValues)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enlarge15Button.addEventListener("click", () => {
|
enlargeButtons.querySelectorAll("button").forEach((button) =>
|
||||||
enlargeImageSize(1.5)
|
button.addEventListener("click", (e) => {
|
||||||
hidePopup()
|
enlargeImageSize(parseFloat(button.dataset["factor"]))
|
||||||
})
|
hidePopup()
|
||||||
|
})
|
||||||
enlarge2Button.addEventListener("click", () => {
|
)
|
||||||
enlargeImageSize(2)
|
|
||||||
hidePopup()
|
|
||||||
})
|
|
||||||
|
|
||||||
enlarge3Button.addEventListener("click", () => {
|
|
||||||
enlargeImageSize(3)
|
|
||||||
hidePopup()
|
|
||||||
})
|
|
||||||
|
|
||||||
customWidthField.addEventListener("change", () => {
|
customWidthField.addEventListener("change", () => {
|
||||||
let w = customWidthField.value
|
let w = customWidthField.value
|
||||||
@ -3034,25 +3109,29 @@ let recentResolutionsValues = []
|
|||||||
recentResolutionsValues = recentResolutionsValues.slice(0, 8)
|
recentResolutionsValues = recentResolutionsValues.slice(0, 8)
|
||||||
|
|
||||||
localStorage.recentResolutionsValues = JSON.stringify(recentResolutionsValues)
|
localStorage.recentResolutionsValues = JSON.stringify(recentResolutionsValues)
|
||||||
makeResolutionButtons()
|
makeResolutionButtons(recentResolutionList, recentResolutionsValues)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const defaultResolutionsValues = [
|
||||||
|
{ w: 512, h: 512 },
|
||||||
|
{ w: 448, h: 640 },
|
||||||
|
{ w: 512, h: 768 },
|
||||||
|
{ w: 768, h: 512 },
|
||||||
|
{ w: 1024, h: 768 },
|
||||||
|
{ w: 768, h: 1024 },
|
||||||
|
{ w: 1024, h: 1024 },
|
||||||
|
{ w: 1920, h: 1080 },
|
||||||
|
]
|
||||||
let _jsonstring = localStorage.recentResolutionsValues
|
let _jsonstring = localStorage.recentResolutionsValues
|
||||||
if (_jsonstring == undefined) {
|
if (_jsonstring == undefined) {
|
||||||
recentResolutionsValues = [
|
recentResolutionsValues = defaultResolutionsValues
|
||||||
{ w: 512, h: 512 },
|
|
||||||
{ w: 640, h: 448 },
|
|
||||||
{ w: 448, h: 640 },
|
|
||||||
{ w: 512, h: 768 },
|
|
||||||
{ w: 768, h: 512 },
|
|
||||||
{ w: 1024, h: 768 },
|
|
||||||
{ w: 768, h: 1024 },
|
|
||||||
]
|
|
||||||
localStorage.recentResolutionsValues = JSON.stringify(recentResolutionsValues)
|
localStorage.recentResolutionsValues = JSON.stringify(recentResolutionsValues)
|
||||||
} else {
|
} else {
|
||||||
recentResolutionsValues = JSON.parse(localStorage.recentResolutionsValues)
|
recentResolutionsValues = JSON.parse(localStorage.recentResolutionsValues)
|
||||||
}
|
}
|
||||||
makeResolutionButtons()
|
|
||||||
|
makeResolutionButtons(recentResolutionList, recentResolutionsValues)
|
||||||
|
makeResolutionButtons(commonResolutionList, defaultResolutionsValues)
|
||||||
|
|
||||||
recentResolutionsValues.forEach((val) => {
|
recentResolutionsValues.forEach((val) => {
|
||||||
addImageSizeOption(val.w)
|
addImageSizeOption(val.w)
|
||||||
@ -3069,6 +3148,9 @@ let recentResolutionsValues = []
|
|||||||
customWidthField.value = widthField.value
|
customWidthField.value = widthField.value
|
||||||
customHeightField.value = heightField.value
|
customHeightField.value = heightField.value
|
||||||
recentResolutionsPopup.classList.remove("displayNone")
|
recentResolutionsPopup.classList.remove("displayNone")
|
||||||
|
resizeSlider.value = 1
|
||||||
|
resizeSlider.dataset["w"] = widthField.value
|
||||||
|
resizeSlider.dataset["h"] = heightField.value
|
||||||
document.addEventListener("click", processClick)
|
document.addEventListener("click", processClick)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3087,6 +3169,20 @@ let recentResolutionsValues = []
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
resizeSlider.addEventListener("input", (e) => {
|
||||||
|
let w = parseInt(resizeSlider.dataset["w"])
|
||||||
|
let h = parseInt(resizeSlider.dataset["h"])
|
||||||
|
let factor = parseFloat(resizeSlider.value)
|
||||||
|
let step = customWidthField.step
|
||||||
|
|
||||||
|
customWidthField.value = roundToMultiple(w * factor * factor, step)
|
||||||
|
customHeightField.value = roundToMultiple(h * factor * factor, step)
|
||||||
|
})
|
||||||
|
|
||||||
|
resizeSlider.addEventListener("change", (e) => {
|
||||||
|
hidePopup()
|
||||||
|
})
|
||||||
|
|
||||||
swapWidthHeightButton.addEventListener("click", (event) => {
|
swapWidthHeightButton.addEventListener("click", (event) => {
|
||||||
let temp = widthField.value
|
let temp = widthField.value
|
||||||
widthField.value = heightField.value
|
widthField.value = heightField.value
|
||||||
@ -3273,7 +3369,12 @@ function layoutGallery() {
|
|||||||
|
|
||||||
galleryModelSearchField.addEventListener("keyup", debounce(e => refreshGallery(true), 500))
|
galleryModelSearchField.addEventListener("keyup", debounce(e => refreshGallery(true), 500))
|
||||||
galleryPromptSearchField.addEventListener("keyup", debounce(e => refreshGallery(true), 500))
|
galleryPromptSearchField.addEventListener("keyup", debounce(e => refreshGallery(true), 500))
|
||||||
|
galleryPageField.addEventListener("keyup", e => {
|
||||||
|
if (e.code === "Enter") {
|
||||||
|
e.preventDefault()
|
||||||
|
refreshGallery(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
function refreshGallery(newsearch = false) {
|
function refreshGallery(newsearch = false) {
|
||||||
if (newsearch) {
|
if (newsearch) {
|
||||||
@ -3281,6 +3382,7 @@ function refreshGallery(newsearch = false) {
|
|||||||
}
|
}
|
||||||
galleryImageContainer.innerHTML = ""
|
galleryImageContainer.innerHTML = ""
|
||||||
let params = new URLSearchParams({
|
let params = new URLSearchParams({
|
||||||
|
workspace: GALLERY_NAME,
|
||||||
prompt: galleryPromptSearchField.value,
|
prompt: galleryPromptSearchField.value,
|
||||||
model: galleryModelSearchField.value,
|
model: galleryModelSearchField.value,
|
||||||
page: galleryPageField.value
|
page: galleryPageField.value
|
||||||
|
@ -97,6 +97,13 @@ var PARAMETERS = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "use_gallery",
|
||||||
|
type: ParameterType.checkbox,
|
||||||
|
label: "Save images to the gallery",
|
||||||
|
note: "Stores metadata of all images into a database so that they show up on the gallery tab.",
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "block_nsfw",
|
id: "block_nsfw",
|
||||||
type: ParameterType.checkbox,
|
type: ParameterType.checkbox,
|
||||||
@ -421,6 +428,7 @@ let uiOpenBrowserOnStartField = document.querySelector("#ui_open_browser_on_star
|
|||||||
let confirmDangerousActionsField = document.querySelector("#confirm_dangerous_actions")
|
let confirmDangerousActionsField = document.querySelector("#confirm_dangerous_actions")
|
||||||
let testDiffusers = document.querySelector("#test_diffusers")
|
let testDiffusers = document.querySelector("#test_diffusers")
|
||||||
let profileNameField = document.querySelector("#profileName")
|
let profileNameField = document.querySelector("#profileName")
|
||||||
|
let useGalleryField = document.querySelector("#use_gallery")
|
||||||
|
|
||||||
let saveSettingsBtn = document.querySelector("#save-system-settings-btn")
|
let saveSettingsBtn = document.querySelector("#save-system-settings-btn")
|
||||||
|
|
||||||
@ -560,6 +568,7 @@ function applySettingsFromConfig(config) {
|
|||||||
saveToDiskField.addEventListener("change", function(e) {
|
saveToDiskField.addEventListener("change", function(e) {
|
||||||
diskPathField.disabled = !this.checked
|
diskPathField.disabled = !this.checked
|
||||||
metadataOutputFormatField.disabled = !this.checked
|
metadataOutputFormatField.disabled = !this.checked
|
||||||
|
useGalleryField.disabled = !this.checked
|
||||||
})
|
})
|
||||||
|
|
||||||
function getCurrentRenderDeviceSelection() {
|
function getCurrentRenderDeviceSelection() {
|
||||||
|
@ -191,19 +191,32 @@
|
|||||||
|
|
||||||
function createDropAreas(container) {
|
function createDropAreas(container) {
|
||||||
// Create two drop areas
|
// Create two drop areas
|
||||||
const dropAreaI2I = document.createElement("div")
|
const dropAreaI2I = createElement("div", {id: "drop-area-I2I"}, ["drop-area"], "Use as Image2Image source")
|
||||||
dropAreaI2I.setAttribute("id", "drop-area-I2I")
|
|
||||||
dropAreaI2I.setAttribute("class", "drop-area")
|
|
||||||
dropAreaI2I.innerHTML = "Use as Image2Image source"
|
|
||||||
container.appendChild(dropAreaI2I)
|
container.appendChild(dropAreaI2I)
|
||||||
|
|
||||||
const dropAreaMD = document.createElement("div")
|
const dropAreaMD = createElement("div", {id: "drop-area-MD"}, ["drop-area"], "Extract embedded metadata")
|
||||||
dropAreaMD.setAttribute("id", "drop-area-MD")
|
|
||||||
dropAreaMD.setAttribute("class", "drop-area")
|
|
||||||
dropAreaMD.innerHTML = "Extract embedded metadata"
|
|
||||||
container.appendChild(dropAreaMD)
|
container.appendChild(dropAreaMD)
|
||||||
|
|
||||||
|
const dropAreaCN = createElement("div", {id: "drop-area-CN"}, ["drop-area"], "Use as Controlnet image")
|
||||||
|
container.appendChild(dropAreaCN)
|
||||||
|
|
||||||
// Add event listeners to drop areas
|
// Add event listeners to drop areas
|
||||||
|
dropAreaCN.addEventListener("dragenter", function(event) {
|
||||||
|
event.preventDefault()
|
||||||
|
dropAreaCN.style.backgroundColor = 'darkGreen'
|
||||||
|
})
|
||||||
|
dropAreaCN.addEventListener("dragleave", function(event) {
|
||||||
|
event.preventDefault()
|
||||||
|
dropAreaCN.style.backgroundColor = ''
|
||||||
|
})
|
||||||
|
dropAreaCN.addEventListener("drop", function(event) {
|
||||||
|
event.stopPropagation()
|
||||||
|
event.preventDefault()
|
||||||
|
hideDropAreas()
|
||||||
|
|
||||||
|
getImageFromDropEvent(event, e => controlImagePreview.src=e)
|
||||||
|
})
|
||||||
|
|
||||||
dropAreaI2I.addEventListener("dragenter", function(event) {
|
dropAreaI2I.addEventListener("dragenter", function(event) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
dropAreaI2I.style.backgroundColor = 'darkGreen'
|
dropAreaI2I.style.backgroundColor = 'darkGreen'
|
||||||
@ -213,15 +226,11 @@
|
|||||||
dropAreaI2I.style.backgroundColor = ''
|
dropAreaI2I.style.backgroundColor = ''
|
||||||
})
|
})
|
||||||
|
|
||||||
dropAreaI2I.addEventListener("drop", function(event) {
|
function getImageFromDropEvent(event, callback) {
|
||||||
event.stopPropagation();
|
|
||||||
event.preventDefault();
|
|
||||||
hideDropAreas()
|
|
||||||
|
|
||||||
// Find the first image file, uri, or moz-url in the items list
|
// Find the first image file, uri, or moz-url in the items list
|
||||||
let imageItem = null;
|
let imageItem = null
|
||||||
for (let i = 0; i < event.dataTransfer.items.length; i++) {
|
for (let i = 0; i < event.dataTransfer.items.length; i++) {
|
||||||
let item = event.dataTransfer.items[i];
|
let item = event.dataTransfer.items[i]
|
||||||
if (item.kind === 'file' && item.type.startsWith('image/')) {
|
if (item.kind === 'file' && item.type.startsWith('image/')) {
|
||||||
imageItem = item;
|
imageItem = item;
|
||||||
break;
|
break;
|
||||||
@ -258,18 +267,22 @@
|
|||||||
// Create a FileReader object to read the dropped file as a data URL
|
// Create a FileReader object to read the dropped file as a data URL
|
||||||
let reader = new FileReader();
|
let reader = new FileReader();
|
||||||
reader.onload = function(e) {
|
reader.onload = function(e) {
|
||||||
// Set the src attribute of the img element to the data URL
|
callback(e.target.result)
|
||||||
imageObj.src = e.target.result;
|
|
||||||
};
|
};
|
||||||
reader.readAsDataURL(file);
|
reader.readAsDataURL(file);
|
||||||
} else {
|
} else {
|
||||||
// If the item is a URL, retrieve it and use it to load the image
|
// If the item is a URL, retrieve it and use it to load the image
|
||||||
imageItem.getAsString(function(url) {
|
imageItem.getAsString(callback)
|
||||||
// Set the src attribute of the img element to the URL
|
|
||||||
imageObj.src = url;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dropAreaI2I.addEventListener("drop", function(event) {
|
||||||
|
event.stopPropagation()
|
||||||
|
event.preventDefault()
|
||||||
|
hideDropAreas()
|
||||||
|
|
||||||
|
getImageFromDropEvent(event, e => imageObj.src=e)
|
||||||
})
|
})
|
||||||
|
|
||||||
dropAreaMD.addEventListener("dragenter", function(event) {
|
dropAreaMD.addEventListener("dragenter", function(event) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user