feat: LyCORIS (also called "locon") model supported.
feat: Support model deletion function in "Extra Network" model viewer. fix: "Download all files" now working as expect. fix: Auto select newest version when load model info from url. fix: Auto select default '/' folder when load model info from url. feat: Press "`" key to toggle "Extra Network" model viewer under "img2img" and "txt2img" tab. feat: Press "x" key to fast paste Civitai model url and load model info under "Civitai Helper" tab,then click "Download Model". feat: Press "ctrl + x" keys trigger model generate. refact: Move scripted css to style.css and other style adjusts.pull/211/head
parent
920ca3267f
commit
b85fe70488
|
|
@ -29,7 +29,7 @@ Civitai: [Civitai Url](https://civitai.com/models/16768/civitai-helper-sd-webui-
|
|||
- 🖼️: Modified "replace preview" text into this icon
|
||||
- 🌐: Open this model's Civitai url in a new tab
|
||||
- 💡: Add this model's trigger words to prompt
|
||||
- 🏷️: Use this model's preview image's prompt
|
||||
- 🪞: Use this model's preview image's prompt
|
||||
* Above buttons support thumbnail mode of Extra Network
|
||||
* Option to always show additional buttons, to work with touchscreen.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,68 +1,58 @@
|
|||
"use strict";
|
||||
|
||||
|
||||
function ch_convert_file_path_to_url(path){
|
||||
function ch_convert_file_path_to_url(path) {
|
||||
let prefix = "file=";
|
||||
let path_to_url = path.replaceAll('\\', '/');
|
||||
return prefix+path_to_url;
|
||||
return prefix + path_to_url;
|
||||
}
|
||||
|
||||
function ch_img_node_str(path){
|
||||
function ch_img_node_str(path) {
|
||||
return `<img src='${ch_convert_file_path_to_url(path)}' style="width:24px"/>`;
|
||||
}
|
||||
|
||||
|
||||
function ch_gradio_version(){
|
||||
function ch_gradio_version() {
|
||||
let foot = gradioApp().getElementById("footer");
|
||||
if (!foot){return null;}
|
||||
if (!foot) { return null; }
|
||||
|
||||
let versions = foot.querySelector(".versions");
|
||||
if (!versions){return null;}
|
||||
if (!versions) { return null; }
|
||||
|
||||
if (versions.innerHTML.indexOf("gradio: 3.16.2")>0) {
|
||||
if (versions.innerHTML.indexOf("gradio: 3.16.2") > 0) {
|
||||
return "3.16.2";
|
||||
} else {
|
||||
return "3.23.0";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// send msg to python side by filling a hidden text box
|
||||
// then will click a button to trigger an action
|
||||
// msg is an object, not a string, will be stringify in this function
|
||||
function send_ch_py_msg(msg){
|
||||
console.log("run send_ch_py_msg")
|
||||
function send_ch_py_msg(msg) {
|
||||
// console.log("run send_ch_py_msg")
|
||||
let js_msg_txtbox = gradioApp().querySelector("#ch_js_msg_txtbox textarea");
|
||||
if (js_msg_txtbox && msg) {
|
||||
// fill to msg box
|
||||
js_msg_txtbox.value = JSON.stringify(msg);
|
||||
js_msg_txtbox.dispatchEvent(new Event("input"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// get msg from python side from a hidden textbox
|
||||
// normally this is an old msg, need to wait for a new msg
|
||||
function get_ch_py_msg(){
|
||||
function get_ch_py_msg() {
|
||||
console.log("run get_ch_py_msg")
|
||||
const py_msg_txtbox = gradioApp().querySelector("#ch_py_msg_txtbox textarea");
|
||||
if (py_msg_txtbox && py_msg_txtbox.value) {
|
||||
console.log("find py_msg_txtbox");
|
||||
console.log("py_msg_txtbox value: ");
|
||||
console.log(py_msg_txtbox.value)
|
||||
console.log("find py_msg_txtbox, value:", py_msg_txtbox.value)
|
||||
return py_msg_txtbox.value
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// get msg from python side from a hidden textbox
|
||||
// it will try once in every sencond, until it reach the max try times
|
||||
const get_new_ch_py_msg = (max_count=3) => new Promise((resolve, reject) => {
|
||||
console.log("run get_new_ch_py_msg")
|
||||
|
||||
const get_new_ch_py_msg = (max_count = 7) => new Promise((resolve, reject) => {
|
||||
let count = 0;
|
||||
let new_msg = "";
|
||||
let find_msg = false;
|
||||
|
|
@ -71,13 +61,10 @@ const get_new_ch_py_msg = (max_count=3) => new Promise((resolve, reject) => {
|
|||
count++;
|
||||
|
||||
if (py_msg_txtbox && py_msg_txtbox.value) {
|
||||
console.log("find py_msg_txtbox");
|
||||
console.log("py_msg_txtbox value: ");
|
||||
console.log(py_msg_txtbox.value)
|
||||
|
||||
console.log("find py_msg_txtbox, value: ", py_msg_txtbox.value)
|
||||
new_msg = py_msg_txtbox.value
|
||||
if (new_msg != "") {
|
||||
find_msg=true
|
||||
find_msg = true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -96,11 +83,9 @@ const get_new_ch_py_msg = (max_count=3) => new Promise((resolve, reject) => {
|
|||
reject('');
|
||||
clearInterval(interval);
|
||||
}
|
||||
|
||||
}, 1000);
|
||||
}, 400);
|
||||
})
|
||||
|
||||
|
||||
function getActiveTabType() {
|
||||
const currentTab = get_uiCurrentTabContent();
|
||||
switch (currentTab.id) {
|
||||
|
|
@ -112,8 +97,6 @@ function getActiveTabType() {
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getActivePrompt() {
|
||||
const currentTab = get_uiCurrentTabContent();
|
||||
switch (currentTab.id) {
|
||||
|
|
@ -136,9 +119,8 @@ function getActiveNegativePrompt() {
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
//button's click function
|
||||
async function open_model_url(event, model_type, search_term){
|
||||
// button's click function
|
||||
async function open_model_url(event, model_type, search_term) {
|
||||
console.log("start open_model_url");
|
||||
|
||||
//get hidden components of extension
|
||||
|
|
@ -147,7 +129,6 @@ async function open_model_url(event, model_type, search_term){
|
|||
return
|
||||
}
|
||||
|
||||
|
||||
//msg to python side
|
||||
let msg = {
|
||||
"action": "",
|
||||
|
|
@ -157,7 +138,6 @@ async function open_model_url(event, model_type, search_term){
|
|||
"neg_prompt": "",
|
||||
}
|
||||
|
||||
|
||||
msg["action"] = "open_url";
|
||||
msg["model_type"] = model_type;
|
||||
msg["search_term"] = search_term;
|
||||
|
|
@ -176,8 +156,7 @@ async function open_model_url(event, model_type, search_term){
|
|||
|
||||
//check response msg from python
|
||||
let new_py_msg = await get_new_ch_py_msg();
|
||||
console.log("new_py_msg:");
|
||||
console.log(new_py_msg);
|
||||
// console.log("new_py_msg:", new_py_msg);
|
||||
|
||||
//check msg
|
||||
if (new_py_msg) {
|
||||
|
|
@ -187,19 +166,12 @@ async function open_model_url(event, model_type, search_term){
|
|||
if (py_msg_json.content.url) {
|
||||
window.open(py_msg_json.content.url, "_blank");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
console.log("end open_model_url");
|
||||
|
||||
|
||||
console.log("end open_model_url")
|
||||
}
|
||||
|
||||
function add_trigger_words(event, model_type, search_term){
|
||||
function add_trigger_words(event, model_type, search_term) {
|
||||
console.log("start add_trigger_words");
|
||||
|
||||
//get hidden components of extension
|
||||
|
|
@ -208,7 +180,6 @@ function add_trigger_words(event, model_type, search_term){
|
|||
return
|
||||
}
|
||||
|
||||
|
||||
//msg to python side
|
||||
let msg = {
|
||||
"action": "",
|
||||
|
|
@ -232,16 +203,13 @@ function add_trigger_words(event, model_type, search_term){
|
|||
|
||||
//click hidden button
|
||||
js_add_trigger_words_btn.click();
|
||||
|
||||
console.log("end add_trigger_words");
|
||||
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
|
||||
|
||||
}
|
||||
|
||||
function use_preview_prompt(event, model_type, search_term){
|
||||
function use_preview_prompt(event, model_type, search_term) {
|
||||
console.log("start use_preview_prompt");
|
||||
|
||||
//get hidden components of extension
|
||||
|
|
@ -281,13 +249,53 @@ function use_preview_prompt(event, model_type, search_term){
|
|||
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
|
||||
}
|
||||
|
||||
async function delete_model(event, model_type, search_term) {
|
||||
if (!confirm('Comfirm delete model: "' + search_term + '"?')) { return }
|
||||
|
||||
//get hidden components of extension
|
||||
let js_delete_model_btn = gradioApp().getElementById("ch_js_delete_model_btn");
|
||||
if (!js_delete_model_btn) {
|
||||
return
|
||||
}
|
||||
|
||||
//msg to python side
|
||||
let msg = {
|
||||
"action": "delete_model",
|
||||
"model_type": model_type,
|
||||
"search_term": search_term
|
||||
}
|
||||
|
||||
// fill to msg box
|
||||
send_ch_py_msg(msg)
|
||||
|
||||
//click hidden button
|
||||
js_delete_model_btn.click();
|
||||
|
||||
// stop parent event
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
|
||||
//check response msg from python
|
||||
let new_py_msg = await get_new_ch_py_msg();
|
||||
console.log("new_py_msg:", new_py_msg);
|
||||
|
||||
//check msg
|
||||
if (new_py_msg) {
|
||||
let py_msg_json = JSON.parse(new_py_msg);
|
||||
//check delete result
|
||||
console.log(py_msg_json)
|
||||
if (py_msg_json && py_msg_json.result) {
|
||||
alert('Model delete successfully!!')
|
||||
let card = event.target.closest('.card')
|
||||
card.parentNode.removeChild(card)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// download model's new version into SD at python side
|
||||
function ch_dl_model_new_version(event, model_path, version_id, download_url){
|
||||
function ch_dl_model_new_version(event, model_path, version_id, download_url) {
|
||||
console.log("start ch_dl_model_new_version");
|
||||
|
||||
// must confirm before downloading
|
||||
|
|
@ -325,10 +333,237 @@ function ch_dl_model_new_version(event, model_path, version_id, download_url){
|
|||
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
|
||||
|
||||
}
|
||||
|
||||
function createAdditionalButton(btnProps) {
|
||||
let el = document.createElement("a");
|
||||
Object.assign(el, btnProps);
|
||||
el.setAttribute('onclick', btnProps.onclick)
|
||||
el.className = 'civitai-helper-action'
|
||||
el.href = "#";
|
||||
return el
|
||||
}
|
||||
|
||||
function convert_to_py_model_type(js_model_type) {
|
||||
//get model_type for python side
|
||||
switch (js_model_type) {
|
||||
case "textual_inversion": return "ti";
|
||||
case "hypernetworks": return "hyper";
|
||||
case "checkpoints": return "ckp";
|
||||
case "lora": return "lora";
|
||||
case "lycoris": return "lycoris";
|
||||
}
|
||||
}
|
||||
|
||||
// add just one model_type cards buttons
|
||||
function update_card_for_one_tab(model_type, container) {
|
||||
|
||||
let ch_btn_txts = ['🌐', '💡', '🪞', '🗑️'];
|
||||
let replace_preview_text = getTranslation("replace preview");
|
||||
if (!replace_preview_text) {
|
||||
replace_preview_text = "replace preview";
|
||||
}
|
||||
|
||||
// get component
|
||||
let ch_always_display_ckb = gradioApp().querySelector("#ch_always_display_ckb input");
|
||||
let ch_show_btn_on_thumb_ckb = gradioApp().querySelector("#ch_show_btn_on_thumb_ckb input");
|
||||
let ch_always_display = false;
|
||||
let ch_show_btn_on_thumb = false;
|
||||
if (ch_always_display_ckb) {
|
||||
ch_always_display = ch_always_display_ckb.checked;
|
||||
}
|
||||
if (ch_show_btn_on_thumb_ckb) {
|
||||
ch_show_btn_on_thumb = ch_show_btn_on_thumb_ckb.checked;
|
||||
}
|
||||
|
||||
//change all "replace preview" into an icon
|
||||
let extra_network_id = "";
|
||||
let metadata_button = null;
|
||||
let additional_node = null;
|
||||
let replace_preview_btn = null;
|
||||
let ul_node = null;
|
||||
let search_term_node = null;
|
||||
let search_term = "";
|
||||
let is_thumb_mode = false;
|
||||
|
||||
// check if extr network is under thumbnail mode
|
||||
is_thumb_mode = false;
|
||||
if (container.className == "extra-network-thumbs") {
|
||||
is_thumb_mode = true;
|
||||
// if (!ch_show_btn_on_thumb) {continue;}
|
||||
}
|
||||
|
||||
model_type = convert_to_py_model_type(model_type);
|
||||
|
||||
for (let card of container.children) {
|
||||
//get ul node, which is the parent of all buttons
|
||||
ul_node = card.querySelector(".actions .additional ul");
|
||||
|
||||
if (ul_node.childElementCount > 1) {
|
||||
// buttons all ready added, just quit
|
||||
console.log('buttons all ready added, just quit')
|
||||
return
|
||||
}
|
||||
|
||||
//metadata_buttoncard
|
||||
metadata_button = card.querySelector(".metadata-button");
|
||||
//additional node
|
||||
additional_node = card.querySelector(".actions .additional");
|
||||
// replace preview text button
|
||||
replace_preview_btn = card.querySelector(".actions .additional a");
|
||||
|
||||
// check thumb mode
|
||||
if (is_thumb_mode) {
|
||||
additional_node.style.display = null;
|
||||
|
||||
if (ch_show_btn_on_thumb) {
|
||||
ul_node.style.background = "rgba(0, 0, 0, .5)";
|
||||
} else {
|
||||
//reset
|
||||
ul_node.style.background = null;
|
||||
// console.log("remove existed buttons");
|
||||
// remove existed buttons
|
||||
if (ul_node) {
|
||||
// find all .a child nodes
|
||||
let atags = ul_node.querySelectorAll("a");
|
||||
|
||||
for (let atag of atags) {
|
||||
//reset display
|
||||
atag.style.display = null;
|
||||
//remove extension's button
|
||||
if (ch_btn_txts.indexOf(atag.innerHTML) >= 0) {
|
||||
//need to remove
|
||||
ul_node.removeChild(atag);
|
||||
} else {
|
||||
//do not remove, just reset
|
||||
atag.innerHTML = replace_preview_text;
|
||||
atag.style.display = null;
|
||||
atag.style.fontSize = null;
|
||||
atag.style.position = null;
|
||||
atag.style.backgroundImage = null;
|
||||
}
|
||||
}
|
||||
|
||||
//also remove br tag in ul
|
||||
let brtag = ul_node.querySelector("br");
|
||||
if (brtag) {
|
||||
ul_node.removeChild(brtag);
|
||||
}
|
||||
}
|
||||
//just reset and remove nodes, do nothing else
|
||||
continue;
|
||||
}
|
||||
|
||||
} else {
|
||||
// full preview mode
|
||||
additional_node.style.display = ch_always_display ? "block" : null;
|
||||
|
||||
// remove br tag
|
||||
let brtag = ul_node.querySelector("br");
|
||||
if (brtag) {
|
||||
ul_node.removeChild(brtag);
|
||||
}
|
||||
}
|
||||
|
||||
// change replace preview text button into icon
|
||||
if (replace_preview_btn) {
|
||||
replace_preview_btn.className = "civitai-helper-action";
|
||||
replace_preview_btn.innerHTML = "🖼️";
|
||||
}
|
||||
|
||||
// search_term node
|
||||
// search_term = subfolder path + model name + ext
|
||||
search_term_node = card.querySelector(".actions .additional .search_term");
|
||||
if (!search_term_node) {
|
||||
console.log("can not find search_term node for cards in " + extra_network_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
// get search_term
|
||||
search_term = search_term_node.innerText;
|
||||
if (!search_term) {
|
||||
console.log("search_term is empty for cards in " + extra_network_id);
|
||||
continue;
|
||||
}
|
||||
// remove webui added extra checkpoint's sha256 value,
|
||||
// in file: stable-diffusion-webui/modules/ui_extra_networks_checkpoints.py
|
||||
// line: 24: "search_term": self.search_terms_from_path(checkpoint.filename) + " " + (checkpoint.sha256 or ""),
|
||||
search_term = search_term.split(" ")[0];
|
||||
|
||||
// if (is_thumb_mode) {
|
||||
// ul_node.style.background = btn_thumb_background;
|
||||
// }
|
||||
|
||||
// then we need to add 4 buttons to each ul node:
|
||||
let open_url_node = createAdditionalButton({
|
||||
innerHTML: "🌐",
|
||||
title: "Open this model's civitai url",
|
||||
onclick: "open_model_url(event, '" + model_type + "', '" + search_term + "')"
|
||||
})
|
||||
|
||||
let add_trigger_words_node = createAdditionalButton({
|
||||
innerHTML: "💡",
|
||||
title: "Add trigger words to prompt",
|
||||
onclick: "add_trigger_words(event, '" + model_type + "', '" + search_term + "')"
|
||||
})
|
||||
|
||||
let use_preview_prompt_node = createAdditionalButton({
|
||||
innerHTML: "🪞",
|
||||
title: "Use prompt from preview image",
|
||||
onclick: "use_preview_prompt(event, '" + model_type + "', '" + search_term + "')"
|
||||
})
|
||||
|
||||
let delete_model_node = createAdditionalButton({
|
||||
innerHTML: "🗑️",
|
||||
title: "Delete model",
|
||||
onclick: "delete_model(event, '" + model_type + "', '" + search_term + "')",
|
||||
})
|
||||
|
||||
//add to card
|
||||
ul_node.appendChild(open_url_node);
|
||||
//add br if metadata_button exists
|
||||
if (is_thumb_mode && metadata_button) {
|
||||
ul_node.appendChild(document.createElement("br"));
|
||||
}
|
||||
ul_node.appendChild(add_trigger_words_node);
|
||||
ul_node.appendChild(use_preview_prompt_node);
|
||||
ul_node.appendChild(delete_model_node);
|
||||
}
|
||||
}
|
||||
|
||||
// fast pasete civitai model url and trigger model info loading
|
||||
async function checkClipboard() {
|
||||
let text = await navigator.clipboard.readText()
|
||||
if (text.startsWith('https://civitai.com/models/')) {
|
||||
let comp = document.querySelector('#model_download_url_txt')
|
||||
let textarea = comp.querySelector('textarea')
|
||||
textarea.value = text
|
||||
textarea.dispatchEvent(new Event('input'))
|
||||
comp.querySelector('button').click()
|
||||
}
|
||||
}
|
||||
|
||||
// shotcut key event listener
|
||||
window.addEventListener('keydown', e => {
|
||||
let el = e.target
|
||||
switch (e.key) {
|
||||
case '`':
|
||||
if (el.isContentEditable || el.tagName === 'INPUT' || el.tagName === 'TEXTAREA') { e.preventDefault() }
|
||||
let type = getActiveTabType()
|
||||
if (type.endsWith('2img')) {
|
||||
document.querySelector('#' + type + '_extra_networks')?.click()
|
||||
}
|
||||
break
|
||||
case 'x':
|
||||
let txt = document.querySelector('#quicksettings + .tabs button.selected').innerText
|
||||
if (txt == 'Civitai Helper')
|
||||
checkClipboard()
|
||||
else if (txt.endsWith('2img') && e.altKey)
|
||||
document.querySelector(`button#${txt}_generate`).click()
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
onUiLoaded(() => {
|
||||
|
||||
|
|
@ -336,12 +571,19 @@ onUiLoaded(() => {
|
|||
let gradio_ver = ch_gradio_version();
|
||||
console.log("gradio_ver:" + gradio_ver);
|
||||
|
||||
// get all extra network tabs
|
||||
let tab_prefix_list = ["txt2img", "img2img"];
|
||||
let model_type_list = ["textual_inversion", "hypernetworks", "checkpoints", "lora"];
|
||||
let cardid_suffix = "cards";
|
||||
let model_type_list = ["textual_inversion", "hypernetworks", "checkpoints", "lora", "lycoris"];
|
||||
|
||||
//get init py msg
|
||||
// add all model_type cards buttons by tab_prefix
|
||||
function update_card_form_all_tab(tab_prefix) {
|
||||
for (let model_type of model_type_list) {
|
||||
let container_id = [tab_prefix, model_type, 'cards'].join('_')
|
||||
let container = document.getElementById(container_id)
|
||||
update_card_for_one_tab(model_type, container);
|
||||
}
|
||||
}
|
||||
|
||||
// get init py msg
|
||||
// let init_py_msg_str = get_ch_py_msg();
|
||||
// let extension_path = "";
|
||||
// if (!init_py_msg_str) {
|
||||
|
|
@ -354,375 +596,80 @@ onUiLoaded(() => {
|
|||
// }
|
||||
// }
|
||||
|
||||
// //icon image node as string
|
||||
// // icon image node as string
|
||||
// function icon(icon_name){
|
||||
// let icon_path = extension_path+"/icon/"+icon_name;
|
||||
// return ch_img_node_str(icon_path);
|
||||
// }
|
||||
|
||||
// check cards number change, and re-craete buttons
|
||||
function checkPeriodically(tab_prefix, model_type) {
|
||||
let container_id = '#' + [tab_prefix, model_type, 'cards_html'].join('_')
|
||||
let container = document.querySelector(container_id + ' ' + container_id)
|
||||
|
||||
// update extra network tab pages' cards
|
||||
// * replace "replace preview" text button into an icon
|
||||
// * add 3 button to each card:
|
||||
// - open model url 🌐
|
||||
// - add trigger words 💡
|
||||
// - use preview image's prompt 🏷️
|
||||
// notice: javascript can not get response from python side
|
||||
// so, these buttons just sent request to python
|
||||
// then, python side gonna open url and update prompt text box, without telling js side.
|
||||
function update_card_for_civitai(){
|
||||
// record current cards size
|
||||
let len = container.querySelectorAll('.card').length
|
||||
|
||||
//css
|
||||
let btn_margin = "0px 5px";
|
||||
let btn_fontSize = "200%";
|
||||
let btn_thumb_fontSize = "100%";
|
||||
let btn_thumb_display = "inline";
|
||||
let btn_thumb_pos = "static";
|
||||
let btn_thumb_backgroundImage = "none";
|
||||
let btn_thumb_background = "rgba(0, 0, 0, 0.8)";
|
||||
// we only wait 5s, after that we assumed that DOM will never changed
|
||||
let millis = 1000 * 5
|
||||
|
||||
let ch_btn_txts = ['🌐', '💡', '🏷️'];
|
||||
let replace_preview_text = getTranslation("replace preview");
|
||||
if (!replace_preview_text) {
|
||||
replace_preview_text = "replace preview";
|
||||
}
|
||||
|
||||
|
||||
|
||||
// get component
|
||||
let ch_always_display_ckb = gradioApp().querySelector("#ch_always_display_ckb input");
|
||||
let ch_show_btn_on_thumb_ckb = gradioApp().querySelector("#ch_show_btn_on_thumb_ckb input");
|
||||
let ch_always_display = false;
|
||||
let ch_show_btn_on_thumb = false;
|
||||
if (ch_always_display_ckb) {
|
||||
ch_always_display = ch_always_display_ckb.checked;
|
||||
}
|
||||
if (ch_show_btn_on_thumb_ckb) {
|
||||
ch_show_btn_on_thumb = ch_show_btn_on_thumb_ckb.checked;
|
||||
}
|
||||
|
||||
|
||||
//change all "replace preview" into an icon
|
||||
let extra_network_id = "";
|
||||
let extra_network_node = null;
|
||||
let metadata_button = null;
|
||||
let additional_node = null;
|
||||
let replace_preview_btn = null;
|
||||
let ul_node = null;
|
||||
let search_term_node = null;
|
||||
let search_term = "";
|
||||
let model_type = "";
|
||||
let cards = null;
|
||||
let need_to_add_buttons = false;
|
||||
let is_thumb_mode = false;
|
||||
|
||||
//get current tab
|
||||
let active_tab_type = getActiveTabType();
|
||||
if (!active_tab_type){active_tab_type = "txt2img";}
|
||||
|
||||
for (const tab_prefix of tab_prefix_list) {
|
||||
if (tab_prefix != active_tab_type) {continue;}
|
||||
|
||||
|
||||
//find out current selected model type tab
|
||||
let active_extra_tab_type = "";
|
||||
let extra_tabs = gradioApp().getElementById(tab_prefix+"_extra_tabs");
|
||||
if (!extra_tabs) {console.log("can not find extra_tabs: " + tab_prefix+"_extra_tabs");}
|
||||
|
||||
//get active extratab
|
||||
const active_extra_tab = Array.from(get_uiCurrentTabContent().querySelectorAll('.extra-network-cards,.extra-network-thumbs'))
|
||||
.find(el => el.closest('.tabitem').style.display === 'block')
|
||||
?.id.match(/^(txt2img|img2img)_(.+)_cards$/)[2]
|
||||
|
||||
|
||||
console.log("found active tab: " + active_extra_tab);
|
||||
|
||||
switch (active_extra_tab) {
|
||||
case "textual_inversion":
|
||||
active_extra_tab_type = "ti";
|
||||
break;
|
||||
case "hypernetworks":
|
||||
active_extra_tab_type = "hyper";
|
||||
break;
|
||||
case "checkpoints":
|
||||
active_extra_tab_type = "ckp";
|
||||
break;
|
||||
case "lora":
|
||||
active_extra_tab_type = "lora";
|
||||
break;
|
||||
// wait for server response and DOM updates, if cards size changed,
|
||||
// then our buttons is losted, put them back again
|
||||
let timer = setInterval(() => {
|
||||
let new_len = container.querySelectorAll('.card').length
|
||||
if (len != new_len) {
|
||||
update_card_for_one_tab(model_type, container.lastElementChild)
|
||||
clearInterval(timer)
|
||||
}
|
||||
|
||||
|
||||
for (const js_model_type of model_type_list) {
|
||||
//get model_type for python side
|
||||
switch (js_model_type) {
|
||||
case "textual_inversion":
|
||||
model_type = "ti";
|
||||
break;
|
||||
case "hypernetworks":
|
||||
model_type = "hyper";
|
||||
break;
|
||||
case "checkpoints":
|
||||
model_type = "ckp";
|
||||
break;
|
||||
case "lora":
|
||||
model_type = "lora";
|
||||
break;
|
||||
}
|
||||
|
||||
if (!model_type) {
|
||||
console.log("can not get model_type from: " + js_model_type);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
//only handle current sub-tab
|
||||
if (model_type != active_extra_tab_type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
console.log("handle active extra tab");
|
||||
|
||||
|
||||
extra_network_id = tab_prefix+"_"+js_model_type+"_"+cardid_suffix;
|
||||
// console.log("searching extra_network_node: " + extra_network_id);
|
||||
extra_network_node = gradioApp().getElementById(extra_network_id);
|
||||
// check if extr network is under thumbnail mode
|
||||
is_thumb_mode = false
|
||||
if (extra_network_node) {
|
||||
if (extra_network_node.className == "extra-network-thumbs") {
|
||||
console.log(extra_network_id + " is in thumbnail mode");
|
||||
is_thumb_mode = true;
|
||||
// if (!ch_show_btn_on_thumb) {continue;}
|
||||
}
|
||||
} else {
|
||||
console.log("can not find extra_network_node: " + extra_network_id);
|
||||
continue;
|
||||
}
|
||||
// console.log("find extra_network_node: " + extra_network_id);
|
||||
|
||||
// get all card nodes
|
||||
cards = extra_network_node.querySelectorAll(".card");
|
||||
for (let card of cards) {
|
||||
//metadata_buttoncard
|
||||
metadata_button = card.querySelector(".metadata-button");
|
||||
//additional node
|
||||
additional_node = card.querySelector(".actions .additional");
|
||||
//get ul node, which is the parent of all buttons
|
||||
ul_node = card.querySelector(".actions .additional ul");
|
||||
// replace preview text button
|
||||
replace_preview_btn = card.querySelector(".actions .additional a");
|
||||
|
||||
// check thumb mode
|
||||
if (is_thumb_mode) {
|
||||
additional_node.style.display = null;
|
||||
|
||||
if (ch_show_btn_on_thumb) {
|
||||
ul_node.style.background = btn_thumb_background;
|
||||
} else {
|
||||
//reset
|
||||
ul_node.style.background = null;
|
||||
// console.log("remove existed buttons");
|
||||
// remove existed buttons
|
||||
if (ul_node) {
|
||||
// find all .a child nodes
|
||||
let atags = ul_node.querySelectorAll("a");
|
||||
|
||||
for (let atag of atags) {
|
||||
//reset display
|
||||
atag.style.display = null;
|
||||
//remove extension's button
|
||||
if (ch_btn_txts.indexOf(atag.innerHTML)>=0) {
|
||||
//need to remove
|
||||
ul_node.removeChild(atag);
|
||||
} else {
|
||||
//do not remove, just reset
|
||||
atag.innerHTML = replace_preview_text;
|
||||
atag.style.display = null;
|
||||
atag.style.fontSize = null;
|
||||
atag.style.position = null;
|
||||
atag.style.backgroundImage = null;
|
||||
}
|
||||
}
|
||||
|
||||
//also remove br tag in ul
|
||||
let brtag = ul_node.querySelector("br");
|
||||
if (brtag) {
|
||||
ul_node.removeChild(brtag);
|
||||
}
|
||||
|
||||
}
|
||||
//just reset and remove nodes, do nothing else
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
// full preview mode
|
||||
if (ch_always_display) {
|
||||
additional_node.style.display = "block";
|
||||
} else {
|
||||
additional_node.style.display = null;
|
||||
}
|
||||
|
||||
// remove br tag
|
||||
let brtag = ul_node.querySelector("br");
|
||||
if (brtag) {
|
||||
ul_node.removeChild(brtag);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// change replace preview text button into icon
|
||||
if (replace_preview_btn) {
|
||||
if (replace_preview_btn.innerHTML !== "🖼️") {
|
||||
need_to_add_buttons = true;
|
||||
replace_preview_btn.innerHTML = "🖼️";
|
||||
if (!is_thumb_mode) {
|
||||
replace_preview_btn.style.fontSize = btn_fontSize;
|
||||
replace_preview_btn.style.margin = btn_margin;
|
||||
} else {
|
||||
replace_preview_btn.style.display = btn_thumb_display;
|
||||
replace_preview_btn.style.fontSize = btn_thumb_fontSize;
|
||||
replace_preview_btn.style.position = btn_thumb_pos;
|
||||
replace_preview_btn.style.backgroundImage = btn_thumb_backgroundImage;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (!need_to_add_buttons) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// search_term node
|
||||
// search_term = subfolder path + model name + ext
|
||||
search_term_node = card.querySelector(".actions .additional .search_term");
|
||||
if (!search_term_node){
|
||||
console.log("can not find search_term node for cards in " + extra_network_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
// get search_term
|
||||
search_term = search_term_node.innerHTML;
|
||||
if (!search_term) {
|
||||
console.log("search_term is empty for cards in " + extra_network_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// if (is_thumb_mode) {
|
||||
// ul_node.style.background = btn_thumb_background;
|
||||
// }
|
||||
|
||||
// then we need to add 3 buttons to each ul node:
|
||||
let open_url_node = document.createElement("a");
|
||||
open_url_node.href = "#";
|
||||
open_url_node.innerHTML = "🌐";
|
||||
if (!is_thumb_mode) {
|
||||
open_url_node.style.fontSize = btn_fontSize;
|
||||
open_url_node.style.margin = btn_margin;
|
||||
} else {
|
||||
open_url_node.style.display = btn_thumb_display;
|
||||
open_url_node.style.fontSize = btn_thumb_fontSize;
|
||||
open_url_node.style.position = btn_thumb_pos;
|
||||
open_url_node.style.backgroundImage = btn_thumb_backgroundImage;
|
||||
}
|
||||
open_url_node.title = "Open this model's civitai url";
|
||||
open_url_node.setAttribute("onclick","open_model_url(event, '"+model_type+"', '"+search_term+"')");
|
||||
|
||||
let add_trigger_words_node = document.createElement("a");
|
||||
add_trigger_words_node.href = "#";
|
||||
add_trigger_words_node.innerHTML = "💡";
|
||||
if (!is_thumb_mode) {
|
||||
add_trigger_words_node.style.fontSize = btn_fontSize;
|
||||
add_trigger_words_node.style.margin = btn_margin;
|
||||
} else {
|
||||
add_trigger_words_node.style.display = btn_thumb_display;
|
||||
add_trigger_words_node.style.fontSize = btn_thumb_fontSize;
|
||||
add_trigger_words_node.style.position = btn_thumb_pos;
|
||||
add_trigger_words_node.style.backgroundImage = btn_thumb_backgroundImage;
|
||||
}
|
||||
|
||||
add_trigger_words_node.title = "Add trigger words to prompt";
|
||||
add_trigger_words_node.setAttribute("onclick","add_trigger_words(event, '"+model_type+"', '"+search_term+"')");
|
||||
|
||||
let use_preview_prompt_node = document.createElement("a");
|
||||
use_preview_prompt_node.href = "#";
|
||||
use_preview_prompt_node.innerHTML = "🏷️";
|
||||
if (!is_thumb_mode) {
|
||||
use_preview_prompt_node.style.fontSize = btn_fontSize;
|
||||
use_preview_prompt_node.style.margin = btn_margin;
|
||||
} else {
|
||||
use_preview_prompt_node.style.display = btn_thumb_display;
|
||||
use_preview_prompt_node.style.fontSize = btn_thumb_fontSize;
|
||||
use_preview_prompt_node.style.position = btn_thumb_pos;
|
||||
use_preview_prompt_node.style.backgroundImage = btn_thumb_backgroundImage;
|
||||
}
|
||||
use_preview_prompt_node.title = "Use prompt from preview image";
|
||||
use_preview_prompt_node.setAttribute("onclick","use_preview_prompt(event, '"+model_type+"', '"+search_term+"')");
|
||||
|
||||
//add to card
|
||||
ul_node.appendChild(open_url_node);
|
||||
//add br if metadata_button exists
|
||||
if (is_thumb_mode && metadata_button) {
|
||||
ul_node.appendChild(document.createElement("br"));
|
||||
}
|
||||
ul_node.appendChild(add_trigger_words_node);
|
||||
ul_node.appendChild(use_preview_prompt_node);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
millis -= 500
|
||||
if (millis <= 0) {
|
||||
clearInterval(timer)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}, 500)
|
||||
}
|
||||
|
||||
|
||||
let tab_id = ""
|
||||
let extra_tab = null;
|
||||
let extra_toolbar = null;
|
||||
let extra_network_refresh_btn = null;
|
||||
//add refresh button to extra network's toolbar
|
||||
for (let prefix of tab_prefix_list) {
|
||||
tab_id = prefix + "_extra_tabs";
|
||||
// add refresh button to extra network's toolbar
|
||||
for (let tab_prefix of tab_prefix_list) {
|
||||
tab_id = tab_prefix + "_extra_tabs";
|
||||
extra_tab = gradioApp().getElementById(tab_id);
|
||||
|
||||
//get toolbar
|
||||
//get Refresh button
|
||||
extra_network_refresh_btn = gradioApp().getElementById(prefix+"_extra_refresh");
|
||||
extra_network_refresh_btn = gradioApp().getElementById(tab_prefix + "_extra_refresh");
|
||||
|
||||
|
||||
if (!extra_network_refresh_btn){
|
||||
if (!extra_network_refresh_btn) {
|
||||
console.log("can not get extra network refresh button for " + tab_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
// add refresh button to toolbar
|
||||
let ch_refresh = document.createElement("button");
|
||||
ch_refresh.innerHTML = "🔁";
|
||||
ch_refresh.innerHTML = "🔄️";
|
||||
ch_refresh.title = "Refresh Civitai Helper's additional buttons";
|
||||
ch_refresh.className = "lg secondary gradio-button";
|
||||
ch_refresh.style.fontSize = "200%";
|
||||
ch_refresh.onclick = update_card_for_civitai;
|
||||
ch_refresh.style.fontSize = "2em";
|
||||
ch_refresh.onclick = () => update_card_form_all_tab(tab_prefix)
|
||||
|
||||
extra_network_refresh_btn.parentNode.appendChild(ch_refresh);
|
||||
|
||||
// listen to refresh buttons' click event
|
||||
// check and re-add buttons back on
|
||||
document.getElementById(tab_prefix + '_extra_refresh').addEventListener('click', e => {
|
||||
let model_type = e.target.closest('.tab-nav').querySelector('button.selected').innerText.replaceAll(' ', '_').toLowerCase()
|
||||
checkPeriodically(tab_prefix, model_type)
|
||||
})
|
||||
|
||||
// listen to "Extra Networks" toggle button's click event,
|
||||
// then initialiy add all buttons, only trigger once,
|
||||
// after that all updates are trigger by refresh button click.
|
||||
document.getElementById(tab_prefix + '_extra_networks').addEventListener('click', () => {
|
||||
// wait UI updates
|
||||
setTimeout(() => update_card_form_all_tab(tab_prefix), 1500);
|
||||
}, { once: true })
|
||||
}
|
||||
|
||||
|
||||
//run it once
|
||||
update_card_for_civitai();
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,8 @@ model_type_dict = {
|
|||
"TextualInversion": "ti",
|
||||
"Hypernetwork": "hyper",
|
||||
"LORA": "lora",
|
||||
"LoCon": "lora",
|
||||
"LoCon": "lycoris",
|
||||
"LyCORIS": "lycoris",
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -277,6 +278,7 @@ def get_model_names_by_type_and_filter(model_type:str, filter:dict) -> list:
|
|||
|
||||
return model_names
|
||||
|
||||
|
||||
def get_model_names_by_input(model_type, empty_info_only):
|
||||
return get_model_names_by_type_and_filter(model_type, {"empty_info_only":empty_info_only})
|
||||
|
||||
|
|
@ -365,9 +367,7 @@ def get_preview_image_by_model_path(model_path:str, max_size_preview, skip_nsfw_
|
|||
# search local model by version id in 1 folder, no subfolder
|
||||
# return - model_info
|
||||
def search_local_model_info_by_version_id(folder:str, version_id:int) -> dict:
|
||||
util.printD("Searching local model by version id")
|
||||
util.printD("folder: " + folder)
|
||||
util.printD("version_id: " + str(version_id))
|
||||
util.printD("Searching local model by version id: " + str(version_id) + "in folder: " + folder)
|
||||
|
||||
if not folder:
|
||||
util.printD("folder is none")
|
||||
|
|
@ -414,9 +414,6 @@ def search_local_model_info_by_version_id(folder:str, version_id:int) -> dict:
|
|||
return
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# check new version for a model by model path
|
||||
# return (model_path, model_id, model_name, new_verion_id, new_version_name, description, download_url, img_url)
|
||||
def check_model_new_version_by_path(model_path:str, delay:float=1) -> tuple:
|
||||
|
|
@ -603,10 +600,46 @@ def check_models_new_version_by_model_types(model_types:list, delay:float=1) ->
|
|||
# add to list
|
||||
new_versions.append(r)
|
||||
|
||||
|
||||
|
||||
|
||||
return new_versions
|
||||
|
||||
|
||||
# delete model file by model type and search_term
|
||||
# parameter: model_type, search_term
|
||||
# return: delete result
|
||||
def delete_model_by_search_term(model_type:str, search_term:str):
|
||||
if model_type not in model.folders.keys():
|
||||
msg = f"unknow model type: {model_type}"
|
||||
util.printD(msg)
|
||||
return
|
||||
|
||||
model_type_key = {k for k in model_type_dict if model_type_dict[k] == model_type}
|
||||
util.printD(f"Find {model_type_key} model file: '{search_term}'")
|
||||
|
||||
# search_term = subfolderpath + model name + ext. And it always start with a / even there is no sub folder
|
||||
base, ext = os.path.splitext(search_term)
|
||||
model_info_base = base
|
||||
if base[:1] == "/":
|
||||
model_info_base = base[1:]
|
||||
|
||||
# find 3 kinds of files: .model.info, .safetensor and .priview.jpeg
|
||||
model_folder = model.folders[model_type]
|
||||
model_info_filename = model_info_base + suffix + model.info_ext
|
||||
model_info_filepath = os.path.join(model_folder, model_info_filename)
|
||||
|
||||
model_image_filepath = os.path.join(model_folder, model_info_base + ".preview.png")
|
||||
model_filename = model_folder + search_term
|
||||
|
||||
if os.path.isfile(model_info_filepath):
|
||||
os.remove(model_info_filepath)
|
||||
|
||||
if os.path.isfile(model_image_filepath):
|
||||
os.remove(model_image_filepath)
|
||||
|
||||
result = False
|
||||
if os.path.isfile(model_filename):
|
||||
os.remove(model_filename)
|
||||
result = True
|
||||
else:
|
||||
print("Error: Model file: %s not found" % model_filename)
|
||||
|
||||
return result
|
||||
|
|
|
|||
|
|
@ -10,6 +10,13 @@ dl_ext = ".downloading"
|
|||
# disable ssl warning info
|
||||
requests.packages.urllib3.disable_warnings()
|
||||
|
||||
def human_readable_size(size, decimal_places=2):
|
||||
for unit in ['B', 'KB', 'MB', 'GB', 'TB', 'PB']:
|
||||
if size < 1024.0 or unit == 'PiB':
|
||||
break
|
||||
size /= 1024.0
|
||||
return f"{size:.{decimal_places}f} {unit}"
|
||||
|
||||
# output is downloaded file path
|
||||
def dl(url, folder, filename, filepath):
|
||||
util.printD("Start downloading from: " + url)
|
||||
|
|
@ -35,7 +42,7 @@ def dl(url, folder, filename, filepath):
|
|||
# get file size
|
||||
total_size = 0
|
||||
total_size = int(rh.headers['Content-Length'])
|
||||
util.printD(f"File size: {total_size}")
|
||||
util.printD(f"File size: {human_readable_size(total_size)}")
|
||||
|
||||
# if file_path is empty, need to get file name from download url's header
|
||||
if not file_path:
|
||||
|
|
@ -65,7 +72,7 @@ def dl(url, folder, filename, filepath):
|
|||
count = 2
|
||||
new_base = base
|
||||
while os.path.isfile(file_path):
|
||||
util.printD("Target file already exist.")
|
||||
util.printD("Target file'" + file_path + "'already exist.")
|
||||
# re-name
|
||||
new_base = base + "_" + str(count)
|
||||
file_path = new_base + ext
|
||||
|
|
@ -81,8 +88,8 @@ def dl(url, folder, filename, filepath):
|
|||
downloaded_size = 0
|
||||
if os.path.exists(dl_file_path):
|
||||
downloaded_size = os.path.getsize(dl_file_path)
|
||||
|
||||
util.printD(f"Downloaded size: {downloaded_size}")
|
||||
if downloaded_size > 0:
|
||||
util.printD(f"Downloaded size: {downloaded_size}")
|
||||
|
||||
# create header range
|
||||
headers = {'Range': 'bytes=%d-' % downloaded_size}
|
||||
|
|
@ -101,15 +108,15 @@ def dl(url, folder, filename, filepath):
|
|||
f.flush()
|
||||
|
||||
# progress
|
||||
progress = int(50 * downloaded_size / total_size)
|
||||
progress = int(100 * downloaded_size / total_size)
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
sys.stdout.write("\r[%s%s] %d%%" % ('-' * progress, ' ' * (50 - progress), 100 * downloaded_size / total_size))
|
||||
sys.stdout.write("\r[%s%s] %d%%" % ('=' * progress, ' ' * (100 - progress), 100 * downloaded_size / total_size))
|
||||
sys.stdout.flush()
|
||||
|
||||
print()
|
||||
|
||||
# rename file
|
||||
os.rename(dl_file_path, file_path)
|
||||
util.printD(f"File Downloaded to: {file_path}")
|
||||
util.printD(f"File save to: {file_path}")
|
||||
return file_path
|
||||
|
||||
|
|
|
|||
|
|
@ -175,6 +175,18 @@ def use_preview_image_prompt(msg):
|
|||
|
||||
return [preview_prompt, preview_neg_prompt, preview_prompt, preview_neg_prompt]
|
||||
|
||||
def delete_model(msg):
|
||||
util.printD("Start delete_model")
|
||||
|
||||
result = msg_handler.parse_js_msg(msg)
|
||||
if not result:
|
||||
util.printD("Parsing js ms failed")
|
||||
return
|
||||
|
||||
model_type = result["model_type"]
|
||||
search_term = result["search_term"]
|
||||
result = civitai.delete_model_by_search_term(model_type, search_term)
|
||||
return json.dumps({"result": result})
|
||||
|
||||
# download model's new verson by model path, version id and download url
|
||||
# output is a md log
|
||||
|
|
@ -251,6 +263,6 @@ def dl_model_new_version(msg, max_size_preview, skip_nsfw_preview):
|
|||
# then, get preview image
|
||||
civitai.get_preview_image_by_model_path(new_model_path, max_size_preview, skip_nsfw_preview)
|
||||
|
||||
output = "Done. Model downloaded to: " + new_model_path
|
||||
output = "Done, model save to: " + new_model_path
|
||||
util.printD(output)
|
||||
return output
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ folders = {
|
|||
"hyper": os.path.join(root_path, "models", "hypernetworks"),
|
||||
"ckp": os.path.join(root_path, "models", "Stable-diffusion"),
|
||||
"lora": os.path.join(root_path, "models", "Lora"),
|
||||
"lycoris": os.path.join(root_path, "models", "LyCORIS"),
|
||||
}
|
||||
|
||||
exts = (".bin", ".pt", ".safetensors", ".ckpt")
|
||||
|
|
@ -48,7 +49,7 @@ def get_custom_model_folder():
|
|||
|
||||
# write model info to file
|
||||
def write_model_info(path, model_info):
|
||||
util.printD("Write model info to file: " + path)
|
||||
util.printD("Write model info to: " + path)
|
||||
with open(os.path.realpath(path), 'w') as f:
|
||||
f.write(json.dumps(model_info, indent=4))
|
||||
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ def get_model_info_by_url(model_url_or_id:str) -> tuple:
|
|||
subfolders = []
|
||||
|
||||
# add default root folder
|
||||
subfolders.append("/")
|
||||
subfolders.append(os.sep)
|
||||
|
||||
util.printD("Get following info for downloading:")
|
||||
util.printD(f"model_name:{model_name}")
|
||||
|
|
@ -436,41 +436,29 @@ def dl_model_by_input(model_info:dict, model_type:str, subfolder_str:str, versio
|
|||
util.printD(output)
|
||||
return output
|
||||
|
||||
version_id = ver_info["id"]
|
||||
|
||||
|
||||
modelVersions = model_info['modelVersions']
|
||||
if dl_all_bool:
|
||||
# get all download url from files info
|
||||
# some model versions have multiple files
|
||||
download_urls = []
|
||||
if "files" in ver_info.keys():
|
||||
for file_info in ver_info["files"]:
|
||||
if "downloadUrl" in file_info.keys():
|
||||
download_urls.append(file_info["downloadUrl"])
|
||||
|
||||
if not len(download_urls):
|
||||
if "downloadUrl" in ver_info.keys():
|
||||
download_urls.append(ver_info["downloadUrl"])
|
||||
|
||||
|
||||
# check if this model is already existed
|
||||
r = civitai.search_local_model_info_by_version_id(model_folder, version_id)
|
||||
if r:
|
||||
output = "This model version is already existed"
|
||||
util.printD(output)
|
||||
return output
|
||||
|
||||
# download
|
||||
filepath = ""
|
||||
for url in download_urls:
|
||||
model_filepath = downloader.dl(url, model_folder, None, None)
|
||||
if not model_filepath:
|
||||
idx = 0
|
||||
for modelVer in modelVersions:
|
||||
# check if this model is already existed
|
||||
r = civitai.search_local_model_info_by_version_id(model_folder, modelVer["id"])
|
||||
if r:
|
||||
util.printD("Model file: '" + r["files"][0]["name"] + "' already existed, skiping it.")
|
||||
continue
|
||||
|
||||
filepath = downloader.dl(modelVer["downloadUrl"], model_folder, None, None)
|
||||
if not filepath:
|
||||
output = "Downloading failed, check console log for detail"
|
||||
util.printD(output)
|
||||
return output
|
||||
continue
|
||||
|
||||
if url == ver_info["downloadUrl"]:
|
||||
filepath = model_filepath
|
||||
idx = idx + 1
|
||||
save_info_and_preview_image(filepath, modelVer, max_size_preview, skip_nsfw_preview)
|
||||
util.printD(str(idx) + " of " + str(len(modelVersions)) + " files downloaded, save to: " + filepath)
|
||||
|
||||
output = "Done, " + str(idx) + "/" + str(len(modelVersions)) + " files downloaded"
|
||||
else:
|
||||
# only download one file
|
||||
# get download url
|
||||
|
|
@ -487,17 +475,18 @@ def dl_model_by_input(model_info:dict, model_type:str, subfolder_str:str, versio
|
|||
util.printD(output)
|
||||
return output
|
||||
|
||||
# get version info
|
||||
version_info = [mv for mv in modelVersions if mv["id"] == ver_info["id"]][0]
|
||||
if not version_info:
|
||||
output = "Model downloaded, but failed to get version info, check console log for detail. Model saved to: " + filepath
|
||||
util.printD(output)
|
||||
return output
|
||||
|
||||
if not filepath:
|
||||
filepath = model_filepath
|
||||
output = save_info_and_preview_image(filepath, version_info, max_size_preview, skip_nsfw_preview)
|
||||
|
||||
# get version info
|
||||
version_info = civitai.get_version_info_by_version_id(version_id)
|
||||
if not version_info:
|
||||
output = "Model downloaded, but failed to get version info, check console log for detail. Model saved to: " + filepath
|
||||
util.printD(output)
|
||||
return output
|
||||
return output
|
||||
|
||||
def save_info_and_preview_image(filepath:str, version_info:dict, max_size_preview:bool, skip_nsfw_preview:bool):
|
||||
# write version info to file
|
||||
base, ext = os.path.splitext(filepath)
|
||||
info_file = base + civitai.suffix + model.info_ext
|
||||
|
|
@ -506,6 +495,7 @@ def dl_model_by_input(model_info:dict, model_type:str, subfolder_str:str, versio
|
|||
# then, get preview image
|
||||
civitai.get_preview_image_by_model_path(filepath, max_size_preview, skip_nsfw_preview)
|
||||
|
||||
output = "Done. Model downloaded to: " + filepath
|
||||
output = "Done, model save to: " + filepath
|
||||
util.printD(output)
|
||||
|
||||
return output
|
||||
|
|
@ -4,7 +4,7 @@ import json
|
|||
from . import util
|
||||
|
||||
# action list
|
||||
js_actions = ("open_url", "add_trigger_words", "use_preview_prompt", "dl_model_new_version")
|
||||
js_actions = ("open_url", "add_trigger_words", "use_preview_prompt", "delete_model", "dl_model_new_version")
|
||||
py_actions = ("open_url")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ def download_file(url, path):
|
|||
r.raw.decode_content = True
|
||||
shutil.copyfileobj(r.raw, f)
|
||||
|
||||
printD("File downloaded to: " + path)
|
||||
printD("File save to: " + path)
|
||||
|
||||
# get subfolder list
|
||||
def get_subfolders(folder:str) -> list:
|
||||
|
|
|
|||
|
|
@ -81,7 +81,9 @@ def on_ui_tabs():
|
|||
if r:
|
||||
model_info, model_name, model_type, subfolders, version_strs = r
|
||||
|
||||
return [model_info, model_name, model_type, dl_subfolder_drop.update(choices=subfolders), dl_version_drop.update(choices=version_strs)]
|
||||
value = os.sep if len(subfolders) == 1 else ""
|
||||
|
||||
return [model_info, model_name, model_type, dl_subfolder_drop.update(choices=subfolders, value=value), dl_version_drop.update(choices=version_strs, value=version_strs[0])]
|
||||
|
||||
# ====UI====
|
||||
with gr.Blocks(analytics_enabled=False) as civitai_helper:
|
||||
|
|
@ -133,7 +135,7 @@ def on_ui_tabs():
|
|||
with gr.Box(elem_classes="ch_box"):
|
||||
with gr.Column():
|
||||
gr.Markdown("### Download Model")
|
||||
with gr.Row():
|
||||
with gr.Row(elem_id="model_download_url_txt"):
|
||||
dl_model_url_or_id_txtbox = gr.Textbox(label="Civitai URL", lines=1, value="")
|
||||
dl_model_info_btn = gr.Button(value="1. Get Model Info by Civitai Url", variant="primary")
|
||||
|
||||
|
|
@ -181,6 +183,7 @@ def on_ui_tabs():
|
|||
js_open_url_btn = gr.Button(value="Open Model Url", visible=False, elem_id="ch_js_open_url_btn")
|
||||
js_add_trigger_words_btn = gr.Button(value="Add Trigger Words", visible=False, elem_id="ch_js_add_trigger_words_btn")
|
||||
js_use_preview_prompt_btn = gr.Button(value="Use Prompt from Preview Image", visible=False, elem_id="ch_js_use_preview_prompt_btn")
|
||||
js_use_delete_model_btn = gr.Button(value="Delete Model", visible=False, elem_id="ch_js_delete_model_btn")
|
||||
js_dl_model_new_version_btn = gr.Button(value="Download Model's new version", visible=False, elem_id="ch_js_dl_model_new_version_btn")
|
||||
|
||||
# ====events====
|
||||
|
|
@ -207,6 +210,7 @@ def on_ui_tabs():
|
|||
js_open_url_btn.click(js_action_civitai.open_model_url, inputs=[js_msg_txtbox, open_url_with_js_ckb], outputs=py_msg_txtbox)
|
||||
js_add_trigger_words_btn.click(js_action_civitai.add_trigger_words, inputs=[js_msg_txtbox], outputs=[txt2img_prompt, img2img_prompt])
|
||||
js_use_preview_prompt_btn.click(js_action_civitai.use_preview_image_prompt, inputs=[js_msg_txtbox], outputs=[txt2img_prompt, txt2img_neg_prompt, img2img_prompt, img2img_neg_prompt])
|
||||
js_use_delete_model_btn.click(js_action_civitai.delete_model, inputs=[js_msg_txtbox], outputs=[py_msg_txtbox])
|
||||
js_dl_model_new_version_btn.click(js_action_civitai.dl_model_new_version, inputs=[js_msg_txtbox, max_size_preview_ckb, skip_nsfw_preview_ckb], outputs=dl_log_md)
|
||||
|
||||
# the third parameter is the element id on html, with a "tab_" as prefix
|
||||
|
|
|
|||
42
style.css
42
style.css
|
|
@ -2,17 +2,51 @@ blockquote ul {
|
|||
list-style:disc;
|
||||
margin:4px 40px;
|
||||
}
|
||||
|
||||
blockquote ol {
|
||||
list-style:decimal;
|
||||
margin:4px 40px;
|
||||
}
|
||||
|
||||
.block.padded.ch_box {
|
||||
padding: 10px !important;
|
||||
}
|
||||
|
||||
.block.padded.ch_vpadding {
|
||||
padding: 10px 0 !important;
|
||||
}
|
||||
|
||||
.civitai-helper-action {
|
||||
font-size: 1.8em;
|
||||
line-height: 1;
|
||||
vertical-align: middle;
|
||||
opacity: .7;
|
||||
}
|
||||
.civitai-helper-action:hover {
|
||||
filter: drop-shadow(2px 4px 6px black);
|
||||
opacity: 1;
|
||||
}
|
||||
.extra-network-cards .civitai-helper-action:nth-child(2) {
|
||||
margin: 0 .1em 0 .15em;
|
||||
font-size: 3em;
|
||||
}
|
||||
.extra-network-thumbs .card {
|
||||
height: 8rem !important;
|
||||
width: 8rem !important;
|
||||
}
|
||||
.extra-network-thumbs .civitai-helper-action {
|
||||
background-image: none !important;
|
||||
display: inline-block !important;
|
||||
position: static !important;
|
||||
font-size: 1.25em !important;
|
||||
line-height: 1.25em;
|
||||
}
|
||||
.extra-network-thumbs .civitai-helper-action:nth-child(2) {
|
||||
font-size: 2em !important;
|
||||
height: 1.35em !important;
|
||||
margin-left: 0.25em;
|
||||
}
|
||||
.extra-network-thumbs .card ul {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 2em;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
Loading…
Reference in New Issue