+
+* Bug fix: Fixed prompt info and model selection after CivitAI API update.
+* Bug fix: Fixed "/" missing from default path/sub-folder
+* Feature: Local images now work in HTML files as preview. (credit: [mx](https://github.com/mx))
+
+---
v3.4.0
* Feature: (BETA) Download queue! rearrange download order and remove models from queue
diff --git a/javascript/civitai-html.js b/javascript/civitai-html.js
index c9fc2ce..7096cdc 100644
--- a/javascript/civitai-html.js
+++ b/javascript/civitai-html.js
@@ -620,14 +620,14 @@ function metaToTxt2Img(type, element) {
let is_positive = false
let is_negative = false
switch(type) {
- case 'prompt':
+ case 'Prompt':
is_positive = true
break;
- case 'negativePrompt':
+ case 'Negative prompt':
inf = 'Negative prompt: ' + inf;
is_negative = true
break;
- case 'seed':
+ case 'Seed':
inf = 'Seed: ' + inf;
inf = inf + inf + inf;
break;
@@ -639,19 +639,19 @@ function metaToTxt2Img(type, element) {
inf = 'Model: ' + inf;
inf = inf + inf + inf;
break;
- case 'clipSkip':
+ case 'Clip skip':
inf = 'Clip skip: ' + inf;
inf = inf + inf + inf;
break;
- case 'sampler':
+ case 'Sampler':
inf = 'Sampler: ' + inf;
inf = inf + inf + inf;
break;
- case 'steps':
+ case 'Steps':
inf = 'Steps: ' + inf;
inf = inf + inf + inf;
break;
- case 'cfgScale':
+ case 'CFG scale':
inf = 'CFG scale: ' + inf;
inf = inf + inf + inf;
break;
@@ -1027,7 +1027,6 @@ function onPageLoad() {
}
observer.observe(civitaiDiv);
- queueObserver.observe(queue_list, queueObserverOptions);
adjustFilterBoxAndButtons();
setupClickOutsideListener();
createLink(infoElement);
diff --git a/scripts/civitai_api.py b/scripts/civitai_api.py
index f8e86e2..deff796 100644
--- a/scripts/civitai_api.py
+++ b/scripts/civitai_api.py
@@ -8,10 +8,12 @@ import os
import re
import datetime
import platform
+import time
from PIL import Image
from io import BytesIO
from collections import defaultdict
from modules.images import read_info_from_image
+from modules.infotext_utils import parse_generation_parameters
from modules.shared import cmd_opts, opts
from modules.paths import models_path, extensions_dir, data_path
from html import escape
@@ -623,17 +625,44 @@ def cleaned_name(file_name):
return f"{clean_name}{extension}"
def fetch_and_process_image(image_url):
- use_local = getattr(opts, "local_path_in_html", False)
- if use_local:
- image = Image.open(image_url)
- geninfo, _ = read_info_from_image(image)
- return geninfo
-
+ try:
+ parsed_url = urllib.parse.urlparse(image_url)
+ if parsed_url.scheme and parsed_url.netloc:
+ response = requests.get(image_url)
+ if response.status_code == 200:
+ image = Image.open(BytesIO(response.content))
+ geninfo, _ = read_info_from_image(image)
+ return geninfo
+ else:
+ image = Image.open(image_url)
+ geninfo, _ = read_info_from_image(image)
+ return geninfo
+ except:
+ return None
+
+def image_url_to_promptInfo(image_url):
response = requests.get(image_url)
if response.status_code == 200:
image = Image.open(BytesIO(response.content))
- geninfo, _ = read_info_from_image(image)
- return geninfo
+
+ prompt, _ = read_info_from_image(image)
+ prompt_dict = parse_generation_parameters(prompt)
+
+ invalid_values = [None, 0, "", "Use same sampler", "Use same checkpoint"]
+ keys_to_remove = [key for key, value in prompt_dict.items() if key != "Clip skip" and value in invalid_values]
+ for key in keys_to_remove:
+ prompt_dict.pop(key, None)
+
+ if "Size-1" in prompt_dict and "Size-2" in prompt_dict:
+ prompt_dict["Size"] = f'{prompt_dict["Size-1"]}x{prompt_dict["Size-2"]}'
+ prompt_dict.pop("Size-1", None)
+ prompt_dict.pop("Size-2", None)
+ if "Hires resize-1" in prompt_dict and "Hires resize-2" in prompt_dict:
+ prompt_dict["Hires resize"] = f'{prompt_dict["Hires resize-1"]}x{prompt_dict["Hires resize-2"]}'
+ prompt_dict.pop("Hires resize-1", None)
+ prompt_dict.pop("Hires resize-2", None)
+
+ return prompt, prompt_dict
return None
def extract_model_info(input_string):
@@ -762,17 +791,21 @@ def update_model_info(model_string=None, model_version=None, only_html=False, in
model_main_url = f"https://civitai.com/models/{item['id']}"
img_html = '
'
for index, pic in enumerate(selected_version['images']):
- meta_button = False
- meta = pic['metadata']
- if meta and meta.get('prompt'):
- meta_button = True
- BtnImage = True
# Change width value in URL to original image width
image_url = re.sub(r'/width=\d+', f'/width={pic["width"]}', pic["url"])
if pic['type'] == "video":
image_url = image_url.replace("width=", "transcode=true,width=")
+ prompt_dict = []
+ else:
+ prompt, prompt_dict = image_url_to_promptInfo(image_url)
+
nsfw = 'class="model-block"'
+ meta_button = False
+ if prompt_dict and prompt_dict.get('Prompt'):
+ meta_button = True
+ BtnImage = True
+
if pic['nsfw'] not in ["None", "Soft"]:
nsfw = 'class="civnsfw model-block"'
@@ -804,21 +837,20 @@ def update_model_info(model_string=None, model_version=None, only_html=False, in
else:
img_html += '
'
- if meta:
+ if prompt_dict:
img_html += '
'
# Define the preferred order of keys and convert them to lowercase
- preferred_order = ["prompt", "negativePrompt", "seed", "Size", "Model", "clipSkip", "sampler", "steps", "cfgScale"]
- preferred_order_lower = [key.lower() for key in preferred_order]
+ preferred_order = ["Prompt", "Negative prompt", "Seed", "Size", "Model", "Clip skip", "Sampler", "Steps", "CFG scale"]
# Loop through the keys in the preferred order and add them to the HTML
for key in preferred_order:
- if key in meta:
- value = meta[key]
+ if key in prompt_dict:
+ value = prompt_dict[key]
if meta_btn:
img_html += f'
{escape(str(key).capitalize())}
{escape(str(value))}
'
else:
img_html += f'
{escape(str(key).capitalize())}
{escape(str(value))}
'
# Check if there are remaining keys in meta
- remaining_keys = [key for key in meta if key.lower() not in preferred_order_lower]
+ remaining_keys = [key for key in prompt_dict if key not in preferred_order]
# Add the rest
if remaining_keys:
@@ -830,7 +862,7 @@ def update_model_info(model_string=None, model_version=None, only_html=False, in
"""
for key in remaining_keys:
- value = meta[key]
+ value = prompt_dict[key]
img_html += f'
{escape(str(key).capitalize())}
{escape(str(value))}
'
img_html = img_html + '
'
@@ -1002,7 +1034,7 @@ def update_model_info(model_string=None, model_version=None, only_html=False, in
if any(key in default_sub for key in variable_mapping.keys()):
path_components = [variable_mapping.get(component.strip(os.sep), component.strip(os.sep)) for component in default_sub.split(os.sep)]
- default_sub = os.path.join(*path_components)
+ default_sub = os.path.join(os.sep, *path_components)
if folder_location == "None":
folder_location = model_folder
diff --git a/scripts/civitai_file_manage.py b/scripts/civitai_file_manage.py
index 72dadba..e5524fe 100644
--- a/scripts/civitai_file_manage.py
+++ b/scripts/civitai_file_manage.py
@@ -1,4 +1,3 @@
-import base64
import json
import gradio as gr
import urllib.request
@@ -11,11 +10,10 @@ import time
import errno
import requests
import hashlib
+import base64
+from PIL import Image
from pathlib import Path
from urllib.parse import urlparse
-
-from PIL import Image
-from sympy import preview
from modules.shared import cmd_opts, opts
from scripts.civitai_global import print
import scripts.civitai_global as gl
@@ -375,7 +373,6 @@ def model_from_sent(model_name, content_type, tile_count, path_input):
not_found = div + "Model ID not found. Maybe the model doesn\'t exist on CivitAI?"
path_not_found = div + "Model ID not found. Could not locate the model path."
offline = div + "CivitAI failed to respond. The servers are likely offline."
-
if path_input == "Not Found":
model_name = re.sub(r'\.\d{3}$', '', model_name)
diff --git a/scripts/civitai_gui.py b/scripts/civitai_gui.py
index b55dfee..39376ec 100644
--- a/scripts/civitai_gui.py
+++ b/scripts/civitai_gui.py
@@ -1176,7 +1176,7 @@ def on_ui_settings():
"Use local images in the HTML",
section=browser,
**({'category_id': cat_id} if ver_bool else {})
- )
+ ).info("Only works if all images of the corresponding model are downloaded")
)
shared.opts.add_option(
@@ -1260,4 +1260,4 @@ def on_ui_settings():
shared.opts.add_option(f"{setting_name}_subfolder", shared.OptionInfo("None", folder_name, gr.Dropdown, make_lambda(folder, desc), section=download, **({'category_id': cat_id} if ver_bool else {})))
script_callbacks.on_ui_tabs(on_ui_tabs)
-script_callbacks.on_ui_settings(on_ui_settings)
+script_callbacks.on_ui_settings(on_ui_settings)
\ No newline at end of file
diff --git a/style.css b/style.css
index 86b5fba..3c7667b 100644
--- a/style.css
+++ b/style.css
@@ -688,7 +688,7 @@
}
#civitai_preview_html .accordionCheckbox:checked ~ .tab-content {
- max-height: 200vh;
+ max-height: unset;
padding: 1em;
}
/*-----------------------------------------*/