diff --git a/README.cn.md b/README.cn.md
index 16520d5..64e0b14 100644
--- a/README.cn.md
+++ b/README.cn.md
@@ -3,23 +3,31 @@ Stable Diffusion Webui 扩展Civitai助手,用于更轻松的管理和使用Ci
[Civitai Url](https://civitai.com/models/16768/civitai-helper-sd-webui-civitai-extension)
+# 注意
+在安装或更新新版本之后,需要整个关闭SD Webui,重新启动它。光是Reload UI对本插件不起作用。
+
# 功能
* 扫描所有模型,从Civitai下载模型信息和预览图
-* 通过civitai模型的页面url,连接一个本地模型和civitai模型的信息
+* 通过civitai模型页面url,连接本地模型和civitai模型信息
+* 通过Civitai模型页面url,下载模型(含信息和预览图)到SD目录或子目录。
+* 下载支持断点续传
* 批量检查本地模型,在civitai上的新版本
+* 直接下载新版本模型到SD模型目录内(含信息和预览图)
* 修改了内置的"Extra Network"模型卡片,每个卡片增加了如下功能按钮:
- 🖼: 修改文字"replace preview"为这个图标
- 🌐: 在新标签页打开这个模型的Civitai页面
- 💡: 一键添加这个模型的触发词到关键词输入框
- 🏷: 一键使用这个模型预览图所使用的关键词
+* 以上额外功能按钮支持thumbnail模式
+* 增加一直显示按钮的选项,以供触屏用户使用
+
# 安装
下载本项目为zip文件,解压到`你的SD webui目录/extensions`下即可。
-然后使用设置页面的"Reload UI"按钮重新加载UI。
+然后整个关闭SD Webui,重新启动它。只是Reload UI不起作用。以后更新也是,必须重启SD Webui。
-(不了解git的国内用户,请勿通过SD webui的插件界面安装或升级。
-它安装的时候,是调用你本地的git命令行工具来下载,不是通过浏览器下载。你的git工具没有配置过代理和SSL的话,就会下载失败)
+(如果用SD webui的插件界面安装,请先给git配置代理。它不是通过浏览器下载,是通过git下载。)
# 使用方法
@@ -67,12 +75,19 @@ Stable Diffusion Webui 扩展Civitai助手,用于更轻松的管理和使用Ci
每次当Extra Network刷新,他都会删除掉额外的修改,我们的按钮就会消失。这时你就需要点击`Refresh Civitai Helper`把这些功能添加回去。
-## 根据URL获取1个模型信息
-如果无法在civitai上找到你的模型的SHA256,但你还是希望能把你的模型连接到一个civitai模型,你可以在本扩展页面,从列表中选择你的模型,并提供一个civitai模型页面的url。
+### 小图模式
+以上功能按钮支持小图模式,但受制于SD Webui的CSS问题,目前,只能要么一直显示,要么一直不显示,不能鼠标滑过才显示。
+
-点击按钮之后,扩展就会下载那个civitai模型的信息,作为你这个本地模型的信息使用。
+## 下载
+通过Civitai模型页面Url下载模型,要3个步骤:
+* 填入url,点击按钮获取模型信息
+* 扩展会自动填入模型名称和类型,你需要选择下载的子目录和模型版本。
+* 点击下载
+
-
+下载过程会显示在命令行界面带个进度条。
+支持断点续传,无畏大文件。
## 批量检查模型新版本
@@ -85,10 +100,30 @@ Stable Diffusion Webui 扩展Civitai助手,用于更轻松的管理和使用Ci
**检查完毕之后**,就会如下图,在UI上显示所有找到的新版本的信息。
-每个模型新版本,都有2个链接。第一个是这个模型的网页。第二个是这个新版本的下载地址。
+每个模型新版本,都有3个链接。
+* 第一个是这个模型的网页。
+* 第二个是这个新版本的下载地址。
+* 第三个是个按钮,在python端,直接下载新版本到模型目录内。
+这种方式下载,下载详情显示在"Download Model"的区域和命令行窗口中。一次一个任务,不支持多任务。

+
+## 根据URL获取模型信息
+如果无法在civitai上找到你的模型的SHA256,但你还是希望能把你的模型连接到一个civitai模型,你可以在本扩展页面,从列表中选择你的模型,并提供一个civitai模型页面的url。
+
+点击按钮之后,扩展就会下载那个civitai模型的信息,作为你这个本地模型的信息使用。
+
+
+
+
+## 其他设置
+**保存设置按钮, 会保存扫描模型区域,以及其他设置 这两个区域的选项**
+
+* "一直显示按钮" 是为了方便触屏。
+* "小图模式显示功能按钮" 会开关功能按钮在小图模式的显示
+
+
## 预览图
Extra Network支持两种预览图命名:`model_name.png` 和 `model_name.preview.png`。其中,`model_name.png`优先级较高。
@@ -116,14 +151,20 @@ civitai不是每个图片都有关键词,一个模型中,也不是所有预
-## Civitai本身挂掉
+## Civitai API失效
Civitai在面临类似DDos的问题的时候,会把整个网站立刻置于Cloudflare验证机制的保护下,包括API的接口。于是,API请求,就会被跳转到Cloudflare的真人验证页面而无法获取任何信息。
-这种情况,请耐心等待Civitai恢复之后,再使用需要连接Civitai的功能。根据以往经验,每次Civitai这样折腾一轮要6-8小时。
+这种情况,请耐心等待Civitai恢复之后,再连接Civitai。根据以往经验,每次Civitai这样折腾一轮要6-8小时。
+## 新特性
+从v1.5开始,v1.x不再接受任何新特性。所有新特性进入2.x。
-Enjoy!
+2.x专注于自定义模型信息,并可能改名为"Model Info Helper"。因为不再是专注Civitai了。
+
+从v1.5开始。v1.x进入维护阶段。
+
+Enjoy!
diff --git a/README.md b/README.md
index 41ac7da..1f929e1 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
[中文](README.cn.md)
# Notice
-After updating to new version, you need to shutdown SD webui and re-launch. Just Reload UI won't work!
+After install or update to new version, you need to shutdown SD webui and re-launch. Just Reload UI won't work!
# Stable-Diffusion-Webui-Civitai-Helper
Stable Diffusion Webui Extension for Civitai, to handle your models much more easily.
@@ -12,21 +12,26 @@ Civitai: [Civitai Url](https://civitai.com/models/16768/civitai-helper-sd-webui-
# Features
* Scans all models to download model information and preview images from Civitai.
* Link 1 model to a civitai model by civitai model's url
-* Checking all your local model's new version from civitai
+* Download a model(with info+preview) by Civitai Url into SD's model folder or subfolder.
+* Downloading can resume from break-point, which is good for large file.
+* Checking all your local model's new version from Civitai
+* Download a new version directly into SD model folder (with info+preview)
* Modified Built-in "Extra Network" cards, to add the following buttons on each card:
- 🖼: 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
+* Also support thumbnail mode of Extra Network
+* Option to always show addtional buttons, so now they work with touch screen.
# Install
Go to SD webui's extension tab, go to `Install from url` sub-tab.
-Copy this project's url into it, click install.
+Copy this project's url into it, click install.
Alternatively, download this project as a zip file, and unzip it to `Your SD webui folder/extensions`.
-Then reload UI with "Reload UI" Button in Setting tab.
+Then shutdown SD Webui and Relaunch it. Just "Reload UI" won't work for this extension.
Done.
@@ -74,13 +79,20 @@ Move your mouse on to the bottom of a model card. It will show 4 icon buttons:

Everytime after Extra Network tab refreshed, it will remove all these additional buttons. So, you need to click `Refresh Civitai Helper` button to bring them back.
-## Get 1 Model Info By Url
-If a model's SHA256 can not be found in civitai, but you still want to link it to a civitai model. You can choose this model from list, then offer a civitai model page's url you want to link.
+### Thumbnail Mode
+Additional buttons work on thumbnail too, but due to SD webui's CSS issue, for now, they must be always displayed on thumbnail or don't display at all.
+
-After clicking button, extension will download that civitai model's model info for this local model file you picked.
-
+## Download
+To download a model by Civitai Model Page's Url, you need 3 steps:
+* Fill url, click button to get model info
+* It will show model name and type automatically. Just choose sub-folder and model version
+* Click download.
+
+Detail will be displayed on console log, with a progress bar.
+Downloading can resume from break-point, so no fear for large file.
## Checking Model's New Version
You can checking your local model's new version from civitai by model types. You can select multiple model types.
@@ -92,47 +104,74 @@ This is to protect Civitai from facing issue like DDos from this extension. Some
**After checking process done**, it will display all new version's information on UI.
-There are 2 urls for each new version. First one is model's page. Second one is this version's download url.
+There are 3 urls for each new version.
+* First one is model's page.
+* Second one is new version's download url.
+* Third one is a button to download it into your SD's model folder with python.
+With this one, output information is on "Download Model" section's log and console log. One task at a time.

+## Get Model Info By Url
+If a model's SHA256 can not be found in civitai, but you still want to link it to a civitai model. You can choose this model from list, then offer a civitai model page's url you want to link.
+
+After clicking button, extension will download that civitai model's model info for this local model file you picked.
+
+
+
+## Other Setting
+**The Save Setting button, will save both "Scan Model"'s setting and other setting.**
+
+* "Always Display Button" is good for touch screen.
+* "Show Buttons on Thumb Mode" will turn on/off additional Buttons on thumbnail.
+
+
+
## Preview Image
Extra network uses both `model_file.png` and `model_file.preview.png` as preview image. But `model_file.png` has higher priority, because it is created by yourself.
When you don't have the higher priority one, it will use the other automatically.
## Prompt
-When you click the button "Use prompt from preview image", it does not use the prompt from your own preview image. It uses the one from civitai's preview image.
+When you click the button "Use prompt from preview image", it does not use the prompt from your own preview image. It uses the one from civitai's preview image.
On civitai, a model's preview images may not has prompt. This extension will check this model's all civitai preview images' information and use the first one has prompt in it.
## SHA256
-To create a file SHA256, it need to read the whole file to generate a hash code. It gonna be slow for big files.
+To create a file SHA256, it need to read the whole file to generate a hash code. It gonna be slow for large files.
-Default, it uses a Memory Optimized SHA256 which won't stuck your system.(It is the only choice in latest version). So, do not uncheck it if you want to use your computer when scanning.
+Also, extension uses Memory Optimized SHA256, which won't stuck your system and works with colab.
There are 2 cases this hash code can not find the model on civitai:
* Some old models, which do not have SHA256 code on civitai.
-* The model's owner changed file on civitai, but does not change version number and description. So, the file on civitai is actually not the one on your manchine.
+* The model's owner changed file on civitai, but does not change version name and description. So, the file on civitai is actually not the one on your manchine.
In these cases, you can always link a model to civitai by filling its URL in this extension.
-## Civitai down
+## Civitai API Fail
When Civitai is facing some issue like DDos, it gonna put civitai under Cloudflare's protection, which gonna re-direct our API request to a real human checking page. Then this extension can not get any information back.
In that case, juse wait for civitai's recovering. It could take 6-8 hours.
+
+## Feature Request
+No new feature for v1.x after v1.5. All new feature will go to 2.x.
+
+2.x will focus on custom model information and may change name to "Model Info Helper", because it is not just focus on Civitai anymore.
+
+From v1.5, v1.x goes into maintenance phase.
+
Enjoy!
-
# Change Log
-## v1.5
+## v1.5.0
+* Download a model by Civitai model page's url
+* Resume downloading from break-point
+* Download new version into SD Webui's model folder
* Addtional button now works on thumbnail mode
-* Add option to always show addtion button, for touch screen.
-* Download a model by model page's url into SD webui's model folder
-* Display checking new version's result as gallery and download new version into SD Webui's model folder
+* Option to always show addtion button, for touch screen.
## v1.4.2
* ignore .vae file in model folder when scanning
diff --git a/img/check_model_new_version_output.jpg b/img/check_model_new_version_output.jpg
index e0fde2e..47761f7 100644
Binary files a/img/check_model_new_version_output.jpg and b/img/check_model_new_version_output.jpg differ
diff --git a/img/download_model.jpg b/img/download_model.jpg
new file mode 100644
index 0000000..f6c052c
Binary files /dev/null and b/img/download_model.jpg differ
diff --git a/img/other_setting.jpg b/img/other_setting.jpg
new file mode 100644
index 0000000..9b9a342
Binary files /dev/null and b/img/other_setting.jpg differ
diff --git a/img/thumb_mode.jpg b/img/thumb_mode.jpg
new file mode 100644
index 0000000..1044e68
Binary files /dev/null and b/img/thumb_mode.jpg differ
diff --git a/javascript/civitai_helper.js b/javascript/civitai_helper.js
index ae5444b..25eff3e 100644
--- a/javascript/civitai_helper.js
+++ b/javascript/civitai_helper.js
@@ -1,5 +1,19 @@
"use strict";
+// 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")
+ 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(){
@@ -17,9 +31,8 @@ function get_ch_py_msg(){
// get msg from python side from a hidden textbox
-// if textbox's value is different from old value then it will consider it is a new msg
// it will try once in every sencond, until it reach the max try times
-const get_new_ch_py_msg = (old_value, max_count=3) => new Promise((resolve, reject) => {
+const get_new_ch_py_msg = (max_count=3) => new Promise((resolve, reject) => {
console.log("run get_new_ch_py_msg")
let count = 0;
@@ -35,15 +48,23 @@ const get_new_ch_py_msg = (old_value, max_count=3) => new Promise((resolve, reje
console.log(py_msg_txtbox.value)
new_msg = py_msg_txtbox.value
- if (new_msg != old_value) {
+ if (new_msg != "") {
find_msg=true
}
}
if (find_msg) {
+ //clear msg in both sides
+ py_msg_txtbox.value = "";
+ py_msg_txtbox.dispatchEvent(new Event("input"));
+
resolve(new_msg);
clearInterval(interval);
} else if (count > max_count) {
+ //clear msg in both sides
+ py_msg_txtbox.value = "";
+ py_msg_txtbox.dispatchEvent(new Event("input"));
+
reject('');
clearInterval(interval);
}
@@ -51,6 +72,9 @@ const get_new_ch_py_msg = (old_value, max_count=3) => new Promise((resolve, reje
}, 1000);
})
+
+
+
function getActivePrompt() {
const currentTab = get_uiCurrentTabContent();
switch (currentTab.id) {
@@ -79,8 +103,10 @@ async function open_model_url(event, model_type, search_term){
console.log("start open_model_url");
//get hidden components of extension
- let js_msg_txtbox = gradioApp().querySelector("#ch_js_msg_txtbox textarea");
let js_open_url_btn = gradioApp().getElementById("ch_js_open_url_btn");
+ if (!js_open_url_btn) {
+ return
+ }
//msg to python side
@@ -100,11 +126,7 @@ async function open_model_url(event, model_type, search_term){
msg["neg_prompt"] = "";
// fill to msg box
- js_msg_txtbox.value = JSON.stringify(msg);
- js_msg_txtbox.dispatchEvent(new Event("input"));
-
- //get old py msg
- let py_msg = get_ch_py_msg();
+ send_ch_py_msg(msg)
//click hidden button
js_open_url_btn.click();
@@ -114,7 +136,7 @@ async function open_model_url(event, model_type, search_term){
event.preventDefault()
//check response msg from python
- let new_py_msg = await get_new_ch_py_msg("");
+ let new_py_msg = await get_new_ch_py_msg();
console.log("new_py_msg:");
console.log(new_py_msg);
@@ -142,9 +164,10 @@ function add_trigger_words(event, model_type, search_term){
console.log("start add_trigger_words");
//get hidden components of extension
- let js_msg_txtbox = gradioApp().querySelector("#ch_js_msg_txtbox textarea");
let js_add_trigger_words_btn = gradioApp().getElementById("ch_js_add_trigger_words_btn");
-
+ if (!js_add_trigger_words_btn) {
+ return
+ }
//msg to python side
@@ -166,8 +189,7 @@ function add_trigger_words(event, model_type, search_term){
msg["prompt"] = prompt.value;
// fill to msg box
- js_msg_txtbox.value = JSON.stringify(msg);
- js_msg_txtbox.dispatchEvent(new Event("input"));
+ send_ch_py_msg(msg)
//click hidden button
js_add_trigger_words_btn.click();
@@ -184,10 +206,10 @@ function use_preview_prompt(event, model_type, search_term){
console.log("start use_preview_prompt");
//get hidden components of extension
- let js_msg_txtbox = gradioApp().querySelector("#ch_js_msg_txtbox textarea");
let js_use_preview_prompt_btn = gradioApp().getElementById("ch_js_use_preview_prompt_btn");
-
-
+ if (!js_use_preview_prompt_btn) {
+ return
+ }
//msg to python side
let msg = {
@@ -211,8 +233,7 @@ function use_preview_prompt(event, model_type, search_term){
msg["neg_prompt"] = neg_prompt.value;
// fill to msg box
- js_msg_txtbox.value = JSON.stringify(msg);
- js_msg_txtbox.dispatchEvent(new Event("input"));
+ send_ch_py_msg(msg)
//click hidden button
js_use_preview_prompt_btn.click();
@@ -225,6 +246,51 @@ function use_preview_prompt(event, model_type, search_term){
}
+
+// download model's new version into SD at python side
+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
+ let dl_confirm = "\nConfirm to download.\n\nCheck Download Model Section's log and console log for detail.";
+ if (!confirm(dl_confirm)) {
+ return
+ }
+
+ //get hidden components of extension
+ let js_dl_model_new_version_btn = gradioApp().getElementById("ch_js_dl_model_new_version_btn");
+ if (!js_dl_model_new_version_btn) {
+ return
+ }
+
+ //msg to python side
+ let msg = {
+ "action": "",
+ "model_path": "",
+ "version_id": "",
+ "download_url": "",
+ }
+
+ msg["action"] = "dl_model_new_version";
+ msg["model_path"] = model_path;
+ msg["version_id"] = version_id;
+ msg["download_url"] = download_url;
+
+ // fill to msg box
+ send_ch_py_msg(msg)
+
+ //click hidden button
+ js_dl_model_new_version_btn.click();
+
+ console.log("end dl_model_new_version");
+
+ event.stopPropagation()
+ event.preventDefault()
+
+
+}
+
+
onUiLoaded(() => {
diff --git a/scripts/civitai_helper.py b/scripts/civitai_helper.py
index d598516..dedb7ba 100644
--- a/scripts/civitai_helper.py
+++ b/scripts/civitai_helper.py
@@ -35,7 +35,6 @@ def on_ui_tabs():
# init
# get prompt textarea
- # UI structure
# check modules/ui.py, search for txt2img_paste_fields
# Negative prompt is the second element
txt2img_prompt = modules.ui.txt2img_paste_fields[0][0]
@@ -49,6 +48,18 @@ def on_ui_tabs():
return model_name_drop.update(choices=names)
+ def get_model_info_by_url(url):
+ r = model_action_civitai.get_model_info_by_url(url)
+
+ model_info = {}
+ model_name = ""
+ model_type = ""
+ subfolders = []
+ version_strs = []
+ 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)]
# ====UI====
# with gr.Blocks(analytics_enabled=False) as civitai_helper:
@@ -64,6 +75,10 @@ def on_ui_tabs():
model_types = list(model.folders.keys())
no_info_model_names = civitai.get_model_names_by_input("ckp", False)
+ # session data
+ dl_model_info = gr.State({})
+
+
# with gr.Tab("Model"):
with gr.Box():
@@ -84,13 +99,30 @@ def on_ui_tabs():
gr.Markdown("### Get Civitai Model Info by Model Page URL")
with gr.Row():
model_type_drop = gr.Dropdown(choices=model_types, label="Model Type", value="ckp", multiselect=False)
- empty_info_only_ckb = gr.Checkbox(label="Only Show Models have no Info file", value=False, elem_id="cn_empty_info_only_ckb")
+ empty_info_only_ckb = gr.Checkbox(label="Only Show Models have no Info", value=False, elem_id="cn_empty_info_only_ckb")
model_name_drop = gr.Dropdown(choices=no_info_model_names, label="Model", value="ckp", multiselect=False)
- model_url_or_id = gr.Textbox(label="Civitai URL or Model ID", lines=1, value="")
+ model_url_or_id_txtbox = gr.Textbox(label="Civitai URL or Model ID", lines=1, value="")
get_civitai_model_info_by_id_btn = gr.Button(value="Get Model Info from Civitai", variant="primary")
get_model_by_id_log_md = gr.Markdown("")
+ with gr.Box():
+ with gr.Column():
+ gr.Markdown("### Download Model")
+ with gr.Row():
+ dl_model_url_or_id_txtbox = gr.Textbox(label="Civitai URL or Model ID", lines=1, value="")
+ dl_model_info_btn = gr.Button(value="1. Get Model Info by Civitai Url", variant="primary")
+
+ gr.Markdown(value="2. Pick Subfolder and Model Version")
+ with gr.Row():
+ dl_model_name_txtbox = gr.Textbox(label="Model Name", interactive=False, lines=1, value="")
+ dl_model_type_txtbox = gr.Textbox(label="Model Type", interactive=False, lines=1, value="")
+ dl_subfolder_drop = gr.Dropdown(choices=[], label="Sub-folder", value="", interactive=True, multiselect=False)
+ dl_version_drop = gr.Dropdown(choices=[], label="Model Version", value="", interactive=True, multiselect=False)
+
+ dl_civitai_model_by_id_btn = gr.Button(value="3. Download Model", variant="primary")
+ dl_log_md = gr.Markdown(value="Check Console log for Downloading Status")
+
with gr.Box():
with gr.Column():
gr.Markdown("### Check models' new version")
@@ -98,19 +130,7 @@ def on_ui_tabs():
model_types_ckbg = gr.CheckboxGroup(choices=model_types, label="Model Types", value=["lora"])
check_models_new_version_btn = gr.Button(value="Check New Version from Civitai", variant="primary")
- check_models_new_version_log_md = gr.Markdown("It takes time, just wait. Check console log for detail")
-
-
- with gr.Box():
- with gr.Column():
- gr.Markdown("### Download Model")
- with gr.Row():
- dl_model_type_drop = gr.Dropdown(choices=model_types, label="Model Type", value="ckp", multiselect=False)
- dl_subfolder_drop = gr.Dropdown(choices=model_types, label="Sub-folder", value="", multiselect=False)
-
- dl_model_url_or_id = gr.Textbox(label="Civitai URL or Model ID", lines=1, value="")
- dl_civitai_model_by_id_btn = gr.Button(value="Download Model from Civitai", variant="primary")
-
+ check_models_new_version_log_md = gr.HTML("It takes time, just wait. Check console log for detail")
with gr.Box():
with gr.Column():
@@ -120,8 +140,8 @@ def on_ui_tabs():
always_display_ckb = gr.Checkbox(label="Always Display Buttons", value=always_display, elem_id="ch_always_display_ckb")
show_btn_on_thumb_ckb = gr.Checkbox(label="Show Button On Thumb Mode", value=show_btn_on_thumb, elem_id="ch_show_btn_on_thumb_ckb")
- save_setting_btn = gr.Button(value="Save Setting", elem_id="ch_save_setting_btn")
- general_log_md = gr.Markdown(value="", elem_id="ch_general_log_md")
+ save_setting_btn = gr.Button(value="Save Setting")
+ general_log_md = gr.Markdown(value="")
# ====Footer====
@@ -130,29 +150,37 @@ def on_ui_tabs():
# ====hidden component for js, not in any tab====
js_msg_txtbox = gr.Textbox(label="Request Msg From Js", visible=False, lines=1, value="", elem_id="ch_js_msg_txtbox")
py_msg_txtbox = gr.Textbox(label="Response Msg From Python", visible=False, lines=1, value="", elem_id="ch_py_msg_txtbox")
+
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_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====
- # Model
+ # Scan Models for Civitai
scan_model_civitai_btn.click(model_action_civitai.scan_model, inputs=[max_size_preview_ckb, skip_nsfw_preview_ckb], outputs=scan_model_log_md)
-
+
+ # Get Civitai Model Info by Model Page URL
model_type_drop.change(get_model_names_by_input, inputs=[model_type_drop, empty_info_only_ckb], outputs=model_name_drop)
empty_info_only_ckb.change(get_model_names_by_input, inputs=[model_type_drop, empty_info_only_ckb], outputs=model_name_drop)
- get_civitai_model_info_by_id_btn.click(model_action_civitai.get_model_info_by_input, inputs=[model_type_drop, model_name_drop, model_url_or_id, max_size_preview_ckb, skip_nsfw_preview_ckb], outputs=get_model_by_id_log_md)
+ get_civitai_model_info_by_id_btn.click(model_action_civitai.get_model_info_by_input, inputs=[model_type_drop, model_name_drop, model_url_or_id_txtbox, max_size_preview_ckb, skip_nsfw_preview_ckb], outputs=get_model_by_id_log_md)
+ # Download Model
+ dl_model_info_btn.click(get_model_info_by_url, inputs=dl_model_url_or_id_txtbox, outputs=[dl_model_info, dl_model_name_txtbox, dl_model_type_txtbox, dl_subfolder_drop, dl_version_drop])
+ dl_civitai_model_by_id_btn.click(model_action_civitai.dl_model_by_input, inputs=[dl_model_info, dl_model_type_txtbox, dl_subfolder_drop, dl_version_drop, max_size_preview_ckb, skip_nsfw_preview_ckb], outputs=dl_log_md)
+
+ # Check models' new version
check_models_new_version_btn.click(model_action_civitai.check_models_new_version_to_md, inputs=model_types_ckbg, outputs=check_models_new_version_log_md)
-
- # General
+ # Other Setting
save_setting_btn.click(setting.save_from_input, inputs=[max_size_preview_ckb, skip_nsfw_preview_ckb, open_url_with_js_ckb, always_display_ckb, show_btn_on_thumb_ckb], outputs=general_log_md)
# js action
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_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
return (civitai_helper , "Civitai Helper", "civitai_helper"),
diff --git a/scripts/lib/civitai.py b/scripts/lib/civitai.py
index b6493a3..6411d0c 100644
--- a/scripts/lib/civitai.py
+++ b/scripts/lib/civitai.py
@@ -18,6 +18,14 @@ url_dict = {
"hash": "https://civitai.com/api/v1/model-versions/by-hash/"
}
+model_type_dict = {
+ "Checkpoint": "ckp",
+ "TextualInversion": "ti",
+ "Hypernetwork": "hyper",
+ "LORA": "lora",
+}
+
+
# get image with full size
# width is in number, not string
# return: url str
@@ -107,7 +115,7 @@ def get_version_info_by_version_id(id:str) -> dict:
util.printD("id is empty")
return
- r = requests.get(url_dict["modelVersionId"]+id)
+ r = requests.get(url_dict["modelVersionId"]+str(id))
if not r.ok:
if r.status_code == 404:
# this is not a civitai model
@@ -303,7 +311,7 @@ def get_model_id_from_url(url:str) -> str:
# get preview image by model path
# image will be saved to file, so no return
-def get_preview_image_by_model_path(model_path:str, max_size_preview, skip_nsfw_preview) -> str:
+def get_preview_image_by_model_path(model_path:str, max_size_preview, skip_nsfw_preview):
if not model_path:
util.printD("model_path is empty")
return
@@ -599,3 +607,4 @@ def check_models_new_version_by_model_types(model_types:list, delay:float=1) ->
return new_versions
+
diff --git a/scripts/lib/dl_helper.py b/scripts/lib/dl_helper.py
deleted file mode 100644
index adb45fd..0000000
--- a/scripts/lib/dl_helper.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# -*- coding: UTF-8 -*-
-import sys
-import requests
-import os
-import util
-
-
-dl_ext = ".downloading"
-
-# disable ssl warning info
-requests.packages.urllib3.disable_warnings()
-
-def download(url, file_path, size):
- # use a temp file for downloading
- base, ext = os.path.splitext(file_path)
- dl_file_path = os.path.join(base, dl_ext)
-
- total_size = 0
- if size:
- total_size = size
- else:
- # get file size
- rhead = requests.get(url, stream=True, verify=False)
- total_size = int(rhead.headers['Content-Length'])
-
- util.printD(f"File size: {total_size}")
-
- util.printD(f"Downloading to temp file: {dl_file_path}")
-
- # check if downloading file is exsited
- 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}")
-
- # get header range
- headers = {'Range': 'bytes=%d-' % downloaded_size}
- # download with header
- r = requests.get(url, stream=True, verify=False, headers=headers)
-
- # write to file
- with open(file_path, "ab") as f:
- for chunk in r.iter_content(chunk_size=1024):
- if chunk:
- downloaded_size += len(chunk)
- f.write(chunk)
- # force to write to disk
- f.flush()
-
- # progress
- progress = int(50 * downloaded_size / total_size)
- sys.stdout.write("\r[%s%s] %d%%" % ('█' * progress, ' ' * (50 - 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}")
-
diff --git a/scripts/lib/downloader.py b/scripts/lib/downloader.py
new file mode 100644
index 0000000..1bc55db
--- /dev/null
+++ b/scripts/lib/downloader.py
@@ -0,0 +1,102 @@
+# -*- coding: UTF-8 -*-
+import sys
+import requests
+import os
+from . import util
+
+
+dl_ext = ".downloading"
+
+# disable ssl warning info
+requests.packages.urllib3.disable_warnings()
+
+# output is downloaded file path
+def dl(url, folder, filename, filepath):
+ util.printD("Start downloading from: " + url)
+ # get file_path
+ file_path = ""
+ if filepath:
+ file_path = filepath
+ else:
+ # if file_path is not in parameter, then folder must be in parameter
+ if not folder:
+ util.printD("folder is none")
+ return
+
+ if not os.path.isdir(folder):
+ util.printD("folder does not exist: "+folder)
+ return
+
+ if filename:
+ file_path = os.path.join(folder, filename)
+
+ # first request for header
+ rh = requests.get(url, stream=True, verify=False)
+ # get file size
+ total_size = 0
+ total_size = int(rh.headers['Content-Length'])
+ util.printD(f"File size: {total_size}")
+
+ # if file_path is empty, need to get file name from download url's header
+ if not file_path:
+ filename = ""
+ if "Content-Disposition" in rh.headers.keys():
+ cd = rh.headers["Content-Disposition"]
+ # Extract the filename from the header
+ # content of a CD: "attachment;filename=FileName.txt"
+ # in case "" is in CD filename's start and end, need to strip them out
+ filename = cd.split("=")[1].strip('"')
+ if not filename:
+ util.printD("Fail to get file name from Content-Disposition: " + cd)
+ return
+
+ if not filename:
+ util.printD("Can not get file name from download url's header")
+ return
+
+ # with folder and filename, now we have the full file path
+ file_path = os.path.join(folder, filename)
+
+
+ util.printD("Target file path: " + file_path)
+
+ # use a temp file for downloading
+ base, ext = os.path.splitext(file_path)
+ dl_file_path = base+dl_ext
+
+
+ util.printD(f"Downloading to temp file: {dl_file_path}")
+
+ # check if downloading file is exsited
+ 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}")
+
+ # create header range
+ headers = {'Range': 'bytes=%d-' % downloaded_size}
+ # download with header
+ r = requests.get(url, stream=True, verify=False, headers=headers)
+
+ # write to file
+ with open(dl_file_path, "ab") as f:
+ for chunk in r.iter_content(chunk_size=1024):
+ if chunk:
+ downloaded_size += len(chunk)
+ f.write(chunk)
+ # force to write to disk
+ f.flush()
+
+ # progress
+ progress = int(50 * downloaded_size / total_size)
+ sys.stdout.write("\r[%s%s] %d%%" % ('█' * progress, ' ' * (50 - 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}")
+ return file_path
+
diff --git a/scripts/lib/js_action_civitai.py b/scripts/lib/js_action_civitai.py
index 7311cc1..00a9430 100644
--- a/scripts/lib/js_action_civitai.py
+++ b/scripts/lib/js_action_civitai.py
@@ -8,7 +8,7 @@ from . import util
from . import model
from . import civitai
from . import msg_handler
-
+from . import downloader
@@ -23,8 +23,9 @@ def open_model_url(msg, open_url_with_js):
if not result:
util.printD("Parsing js ms failed")
return
-
- action, model_type, search_term, prompt, neg_prompt = result
+
+ model_type = result["model_type"]
+ search_term = result["search_term"]
model_info = civitai.load_model_info_by_search_term(model_type, search_term)
if not model_info:
@@ -73,7 +74,9 @@ def add_trigger_words(msg):
util.printD("Parsing js ms failed")
return
- action, model_type, search_term, prompt, neg_prompt = result
+ model_type = result["model_type"]
+ search_term = result["search_term"]
+ prompt = result["prompt"]
model_info = civitai.load_model_info_by_search_term(model_type, search_term)
@@ -122,7 +125,10 @@ def use_preview_image_prompt(msg):
util.printD("Parsing js ms failed")
return
- action, model_type, search_term, prompt, neg_prompt = result
+ model_type = result["model_type"]
+ search_term = result["search_term"]
+ prompt = result["prompt"]
+ neg_prompt = result["neg_prompt"]
model_info = civitai.load_model_info_by_search_term(model_type, search_term)
@@ -170,3 +176,73 @@ def use_preview_image_prompt(msg):
return [preview_prompt, preview_neg_prompt, preview_prompt, preview_neg_prompt]
+# download model's new verson by model path, version id and download url
+# output is a md log
+def dl_model_new_version(msg, max_size_preview, skip_nsfw_preview):
+ util.printD("Start dl_model_new_version")
+
+ output = ""
+
+ result = msg_handler.parse_js_msg(msg)
+ if not result:
+ output = "Parsing js ms failed"
+ util.printD(output)
+ return output
+
+ model_path = result["model_path"]
+ version_id = result["version_id"]
+ download_url = result["download_url"]
+
+ util.printD("model_path: " + model_path)
+ util.printD("version_id: " + str(version_id))
+ util.printD("download_url: " + download_url)
+
+ # check data
+ if not model_path:
+ output = "model_path is empty"
+ util.printD(output)
+ return output
+
+ if not version_id:
+ output = "version_id is empty"
+ util.printD(output)
+ return output
+
+ if not download_url:
+ output = "download_url is empty"
+ util.printD(output)
+ return output
+
+ if not os.path.isfile(model_path):
+ output = "model_path is not a file: "+ model_path
+ util.printD(output)
+ return output
+
+ # get model folder from model path
+ model_folder = os.path.dirname(model_path)
+
+ # download file
+ new_model_path = downloader.dl(download_url, model_folder, None, None)
+ if not new_model_path:
+ output = "Download failed, check console log for detail. Download url: " + download_url
+ util.printD(output)
+ return output
+
+ # 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: " + new_model_path
+ util.printD(output)
+ return output
+
+ # now write version info to file
+ base, ext = os.path.splitext(new_model_path)
+ info_file = base + civitai.suffix + model.info_ext
+ model.write_model_info(info_file, version_info)
+
+ # 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
+ util.printD(output)
+ return output
diff --git a/scripts/lib/model_action_civitai.py b/scripts/lib/model_action_civitai.py
index a80e285..e2dd9c9 100644
--- a/scripts/lib/model_action_civitai.py
+++ b/scripts/lib/model_action_civitai.py
@@ -4,7 +4,7 @@ import os
from . import util
from . import model
from . import civitai
-
+from . import downloader
# scan model to generate SHA256, then use this SHA256 to get model info from civitai
@@ -139,24 +139,33 @@ def check_models_new_version_to_md(model_types:list) -> str:
model_path, model_id, model_name, new_verion_id, new_version_name, description, download_url, img_url = new_version
# in md, each part is something like this:
# [model_name](model_url)
+ # [version_name](download_url)
# version description
url = civitai.url_dict["modelPage"]+str(model_id)
- part = f'Model: {model_name}
'
- part = part + f"File: {model_path}
"
+ part = f'
'+ description + '