Update to v3.3.1

pull/196/head v3.3.1
BlafKing 2024-02-09 16:37:38 +01:00
parent 177ce5d155
commit e4ef29afc1
No known key found for this signature in database
GPG Key ID: BFD6B0BCA6280F8B
8 changed files with 306 additions and 142 deletions

View File

@ -100,6 +100,20 @@ https://github.com/BlafKing/sd-civitai-browser-plus/assets/9644716/44c5c7a0-4854
# Changelog 📋
<h3>v3.3.1</h3>
* Feature: Ability to send individual parts of image generation data to txt2img.
* Feature: Added compatibility for [stable-diffusion-webui-forge](https://github.com/lllyasviel/stable-diffusion-webui-forge) fork.
* New setting: Use local images in the HTML
- Does not work in combination with the "Use local HTML file for model info" option!
* New setting: Store the HTML and api_info in the custom images location
* Bug fix: New HTML model info now scales with width so it should always fit.
* Bug fix: Various bug fixes to the "Update model info & tags" function.
* Bug fix: Auto save all images now uses correctly uses custom image path if set.
* Bug fix: "Save model info" button should no longer return errors.
* Bug fix: Old download method (non Aria2) should now work again.
---
<h3>v3.3.0</h3>
* Feature: New txt2img and img2img model info overlay on CivitAI button press.

View File

@ -465,15 +465,14 @@ function createCardButtons(event) {
}, 100);
}
}
document.addEventListener('click', createCardButtons);
// Sends the selected model list to a python function
function modelInfoPopUp(modelName, content_type) {
select_model(modelName, null, true, content_type);
// Create the overlay
var overlay = document.createElement('div');
overlay.classList.add('civitaiOverlayGlobal');
overlay.classList.add('civitai-overlay');
overlay.style.position = 'fixed';
overlay.style.top = '0';
overlay.style.left = '0';
@ -483,38 +482,13 @@ function modelInfoPopUp(modelName, content_type) {
overlay.style.zIndex = '1001';
overlay.style.overflowY = 'auto';
// Create the pop-up window
var popup = document.createElement('div');
popup.classList.add('civitaiOverlay');
popup.style.display = 'flex';
popup.style.justifyContent = 'center';
popup.style.position = 'absolute';
popup.style.top = '50%';
popup.style.left = '50%';
popup.style.width = '56em';
popup.style.transform = 'translate(-50%, -50%)';
popup.style.background = 'var(--body-background-fill)';
popup.style.padding = '2em';
popup.style.borderRadius = 'var(--block-radius)';
popup.style.borderStyle = 'solid';
popup.style.borderWidth = 'var(--block-border-width)';
popup.style.borderColor = 'var(--block-border-color)';
popup.style.zIndex = '1001';
// Add content to the popup
var popupContent = document.createElement('div'); // Change from <p> to <div>
popupContent.classList.add('civitaiLoadingText');
popupContent.textContent = 'Loading model info, please wait!';
popupContent.style.fontSize = '24px';
popupContent.style.color = 'white';
popupContent.style.fontFamily = 'var(--font)';
popup.appendChild(popupContent);
// Create the close button
var closeButton = document.createElement('div');
closeButton.classList.add('civitai-overlay-close');
closeButton.textContent = '×';
closeButton.style.zIndex = '1011';
closeButton.style.position = 'fixed';
closeButton.style.right = '0.25em';
closeButton.style.right = '22px';
closeButton.style.top = '0';
closeButton.style.cursor = 'pointer';
closeButton.style.color = 'white';
@ -522,29 +496,63 @@ function modelInfoPopUp(modelName, content_type) {
closeButton.addEventListener('click', hidePopup);
document.addEventListener('keydown', handleKeyPress);
// Append the close button to the overlay
overlay.appendChild(closeButton);
// Create the pop-up window
var inner = document.createElement('div');
inner.classList.add('civitai-overlay-inner');
inner.style.position = 'absolute';
inner.style.top = '50%';
inner.style.left = '50%';
inner.style.width = 'auto';
inner.style.transform = 'translate(-50%, -50%)';
inner.style.background = 'var(--body-background-fill)';
inner.style.padding = '2em';
inner.style.borderRadius = 'var(--block-radius)';
inner.style.borderStyle = 'solid';
inner.style.borderWidth = 'var(--block-border-width)';
inner.style.borderColor = 'var(--block-border-color)';
inner.style.zIndex = '1001';
// Append the popup to the overlay
overlay.appendChild(popup);
// Placeholder model content until model is loaded by other function
var modelInfo = document.createElement('div');
modelInfo.classList.add('civitai-overlay-text');
modelInfo.textContent = 'Loading model info, please wait!';
modelInfo.style.fontSize = '24px';
modelInfo.style.color = 'white';
modelInfo.style.fontFamily = 'var(--font)';
// Append the overlay to the body
document.body.style.overflow = 'hidden'; // Prevent scrolling on the main page
document.body.style.overflow = 'hidden';
document.body.appendChild(overlay);
overlay.appendChild(closeButton);
overlay.appendChild(inner);
inner.appendChild(modelInfo);
overlay.addEventListener('click', function (event) {
if (event.target === overlay) {
hidePopup();
}
});
setDynamicWidth(inner);
// Update width on window resize
window.addEventListener('resize', function() {
setDynamicWidth(inner);
});
}
function setDynamicWidth(inner) {
var windowWidth = window.innerWidth;
var dynamicWidth = Math.min(Math.max(windowWidth - 150, 350), 900);
inner.style.width = dynamicWidth + 'px';
}
// Function to hide the popup
function hidePopup() {
var overlay = document.querySelector('.civitaiOverlayGlobal');
var overlay = document.querySelector('.civitai-overlay');
if (overlay) {
document.body.removeChild(overlay);
document.body.style.overflow = 'auto';
window.removeEventListener('resize', setDynamicWidth);
}
}
@ -555,6 +563,102 @@ function handleKeyPress(event) {
}
}
function inputHTMLPreviewContent(html_input) {
var inner = document.querySelector('.civitai-overlay-inner')
let startIndex = html_input.indexOf("'value': '");
if (startIndex !== -1) {
startIndex += "'value': '".length;
const endIndex = html_input.indexOf("', 'type': None,", startIndex);
if (endIndex !== -1) {
let extractedText = html_input.substring(startIndex, endIndex);
var modelIdNotFound = extractedText.includes(">Model ID not found.<br>The");
extractedText = extractedText.replace(/\\n\s*</g, '<');
extractedText = extractedText.replace(/\\n/g, ' ');
extractedText = extractedText.replace(/\\t/g, '');
extractedText = extractedText.replace(/\\'/g, "'");
var overlayText = document.querySelector('.civitai-overlay-text');
var modelInfo = document.createElement('div');
overlayText.parentNode.removeChild(overlayText);
if (!modelIdNotFound) {
inner.style.top = 0;
inner.style.transform = 'translate(-50%, 0)';
}
modelInfo.innerHTML = extractedText;
inner.appendChild(modelInfo);
}
}
}
function metaToTxt2Img(type, element) {
const genButton = gradioApp().querySelector('#txt2img_extra_tabs > div > button')
let input = element.querySelector('dd').textContent;
let inf;
if (input.endsWith(',')) {
inf = input + ' ';
} else {
inf = input + ', ';
}
let is_positive = false
let is_negative = false
switch(type) {
case 'prompt':
is_positive = true
break;
case 'negativePrompt':
inf = 'Negative prompt: ' + inf;
is_negative = true
break;
case 'seed':
inf = 'Seed: ' + inf;
inf = inf + inf + inf;
break;
case 'Size':
inf = 'Size: ' + inf;
inf = inf + inf + inf;
break;
case 'Model':
inf = 'Model: ' + inf;
inf = inf + inf + inf;
break;
case 'clipSkip':
inf = 'Clip skip: ' + inf;
inf = inf + inf + inf;
break;
case 'sampler':
inf = 'Sampler: ' + inf;
inf = inf + inf + inf;
break;
case 'steps':
inf = 'Steps: ' + inf;
inf = inf + inf + inf;
break;
case 'cfgScale':
inf = 'CFG scale: ' + inf;
inf = inf + inf + inf;
break;
}
const prompt = gradioApp().querySelector('#txt2img_prompt textarea');
const neg_prompt = gradioApp().querySelector('#txt2img_neg_prompt textarea');
const cfg_scale = gradioApp().querySelector('#txt2img_cfg_scale > div:nth-child(2) > div > input');
let final = '';
let cfg = 'CFG scale: ' + cfg_scale.value + ", "
let prompt_addon = cfg + cfg + cfg
if (is_positive) {
final = inf + "\nNegative prompt: " + neg_prompt.value + "\n" + prompt_addon;
} else if (is_negative) {
final = prompt.value + "\n" + inf + "\n" + prompt_addon;
} else {
final = prompt.value + "\nNegative prompt: " + neg_prompt.value + "\n" + inf;
}
console.log(final)
genInfo_to_txt2img(final, false)
hidePopup();
sendClick(genButton);
}
// Creates a list of the selected models
var selectedModels = [];
var selectedTypes = [];
@ -605,37 +709,6 @@ document.addEventListener('click', function(event) {
}
}, true);
function inputHTMLPreviewContent(html_input) {
var overlay = document.querySelector('.civitaiOverlay')
let startIndex = html_input.indexOf("'value': '");
if (startIndex !== -1) {
startIndex += "'value': '".length;
const endIndex = html_input.indexOf("', 'type': None,", startIndex);
if (endIndex !== -1) {
let extractedText = html_input.substring(startIndex, endIndex);
var modelIdNotFound = extractedText.includes(">Model ID not found.<br>Maybe");
extractedText = extractedText.replace(/\\n\s*</g, '<');
extractedText = extractedText.replace(/\\n/g, ' ');
extractedText = extractedText.replace(/\\t/g, '');
var loadingText = document.querySelector('.civitaiLoadingText');
var modelInfo = document.createElement('div');
loadingText.parentNode.removeChild(loadingText);
if (!modelIdNotFound) {
overlay.style.top = 0;
overlay.style.transform = 'translate(-50%, 0)';
extractedText = extractedText.replace(/\\'/g, "");
} else {
extractedText = extractedText.replace(/\\'/g, "'");
}
modelInfo.innerHTML = extractedText;
overlay.appendChild(modelInfo);
}
}
}
// CivitAI Link Button Creation
function onEditButtonCardClick(nameValue) {
var checkInterval = setInterval(function() {
@ -720,14 +793,12 @@ function sendImgUrl(image_url) {
}
// Sends txt2img info to txt2img tab
function genInfo_to_txt2img(genInfo) {
function genInfo_to_txt2img(genInfo, do_slice=true) {
let insert = gradioApp().querySelector('#txt2img_prompt textarea');
let pasteButton = gradioApp().querySelector('#paste');
if (genInfo) {
var cleanGenInfo = genInfo.slice(5);
insert.value = cleanGenInfo;
insert.value = do_slice ? genInfo.slice(5) : genInfo;
insert.dispatchEvent(new Event('input', { bubbles: true }));
pasteButton.dispatchEvent(new Event('click', { bubbles: true }));
}
}

View File

@ -669,6 +669,7 @@ def update_model_info(model_string=None, model_version=None, only_html=False, in
dl_dict = {}
is_LORA = False
file_list = []
file_dict = []
default_file = None
model_filename = None
sha256_value = None
@ -688,6 +689,9 @@ def update_model_info(model_string=None, model_version=None, only_html=False, in
uploader_avatar = f'<div class="avatar"><img src={uploader_avatar}></div>'
tags = item.get('tags', "")
model_desc = item.get('description', "")
if model_desc:
model_desc = model_desc.replace('<img', '<img style="max-width: -webkit-fill-available;"')
model_desc = model_desc.replace('<code>', '<code style="text-wrap: wrap">')
if model_version is None:
selected_version = item['modelVersions'][0]
else:
@ -721,6 +725,10 @@ def update_model_info(model_string=None, model_version=None, only_html=False, in
unique_file_name = f"{size} {format} {fp} ({filesize})"
is_primary = file.get('primary', False)
file_list.append(unique_file_name)
file_dict.append({
"format": format,
"sizeKB": sizeKB
})
if is_primary:
default_file = unique_file_name
model_filename = file['name']
@ -728,15 +736,22 @@ def update_model_info(model_string=None, model_version=None, only_html=False, in
gl.json_info = item
sha256_value = file['hashes'].get('SHA256', 'Unknown')
if is_LORA and file_list:
extracted_formats = [file.split(' ')[1] for file in file_list]
if "SafeTensor" in extracted_formats and "PickleTensor" in extracted_formats:
if "PickleTensor" in file_list[0].split(' ')[1]:
if float(file_list[0].split(' ')[0]) <= 100:
safe_tensor_found = False
pickle_tensor_found = False
if is_LORA and file_dict:
for file_info in file_dict:
file_format = file_info.get("format", "")
if "SafeTensor" in file_format:
safe_tensor_found = True
if "PickleTensor" in file_format:
pickle_tensor_found = True
if safe_tensor_found and pickle_tensor_found:
if "PickleTensor" in file_dict[0].get("format", ""):
if file_dict[0].get("sizeKB", 0) <= 100:
model_folder = os.path.join(contenttype_folder("TextualInversion"))
model_url = selected_version['downloadUrl']
model_url = selected_version.get('downloadUrl', '')
model_main_url = f"https://civitai.com/models/{item['id']}"
img_html = '<div class="sampleimgs"><input type="radio" name="zoomRadio" id="resetZoom" class="zoom-radio" checked>'
for index, pic in enumerate(selected_version['images']):
@ -783,7 +798,7 @@ def update_model_info(model_string=None, model_version=None, only_html=False, in
img_html += '</div>'
if meta:
img_html += '<div style="margin:1em 0em 1em 1em;text-align:left;line-height:1.5em;" id="image_info"><dl>'
img_html += '<div style="margin:1em 0em 1em 1em;text-align:left;line-height:1.5em;" id="image_info"><dl style="gap:10px; display:grid;">'
# 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]
@ -791,7 +806,7 @@ def update_model_info(model_string=None, model_version=None, only_html=False, in
for key in preferred_order:
if key in meta:
value = meta[key]
img_html += f'<dt>{escape(str(key).capitalize())}</dt><dd>{escape(str(value))}</dd>'
img_html += f'<div class="civitai-meta-btn" onclick="metaToTxt2Img(\'{escape(str(key))}\', this)"><dt>{escape(str(key).capitalize())}</dt><dd>{escape(str(value))}</dd></div>'
# Check if there are remaining keys in meta
remaining_keys = [key for key in meta if key.lower() not in preferred_order_lower]
@ -806,7 +821,7 @@ def update_model_info(model_string=None, model_version=None, only_html=False, in
"""
for key in remaining_keys:
value = meta[key]
img_html += f'<dt>{escape(str(key).capitalize())}</dt><dd>{escape(str(value))}</dd>'
img_html += f'<div><dt>{escape(str(key).capitalize())}</dt><dd>{escape(str(value))}</dd></div>'
img_html = img_html + '</div></div></div>'
img_html += '</dl></div>'
@ -844,8 +859,8 @@ def update_model_info(model_string=None, model_version=None, only_html=False, in
{tags_html}
</div>
</dd>
<dt>Download Link</dt>
<dd><a href={model_url} target="_blank">{model_url}</a></dd>
{"<dt>Download Link</dt>" if model_url else ''}
{f'<dd><a href={model_url} target="_blank">{model_url}</a></dd>' if model_url else ''}
</dl>
<div style="align-self:center; min-width:320px;">
<div>
@ -853,7 +868,7 @@ def update_model_info(model_string=None, model_version=None, only_html=False, in
</div>
</div>
</div>
<div class="model-description">
<div class="model-description" style="overflow-wrap: break-word;">
<h2>Description</h2>
{model_desc}
</div>

View File

@ -108,8 +108,13 @@ def create_model_item(dl_url, model_filename, install_path, model_name, version_
for item in gl.json_data['items']:
if int(item['id']) == int(model_id):
filtered_items.append(item)
content_type = item['type']
desc = item['description']
main_folder = _api.contenttype_folder(content_type, desc)
break
sub_folder = os.path.normpath(os.path.relpath(install_path, main_folder))
model_json = {"items": filtered_items}
model_versions = _api.update_model_versions(model_id)
(preview_html,_,_,_,_,_,_,_,_,_,_,existing_path,_) = _api.update_model_info(None, model_versions.get('value'), False, model_id)
@ -131,7 +136,8 @@ def create_model_item(dl_url, model_filename, install_path, model_name, version_
"model_versions" : model_versions,
"preview_html" : preview_html['value'],
"existing_path": existing_path['value'],
"from_batch" : from_batch
"from_batch" : from_batch,
"sub_folder" : sub_folder
}
return item
@ -639,12 +645,11 @@ def download_create_thread(download_finish, queue_trigger, progress=gr.Progress(
print(f"Failed to extract {item['model_filename']} with error: {e}")
if not gl.cancel_status:
if item['create_json']:
_file.save_model_info(item['install_path'], item['model_filename'], item['model_sha256'], item['preview_html'], api_response=item['model_json'])
_file.save_model_info(item['install_path'], item['model_filename'], item['sub_folder'], item['model_sha256'], item['preview_html'], api_response=item['model_json'])
info_to_json(path_to_new_file, item['model_id'], item['model_sha256'], unpackList)
_file.save_preview(path_to_new_file, item['model_json'], True, item['model_sha256'])
if save_all_images:
_file.save_images(item['preview_html'], item['model_filename'], item['install_path'], )
else:
_file.save_preview(path_to_new_file, item['model_json'], True, item['model_sha256'])
_file.save_images(item['preview_html'], item['model_filename'], item['install_path'], item['sub_folder'], api_response=item['model_json'])
base_name = os.path.splitext(item['model_filename'])[0]
base_name_preview = base_name + '.preview'

View File

@ -151,7 +151,7 @@ def delete_model(delete_finish=None, model_filename=None, model_string=None, lis
def delete_associated_files(directory, base_name):
for file in os.listdir(directory):
current_base_name, ext = os.path.splitext(file)
if current_base_name == base_name or current_base_name == f"{base_name}.preview":
if current_base_name == base_name or current_base_name == f"{base_name}.preview" or current_base_name == f"{base_name}.api_info":
path_to_delete = os.path.join(directory, file)
try:
send2trash(path_to_delete)
@ -203,25 +203,30 @@ def save_preview(file_path, api_response, overwrite_toggle=False, sha256=None):
print(f"No preview images found for \"{name}\"")
return
def save_images(preview_html, model_filename, install_path, sub_folder=None):
def get_image_path(install_path, api_response, sub_folder):
image_location = getattr(opts, "image_location", r"")
sub_image_location = getattr(opts, "sub_image_location", True)
image_path = install_path
if api_response:
json_info = api_response['items'][0]
else:
json_info = gl.json_info
if image_location:
if sub_image_location:
desc = gl.json_info['description']
content_type = gl.json_info['type']
desc = json_info['description']
content_type = json_info['type']
image_path = os.path.join(_api.contenttype_folder(content_type, desc, custom_folder=image_location))
if not sub_folder:
sub_folder = os.path.relpath(install_path, image_path)
if sub_folder and sub_folder != "None":
image_path = os.path.join(image_path, sub_folder.lstrip("/").lstrip("\\"))
else:
image_path = Path(image_location)
if not os.path.exists(image_path):
os.makedirs(image_path)
return image_path
def save_images(preview_html, model_filename, install_path, sub_folder, api_response=None):
image_path = get_image_path(install_path, api_response, sub_folder)
img_urls = re.findall(r'data-sampleimg="true" src=[\'"]?([^\'" >]+)', preview_html)
name = os.path.splitext(model_filename)[0]
@ -231,14 +236,11 @@ def save_images(preview_html, model_filename, install_path, sub_folder=None):
urllib.request.install_opener(opener)
for i, img_url in enumerate(img_urls):
if i == 0:
filename = f'{name}.preview.png'
else:
filename = f'{name}_{i}.png'
filename = f'{name}_{i}.png'
img_url = urllib.parse.quote(img_url, safe=':/=')
try:
with urllib.request.urlopen(img_url) as url:
with open(os.path.join(install_path if i == 0 else image_path, filename), 'wb') as f:
with open(os.path.join(image_path, filename), 'wb') as f:
f.write(url.read())
print(f"Downloaded {filename}")
@ -343,6 +345,11 @@ def model_from_sent(model_name, content_type, tile_count):
modelID_failed = False
output_html = None
use_local_html = getattr(opts, "use_local_html", False)
local_path_in_html = getattr(opts, "local_path_in_html", False)
if local_path_in_html:
use_local_html = False
model_name = re.sub(r'\.\d{3}$', '', model_name)
content_type = re.sub(r'\.\d{3}$', '', content_type)
content_mapping = {
@ -371,22 +378,23 @@ def model_from_sent(model_name, content_type, tile_count):
if index != -1:
output_html = output_html[index + len("</head>"):]
fail_html = '<div style="color: white; font-family: var(--font); font-size: 24px; text-align: center; margin: 50px !important;">Model ID not found.<br>Maybe the model doesn\'t exist on CivitAI?</div>'
div = '<div style="color: white; font-family: var(--font); font-size: 24px; text-align: center; margin: 50px !important;">'
not_found = div + "Model ID not found.<br>Maybe the model doesn\'t exist on CivitAI?</div>"
offline = div + "CivitAI failed to respond.<br>The servers are likely offline."
if not output_html:
modelID = get_models(model_file, True)
if not modelID or modelID == "Model not found":
output_html = fail_html
output_html = not_found
modelID_failed = True
if modelID == "offline":
output_html = fail_html
output_html = offline
modelID_failed = True
if not modelID_failed:
json_data = _api.api_to_data(content_type, "Newest", "AllTime", "Model name", None, None, None, tile_count, f"civitai.com/models/{modelID}")
else: json_data = None
if json_data == "timeout":
output_html = fail_html
output_html = offline
if json_data != None and json_data != "timeout":
model_versions = _api.update_model_versions(modelID, json_data)
output_html = _api.update_model_info(None, model_versions.get('value'), True, modelID, json_data)
@ -402,6 +410,7 @@ def model_from_sent(model_name, content_type, tile_count):
'#60A5FA': 'var(--link-text-color-hover)',
'#1F2937': 'var(--input-background-fill)',
'#374151': 'var(--input-border-color)',
'#111827': 'var(--error-background-fill)',
'top: 50%;': '',
'padding-top: 0px;': 'padding-top: 475px;',
'.civitai_txt2img': '.civitai_placeholder'
@ -446,30 +455,37 @@ def clean_description(desc):
cleaned_text = desc
return cleaned_text
def save_model_info(install_path, file_name, sha256=None, preview_html=None, overwrite_toggle=False, api_response=None):
def save_model_info(install_path, file_name, sub_folder, sha256=None, preview_html=None, overwrite_toggle=False, api_response=None, from_update=False):
filename = os.path.splitext(file_name)[0]
json_file = os.path.join(install_path, f'{filename}.json')
if not os.path.exists(install_path):
os.makedirs(install_path)
save_api_info = getattr(opts, "save_api_info", False)
if not sha256:
if os.path.exists(json_file):
try:
with open(json_file, 'r', encoding="utf-8") as f:
data = json.load(f)
if 'sha256' in data and data['sha256']:
sha256 = data['sha256'].upper()
except Exception as e:
print(f"Failed to open {json_file}: {e}")
use_local = getattr(opts, "local_path_in_html", False)
save_to_custom = getattr(opts, "inf_files_in_imgs", False)
if not api_response:
api_response = gl.json_data
image_path = get_image_path(install_path, api_response, sub_folder)
if save_to_custom:
save_path = image_path
else:
save_path = install_path
result = find_and_save(api_response, sha256, file_name, json_file, False, overwrite_toggle)
if result != "found":
result = find_and_save(api_response, sha256, file_name, json_file, True, overwrite_toggle)
if preview_html:
if use_local:
img_urls = re.findall(r'data-sampleimg="true" src=[\'"]?([^\'" >]+)', preview_html)
for i, img_url in enumerate(img_urls):
img_name = f'{filename}_{i}.png'
preview_html = preview_html.replace(img_url,f'{os.path.join(image_path, img_name)}')
match = re.search(r'(\s*)<div class="model-block">', preview_html)
if match:
indentation = match.group(1)
@ -479,12 +495,12 @@ def save_model_info(install_path, file_name, sha256=None, preview_html=None, ove
utf8_meta_tag = f'{indentation}<meta charset="UTF-8">'
head_section = f'{indentation}<head>{indentation} {utf8_meta_tag}{indentation} {css_link}{indentation}</head>'
HTML = head_section + preview_html
path_to_new_file = os.path.join(install_path, f'{filename}.html')
path_to_new_file = os.path.join(save_path, f'{filename}.html')
with open(path_to_new_file, 'wb') as f:
f.write(HTML.encode('utf8'))
if save_api_info:
path_to_new_file = os.path.join(install_path, f'{filename}.api_info.json')
path_to_new_file = os.path.join(save_path, f'{filename}.api_info.json')
with open(path_to_new_file, mode="w", encoding="utf-8") as f:
json.dump(gl.json_info, f, indent=4, ensure_ascii=False)
@ -954,7 +970,8 @@ def file_scan(folders, ver_finish, tag_finish, installed_finish, preview_finish,
install_path, file_name = os.path.split(file_path)
model_versions = _api.update_model_versions(id_value, api_response)
preview_html = _api.update_model_info(None, model_versions.get('value'), True, id_value, api_response)
save_model_info(install_path, file_name, preview_html=preview_html, api_response=api_response, overwrite_toggle=overwrite_toggle)
sub_folder = os.path.normpath(os.path.relpath(install_path, gl.main_folder))
save_model_info(install_path, file_name, sub_folder, preview_html=preview_html, api_response=api_response, overwrite_toggle=overwrite_toggle, from_update=True)
if progress != None:
progress(1, desc=f"All tags succesfully saved!")
gl.scan_files = False

View File

@ -20,21 +20,30 @@ def git_tag():
return None
try:
from packaging import version
ver = git_tag()
if not ver:
try:
from modules import launch_utils
ver = launch_utils.git_tag()
except:
print("Failed to fetch SD-WebUI version")
ver_bool = False
if ver:
ver = ver.split('-')[0].rsplit('-', 1)[0]
ver_bool = version.parse(ver[0:]) >= version.parse("1.7")
import modules_forge
forge = True
ver_bool = True
except ImportError:
print("Python module 'packaging' has not been imported correctly, please try to restart or install it manually.")
ver_bool = False
forge = False
if not forge:
try:
from packaging import version
ver = git_tag()
if not ver:
try:
from modules import launch_utils
ver = launch_utils.git_tag()
except:
print("Failed to fetch SD-WebUI version")
ver_bool = False
if ver:
ver = ver.split('-')[0].rsplit('-', 1)[0]
ver_bool = version.parse(ver[0:]) >= version.parse("1.7")
except ImportError:
print("Python module 'packaging' has not been imported correctly, please try to restart or install it manually.")
ver_bool = False
gl.init()
@ -558,6 +567,7 @@ def on_ui_tabs():
inputs=[
install_path,
model_filename,
sub_folder,
current_sha256,
preview_html
],
@ -1011,7 +1021,7 @@ def on_ui_settings():
**({'category_id': cat_id} if ver_bool else {})
).info("Uses the matching local HTML file when pressing CivitAI button on model cards in txt2img and img2img")
)
shared.opts.add_option(
"page_header",
shared.OptionInfo(
@ -1061,6 +1071,26 @@ def on_ui_settings():
**({'category_id': cat_id} if ver_bool else {})
).info("Will append any content type and sub folders to the custom path.")
)
shared.opts.add_option(
"local_path_in_html",
shared.OptionInfo(
False,
"Use local images in the HTML",
section=browser,
**({'category_id': cat_id} if ver_bool else {})
).info("Does not work in combination with the \"Use local HTML file for model info\" option!")
)
shared.opts.add_option(
"save_to_custom",
shared.OptionInfo(
False,
"Store the HTML and api_info in the custom images location",
section=browser,
**({'category_id': cat_id} if ver_bool else {})
)
)

View File

@ -322,13 +322,19 @@
gap: 5px;
}
.civitai-tag {
background-color: var(--input-background-fill);
.civitai-tag,
.civitai-meta-btn {
background-color: var(--error-background-fill);
border-radius: 8px;
padding: 4px 6px;
border: 1px solid var(--input-border-color);
}
.civitai-meta-btn:hover {
cursor: pointer;
background-color: var(--input-background-fill);
}
#select_all_models_container {
display: flex;
justify-content: flex-end;

View File

@ -192,13 +192,19 @@ a:hover {
gap: 5px;
}
.civitai-tag {
background-color: #1F2937;
.civitai-tag,
.civitai-meta-btn {
background-color: #111827;
border-radius: 8px;
padding: 4px 6px;
border: 1px solid #374151;
}
.civitai-meta-btn:hover {
cursor: pointer;
background-color: #1F2937;
}
/* Icon */
.tab-label::before {
content: "";