7e66807da6418cef8d9b2da1fecc08190b3442be447febbb68dfe89fdcbb16d8
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +1 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/claim_wall.md +91 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/icon/.keep +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/img/all_in_one.png +3 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/img/check_model_new_version.jpg +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/img/check_model_new_version_output.jpg +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/img/download_model.jpg +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/img/extension_tab.jpg +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/img/extra_network.jpg +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/img/get_one_model_info.jpg +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/img/model_card.jpg +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/img/model_info_file.jpg +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/img/other_setting.jpg +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/img/refresh_ch.jpg +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/img/thumb_mode.jpg +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/blame_sdweui_update_to_this_ext.jpg +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/changed_model_folder_name_then_forget_part1.jpg +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/changed_model_folder_name_then_forget_part2.jpg +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/changed_model_folder_name_then_forget_part3.jpg +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/changed_model_folder_name_then_forget_part4.jpg +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/css_issue_part1.jpg +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/css_issue_part2.jpg +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/css_issue_part3.jpg +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/css_issue_part4.jpg +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/did_not_relaunch_sdwebui.jpg +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/do_not_even_use_this_ext.jpg +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/have_not_scan_model.jpg +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/have_not_update_sdwebui.jpg +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/request_a_feature_it_already_has.jpg +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/javascript/civitai_helper.js +728 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/__pycache__/civitai_helper.cpython-310.pyc +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__init__.py +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/__init__.cpython-310.pyc +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/civitai.cpython-310.pyc +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/downloader.cpython-310.pyc +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/js_action_civitai.cpython-310.pyc +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/model.cpython-310.pyc +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/model_action_civitai.cpython-310.pyc +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/msg_handler.cpython-310.pyc +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/setting.cpython-310.pyc +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/util.cpython-310.pyc +0 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/civitai.py +612 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/downloader.py +115 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/js_action_civitai.py +256 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/model.py +120 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/model_action_civitai.py +511 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/msg_handler.py +64 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/setting.py +113 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/util.py +105 -0
- extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/civitai_helper.py +218 -0
.gitattributes
CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
36 |
+
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/all_in_one.png filter=lfs diff=lfs merge=lfs -text
|
extensions/Stable-Diffusion-Webui-Civitai-Helper/claim_wall.md
ADDED
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Claim Wall
|
2 |
+
|
3 |
+
Since this extension got a little hot, some users come to **claim many other issues to this extension**.
|
4 |
+
|
5 |
+
Following is a wall, to show a few examples how they claim this extension doesn't work, because they don't read document or forget what they did before.
|
6 |
+
|
7 |
+
If you are looking for guideline, go to section [What you should do](#what-you-should-do)
|
8 |
+
|
9 |
+
# Wall
|
10 |
+
|
11 |
+
### Didn't even update SD Webui and claim "tried everything"
|
12 |
+
|
13 |
+
![](img/user_claim_wall/have_not_update_sdwebui.jpg)
|
14 |
+
|
15 |
+
|
16 |
+
### Havn't even scanned model
|
17 |
+
After 4 replies, find that out, and modified his comment.
|
18 |
+
|
19 |
+
![](img/user_claim_wall/have_not_scan_model.jpg)
|
20 |
+
|
21 |
+
### Claim "pretty sure" this extension breaks his UI, takes 2days to find out it is not
|
22 |
+
Then removed his comment from civitai, but his post on reddit is still there, so you can know what's really going on there.
|
23 |
+
|
24 |
+
1. Claim "pretty sure" this extension breaks his UI
|
25 |
+
|
26 |
+
![](img/user_claim_wall/css_issue_part1.jpg)
|
27 |
+
|
28 |
+
![](img/user_claim_wall/css_issue_part2.jpg)
|
29 |
+
|
30 |
+
2. Find out it is not, after 2 days
|
31 |
+
|
32 |
+
![](img/user_claim_wall/css_issue_part3.jpg)
|
33 |
+
|
34 |
+
3. Still don't remember what he did with other extensions, until another user tells him, about 4 days later.
|
35 |
+
|
36 |
+
![](img/user_claim_wall/css_issue_part4.jpg)
|
37 |
+
|
38 |
+
### **Blame SD Webui's modification to this extension**
|
39 |
+
Latest SD webui removed a button from UI, they claim this extension did that, and want it back by this extension
|
40 |
+
|
41 |
+
![](img/user_claim_wall/blame_sdweui_update_to_this_ext.jpg)
|
42 |
+
|
43 |
+
### Claim other extension's error to this extension
|
44 |
+
Just because both extensions have "Civitai" in extension's name
|
45 |
+
|
46 |
+
![](img/user_claim_wall/do_not_even_use_this_ext.jpg)
|
47 |
+
|
48 |
+
|
49 |
+
### **Didn't even use this extension and request a feature it already has**
|
50 |
+
|
51 |
+
![](img/user_claim_wall/request_a_feature_it_already_has.jpg)
|
52 |
+
|
53 |
+
### **Renamed model folder's name carelessly and forgot that**
|
54 |
+
Takes about 8 hours to find out why this extension doesn't work on his SDwebui and ready to re-install SD webui from beginning.
|
55 |
+
|
56 |
+
1. claim this extension can not open civitai url on checkpoint models
|
57 |
+
|
58 |
+
![](img/user_claim_wall/changed_model_folder_name_then_forget_part1.jpg)
|
59 |
+
|
60 |
+
2. I reply that model he mentioned works well in my SDwebui
|
61 |
+
|
62 |
+
![](img/user_claim_wall/changed_model_folder_name_then_forget_part2.jpg)
|
63 |
+
|
64 |
+
3. After 6 hours' trying, find out his model folder's name is modified.
|
65 |
+
|
66 |
+
![](img/user_claim_wall/changed_model_folder_name_then_forget_part3.jpg)
|
67 |
+
|
68 |
+
![](img/user_claim_wall/changed_model_folder_name_then_forget_part4.jpg)
|
69 |
+
|
70 |
+
|
71 |
+
# What you should do
|
72 |
+
Above are just a very small piece of this kind of claims. Those claims won't help you. If you have an issue, following is the guidline:
|
73 |
+
|
74 |
+
* If you want to make your extension work, read the document.
|
75 |
+
|
76 |
+
* If your SD webui is broken, before you claim it is caused by this extension, you can disable it and try again.
|
77 |
+
|
78 |
+
* If you followed document, but it still doesn't work well, you can check console log's msg to find out the reason. If you can not understand those msg, you can come and ask for help, with console log's msg or screenshot.
|
79 |
+
|
80 |
+
* If you are using colab, and get an error from colab, then search that error msg in google. Because it's a colab's issue or limitation.
|
81 |
+
|
82 |
+
* If you checked console log window's msg and understand what it means, you are welcome to submit your issue.
|
83 |
+
|
84 |
+
|
85 |
+
|
86 |
+
|
87 |
+
|
88 |
+
|
89 |
+
|
90 |
+
|
91 |
+
|
extensions/Stable-Diffusion-Webui-Civitai-Helper/icon/.keep
ADDED
File without changes
|
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/all_in_one.png
ADDED
Git LFS Details
|
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/check_model_new_version.jpg
ADDED
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/check_model_new_version_output.jpg
ADDED
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/download_model.jpg
ADDED
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/extension_tab.jpg
ADDED
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/extra_network.jpg
ADDED
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/get_one_model_info.jpg
ADDED
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/model_card.jpg
ADDED
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/model_info_file.jpg
ADDED
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/other_setting.jpg
ADDED
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/refresh_ch.jpg
ADDED
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/thumb_mode.jpg
ADDED
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/blame_sdweui_update_to_this_ext.jpg
ADDED
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/changed_model_folder_name_then_forget_part1.jpg
ADDED
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/changed_model_folder_name_then_forget_part2.jpg
ADDED
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/changed_model_folder_name_then_forget_part3.jpg
ADDED
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/changed_model_folder_name_then_forget_part4.jpg
ADDED
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/css_issue_part1.jpg
ADDED
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/css_issue_part2.jpg
ADDED
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/css_issue_part3.jpg
ADDED
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/css_issue_part4.jpg
ADDED
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/did_not_relaunch_sdwebui.jpg
ADDED
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/do_not_even_use_this_ext.jpg
ADDED
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/have_not_scan_model.jpg
ADDED
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/have_not_update_sdwebui.jpg
ADDED
extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/request_a_feature_it_already_has.jpg
ADDED
extensions/Stable-Diffusion-Webui-Civitai-Helper/javascript/civitai_helper.js
ADDED
@@ -0,0 +1,728 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"use strict";
|
2 |
+
|
3 |
+
|
4 |
+
function ch_convert_file_path_to_url(path){
|
5 |
+
let prefix = "file=";
|
6 |
+
let path_to_url = path.replaceAll('\\', '/');
|
7 |
+
return prefix+path_to_url;
|
8 |
+
}
|
9 |
+
|
10 |
+
function ch_img_node_str(path){
|
11 |
+
return `<img src='${ch_convert_file_path_to_url(path)}' style="width:24px"/>`;
|
12 |
+
}
|
13 |
+
|
14 |
+
|
15 |
+
function ch_gradio_version(){
|
16 |
+
let foot = gradioApp().getElementById("footer");
|
17 |
+
if (!foot){return null;}
|
18 |
+
|
19 |
+
let versions = foot.querySelector(".versions");
|
20 |
+
if (!versions){return null;}
|
21 |
+
|
22 |
+
if (versions.innerHTML.indexOf("gradio: 3.16.2")>0) {
|
23 |
+
return "3.16.2";
|
24 |
+
} else {
|
25 |
+
return "3.23.0";
|
26 |
+
}
|
27 |
+
|
28 |
+
}
|
29 |
+
|
30 |
+
|
31 |
+
// send msg to python side by filling a hidden text box
|
32 |
+
// then will click a button to trigger an action
|
33 |
+
// msg is an object, not a string, will be stringify in this function
|
34 |
+
function send_ch_py_msg(msg){
|
35 |
+
console.log("run send_ch_py_msg")
|
36 |
+
let js_msg_txtbox = gradioApp().querySelector("#ch_js_msg_txtbox textarea");
|
37 |
+
if (js_msg_txtbox && msg) {
|
38 |
+
// fill to msg box
|
39 |
+
js_msg_txtbox.value = JSON.stringify(msg);
|
40 |
+
js_msg_txtbox.dispatchEvent(new Event("input"));
|
41 |
+
}
|
42 |
+
|
43 |
+
}
|
44 |
+
|
45 |
+
// get msg from python side from a hidden textbox
|
46 |
+
// normally this is an old msg, need to wait for a new msg
|
47 |
+
function get_ch_py_msg(){
|
48 |
+
console.log("run get_ch_py_msg")
|
49 |
+
const py_msg_txtbox = gradioApp().querySelector("#ch_py_msg_txtbox textarea");
|
50 |
+
if (py_msg_txtbox && py_msg_txtbox.value) {
|
51 |
+
console.log("find py_msg_txtbox");
|
52 |
+
console.log("py_msg_txtbox value: ");
|
53 |
+
console.log(py_msg_txtbox.value)
|
54 |
+
return py_msg_txtbox.value
|
55 |
+
} else {
|
56 |
+
return ""
|
57 |
+
}
|
58 |
+
}
|
59 |
+
|
60 |
+
|
61 |
+
// get msg from python side from a hidden textbox
|
62 |
+
// it will try once in every sencond, until it reach the max try times
|
63 |
+
const get_new_ch_py_msg = (max_count=3) => new Promise((resolve, reject) => {
|
64 |
+
console.log("run get_new_ch_py_msg")
|
65 |
+
|
66 |
+
let count = 0;
|
67 |
+
let new_msg = "";
|
68 |
+
let find_msg = false;
|
69 |
+
const interval = setInterval(() => {
|
70 |
+
const py_msg_txtbox = gradioApp().querySelector("#ch_py_msg_txtbox textarea");
|
71 |
+
count++;
|
72 |
+
|
73 |
+
if (py_msg_txtbox && py_msg_txtbox.value) {
|
74 |
+
console.log("find py_msg_txtbox");
|
75 |
+
console.log("py_msg_txtbox value: ");
|
76 |
+
console.log(py_msg_txtbox.value)
|
77 |
+
|
78 |
+
new_msg = py_msg_txtbox.value
|
79 |
+
if (new_msg != "") {
|
80 |
+
find_msg=true
|
81 |
+
}
|
82 |
+
}
|
83 |
+
|
84 |
+
if (find_msg) {
|
85 |
+
//clear msg in both sides
|
86 |
+
py_msg_txtbox.value = "";
|
87 |
+
py_msg_txtbox.dispatchEvent(new Event("input"));
|
88 |
+
|
89 |
+
resolve(new_msg);
|
90 |
+
clearInterval(interval);
|
91 |
+
} else if (count > max_count) {
|
92 |
+
//clear msg in both sides
|
93 |
+
py_msg_txtbox.value = "";
|
94 |
+
py_msg_txtbox.dispatchEvent(new Event("input"));
|
95 |
+
|
96 |
+
reject('');
|
97 |
+
clearInterval(interval);
|
98 |
+
}
|
99 |
+
|
100 |
+
}, 1000);
|
101 |
+
})
|
102 |
+
|
103 |
+
|
104 |
+
function getActiveTabType() {
|
105 |
+
const currentTab = get_uiCurrentTabContent();
|
106 |
+
switch (currentTab.id) {
|
107 |
+
case "tab_txt2img":
|
108 |
+
return "txt2img";
|
109 |
+
case "tab_img2img":
|
110 |
+
return "img2img";
|
111 |
+
}
|
112 |
+
return null;
|
113 |
+
}
|
114 |
+
|
115 |
+
|
116 |
+
|
117 |
+
function getActivePrompt() {
|
118 |
+
const currentTab = get_uiCurrentTabContent();
|
119 |
+
switch (currentTab.id) {
|
120 |
+
case "tab_txt2img":
|
121 |
+
return currentTab.querySelector("#txt2img_prompt textarea");
|
122 |
+
case "tab_img2img":
|
123 |
+
return currentTab.querySelector("#img2img_prompt textarea");
|
124 |
+
}
|
125 |
+
return null;
|
126 |
+
}
|
127 |
+
|
128 |
+
function getActiveNegativePrompt() {
|
129 |
+
const currentTab = get_uiCurrentTabContent();
|
130 |
+
switch (currentTab.id) {
|
131 |
+
case "tab_txt2img":
|
132 |
+
return currentTab.querySelector("#txt2img_neg_prompt textarea");
|
133 |
+
case "tab_img2img":
|
134 |
+
return currentTab.querySelector("#img2img_neg_prompt textarea");
|
135 |
+
}
|
136 |
+
return null;
|
137 |
+
}
|
138 |
+
|
139 |
+
|
140 |
+
//button's click function
|
141 |
+
async function open_model_url(event, model_type, search_term){
|
142 |
+
console.log("start open_model_url");
|
143 |
+
|
144 |
+
//get hidden components of extension
|
145 |
+
let js_open_url_btn = gradioApp().getElementById("ch_js_open_url_btn");
|
146 |
+
if (!js_open_url_btn) {
|
147 |
+
return
|
148 |
+
}
|
149 |
+
|
150 |
+
|
151 |
+
//msg to python side
|
152 |
+
let msg = {
|
153 |
+
"action": "",
|
154 |
+
"model_type": "",
|
155 |
+
"search_term": "",
|
156 |
+
"prompt": "",
|
157 |
+
"neg_prompt": "",
|
158 |
+
}
|
159 |
+
|
160 |
+
|
161 |
+
msg["action"] = "open_url";
|
162 |
+
msg["model_type"] = model_type;
|
163 |
+
msg["search_term"] = search_term;
|
164 |
+
msg["prompt"] = "";
|
165 |
+
msg["neg_prompt"] = "";
|
166 |
+
|
167 |
+
// fill to msg box
|
168 |
+
send_ch_py_msg(msg)
|
169 |
+
|
170 |
+
//click hidden button
|
171 |
+
js_open_url_btn.click();
|
172 |
+
|
173 |
+
// stop parent event
|
174 |
+
event.stopPropagation()
|
175 |
+
event.preventDefault()
|
176 |
+
|
177 |
+
//check response msg from python
|
178 |
+
let new_py_msg = await get_new_ch_py_msg();
|
179 |
+
console.log("new_py_msg:");
|
180 |
+
console.log(new_py_msg);
|
181 |
+
|
182 |
+
//check msg
|
183 |
+
if (new_py_msg) {
|
184 |
+
let py_msg_json = JSON.parse(new_py_msg);
|
185 |
+
//check for url
|
186 |
+
if (py_msg_json && py_msg_json.content) {
|
187 |
+
if (py_msg_json.content.url) {
|
188 |
+
window.open(py_msg_json.content.url, "_blank");
|
189 |
+
}
|
190 |
+
|
191 |
+
}
|
192 |
+
|
193 |
+
|
194 |
+
}
|
195 |
+
|
196 |
+
|
197 |
+
console.log("end open_model_url");
|
198 |
+
|
199 |
+
|
200 |
+
}
|
201 |
+
|
202 |
+
function add_trigger_words(event, model_type, search_term){
|
203 |
+
console.log("start add_trigger_words");
|
204 |
+
|
205 |
+
//get hidden components of extension
|
206 |
+
let js_add_trigger_words_btn = gradioApp().getElementById("ch_js_add_trigger_words_btn");
|
207 |
+
if (!js_add_trigger_words_btn) {
|
208 |
+
return
|
209 |
+
}
|
210 |
+
|
211 |
+
|
212 |
+
//msg to python side
|
213 |
+
let msg = {
|
214 |
+
"action": "",
|
215 |
+
"model_type": "",
|
216 |
+
"search_term": "",
|
217 |
+
"prompt": "",
|
218 |
+
"neg_prompt": "",
|
219 |
+
}
|
220 |
+
|
221 |
+
msg["action"] = "add_trigger_words";
|
222 |
+
msg["model_type"] = model_type;
|
223 |
+
msg["search_term"] = search_term;
|
224 |
+
msg["neg_prompt"] = "";
|
225 |
+
|
226 |
+
// get active prompt
|
227 |
+
let act_prompt = getActivePrompt();
|
228 |
+
msg["prompt"] = act_prompt.value;
|
229 |
+
|
230 |
+
// fill to msg box
|
231 |
+
send_ch_py_msg(msg)
|
232 |
+
|
233 |
+
//click hidden button
|
234 |
+
js_add_trigger_words_btn.click();
|
235 |
+
|
236 |
+
console.log("end add_trigger_words");
|
237 |
+
|
238 |
+
event.stopPropagation()
|
239 |
+
event.preventDefault()
|
240 |
+
|
241 |
+
|
242 |
+
}
|
243 |
+
|
244 |
+
function use_preview_prompt(event, model_type, search_term){
|
245 |
+
console.log("start use_preview_prompt");
|
246 |
+
|
247 |
+
//get hidden components of extension
|
248 |
+
let js_use_preview_prompt_btn = gradioApp().getElementById("ch_js_use_preview_prompt_btn");
|
249 |
+
if (!js_use_preview_prompt_btn) {
|
250 |
+
return
|
251 |
+
}
|
252 |
+
|
253 |
+
//msg to python side
|
254 |
+
let msg = {
|
255 |
+
"action": "",
|
256 |
+
"model_type": "",
|
257 |
+
"search_term": "",
|
258 |
+
"prompt": "",
|
259 |
+
"neg_prompt": "",
|
260 |
+
}
|
261 |
+
|
262 |
+
msg["action"] = "use_preview_prompt";
|
263 |
+
msg["model_type"] = model_type;
|
264 |
+
msg["search_term"] = search_term;
|
265 |
+
|
266 |
+
// get active prompt
|
267 |
+
let act_prompt = getActivePrompt();
|
268 |
+
msg["prompt"] = act_prompt.value;
|
269 |
+
|
270 |
+
// get active neg prompt
|
271 |
+
let neg_prompt = getActiveNegativePrompt();
|
272 |
+
msg["neg_prompt"] = neg_prompt.value;
|
273 |
+
|
274 |
+
// fill to msg box
|
275 |
+
send_ch_py_msg(msg)
|
276 |
+
|
277 |
+
//click hidden button
|
278 |
+
js_use_preview_prompt_btn.click();
|
279 |
+
|
280 |
+
console.log("end use_preview_prompt");
|
281 |
+
|
282 |
+
event.stopPropagation()
|
283 |
+
event.preventDefault()
|
284 |
+
|
285 |
+
}
|
286 |
+
|
287 |
+
|
288 |
+
|
289 |
+
// download model's new version into SD at python side
|
290 |
+
function ch_dl_model_new_version(event, model_path, version_id, download_url){
|
291 |
+
console.log("start ch_dl_model_new_version");
|
292 |
+
|
293 |
+
// must confirm before downloading
|
294 |
+
let dl_confirm = "\nConfirm to download.\n\nCheck Download Model Section's log and console log for detail.";
|
295 |
+
if (!confirm(dl_confirm)) {
|
296 |
+
return
|
297 |
+
}
|
298 |
+
|
299 |
+
//get hidden components of extension
|
300 |
+
let js_dl_model_new_version_btn = gradioApp().getElementById("ch_js_dl_model_new_version_btn");
|
301 |
+
if (!js_dl_model_new_version_btn) {
|
302 |
+
return
|
303 |
+
}
|
304 |
+
|
305 |
+
//msg to python side
|
306 |
+
let msg = {
|
307 |
+
"action": "",
|
308 |
+
"model_path": "",
|
309 |
+
"version_id": "",
|
310 |
+
"download_url": "",
|
311 |
+
}
|
312 |
+
|
313 |
+
msg["action"] = "dl_model_new_version";
|
314 |
+
msg["model_path"] = model_path;
|
315 |
+
msg["version_id"] = version_id;
|
316 |
+
msg["download_url"] = download_url;
|
317 |
+
|
318 |
+
// fill to msg box
|
319 |
+
send_ch_py_msg(msg)
|
320 |
+
|
321 |
+
//click hidden button
|
322 |
+
js_dl_model_new_version_btn.click();
|
323 |
+
|
324 |
+
console.log("end dl_model_new_version");
|
325 |
+
|
326 |
+
event.stopPropagation()
|
327 |
+
event.preventDefault()
|
328 |
+
|
329 |
+
|
330 |
+
}
|
331 |
+
|
332 |
+
|
333 |
+
onUiLoaded(() => {
|
334 |
+
|
335 |
+
//get gradio version
|
336 |
+
let gradio_ver = ch_gradio_version();
|
337 |
+
console.log("gradio_ver:" + gradio_ver);
|
338 |
+
|
339 |
+
// get all extra network tabs
|
340 |
+
let tab_prefix_list = ["txt2img", "img2img"];
|
341 |
+
let model_type_list = ["textual_inversion", "hypernetworks", "checkpoints", "lora"];
|
342 |
+
let cardid_suffix = "cards";
|
343 |
+
|
344 |
+
//get init py msg
|
345 |
+
// let init_py_msg_str = get_ch_py_msg();
|
346 |
+
// let extension_path = "";
|
347 |
+
// if (!init_py_msg_str) {
|
348 |
+
// console.log("Can not get init_py_msg");
|
349 |
+
// } else {
|
350 |
+
// init_py_msg = JSON.parse(init_py_msg_str);
|
351 |
+
// if (init_py_msg) {
|
352 |
+
// extension_path = init_py_msg.extension_path;
|
353 |
+
// console.log("get extension path: " + extension_path);
|
354 |
+
// }
|
355 |
+
// }
|
356 |
+
|
357 |
+
// //icon image node as string
|
358 |
+
// function icon(icon_name){
|
359 |
+
// let icon_path = extension_path+"/icon/"+icon_name;
|
360 |
+
// return ch_img_node_str(icon_path);
|
361 |
+
// }
|
362 |
+
|
363 |
+
|
364 |
+
// update extra network tab pages' cards
|
365 |
+
// * replace "replace preview" text button into an icon
|
366 |
+
// * add 3 button to each card:
|
367 |
+
// - open model url 🌐
|
368 |
+
// - add trigger words 💡
|
369 |
+
// - use preview image's prompt 🏷️
|
370 |
+
// notice: javascript can not get response from python side
|
371 |
+
// so, these buttons just sent request to python
|
372 |
+
// then, python side gonna open url and update prompt text box, without telling js side.
|
373 |
+
function update_card_for_civitai(){
|
374 |
+
|
375 |
+
//css
|
376 |
+
let btn_margin = "0px 5px";
|
377 |
+
let btn_fontSize = "200%";
|
378 |
+
let btn_thumb_fontSize = "100%";
|
379 |
+
let btn_thumb_display = "inline";
|
380 |
+
let btn_thumb_pos = "static";
|
381 |
+
let btn_thumb_backgroundImage = "none";
|
382 |
+
let btn_thumb_background = "rgba(0, 0, 0, 0.8)";
|
383 |
+
|
384 |
+
let ch_btn_txts = ['🌐', '💡', '🏷️'];
|
385 |
+
let replace_preview_text = getTranslation("replace preview");
|
386 |
+
if (!replace_preview_text) {
|
387 |
+
replace_preview_text = "replace preview";
|
388 |
+
}
|
389 |
+
|
390 |
+
|
391 |
+
|
392 |
+
// get component
|
393 |
+
let ch_always_display_ckb = gradioApp().querySelector("#ch_always_display_ckb input");
|
394 |
+
let ch_show_btn_on_thumb_ckb = gradioApp().querySelector("#ch_show_btn_on_thumb_ckb input");
|
395 |
+
let ch_always_display = false;
|
396 |
+
let ch_show_btn_on_thumb = false;
|
397 |
+
if (ch_always_display_ckb) {
|
398 |
+
ch_always_display = ch_always_display_ckb.checked;
|
399 |
+
}
|
400 |
+
if (ch_show_btn_on_thumb_ckb) {
|
401 |
+
ch_show_btn_on_thumb = ch_show_btn_on_thumb_ckb.checked;
|
402 |
+
}
|
403 |
+
|
404 |
+
|
405 |
+
//change all "replace preview" into an icon
|
406 |
+
let extra_network_id = "";
|
407 |
+
let extra_network_node = null;
|
408 |
+
let metadata_button = null;
|
409 |
+
let additional_node = null;
|
410 |
+
let replace_preview_btn = null;
|
411 |
+
let ul_node = null;
|
412 |
+
let search_term_node = null;
|
413 |
+
let search_term = "";
|
414 |
+
let model_type = "";
|
415 |
+
let cards = null;
|
416 |
+
let need_to_add_buttons = false;
|
417 |
+
let is_thumb_mode = false;
|
418 |
+
|
419 |
+
//get current tab
|
420 |
+
let active_tab_type = getActiveTabType();
|
421 |
+
if (!active_tab_type){active_tab_type = "txt2img";}
|
422 |
+
|
423 |
+
for (const tab_prefix of tab_prefix_list) {
|
424 |
+
if (tab_prefix != active_tab_type) {continue;}
|
425 |
+
|
426 |
+
|
427 |
+
//find out current selected model type tab
|
428 |
+
let active_extra_tab_type = "";
|
429 |
+
let extra_tabs = gradioApp().getElementById(tab_prefix+"_extra_tabs");
|
430 |
+
if (!extra_tabs) {console.log("can not find extra_tabs: " + tab_prefix+"_extra_tabs");}
|
431 |
+
|
432 |
+
//get active extratab
|
433 |
+
const active_extra_tab = Array.from(get_uiCurrentTabContent().querySelectorAll('.extra-network-cards,.extra-network-thumbs'))
|
434 |
+
.find(el => el.closest('.tabitem').style.display === 'block')
|
435 |
+
?.id.match(/^(txt2img|img2img)_(.+)_cards$/)[2]
|
436 |
+
|
437 |
+
|
438 |
+
console.log("found active tab: " + active_extra_tab);
|
439 |
+
|
440 |
+
switch (active_extra_tab) {
|
441 |
+
case "textual_inversion":
|
442 |
+
active_extra_tab_type = "ti";
|
443 |
+
break;
|
444 |
+
case "hypernetworks":
|
445 |
+
active_extra_tab_type = "hyper";
|
446 |
+
break;
|
447 |
+
case "checkpoints":
|
448 |
+
active_extra_tab_type = "ckp";
|
449 |
+
break;
|
450 |
+
case "lora":
|
451 |
+
active_extra_tab_type = "lora";
|
452 |
+
break;
|
453 |
+
}
|
454 |
+
|
455 |
+
|
456 |
+
for (const js_model_type of model_type_list) {
|
457 |
+
//get model_type for python side
|
458 |
+
switch (js_model_type) {
|
459 |
+
case "textual_inversion":
|
460 |
+
model_type = "ti";
|
461 |
+
break;
|
462 |
+
case "hypernetworks":
|
463 |
+
model_type = "hyper";
|
464 |
+
break;
|
465 |
+
case "checkpoints":
|
466 |
+
model_type = "ckp";
|
467 |
+
break;
|
468 |
+
case "lora":
|
469 |
+
model_type = "lora";
|
470 |
+
break;
|
471 |
+
}
|
472 |
+
|
473 |
+
if (!model_type) {
|
474 |
+
console.log("can not get model_type from: " + js_model_type);
|
475 |
+
continue;
|
476 |
+
}
|
477 |
+
|
478 |
+
|
479 |
+
//only handle current sub-tab
|
480 |
+
if (model_type != active_extra_tab_type) {
|
481 |
+
continue;
|
482 |
+
}
|
483 |
+
|
484 |
+
console.log("handle active extra tab");
|
485 |
+
|
486 |
+
|
487 |
+
extra_network_id = tab_prefix+"_"+js_model_type+"_"+cardid_suffix;
|
488 |
+
// console.log("searching extra_network_node: " + extra_network_id);
|
489 |
+
extra_network_node = gradioApp().getElementById(extra_network_id);
|
490 |
+
// check if extr network is under thumbnail mode
|
491 |
+
is_thumb_mode = false
|
492 |
+
if (extra_network_node) {
|
493 |
+
if (extra_network_node.className == "extra-network-thumbs") {
|
494 |
+
console.log(extra_network_id + " is in thumbnail mode");
|
495 |
+
is_thumb_mode = true;
|
496 |
+
// if (!ch_show_btn_on_thumb) {continue;}
|
497 |
+
}
|
498 |
+
} else {
|
499 |
+
console.log("can not find extra_network_node: " + extra_network_id);
|
500 |
+
continue;
|
501 |
+
}
|
502 |
+
// console.log("find extra_network_node: " + extra_network_id);
|
503 |
+
|
504 |
+
// get all card nodes
|
505 |
+
cards = extra_network_node.querySelectorAll(".card");
|
506 |
+
for (let card of cards) {
|
507 |
+
//metadata_buttoncard
|
508 |
+
metadata_button = card.querySelector(".metadata-button");
|
509 |
+
//additional node
|
510 |
+
additional_node = card.querySelector(".actions .additional");
|
511 |
+
//get ul node, which is the parent of all buttons
|
512 |
+
ul_node = card.querySelector(".actions .additional ul");
|
513 |
+
// replace preview text button
|
514 |
+
replace_preview_btn = card.querySelector(".actions .additional a");
|
515 |
+
|
516 |
+
// check thumb mode
|
517 |
+
if (is_thumb_mode) {
|
518 |
+
additional_node.style.display = null;
|
519 |
+
|
520 |
+
if (ch_show_btn_on_thumb) {
|
521 |
+
ul_node.style.background = btn_thumb_background;
|
522 |
+
} else {
|
523 |
+
//reset
|
524 |
+
ul_node.style.background = null;
|
525 |
+
// console.log("remove existed buttons");
|
526 |
+
// remove existed buttons
|
527 |
+
if (ul_node) {
|
528 |
+
// find all .a child nodes
|
529 |
+
let atags = ul_node.querySelectorAll("a");
|
530 |
+
|
531 |
+
for (let atag of atags) {
|
532 |
+
//reset display
|
533 |
+
atag.style.display = null;
|
534 |
+
//remove extension's button
|
535 |
+
if (ch_btn_txts.indexOf(atag.innerHTML)>=0) {
|
536 |
+
//need to remove
|
537 |
+
ul_node.removeChild(atag);
|
538 |
+
} else {
|
539 |
+
//do not remove, just reset
|
540 |
+
atag.innerHTML = replace_preview_text;
|
541 |
+
atag.style.display = null;
|
542 |
+
atag.style.fontSize = null;
|
543 |
+
atag.style.position = null;
|
544 |
+
atag.style.backgroundImage = null;
|
545 |
+
}
|
546 |
+
}
|
547 |
+
|
548 |
+
//also remove br tag in ul
|
549 |
+
let brtag = ul_node.querySelector("br");
|
550 |
+
if (brtag) {
|
551 |
+
ul_node.removeChild(brtag);
|
552 |
+
}
|
553 |
+
|
554 |
+
}
|
555 |
+
//just reset and remove nodes, do nothing else
|
556 |
+
continue;
|
557 |
+
|
558 |
+
}
|
559 |
+
|
560 |
+
} else {
|
561 |
+
// full preview mode
|
562 |
+
if (ch_always_display) {
|
563 |
+
additional_node.style.display = "block";
|
564 |
+
} else {
|
565 |
+
additional_node.style.display = null;
|
566 |
+
}
|
567 |
+
|
568 |
+
// remove br tag
|
569 |
+
let brtag = ul_node.querySelector("br");
|
570 |
+
if (brtag) {
|
571 |
+
ul_node.removeChild(brtag);
|
572 |
+
}
|
573 |
+
|
574 |
+
}
|
575 |
+
|
576 |
+
// change replace preview text button into icon
|
577 |
+
if (replace_preview_btn) {
|
578 |
+
if (replace_preview_btn.innerHTML !== "🖼️") {
|
579 |
+
need_to_add_buttons = true;
|
580 |
+
replace_preview_btn.innerHTML = "🖼️";
|
581 |
+
if (!is_thumb_mode) {
|
582 |
+
replace_preview_btn.style.fontSize = btn_fontSize;
|
583 |
+
replace_preview_btn.style.margin = btn_margin;
|
584 |
+
} else {
|
585 |
+
replace_preview_btn.style.display = btn_thumb_display;
|
586 |
+
replace_preview_btn.style.fontSize = btn_thumb_fontSize;
|
587 |
+
replace_preview_btn.style.position = btn_thumb_pos;
|
588 |
+
replace_preview_btn.style.backgroundImage = btn_thumb_backgroundImage;
|
589 |
+
}
|
590 |
+
|
591 |
+
}
|
592 |
+
}
|
593 |
+
|
594 |
+
if (!need_to_add_buttons) {
|
595 |
+
continue;
|
596 |
+
}
|
597 |
+
|
598 |
+
|
599 |
+
// search_term node
|
600 |
+
// search_term = subfolder path + model name + ext
|
601 |
+
search_term_node = card.querySelector(".actions .additional .search_term");
|
602 |
+
if (!search_term_node){
|
603 |
+
console.log("can not find search_term node for cards in " + extra_network_id);
|
604 |
+
continue;
|
605 |
+
}
|
606 |
+
|
607 |
+
// get search_term
|
608 |
+
search_term = search_term_node.innerHTML;
|
609 |
+
if (!search_term) {
|
610 |
+
console.log("search_term is empty for cards in " + extra_network_id);
|
611 |
+
continue;
|
612 |
+
}
|
613 |
+
|
614 |
+
|
615 |
+
|
616 |
+
// if (is_thumb_mode) {
|
617 |
+
// ul_node.style.background = btn_thumb_background;
|
618 |
+
// }
|
619 |
+
|
620 |
+
// then we need to add 3 buttons to each ul node:
|
621 |
+
let open_url_node = document.createElement("a");
|
622 |
+
open_url_node.href = "#";
|
623 |
+
open_url_node.innerHTML = "🌐";
|
624 |
+
if (!is_thumb_mode) {
|
625 |
+
open_url_node.style.fontSize = btn_fontSize;
|
626 |
+
open_url_node.style.margin = btn_margin;
|
627 |
+
} else {
|
628 |
+
open_url_node.style.display = btn_thumb_display;
|
629 |
+
open_url_node.style.fontSize = btn_thumb_fontSize;
|
630 |
+
open_url_node.style.position = btn_thumb_pos;
|
631 |
+
open_url_node.style.backgroundImage = btn_thumb_backgroundImage;
|
632 |
+
}
|
633 |
+
open_url_node.title = "Open this model's civitai url";
|
634 |
+
open_url_node.setAttribute("onclick","open_model_url(event, '"+model_type+"', '"+search_term+"')");
|
635 |
+
|
636 |
+
let add_trigger_words_node = document.createElement("a");
|
637 |
+
add_trigger_words_node.href = "#";
|
638 |
+
add_trigger_words_node.innerHTML = "💡";
|
639 |
+
if (!is_thumb_mode) {
|
640 |
+
add_trigger_words_node.style.fontSize = btn_fontSize;
|
641 |
+
add_trigger_words_node.style.margin = btn_margin;
|
642 |
+
} else {
|
643 |
+
add_trigger_words_node.style.display = btn_thumb_display;
|
644 |
+
add_trigger_words_node.style.fontSize = btn_thumb_fontSize;
|
645 |
+
add_trigger_words_node.style.position = btn_thumb_pos;
|
646 |
+
add_trigger_words_node.style.backgroundImage = btn_thumb_backgroundImage;
|
647 |
+
}
|
648 |
+
|
649 |
+
add_trigger_words_node.title = "Add trigger words to prompt";
|
650 |
+
add_trigger_words_node.setAttribute("onclick","add_trigger_words(event, '"+model_type+"', '"+search_term+"')");
|
651 |
+
|
652 |
+
let use_preview_prompt_node = document.createElement("a");
|
653 |
+
use_preview_prompt_node.href = "#";
|
654 |
+
use_preview_prompt_node.innerHTML = "🏷️";
|
655 |
+
if (!is_thumb_mode) {
|
656 |
+
use_preview_prompt_node.style.fontSize = btn_fontSize;
|
657 |
+
use_preview_prompt_node.style.margin = btn_margin;
|
658 |
+
} else {
|
659 |
+
use_preview_prompt_node.style.display = btn_thumb_display;
|
660 |
+
use_preview_prompt_node.style.fontSize = btn_thumb_fontSize;
|
661 |
+
use_preview_prompt_node.style.position = btn_thumb_pos;
|
662 |
+
use_preview_prompt_node.style.backgroundImage = btn_thumb_backgroundImage;
|
663 |
+
}
|
664 |
+
use_preview_prompt_node.title = "Use prompt from preview image";
|
665 |
+
use_preview_prompt_node.setAttribute("onclick","use_preview_prompt(event, '"+model_type+"', '"+search_term+"')");
|
666 |
+
|
667 |
+
//add to card
|
668 |
+
ul_node.appendChild(open_url_node);
|
669 |
+
//add br if metadata_button exists
|
670 |
+
if (is_thumb_mode && metadata_button) {
|
671 |
+
ul_node.appendChild(document.createElement("br"));
|
672 |
+
}
|
673 |
+
ul_node.appendChild(add_trigger_words_node);
|
674 |
+
ul_node.appendChild(use_preview_prompt_node);
|
675 |
+
|
676 |
+
|
677 |
+
|
678 |
+
|
679 |
+
}
|
680 |
+
|
681 |
+
|
682 |
+
}
|
683 |
+
}
|
684 |
+
|
685 |
+
|
686 |
+
}
|
687 |
+
|
688 |
+
|
689 |
+
let tab_id = ""
|
690 |
+
let extra_tab = null;
|
691 |
+
let extra_toolbar = null;
|
692 |
+
let extra_network_refresh_btn = null;
|
693 |
+
//add refresh button to extra network's toolbar
|
694 |
+
for (let prefix of tab_prefix_list) {
|
695 |
+
tab_id = prefix + "_extra_tabs";
|
696 |
+
extra_tab = gradioApp().getElementById(tab_id);
|
697 |
+
|
698 |
+
//get toolbar
|
699 |
+
//get Refresh button
|
700 |
+
extra_network_refresh_btn = gradioApp().getElementById(prefix+"_extra_refresh");
|
701 |
+
|
702 |
+
|
703 |
+
if (!extra_network_refresh_btn){
|
704 |
+
console.log("can not get extra network refresh button for " + tab_id);
|
705 |
+
continue;
|
706 |
+
}
|
707 |
+
|
708 |
+
// add refresh button to toolbar
|
709 |
+
let ch_refresh = document.createElement("button");
|
710 |
+
ch_refresh.innerHTML = "🔁";
|
711 |
+
ch_refresh.title = "Refresh Civitai Helper's additional buttons";
|
712 |
+
ch_refresh.className = "lg secondary gradio-button";
|
713 |
+
ch_refresh.style.fontSize = "200%";
|
714 |
+
ch_refresh.onclick = update_card_for_civitai;
|
715 |
+
|
716 |
+
extra_network_refresh_btn.parentNode.appendChild(ch_refresh);
|
717 |
+
|
718 |
+
}
|
719 |
+
|
720 |
+
|
721 |
+
//run it once
|
722 |
+
update_card_for_civitai();
|
723 |
+
|
724 |
+
|
725 |
+
});
|
726 |
+
|
727 |
+
|
728 |
+
|
extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/__pycache__/civitai_helper.cpython-310.pyc
ADDED
Binary file (6.99 kB). View file
|
|
extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__init__.py
ADDED
File without changes
|
extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/__init__.cpython-310.pyc
ADDED
Binary file (192 Bytes). View file
|
|
extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/civitai.cpython-310.pyc
ADDED
Binary file (9.18 kB). View file
|
|
extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/downloader.cpython-310.pyc
ADDED
Binary file (2.14 kB). View file
|
|
extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/js_action_civitai.cpython-310.pyc
ADDED
Binary file (4.56 kB). View file
|
|
extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/model.cpython-310.pyc
ADDED
Binary file (2.68 kB). View file
|
|
extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/model_action_civitai.cpython-310.pyc
ADDED
Binary file (8.58 kB). View file
|
|
extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/msg_handler.cpython-310.pyc
ADDED
Binary file (1.21 kB). View file
|
|
extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/setting.cpython-310.pyc
ADDED
Binary file (1.78 kB). View file
|
|
extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/util.cpython-310.pyc
ADDED
Binary file (2.63 kB). View file
|
|
extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/civitai.py
ADDED
@@ -0,0 +1,612 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: UTF-8 -*-
|
2 |
+
# handle msg between js and python side
|
3 |
+
import os
|
4 |
+
import time
|
5 |
+
import json
|
6 |
+
import re
|
7 |
+
import requests
|
8 |
+
from . import util
|
9 |
+
from . import model
|
10 |
+
from . import setting
|
11 |
+
|
12 |
+
suffix = ".civitai"
|
13 |
+
|
14 |
+
url_dict = {
|
15 |
+
"modelPage":"https://civitai.com/models/",
|
16 |
+
"modelId": "https://civitai.com/api/v1/models/",
|
17 |
+
"modelVersionId": "https://civitai.com/api/v1/model-versions/",
|
18 |
+
"hash": "https://civitai.com/api/v1/model-versions/by-hash/"
|
19 |
+
}
|
20 |
+
|
21 |
+
model_type_dict = {
|
22 |
+
"Checkpoint": "ckp",
|
23 |
+
"TextualInversion": "ti",
|
24 |
+
"Hypernetwork": "hyper",
|
25 |
+
"LORA": "lora",
|
26 |
+
"LoCon": "lora",
|
27 |
+
}
|
28 |
+
|
29 |
+
|
30 |
+
|
31 |
+
# get image with full size
|
32 |
+
# width is in number, not string
|
33 |
+
# return: url str
|
34 |
+
def get_full_size_image_url(image_url, width):
|
35 |
+
return re.sub('/width=\d+/', '/width=' + str(width) + '/', image_url)
|
36 |
+
|
37 |
+
|
38 |
+
# use this sha256 to get model info from civitai
|
39 |
+
# return: model info dict
|
40 |
+
def get_model_info_by_hash(hash:str):
|
41 |
+
util.printD("Request model info from civitai")
|
42 |
+
|
43 |
+
if not hash:
|
44 |
+
util.printD("hash is empty")
|
45 |
+
return
|
46 |
+
|
47 |
+
r = requests.get(url_dict["hash"]+hash, headers=util.def_headers, proxies=util.proxies)
|
48 |
+
if not r.ok:
|
49 |
+
if r.status_code == 404:
|
50 |
+
# this is not a civitai model
|
51 |
+
util.printD("Civitai does not have this model")
|
52 |
+
return {}
|
53 |
+
else:
|
54 |
+
util.printD("Get error code: " + str(r.status_code))
|
55 |
+
util.printD(r.text)
|
56 |
+
return
|
57 |
+
|
58 |
+
# try to get content
|
59 |
+
content = None
|
60 |
+
try:
|
61 |
+
content = r.json()
|
62 |
+
except Exception as e:
|
63 |
+
util.printD("Parse response json failed")
|
64 |
+
util.printD(str(e))
|
65 |
+
util.printD("response:")
|
66 |
+
util.printD(r.text)
|
67 |
+
return
|
68 |
+
|
69 |
+
if not content:
|
70 |
+
util.printD("error, content from civitai is None")
|
71 |
+
return
|
72 |
+
|
73 |
+
return content
|
74 |
+
|
75 |
+
|
76 |
+
|
77 |
+
def get_model_info_by_id(id:str) -> dict:
|
78 |
+
util.printD("Request model info from civitai")
|
79 |
+
|
80 |
+
if not id:
|
81 |
+
util.printD("id is empty")
|
82 |
+
return
|
83 |
+
|
84 |
+
r = requests.get(url_dict["modelId"]+str(id), headers=util.def_headers, proxies=util.proxies)
|
85 |
+
if not r.ok:
|
86 |
+
if r.status_code == 404:
|
87 |
+
# this is not a civitai model
|
88 |
+
util.printD("Civitai does not have this model")
|
89 |
+
return {}
|
90 |
+
else:
|
91 |
+
util.printD("Get error code: " + str(r.status_code))
|
92 |
+
util.printD(r.text)
|
93 |
+
return
|
94 |
+
|
95 |
+
# try to get content
|
96 |
+
content = None
|
97 |
+
try:
|
98 |
+
content = r.json()
|
99 |
+
except Exception as e:
|
100 |
+
util.printD("Parse response json failed")
|
101 |
+
util.printD(str(e))
|
102 |
+
util.printD("response:")
|
103 |
+
util.printD(r.text)
|
104 |
+
return
|
105 |
+
|
106 |
+
if not content:
|
107 |
+
util.printD("error, content from civitai is None")
|
108 |
+
return
|
109 |
+
|
110 |
+
return content
|
111 |
+
|
112 |
+
|
113 |
+
def get_version_info_by_version_id(id:str) -> dict:
|
114 |
+
util.printD("Request version info from civitai")
|
115 |
+
|
116 |
+
if not id:
|
117 |
+
util.printD("id is empty")
|
118 |
+
return
|
119 |
+
|
120 |
+
r = requests.get(url_dict["modelVersionId"]+str(id), headers=util.def_headers, proxies=util.proxies)
|
121 |
+
if not r.ok:
|
122 |
+
if r.status_code == 404:
|
123 |
+
# this is not a civitai model
|
124 |
+
util.printD("Civitai does not have this model version")
|
125 |
+
return {}
|
126 |
+
else:
|
127 |
+
util.printD("Get error code: " + str(r.status_code))
|
128 |
+
util.printD(r.text)
|
129 |
+
return
|
130 |
+
|
131 |
+
# try to get content
|
132 |
+
content = None
|
133 |
+
try:
|
134 |
+
content = r.json()
|
135 |
+
except Exception as e:
|
136 |
+
util.printD("Parse response json failed")
|
137 |
+
util.printD(str(e))
|
138 |
+
util.printD("response:")
|
139 |
+
util.printD(r.text)
|
140 |
+
return
|
141 |
+
|
142 |
+
if not content:
|
143 |
+
util.printD("error, content from civitai is None")
|
144 |
+
return
|
145 |
+
|
146 |
+
return content
|
147 |
+
|
148 |
+
|
149 |
+
def get_version_info_by_model_id(id:str) -> dict:
|
150 |
+
|
151 |
+
model_info = get_model_info_by_id(id)
|
152 |
+
if not model_info:
|
153 |
+
util.printD(f"Failed to get model info by id: {id}")
|
154 |
+
return
|
155 |
+
|
156 |
+
# check content to get version id
|
157 |
+
if "modelVersions" not in model_info.keys():
|
158 |
+
util.printD("There is no modelVersions in this model_info")
|
159 |
+
return
|
160 |
+
|
161 |
+
if not model_info["modelVersions"]:
|
162 |
+
util.printD("modelVersions is None")
|
163 |
+
return
|
164 |
+
|
165 |
+
if len(model_info["modelVersions"])==0:
|
166 |
+
util.printD("modelVersions is Empty")
|
167 |
+
return
|
168 |
+
|
169 |
+
def_version = model_info["modelVersions"][0]
|
170 |
+
if not def_version:
|
171 |
+
util.printD("default version is None")
|
172 |
+
return
|
173 |
+
|
174 |
+
if "id" not in def_version.keys():
|
175 |
+
util.printD("default version has no id")
|
176 |
+
return
|
177 |
+
|
178 |
+
version_id = def_version["id"]
|
179 |
+
|
180 |
+
if not version_id:
|
181 |
+
util.printD("default version's id is None")
|
182 |
+
return
|
183 |
+
|
184 |
+
# get version info
|
185 |
+
version_info = get_version_info_by_version_id(str(version_id))
|
186 |
+
if not version_info:
|
187 |
+
util.printD(f"Failed to get version info by version_id: {version_id}")
|
188 |
+
return
|
189 |
+
|
190 |
+
return version_info
|
191 |
+
|
192 |
+
|
193 |
+
|
194 |
+
|
195 |
+
# get model info file's content by model type and search_term
|
196 |
+
# parameter: model_type, search_term
|
197 |
+
# return: model_info
|
198 |
+
def load_model_info_by_search_term(model_type, search_term):
|
199 |
+
util.printD(f"Load model info of {search_term} in {model_type}")
|
200 |
+
if model_type not in model.folders.keys():
|
201 |
+
util.printD("unknow model type: " + model_type)
|
202 |
+
return
|
203 |
+
|
204 |
+
# search_term = subfolderpath + model name + ext. And it always start with a / even there is no sub folder
|
205 |
+
base, ext = os.path.splitext(search_term)
|
206 |
+
model_info_base = base
|
207 |
+
if base[:1] == "/":
|
208 |
+
model_info_base = base[1:]
|
209 |
+
|
210 |
+
model_folder = model.folders[model_type]
|
211 |
+
model_info_filename = model_info_base + suffix + model.info_ext
|
212 |
+
model_info_filepath = os.path.join(model_folder, model_info_filename)
|
213 |
+
|
214 |
+
if not os.path.isfile(model_info_filepath):
|
215 |
+
util.printD("Can not find model info file: " + model_info_filepath)
|
216 |
+
return
|
217 |
+
|
218 |
+
return model.load_model_info(model_info_filepath)
|
219 |
+
|
220 |
+
|
221 |
+
|
222 |
+
|
223 |
+
|
224 |
+
# get model file names by model type
|
225 |
+
# parameter: model_type - string
|
226 |
+
# parameter: filter - dict, which kind of model you need
|
227 |
+
# return: model name list
|
228 |
+
def get_model_names_by_type_and_filter(model_type:str, filter:dict) -> list:
|
229 |
+
|
230 |
+
model_folder = model.folders[model_type]
|
231 |
+
|
232 |
+
# set filter
|
233 |
+
# only get models don't have a civitai info file
|
234 |
+
no_info_only = False
|
235 |
+
empty_info_only = False
|
236 |
+
|
237 |
+
if filter:
|
238 |
+
if "no_info_only" in filter.keys():
|
239 |
+
no_info_only = filter["no_info_only"]
|
240 |
+
if "empty_info_only" in filter.keys():
|
241 |
+
empty_info_only = filter["empty_info_only"]
|
242 |
+
|
243 |
+
|
244 |
+
|
245 |
+
# get information from filter
|
246 |
+
# only get those model names don't have a civitai model info file
|
247 |
+
model_names = []
|
248 |
+
for root, dirs, files in os.walk(model_folder, followlinks=True):
|
249 |
+
for filename in files:
|
250 |
+
item = os.path.join(root, filename)
|
251 |
+
# check extension
|
252 |
+
base, ext = os.path.splitext(item)
|
253 |
+
if ext in model.exts:
|
254 |
+
# find a model
|
255 |
+
|
256 |
+
# check filter
|
257 |
+
if no_info_only:
|
258 |
+
# check model info file
|
259 |
+
info_file = base + suffix + model.info_ext
|
260 |
+
if os.path.isfile(info_file):
|
261 |
+
continue
|
262 |
+
|
263 |
+
if empty_info_only:
|
264 |
+
# check model info file
|
265 |
+
info_file = base + suffix + model.info_ext
|
266 |
+
if os.path.isfile(info_file):
|
267 |
+
# load model info
|
268 |
+
model_info = model.load_model_info(info_file)
|
269 |
+
# check content
|
270 |
+
if model_info:
|
271 |
+
if "id" in model_info.keys():
|
272 |
+
# find a non-empty model info file
|
273 |
+
continue
|
274 |
+
|
275 |
+
model_names.append(filename)
|
276 |
+
|
277 |
+
|
278 |
+
return model_names
|
279 |
+
|
280 |
+
def get_model_names_by_input(model_type, empty_info_only):
|
281 |
+
return get_model_names_by_type_and_filter(model_type, {"empty_info_only":empty_info_only})
|
282 |
+
|
283 |
+
|
284 |
+
# get id from url
|
285 |
+
def get_model_id_from_url(url:str) -> str:
|
286 |
+
util.printD("Run get_model_id_from_url")
|
287 |
+
id = ""
|
288 |
+
|
289 |
+
if not url:
|
290 |
+
util.printD("url or model id can not be empty")
|
291 |
+
return ""
|
292 |
+
|
293 |
+
if url.isnumeric():
|
294 |
+
# is already an id
|
295 |
+
id = str(url)
|
296 |
+
return id
|
297 |
+
|
298 |
+
s = re.sub("\\?.+$", "", url).split("/")
|
299 |
+
if len(s) < 2:
|
300 |
+
util.printD("url is not valid")
|
301 |
+
return ""
|
302 |
+
|
303 |
+
if s[-2].isnumeric():
|
304 |
+
id = s[-2]
|
305 |
+
elif s[-1].isnumeric():
|
306 |
+
id = s[-1]
|
307 |
+
else:
|
308 |
+
util.printD("There is no model id in this url")
|
309 |
+
return ""
|
310 |
+
|
311 |
+
return id
|
312 |
+
|
313 |
+
|
314 |
+
# get preview image by model path
|
315 |
+
# image will be saved to file, so no return
|
316 |
+
def get_preview_image_by_model_path(model_path:str, max_size_preview, skip_nsfw_preview):
|
317 |
+
if not model_path:
|
318 |
+
util.printD("model_path is empty")
|
319 |
+
return
|
320 |
+
|
321 |
+
if not os.path.isfile(model_path):
|
322 |
+
util.printD("model_path is not a file: "+model_path)
|
323 |
+
return
|
324 |
+
|
325 |
+
base, ext = os.path.splitext(model_path)
|
326 |
+
first_preview = base+".png"
|
327 |
+
sec_preview = base+".preview.png"
|
328 |
+
info_file = base + suffix + model.info_ext
|
329 |
+
|
330 |
+
# check preview image
|
331 |
+
if not os.path.isfile(sec_preview):
|
332 |
+
# need to download preview image
|
333 |
+
util.printD("Checking preview image for model: " + model_path)
|
334 |
+
# load model_info file
|
335 |
+
if os.path.isfile(info_file):
|
336 |
+
model_info = model.load_model_info(info_file)
|
337 |
+
if not model_info:
|
338 |
+
util.printD("Model Info is empty")
|
339 |
+
return
|
340 |
+
|
341 |
+
if "images" in model_info.keys():
|
342 |
+
if model_info["images"]:
|
343 |
+
for img_dict in model_info["images"]:
|
344 |
+
if "nsfw" in img_dict.keys():
|
345 |
+
if img_dict["nsfw"]:
|
346 |
+
util.printD("This image is NSFW")
|
347 |
+
if skip_nsfw_preview:
|
348 |
+
util.printD("Skip NSFW image")
|
349 |
+
continue
|
350 |
+
|
351 |
+
if "url" in img_dict.keys():
|
352 |
+
img_url = img_dict["url"]
|
353 |
+
if max_size_preview:
|
354 |
+
# use max width
|
355 |
+
if "width" in img_dict.keys():
|
356 |
+
if img_dict["width"]:
|
357 |
+
img_url = get_full_size_image_url(img_url, img_dict["width"])
|
358 |
+
|
359 |
+
util.download_file(img_url, sec_preview)
|
360 |
+
# we only need 1 preview image
|
361 |
+
break
|
362 |
+
|
363 |
+
|
364 |
+
|
365 |
+
# search local model by version id in 1 folder, no subfolder
|
366 |
+
# return - model_info
|
367 |
+
def search_local_model_info_by_version_id(folder:str, version_id:int) -> dict:
|
368 |
+
util.printD("Searching local model by version id")
|
369 |
+
util.printD("folder: " + folder)
|
370 |
+
util.printD("version_id: " + str(version_id))
|
371 |
+
|
372 |
+
if not folder:
|
373 |
+
util.printD("folder is none")
|
374 |
+
return
|
375 |
+
|
376 |
+
if not os.path.isdir(folder):
|
377 |
+
util.printD("folder is not a dir")
|
378 |
+
return
|
379 |
+
|
380 |
+
if not version_id:
|
381 |
+
util.printD("version_id is none")
|
382 |
+
return
|
383 |
+
|
384 |
+
# search civitai model info file
|
385 |
+
for filename in os.listdir(folder):
|
386 |
+
# check ext
|
387 |
+
base, ext = os.path.splitext(filename)
|
388 |
+
if ext == model.info_ext:
|
389 |
+
# find info file
|
390 |
+
if len(base) < 9:
|
391 |
+
# not a civitai info file
|
392 |
+
continue
|
393 |
+
|
394 |
+
if base[-8:] == suffix:
|
395 |
+
# find a civitai info file
|
396 |
+
path = os.path.join(folder, filename)
|
397 |
+
model_info = model.load_model_info(path)
|
398 |
+
if not model_info:
|
399 |
+
continue
|
400 |
+
|
401 |
+
if "id" not in model_info.keys():
|
402 |
+
continue
|
403 |
+
|
404 |
+
id = model_info["id"]
|
405 |
+
if not id:
|
406 |
+
continue
|
407 |
+
|
408 |
+
# util.printD(f"Compare version id, src: {id}, target:{version_id}")
|
409 |
+
if str(id) == str(version_id):
|
410 |
+
# find the one
|
411 |
+
return model_info
|
412 |
+
|
413 |
+
|
414 |
+
return
|
415 |
+
|
416 |
+
|
417 |
+
|
418 |
+
|
419 |
+
|
420 |
+
# check new version for a model by model path
|
421 |
+
# return (model_path, model_id, model_name, new_verion_id, new_version_name, description, download_url, img_url)
|
422 |
+
def check_model_new_version_by_path(model_path:str, delay:float=1) -> tuple:
|
423 |
+
if not model_path:
|
424 |
+
util.printD("model_path is empty")
|
425 |
+
return
|
426 |
+
|
427 |
+
if not os.path.isfile(model_path):
|
428 |
+
util.printD("model_path is not a file: "+model_path)
|
429 |
+
return
|
430 |
+
|
431 |
+
# get model info file name
|
432 |
+
base, ext = os.path.splitext(model_path)
|
433 |
+
info_file = base + suffix + model.info_ext
|
434 |
+
|
435 |
+
if not os.path.isfile(info_file):
|
436 |
+
return
|
437 |
+
|
438 |
+
# get model info
|
439 |
+
model_info_file = model.load_model_info(info_file)
|
440 |
+
if not model_info_file:
|
441 |
+
return
|
442 |
+
|
443 |
+
if "id" not in model_info_file.keys():
|
444 |
+
return
|
445 |
+
|
446 |
+
local_version_id = model_info_file["id"]
|
447 |
+
if not local_version_id:
|
448 |
+
return
|
449 |
+
|
450 |
+
if "modelId" not in model_info_file.keys():
|
451 |
+
return
|
452 |
+
|
453 |
+
model_id = model_info_file["modelId"]
|
454 |
+
if not model_id:
|
455 |
+
return
|
456 |
+
|
457 |
+
# get model info by id from civitai
|
458 |
+
model_info = get_model_info_by_id(model_id)
|
459 |
+
# delay before next request, to prevent to be treat as DDoS
|
460 |
+
util.printD(f"delay:{delay} second")
|
461 |
+
time.sleep(delay)
|
462 |
+
|
463 |
+
if not model_info:
|
464 |
+
return
|
465 |
+
|
466 |
+
if "modelVersions" not in model_info.keys():
|
467 |
+
return
|
468 |
+
|
469 |
+
modelVersions = model_info["modelVersions"]
|
470 |
+
if not modelVersions:
|
471 |
+
return
|
472 |
+
|
473 |
+
if not len(modelVersions):
|
474 |
+
return
|
475 |
+
|
476 |
+
current_version = modelVersions[0]
|
477 |
+
if not current_version:
|
478 |
+
return
|
479 |
+
|
480 |
+
if "id" not in current_version.keys():
|
481 |
+
return
|
482 |
+
|
483 |
+
current_version_id = current_version["id"]
|
484 |
+
if not current_version_id:
|
485 |
+
return
|
486 |
+
|
487 |
+
util.printD(f"Compare version id, local: {local_version_id}, remote: {current_version_id} ")
|
488 |
+
if current_version_id == local_version_id:
|
489 |
+
return
|
490 |
+
|
491 |
+
model_name = ""
|
492 |
+
if "name" in model_info.keys():
|
493 |
+
model_name = model_info["name"]
|
494 |
+
|
495 |
+
if not model_name:
|
496 |
+
model_name = ""
|
497 |
+
|
498 |
+
|
499 |
+
new_version_name = ""
|
500 |
+
if "name" in current_version.keys():
|
501 |
+
new_version_name = current_version["name"]
|
502 |
+
|
503 |
+
if not new_version_name:
|
504 |
+
new_version_name = ""
|
505 |
+
|
506 |
+
description = ""
|
507 |
+
if "description" in current_version.keys():
|
508 |
+
description = current_version["description"]
|
509 |
+
|
510 |
+
if not description:
|
511 |
+
description = ""
|
512 |
+
|
513 |
+
downloadUrl = ""
|
514 |
+
if "downloadUrl" in current_version.keys():
|
515 |
+
downloadUrl = current_version["downloadUrl"]
|
516 |
+
|
517 |
+
if not downloadUrl:
|
518 |
+
downloadUrl = ""
|
519 |
+
|
520 |
+
# get 1 preview image
|
521 |
+
img_url = ""
|
522 |
+
if "images" in current_version.keys():
|
523 |
+
if current_version["images"]:
|
524 |
+
if current_version["images"][0]:
|
525 |
+
if "url" in current_version["images"][0].keys():
|
526 |
+
img_url = current_version["images"][0]["url"]
|
527 |
+
if not img_url:
|
528 |
+
img_url = ""
|
529 |
+
|
530 |
+
|
531 |
+
|
532 |
+
return (model_path, model_id, model_name, current_version_id, new_version_name, description, downloadUrl, img_url)
|
533 |
+
|
534 |
+
|
535 |
+
|
536 |
+
|
537 |
+
# check model's new version
|
538 |
+
# parameter: delay - float, how many seconds to delay between each request to civitai
|
539 |
+
# return: new_versions - a list for all new versions, each one is (model_path, model_id, model_name, new_verion_id, new_version_name, description, download_url, img_url)
|
540 |
+
def check_models_new_version_by_model_types(model_types:list, delay:float=1) -> list:
|
541 |
+
util.printD("Checking models' new version")
|
542 |
+
|
543 |
+
if not model_types:
|
544 |
+
return []
|
545 |
+
|
546 |
+
# check model types, which cloud be a string as 1 type
|
547 |
+
mts = []
|
548 |
+
if type(model_types) == str:
|
549 |
+
mts.append(model_types)
|
550 |
+
elif type(model_types) == list:
|
551 |
+
mts = model_types
|
552 |
+
else:
|
553 |
+
util.printD("Unknow model types:")
|
554 |
+
util.printD(model_types)
|
555 |
+
return []
|
556 |
+
|
557 |
+
# output is a markdown document string to show a list of new versions on UI
|
558 |
+
output = ""
|
559 |
+
# new version list
|
560 |
+
new_versions = []
|
561 |
+
|
562 |
+
# walk all models
|
563 |
+
for model_type, model_folder in model.folders.items():
|
564 |
+
if model_type not in mts:
|
565 |
+
continue
|
566 |
+
|
567 |
+
util.printD("Scanning path: " + model_folder)
|
568 |
+
for root, dirs, files in os.walk(model_folder, followlinks=True):
|
569 |
+
for filename in files:
|
570 |
+
# check ext
|
571 |
+
item = os.path.join(root, filename)
|
572 |
+
base, ext = os.path.splitext(item)
|
573 |
+
if ext in model.exts:
|
574 |
+
# find a model
|
575 |
+
r = check_model_new_version_by_path(item, delay)
|
576 |
+
|
577 |
+
if not r:
|
578 |
+
continue
|
579 |
+
|
580 |
+
model_path, model_id, model_name, current_version_id, new_version_name, description, downloadUrl, img_url = r
|
581 |
+
# check exist
|
582 |
+
if not current_version_id:
|
583 |
+
continue
|
584 |
+
|
585 |
+
# check this version id in list
|
586 |
+
is_already_in_list = False
|
587 |
+
for new_version in new_versions:
|
588 |
+
if current_version_id == new_version[3]:
|
589 |
+
# already in list
|
590 |
+
is_already_in_list = True
|
591 |
+
break
|
592 |
+
|
593 |
+
if is_already_in_list:
|
594 |
+
util.printD("New version is already in list")
|
595 |
+
continue
|
596 |
+
|
597 |
+
# search this new version id to check if this model is already downloaded
|
598 |
+
target_model_info = search_local_model_info_by_version_id(root, current_version_id)
|
599 |
+
if target_model_info:
|
600 |
+
util.printD("New version is already existed")
|
601 |
+
continue
|
602 |
+
|
603 |
+
# add to list
|
604 |
+
new_versions.append(r)
|
605 |
+
|
606 |
+
|
607 |
+
|
608 |
+
|
609 |
+
return new_versions
|
610 |
+
|
611 |
+
|
612 |
+
|
extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/downloader.py
ADDED
@@ -0,0 +1,115 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: UTF-8 -*-
|
2 |
+
import sys
|
3 |
+
import requests
|
4 |
+
import os
|
5 |
+
from . import util
|
6 |
+
|
7 |
+
|
8 |
+
dl_ext = ".downloading"
|
9 |
+
|
10 |
+
# disable ssl warning info
|
11 |
+
requests.packages.urllib3.disable_warnings()
|
12 |
+
|
13 |
+
# output is downloaded file path
|
14 |
+
def dl(url, folder, filename, filepath):
|
15 |
+
util.printD("Start downloading from: " + url)
|
16 |
+
# get file_path
|
17 |
+
file_path = ""
|
18 |
+
if filepath:
|
19 |
+
file_path = filepath
|
20 |
+
else:
|
21 |
+
# if file_path is not in parameter, then folder must be in parameter
|
22 |
+
if not folder:
|
23 |
+
util.printD("folder is none")
|
24 |
+
return
|
25 |
+
|
26 |
+
if not os.path.isdir(folder):
|
27 |
+
util.printD("folder does not exist: "+folder)
|
28 |
+
return
|
29 |
+
|
30 |
+
if filename:
|
31 |
+
file_path = os.path.join(folder, filename)
|
32 |
+
|
33 |
+
# first request for header
|
34 |
+
rh = requests.get(url, stream=True, verify=False, headers=util.def_headers, proxies=util.proxies)
|
35 |
+
# get file size
|
36 |
+
total_size = 0
|
37 |
+
total_size = int(rh.headers['Content-Length'])
|
38 |
+
util.printD(f"File size: {total_size}")
|
39 |
+
|
40 |
+
# if file_path is empty, need to get file name from download url's header
|
41 |
+
if not file_path:
|
42 |
+
filename = ""
|
43 |
+
if "Content-Disposition" in rh.headers.keys():
|
44 |
+
cd = rh.headers["Content-Disposition"]
|
45 |
+
# Extract the filename from the header
|
46 |
+
# content of a CD: "attachment;filename=FileName.txt"
|
47 |
+
# in case "" is in CD filename's start and end, need to strip them out
|
48 |
+
filename = cd.split("=")[1].strip('"')
|
49 |
+
if not filename:
|
50 |
+
util.printD("Fail to get file name from Content-Disposition: " + cd)
|
51 |
+
return
|
52 |
+
|
53 |
+
if not filename:
|
54 |
+
util.printD("Can not get file name from download url's header")
|
55 |
+
return
|
56 |
+
|
57 |
+
# with folder and filename, now we have the full file path
|
58 |
+
file_path = os.path.join(folder, filename)
|
59 |
+
|
60 |
+
|
61 |
+
util.printD("Target file path: " + file_path)
|
62 |
+
base, ext = os.path.splitext(file_path)
|
63 |
+
|
64 |
+
# check if file is already exist
|
65 |
+
count = 2
|
66 |
+
new_base = base
|
67 |
+
while os.path.isfile(file_path):
|
68 |
+
util.printD("Target file already exist.")
|
69 |
+
# re-name
|
70 |
+
new_base = base + "_" + str(count)
|
71 |
+
file_path = new_base + ext
|
72 |
+
count += 1
|
73 |
+
|
74 |
+
# use a temp file for downloading
|
75 |
+
dl_file_path = new_base+dl_ext
|
76 |
+
|
77 |
+
|
78 |
+
util.printD(f"Downloading to temp file: {dl_file_path}")
|
79 |
+
|
80 |
+
# check if downloading file is exsited
|
81 |
+
downloaded_size = 0
|
82 |
+
if os.path.exists(dl_file_path):
|
83 |
+
downloaded_size = os.path.getsize(dl_file_path)
|
84 |
+
|
85 |
+
util.printD(f"Downloaded size: {downloaded_size}")
|
86 |
+
|
87 |
+
# create header range
|
88 |
+
headers = {'Range': 'bytes=%d-' % downloaded_size}
|
89 |
+
headers['User-Agent'] = util.def_headers['User-Agent']
|
90 |
+
|
91 |
+
# download with header
|
92 |
+
r = requests.get(url, stream=True, verify=False, headers=headers, proxies=util.proxies)
|
93 |
+
|
94 |
+
# write to file
|
95 |
+
with open(dl_file_path, "ab") as f:
|
96 |
+
for chunk in r.iter_content(chunk_size=1024):
|
97 |
+
if chunk:
|
98 |
+
downloaded_size += len(chunk)
|
99 |
+
f.write(chunk)
|
100 |
+
# force to write to disk
|
101 |
+
f.flush()
|
102 |
+
|
103 |
+
# progress
|
104 |
+
progress = int(50 * downloaded_size / total_size)
|
105 |
+
sys.stdout.reconfigure(encoding='utf-8')
|
106 |
+
sys.stdout.write("\r[%s%s] %d%%" % ('-' * progress, ' ' * (50 - progress), 100 * downloaded_size / total_size))
|
107 |
+
sys.stdout.flush()
|
108 |
+
|
109 |
+
print()
|
110 |
+
|
111 |
+
# rename file
|
112 |
+
os.rename(dl_file_path, file_path)
|
113 |
+
util.printD(f"File Downloaded to: {file_path}")
|
114 |
+
return file_path
|
115 |
+
|
extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/js_action_civitai.py
ADDED
@@ -0,0 +1,256 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: UTF-8 -*-
|
2 |
+
# handle msg between js and python side
|
3 |
+
import os
|
4 |
+
import json
|
5 |
+
import requests
|
6 |
+
import webbrowser
|
7 |
+
from . import util
|
8 |
+
from . import model
|
9 |
+
from . import civitai
|
10 |
+
from . import msg_handler
|
11 |
+
from . import downloader
|
12 |
+
|
13 |
+
|
14 |
+
|
15 |
+
# get civitai's model url and open it in browser
|
16 |
+
# parameter: model_type, search_term
|
17 |
+
# output: python msg - will be sent to hidden textbox then picked by js side
|
18 |
+
def open_model_url(msg, open_url_with_js):
|
19 |
+
util.printD("Start open_model_url")
|
20 |
+
|
21 |
+
output = ""
|
22 |
+
result = msg_handler.parse_js_msg(msg)
|
23 |
+
if not result:
|
24 |
+
util.printD("Parsing js ms failed")
|
25 |
+
return
|
26 |
+
|
27 |
+
model_type = result["model_type"]
|
28 |
+
search_term = result["search_term"]
|
29 |
+
|
30 |
+
model_info = civitai.load_model_info_by_search_term(model_type, search_term)
|
31 |
+
if not model_info:
|
32 |
+
util.printD(f"Failed to get model info for {model_type} {search_term}")
|
33 |
+
return ""
|
34 |
+
|
35 |
+
if "modelId" not in model_info.keys():
|
36 |
+
util.printD(f"Failed to get model id from info file for {model_type} {search_term}")
|
37 |
+
return ""
|
38 |
+
|
39 |
+
model_id = model_info["modelId"]
|
40 |
+
if not model_id:
|
41 |
+
util.printD(f"model id from info file of {model_type} {search_term} is None")
|
42 |
+
return ""
|
43 |
+
|
44 |
+
url = civitai.url_dict["modelPage"]+str(model_id)
|
45 |
+
|
46 |
+
|
47 |
+
# msg content for js
|
48 |
+
content = {
|
49 |
+
"url":""
|
50 |
+
}
|
51 |
+
|
52 |
+
if not open_url_with_js:
|
53 |
+
util.printD("Open Url: " + url)
|
54 |
+
# open url
|
55 |
+
webbrowser.open_new_tab(url)
|
56 |
+
else:
|
57 |
+
util.printD("Send Url to js")
|
58 |
+
content["url"] = url
|
59 |
+
output = msg_handler.build_py_msg("open_url", content)
|
60 |
+
|
61 |
+
util.printD("End open_model_url")
|
62 |
+
return output
|
63 |
+
|
64 |
+
|
65 |
+
|
66 |
+
# add trigger words to prompt
|
67 |
+
# parameter: model_type, search_term, prompt
|
68 |
+
# return: [new_prompt, new_prompt] - new prompt with trigger words, return twice for txt2img and img2img
|
69 |
+
def add_trigger_words(msg):
|
70 |
+
util.printD("Start add_trigger_words")
|
71 |
+
|
72 |
+
result = msg_handler.parse_js_msg(msg)
|
73 |
+
if not result:
|
74 |
+
util.printD("Parsing js ms failed")
|
75 |
+
return
|
76 |
+
|
77 |
+
model_type = result["model_type"]
|
78 |
+
search_term = result["search_term"]
|
79 |
+
prompt = result["prompt"]
|
80 |
+
|
81 |
+
|
82 |
+
model_info = civitai.load_model_info_by_search_term(model_type, search_term)
|
83 |
+
if not model_info:
|
84 |
+
util.printD(f"Failed to get model info for {model_type} {search_term}")
|
85 |
+
return [prompt, prompt]
|
86 |
+
|
87 |
+
if "trainedWords" not in model_info.keys():
|
88 |
+
util.printD(f"Failed to get trainedWords from info file for {model_type} {search_term}")
|
89 |
+
return [prompt, prompt]
|
90 |
+
|
91 |
+
trainedWords = model_info["trainedWords"]
|
92 |
+
if not trainedWords:
|
93 |
+
util.printD(f"No trainedWords from info file for {model_type} {search_term}")
|
94 |
+
return [prompt, prompt]
|
95 |
+
|
96 |
+
if len(trainedWords) == 0:
|
97 |
+
util.printD(f"trainedWords from info file for {model_type} {search_term} is empty")
|
98 |
+
return [prompt, prompt]
|
99 |
+
|
100 |
+
# get ful trigger words
|
101 |
+
trigger_words = ""
|
102 |
+
for word in trainedWords:
|
103 |
+
trigger_words = trigger_words + word + ", "
|
104 |
+
|
105 |
+
new_prompt = prompt + " " + trigger_words
|
106 |
+
util.printD("trigger_words: " + trigger_words)
|
107 |
+
util.printD("prompt: " + prompt)
|
108 |
+
util.printD("new_prompt: " + new_prompt)
|
109 |
+
|
110 |
+
util.printD("End add_trigger_words")
|
111 |
+
|
112 |
+
# add to prompt
|
113 |
+
return [new_prompt, new_prompt]
|
114 |
+
|
115 |
+
|
116 |
+
|
117 |
+
# use preview image's prompt as prompt
|
118 |
+
# parameter: model_type, model_name, prompt, neg_prompt
|
119 |
+
# return: [new_prompt, new_neg_prompt, new_prompt, new_neg_prompt,] - return twice for txt2img and img2img
|
120 |
+
def use_preview_image_prompt(msg):
|
121 |
+
util.printD("Start use_preview_image_prompt")
|
122 |
+
|
123 |
+
result = msg_handler.parse_js_msg(msg)
|
124 |
+
if not result:
|
125 |
+
util.printD("Parsing js ms failed")
|
126 |
+
return
|
127 |
+
|
128 |
+
model_type = result["model_type"]
|
129 |
+
search_term = result["search_term"]
|
130 |
+
prompt = result["prompt"]
|
131 |
+
neg_prompt = result["neg_prompt"]
|
132 |
+
|
133 |
+
|
134 |
+
model_info = civitai.load_model_info_by_search_term(model_type, search_term)
|
135 |
+
if not model_info:
|
136 |
+
util.printD(f"Failed to get model info for {model_type} {search_term}")
|
137 |
+
return [prompt, neg_prompt, prompt, neg_prompt]
|
138 |
+
|
139 |
+
if "images" not in model_info.keys():
|
140 |
+
util.printD(f"Failed to get images from info file for {model_type} {search_term}")
|
141 |
+
return [prompt, neg_prompt, prompt, neg_prompt]
|
142 |
+
|
143 |
+
images = model_info["images"]
|
144 |
+
if not images:
|
145 |
+
util.printD(f"No images from info file for {model_type} {search_term}")
|
146 |
+
return [prompt, neg_prompt, prompt, neg_prompt]
|
147 |
+
|
148 |
+
if len(images) == 0:
|
149 |
+
util.printD(f"images from info file for {model_type} {search_term} is empty")
|
150 |
+
return [prompt, neg_prompt, prompt, neg_prompt]
|
151 |
+
|
152 |
+
# get prompt from preview images' meta data
|
153 |
+
preview_prompt = ""
|
154 |
+
preview_neg_prompt = ""
|
155 |
+
for img in images:
|
156 |
+
if "meta" in img.keys():
|
157 |
+
if img["meta"]:
|
158 |
+
if "prompt" in img["meta"].keys():
|
159 |
+
if img["meta"]["prompt"]:
|
160 |
+
preview_prompt = img["meta"]["prompt"]
|
161 |
+
|
162 |
+
if "negativePrompt" in img["meta"].keys():
|
163 |
+
if img["meta"]["negativePrompt"]:
|
164 |
+
preview_neg_prompt = img["meta"]["negativePrompt"]
|
165 |
+
|
166 |
+
# we only need 1 prompt
|
167 |
+
if preview_prompt:
|
168 |
+
break
|
169 |
+
|
170 |
+
if not preview_prompt:
|
171 |
+
util.printD(f"There is no prompt of {model_type} {search_term} in its preview image")
|
172 |
+
return [prompt, neg_prompt, prompt, neg_prompt]
|
173 |
+
|
174 |
+
util.printD("End use_preview_image_prompt")
|
175 |
+
|
176 |
+
return [preview_prompt, preview_neg_prompt, preview_prompt, preview_neg_prompt]
|
177 |
+
|
178 |
+
|
179 |
+
# download model's new verson by model path, version id and download url
|
180 |
+
# output is a md log
|
181 |
+
def dl_model_new_version(msg, max_size_preview, skip_nsfw_preview):
|
182 |
+
util.printD("Start dl_model_new_version")
|
183 |
+
|
184 |
+
output = ""
|
185 |
+
|
186 |
+
result = msg_handler.parse_js_msg(msg)
|
187 |
+
if not result:
|
188 |
+
output = "Parsing js ms failed"
|
189 |
+
util.printD(output)
|
190 |
+
return output
|
191 |
+
|
192 |
+
model_path = result["model_path"]
|
193 |
+
version_id = result["version_id"]
|
194 |
+
download_url = result["download_url"]
|
195 |
+
|
196 |
+
util.printD("model_path: " + model_path)
|
197 |
+
util.printD("version_id: " + str(version_id))
|
198 |
+
util.printD("download_url: " + download_url)
|
199 |
+
|
200 |
+
# check data
|
201 |
+
if not model_path:
|
202 |
+
output = "model_path is empty"
|
203 |
+
util.printD(output)
|
204 |
+
return output
|
205 |
+
|
206 |
+
if not version_id:
|
207 |
+
output = "version_id is empty"
|
208 |
+
util.printD(output)
|
209 |
+
return output
|
210 |
+
|
211 |
+
if not download_url:
|
212 |
+
output = "download_url is empty"
|
213 |
+
util.printD(output)
|
214 |
+
return output
|
215 |
+
|
216 |
+
if not os.path.isfile(model_path):
|
217 |
+
output = "model_path is not a file: "+ model_path
|
218 |
+
util.printD(output)
|
219 |
+
return output
|
220 |
+
|
221 |
+
# get model folder from model path
|
222 |
+
model_folder = os.path.dirname(model_path)
|
223 |
+
|
224 |
+
# no need to check when downloading new version, since checking new version is already checked
|
225 |
+
# check if this model is already existed
|
226 |
+
# r = civitai.search_local_model_info_by_version_id(model_folder, version_id)
|
227 |
+
# if r:
|
228 |
+
# output = "This model version is already existed"
|
229 |
+
# util.printD(output)
|
230 |
+
# return output
|
231 |
+
|
232 |
+
# download file
|
233 |
+
new_model_path = downloader.dl(download_url, model_folder, None, None)
|
234 |
+
if not new_model_path:
|
235 |
+
output = "Download failed, check console log for detail. Download url: " + download_url
|
236 |
+
util.printD(output)
|
237 |
+
return output
|
238 |
+
|
239 |
+
# get version info
|
240 |
+
version_info = civitai.get_version_info_by_version_id(version_id)
|
241 |
+
if not version_info:
|
242 |
+
output = "Model downloaded, but failed to get version info, check console log for detail. Model saved to: " + new_model_path
|
243 |
+
util.printD(output)
|
244 |
+
return output
|
245 |
+
|
246 |
+
# now write version info to file
|
247 |
+
base, ext = os.path.splitext(new_model_path)
|
248 |
+
info_file = base + civitai.suffix + model.info_ext
|
249 |
+
model.write_model_info(info_file, version_info)
|
250 |
+
|
251 |
+
# then, get preview image
|
252 |
+
civitai.get_preview_image_by_model_path(new_model_path, max_size_preview, skip_nsfw_preview)
|
253 |
+
|
254 |
+
output = "Done. Model downloaded to: " + new_model_path
|
255 |
+
util.printD(output)
|
256 |
+
return output
|
extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/model.py
ADDED
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: UTF-8 -*-
|
2 |
+
# handle msg between js and python side
|
3 |
+
import os
|
4 |
+
import json
|
5 |
+
from . import util
|
6 |
+
from modules import shared
|
7 |
+
|
8 |
+
|
9 |
+
# this is the default root path
|
10 |
+
root_path = os.getcwd()
|
11 |
+
|
12 |
+
# if command line arguement is used to change model folder,
|
13 |
+
# then model folder is in absolute path, not based on this root path anymore.
|
14 |
+
# so to make extension work with those absolute model folder paths, model folder also need to be in absolute path
|
15 |
+
folders = {
|
16 |
+
"ti": os.path.join(root_path, "embeddings"),
|
17 |
+
"hyper": os.path.join(root_path, "models", "hypernetworks"),
|
18 |
+
"ckp": os.path.join(root_path, "models", "Stable-diffusion"),
|
19 |
+
"lora": os.path.join(root_path, "models", "Lora"),
|
20 |
+
}
|
21 |
+
|
22 |
+
exts = (".bin", ".pt", ".safetensors", ".ckpt")
|
23 |
+
info_ext = ".info"
|
24 |
+
vae_suffix = ".vae"
|
25 |
+
|
26 |
+
|
27 |
+
# get cusomter model path
|
28 |
+
def get_custom_model_folder():
|
29 |
+
util.printD("Get Custom Model Folder")
|
30 |
+
|
31 |
+
global folders
|
32 |
+
|
33 |
+
if shared.cmd_opts.embeddings_dir and os.path.isdir(shared.cmd_opts.embeddings_dir):
|
34 |
+
folders["ti"] = shared.cmd_opts.embeddings_dir
|
35 |
+
|
36 |
+
if shared.cmd_opts.hypernetwork_dir and os.path.isdir(shared.cmd_opts.hypernetwork_dir):
|
37 |
+
folders["hyper"] = shared.cmd_opts.hypernetwork_dir
|
38 |
+
|
39 |
+
if shared.cmd_opts.ckpt_dir and os.path.isdir(shared.cmd_opts.ckpt_dir):
|
40 |
+
folders["ckp"] = shared.cmd_opts.ckpt_dir
|
41 |
+
|
42 |
+
if shared.cmd_opts.lora_dir and os.path.isdir(shared.cmd_opts.lora_dir):
|
43 |
+
folders["lora"] = shared.cmd_opts.lora_dir
|
44 |
+
|
45 |
+
|
46 |
+
|
47 |
+
|
48 |
+
|
49 |
+
# write model info to file
|
50 |
+
def write_model_info(path, model_info):
|
51 |
+
util.printD("Write model info to file: " + path)
|
52 |
+
with open(os.path.realpath(path), 'w') as f:
|
53 |
+
f.write(json.dumps(model_info, indent=4))
|
54 |
+
|
55 |
+
|
56 |
+
def load_model_info(path):
|
57 |
+
# util.printD("Load model info from file: " + path)
|
58 |
+
model_info = None
|
59 |
+
with open(os.path.realpath(path), 'r') as f:
|
60 |
+
try:
|
61 |
+
model_info = json.load(f)
|
62 |
+
except Exception as e:
|
63 |
+
util.printD("Selected file is not json: " + path)
|
64 |
+
util.printD(e)
|
65 |
+
return
|
66 |
+
|
67 |
+
return model_info
|
68 |
+
|
69 |
+
|
70 |
+
# get model file names by model type
|
71 |
+
# parameter: model_type - string
|
72 |
+
# return: model name list
|
73 |
+
def get_model_names_by_type(model_type:str) -> list:
|
74 |
+
|
75 |
+
model_folder = folders[model_type]
|
76 |
+
|
77 |
+
# get information from filter
|
78 |
+
# only get those model names don't have a civitai model info file
|
79 |
+
model_names = []
|
80 |
+
for root, dirs, files in os.walk(model_folder, followlinks=True):
|
81 |
+
for filename in files:
|
82 |
+
item = os.path.join(root, filename)
|
83 |
+
# check extension
|
84 |
+
base, ext = os.path.splitext(item)
|
85 |
+
if ext in exts:
|
86 |
+
# find a model
|
87 |
+
model_names.append(filename)
|
88 |
+
|
89 |
+
|
90 |
+
return model_names
|
91 |
+
|
92 |
+
|
93 |
+
# return 2 values: (model_root, model_path)
|
94 |
+
def get_model_path_by_type_and_name(model_type:str, model_name:str) -> str:
|
95 |
+
util.printD("Run get_model_path_by_type_and_name")
|
96 |
+
if model_type not in folders.keys():
|
97 |
+
util.printD("unknown model_type: " + model_type)
|
98 |
+
return
|
99 |
+
|
100 |
+
if not model_name:
|
101 |
+
util.printD("model name can not be empty")
|
102 |
+
return
|
103 |
+
|
104 |
+
folder = folders[model_type]
|
105 |
+
|
106 |
+
# model could be in subfolder, need to walk.
|
107 |
+
model_root = ""
|
108 |
+
model_path = ""
|
109 |
+
for root, dirs, files in os.walk(folder, followlinks=True):
|
110 |
+
for filename in files:
|
111 |
+
if filename == model_name:
|
112 |
+
# find model
|
113 |
+
model_root = root
|
114 |
+
model_path = os.path.join(root, filename)
|
115 |
+
return (model_root, model_path)
|
116 |
+
|
117 |
+
return
|
118 |
+
|
119 |
+
|
120 |
+
|
extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/model_action_civitai.py
ADDED
@@ -0,0 +1,511 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: UTF-8 -*-
|
2 |
+
# handle msg between js and python side
|
3 |
+
import os
|
4 |
+
import time
|
5 |
+
from . import util
|
6 |
+
from . import model
|
7 |
+
from . import civitai
|
8 |
+
from . import downloader
|
9 |
+
|
10 |
+
|
11 |
+
# scan model to generate SHA256, then use this SHA256 to get model info from civitai
|
12 |
+
# return output msg
|
13 |
+
def scan_model(scan_model_types, max_size_preview, skip_nsfw_preview):
|
14 |
+
util.printD("Start scan_model")
|
15 |
+
output = ""
|
16 |
+
|
17 |
+
# check model types
|
18 |
+
if not scan_model_types:
|
19 |
+
output = "Model Types is None, can not scan."
|
20 |
+
util.printD(output)
|
21 |
+
return output
|
22 |
+
|
23 |
+
model_types = []
|
24 |
+
# check type if it is a string
|
25 |
+
if type(scan_model_types) == str:
|
26 |
+
model_types.append(scan_model_types)
|
27 |
+
else:
|
28 |
+
model_types = scan_model_types
|
29 |
+
|
30 |
+
model_count = 0
|
31 |
+
image_count = 0
|
32 |
+
# scan_log = ""
|
33 |
+
for model_type, model_folder in model.folders.items():
|
34 |
+
if model_type not in model_types:
|
35 |
+
continue
|
36 |
+
|
37 |
+
util.printD("Scanning path: " + model_folder)
|
38 |
+
for root, dirs, files in os.walk(model_folder, followlinks=True):
|
39 |
+
for filename in files:
|
40 |
+
# check ext
|
41 |
+
item = os.path.join(root, filename)
|
42 |
+
base, ext = os.path.splitext(item)
|
43 |
+
if ext in model.exts:
|
44 |
+
# ignore vae file
|
45 |
+
if len(base) > 4:
|
46 |
+
if base[-4:] == model.vae_suffix:
|
47 |
+
# find .vae
|
48 |
+
util.printD("This is a vae file: " + filename)
|
49 |
+
continue
|
50 |
+
|
51 |
+
# find a model
|
52 |
+
# get info file
|
53 |
+
info_file = base + civitai.suffix + model.info_ext
|
54 |
+
# check info file
|
55 |
+
if not os.path.isfile(info_file):
|
56 |
+
util.printD("Creating model info for: " + filename)
|
57 |
+
# get model's sha256
|
58 |
+
hash = util.gen_file_sha256(item)
|
59 |
+
|
60 |
+
if not hash:
|
61 |
+
output = "failed generating SHA256 for model:" + filename
|
62 |
+
util.printD(output)
|
63 |
+
return output
|
64 |
+
|
65 |
+
# use this sha256 to get model info from civitai
|
66 |
+
model_info = civitai.get_model_info_by_hash(hash)
|
67 |
+
# delay 1 second for ti
|
68 |
+
if model_type == "ti":
|
69 |
+
util.printD("Delay 1 second for TI")
|
70 |
+
time.sleep(1)
|
71 |
+
|
72 |
+
if model_info is None:
|
73 |
+
output = "Connect to Civitai API service failed. Wait a while and try again"
|
74 |
+
util.printD(output)
|
75 |
+
return output+", check console log for detail"
|
76 |
+
|
77 |
+
# write model info to file
|
78 |
+
model.write_model_info(info_file, model_info)
|
79 |
+
|
80 |
+
# set model_count
|
81 |
+
model_count = model_count+1
|
82 |
+
|
83 |
+
# check preview image
|
84 |
+
civitai.get_preview_image_by_model_path(item, max_size_preview, skip_nsfw_preview)
|
85 |
+
image_count = image_count+1
|
86 |
+
|
87 |
+
|
88 |
+
# scan_log = "Done"
|
89 |
+
|
90 |
+
output = f"Done. Scanned {model_count} models, checked {image_count} images"
|
91 |
+
|
92 |
+
util.printD(output)
|
93 |
+
|
94 |
+
return output
|
95 |
+
|
96 |
+
|
97 |
+
|
98 |
+
# Get model info by model type, name and url
|
99 |
+
# output is log info to display on markdown component
|
100 |
+
def get_model_info_by_input(model_type, model_name, model_url_or_id, max_size_preview, skip_nsfw_preview):
|
101 |
+
output = ""
|
102 |
+
# parse model id
|
103 |
+
model_id = civitai.get_model_id_from_url(model_url_or_id)
|
104 |
+
if not model_id:
|
105 |
+
output = "failed to parse model id from url: " + model_url_or_id
|
106 |
+
util.printD(output)
|
107 |
+
return output
|
108 |
+
|
109 |
+
# get model file path
|
110 |
+
# model could be in subfolder
|
111 |
+
result = model.get_model_path_by_type_and_name(model_type, model_name)
|
112 |
+
if not result:
|
113 |
+
output = "failed to get model file path"
|
114 |
+
util.printD(output)
|
115 |
+
return output
|
116 |
+
|
117 |
+
model_root, model_path = result
|
118 |
+
if not model_path:
|
119 |
+
output = "model path is empty"
|
120 |
+
util.printD(output)
|
121 |
+
return output
|
122 |
+
|
123 |
+
# get info file path
|
124 |
+
base, ext = os.path.splitext(model_path)
|
125 |
+
info_file = base + civitai.suffix + model.info_ext
|
126 |
+
|
127 |
+
# get model info
|
128 |
+
#we call it model_info, but in civitai, it is actually version info
|
129 |
+
model_info = civitai.get_version_info_by_model_id(model_id)
|
130 |
+
|
131 |
+
if not model_info:
|
132 |
+
output = "failed to get model info from url: " + model_url_or_id
|
133 |
+
util.printD(output)
|
134 |
+
return output
|
135 |
+
|
136 |
+
# write model info to file
|
137 |
+
model.write_model_info(info_file, model_info)
|
138 |
+
|
139 |
+
util.printD("Saved model info to: "+ info_file)
|
140 |
+
|
141 |
+
# check preview image
|
142 |
+
civitai.get_preview_image_by_model_path(model_path, max_size_preview, skip_nsfw_preview)
|
143 |
+
|
144 |
+
output = "Model Info saved to: " + info_file
|
145 |
+
return output
|
146 |
+
|
147 |
+
|
148 |
+
|
149 |
+
# check models' new version and output to UI as markdown doc
|
150 |
+
def check_models_new_version_to_md(model_types:list) -> str:
|
151 |
+
new_versions = civitai.check_models_new_version_by_model_types(model_types, 1)
|
152 |
+
|
153 |
+
count = 0
|
154 |
+
output = ""
|
155 |
+
if not new_versions:
|
156 |
+
output = "No model has new version"
|
157 |
+
else:
|
158 |
+
output = "Found new version for following models: <br>"
|
159 |
+
for new_version in new_versions:
|
160 |
+
count = count+1
|
161 |
+
model_path, model_id, model_name, new_verion_id, new_version_name, description, download_url, img_url = new_version
|
162 |
+
# in md, each part is something like this:
|
163 |
+
# [model_name](model_url)
|
164 |
+
# [version_name](download_url)
|
165 |
+
# version description
|
166 |
+
url = civitai.url_dict["modelPage"]+str(model_id)
|
167 |
+
|
168 |
+
part = f'<div style="font-size:20px;margin:6px 0px;"><b>Model: <a href="{url}" target="_blank"><u>{model_name}</u></a></b></div>'
|
169 |
+
part = part + f'<div style="font-size:16px">File: {model_path}</div>'
|
170 |
+
if download_url:
|
171 |
+
# replace "\" to "/" in model_path for windows
|
172 |
+
model_path = model_path.replace('\\', '\\\\')
|
173 |
+
part = part + f'<div style="font-size:16px;margin:6px 0px;">New Version: <u><a href="{download_url}" target="_blank" style="margin:0px 10px;">{new_version_name}</a></u>'
|
174 |
+
# add js function to download new version into SD webui by python
|
175 |
+
part = part + " "
|
176 |
+
# in embed HTML, onclick= will also follow a ", never a ', so have to write it as following
|
177 |
+
part = part + f"<u><a href='#' style='margin:0px 10px;' onclick=\"ch_dl_model_new_version(event, '{model_path}', '{new_verion_id}', '{download_url}')\">[Download into SD]</a></u>"
|
178 |
+
|
179 |
+
else:
|
180 |
+
part = part + f'<div style="font-size:16px;margin:6px 0px;">New Version: {new_version_name}'
|
181 |
+
part = part + '</div>'
|
182 |
+
|
183 |
+
# description
|
184 |
+
if description:
|
185 |
+
part = part + '<blockquote style="font-size:16px;margin:6px 0px;">'+ description + '</blockquote><br>'
|
186 |
+
|
187 |
+
# preview image
|
188 |
+
if img_url:
|
189 |
+
part = part + f"<img src='{img_url}'><br>"
|
190 |
+
|
191 |
+
|
192 |
+
output = output + part
|
193 |
+
|
194 |
+
util.printD(f"Done. Find {count} models have new version. Check UI for detail.")
|
195 |
+
|
196 |
+
return output
|
197 |
+
|
198 |
+
|
199 |
+
# get model info by url
|
200 |
+
def get_model_info_by_url(model_url_or_id:str) -> tuple:
|
201 |
+
util.printD("Getting model info by: " + model_url_or_id)
|
202 |
+
|
203 |
+
# parse model id
|
204 |
+
model_id = civitai.get_model_id_from_url(model_url_or_id)
|
205 |
+
if not model_id:
|
206 |
+
util.printD("failed to parse model id from url or id")
|
207 |
+
return
|
208 |
+
|
209 |
+
model_info = civitai.get_model_info_by_id(model_id)
|
210 |
+
if model_info is None:
|
211 |
+
util.printD("Connect to Civitai API service failed. Wait a while and try again")
|
212 |
+
return
|
213 |
+
|
214 |
+
if not model_info:
|
215 |
+
util.printD("failed to get model info from url or id")
|
216 |
+
return
|
217 |
+
|
218 |
+
# parse model type, model name, subfolder, version from this model info
|
219 |
+
# get model type
|
220 |
+
if "type" not in model_info.keys():
|
221 |
+
util.printD("model type is not in model_info")
|
222 |
+
return
|
223 |
+
|
224 |
+
civitai_model_type = model_info["type"]
|
225 |
+
if civitai_model_type not in civitai.model_type_dict.keys():
|
226 |
+
util.printD("This model type is not supported:"+civitai_model_type)
|
227 |
+
return
|
228 |
+
|
229 |
+
model_type = civitai.model_type_dict[civitai_model_type]
|
230 |
+
|
231 |
+
# get model type
|
232 |
+
if "name" not in model_info.keys():
|
233 |
+
util.printD("model name is not in model_info")
|
234 |
+
return
|
235 |
+
|
236 |
+
model_name = model_info["name"]
|
237 |
+
if not model_name:
|
238 |
+
util.printD("model name is Empty")
|
239 |
+
model_name = ""
|
240 |
+
|
241 |
+
# get version list
|
242 |
+
if "modelVersions" not in model_info.keys():
|
243 |
+
util.printD("modelVersions is not in model_info")
|
244 |
+
return
|
245 |
+
|
246 |
+
modelVersions = model_info["modelVersions"]
|
247 |
+
if not modelVersions:
|
248 |
+
util.printD("modelVersions is Empty")
|
249 |
+
return
|
250 |
+
|
251 |
+
version_strs = []
|
252 |
+
for version in modelVersions:
|
253 |
+
# version name can not be used as id
|
254 |
+
# version id is not readable
|
255 |
+
# so , we use name_id as version string
|
256 |
+
version_str = version["name"]+"_"+str(version["id"])
|
257 |
+
version_strs.append(version_str)
|
258 |
+
|
259 |
+
# get folder by model type
|
260 |
+
folder = model.folders[model_type]
|
261 |
+
# get subfolders
|
262 |
+
subfolders = util.get_subfolders(folder)
|
263 |
+
if not subfolders:
|
264 |
+
subfolders = []
|
265 |
+
|
266 |
+
# add default root folder
|
267 |
+
subfolders.append("/")
|
268 |
+
|
269 |
+
util.printD("Get following info for downloading:")
|
270 |
+
util.printD(f"model_name:{model_name}")
|
271 |
+
util.printD(f"model_type:{model_type}")
|
272 |
+
util.printD(f"subfolders:{subfolders}")
|
273 |
+
util.printD(f"version_strs:{version_strs}")
|
274 |
+
|
275 |
+
return (model_info, model_name, model_type, subfolders, version_strs)
|
276 |
+
|
277 |
+
# get version info by version string
|
278 |
+
def get_ver_info_by_ver_str(version_str:str, model_info:dict) -> dict:
|
279 |
+
if not version_str:
|
280 |
+
util.printD("version_str is empty")
|
281 |
+
return
|
282 |
+
|
283 |
+
if not model_info:
|
284 |
+
util.printD("model_info is None")
|
285 |
+
return
|
286 |
+
|
287 |
+
# get version list
|
288 |
+
if "modelVersions" not in model_info.keys():
|
289 |
+
util.printD("modelVersions is not in model_info")
|
290 |
+
return
|
291 |
+
|
292 |
+
modelVersions = model_info["modelVersions"]
|
293 |
+
if not modelVersions:
|
294 |
+
util.printD("modelVersions is Empty")
|
295 |
+
return
|
296 |
+
|
297 |
+
# find version by version_str
|
298 |
+
version = None
|
299 |
+
for ver in modelVersions:
|
300 |
+
# version name can not be used as id
|
301 |
+
# version id is not readable
|
302 |
+
# so , we use name_id as version string
|
303 |
+
ver_str = ver["name"]+"_"+str(ver["id"])
|
304 |
+
if ver_str == version_str:
|
305 |
+
# find version
|
306 |
+
version = ver
|
307 |
+
|
308 |
+
if not version:
|
309 |
+
util.printD("can not find version by version string: " + version_str)
|
310 |
+
return
|
311 |
+
|
312 |
+
# get version id
|
313 |
+
if "id" not in version.keys():
|
314 |
+
util.printD("this version has no id")
|
315 |
+
return
|
316 |
+
|
317 |
+
return version
|
318 |
+
|
319 |
+
|
320 |
+
# get download url from model info by version string
|
321 |
+
# return - (version_id, download_url)
|
322 |
+
def get_id_and_dl_url_by_version_str(version_str:str, model_info:dict) -> tuple:
|
323 |
+
if not version_str:
|
324 |
+
util.printD("version_str is empty")
|
325 |
+
return
|
326 |
+
|
327 |
+
if not model_info:
|
328 |
+
util.printD("model_info is None")
|
329 |
+
return
|
330 |
+
|
331 |
+
# get version list
|
332 |
+
if "modelVersions" not in model_info.keys():
|
333 |
+
util.printD("modelVersions is not in model_info")
|
334 |
+
return
|
335 |
+
|
336 |
+
modelVersions = model_info["modelVersions"]
|
337 |
+
if not modelVersions:
|
338 |
+
util.printD("modelVersions is Empty")
|
339 |
+
return
|
340 |
+
|
341 |
+
# find version by version_str
|
342 |
+
version = None
|
343 |
+
for ver in modelVersions:
|
344 |
+
# version name can not be used as id
|
345 |
+
# version id is not readable
|
346 |
+
# so , we use name_id as version string
|
347 |
+
ver_str = ver["name"]+"_"+str(ver["id"])
|
348 |
+
if ver_str == version_str:
|
349 |
+
# find version
|
350 |
+
version = ver
|
351 |
+
|
352 |
+
if not version:
|
353 |
+
util.printD("can not find version by version string: " + version_str)
|
354 |
+
return
|
355 |
+
|
356 |
+
# get version id
|
357 |
+
if "id" not in version.keys():
|
358 |
+
util.printD("this version has no id")
|
359 |
+
return
|
360 |
+
|
361 |
+
version_id = version["id"]
|
362 |
+
if not version_id:
|
363 |
+
util.printD("version id is Empty")
|
364 |
+
return
|
365 |
+
|
366 |
+
# get download url
|
367 |
+
if "downloadUrl" not in version.keys():
|
368 |
+
util.printD("downloadUrl is not in this version")
|
369 |
+
return
|
370 |
+
|
371 |
+
downloadUrl = version["downloadUrl"]
|
372 |
+
if not downloadUrl:
|
373 |
+
util.printD("downloadUrl is Empty")
|
374 |
+
return
|
375 |
+
|
376 |
+
util.printD("Get Download Url: " + downloadUrl)
|
377 |
+
|
378 |
+
return (version_id, downloadUrl)
|
379 |
+
|
380 |
+
|
381 |
+
# download model from civitai by input
|
382 |
+
# output to markdown log
|
383 |
+
def dl_model_by_input(model_info:dict, model_type:str, subfolder_str:str, version_str:str, dl_all_bool:bool, max_size_preview:bool, skip_nsfw_preview:bool) -> str:
|
384 |
+
|
385 |
+
output = ""
|
386 |
+
|
387 |
+
if not model_info:
|
388 |
+
output = "model_info is None"
|
389 |
+
util.printD(output)
|
390 |
+
return output
|
391 |
+
|
392 |
+
if not model_type:
|
393 |
+
output = "model_type is None"
|
394 |
+
util.printD(output)
|
395 |
+
return output
|
396 |
+
|
397 |
+
if not subfolder_str:
|
398 |
+
output = "subfolder string is None"
|
399 |
+
util.printD(output)
|
400 |
+
return output
|
401 |
+
|
402 |
+
if not version_str:
|
403 |
+
output = "version_str is None"
|
404 |
+
util.printD(output)
|
405 |
+
return output
|
406 |
+
|
407 |
+
# get model root folder
|
408 |
+
if model_type not in model.folders.keys():
|
409 |
+
output = "Unknow model type: "+model_type
|
410 |
+
util.printD(output)
|
411 |
+
return output
|
412 |
+
|
413 |
+
model_root_folder = model.folders[model_type]
|
414 |
+
|
415 |
+
|
416 |
+
# get subfolder
|
417 |
+
subfolder = ""
|
418 |
+
if subfolder_str == "/" or subfolder_str == "\\":
|
419 |
+
subfolder = ""
|
420 |
+
elif subfolder_str[:1] == "/" or subfolder_str[:1] == "\\":
|
421 |
+
subfolder = subfolder_str[1:]
|
422 |
+
else:
|
423 |
+
subfolder = subfolder_str
|
424 |
+
|
425 |
+
# get model folder for downloading
|
426 |
+
model_folder = os.path.join(model_root_folder, subfolder)
|
427 |
+
if not os.path.isdir(model_folder):
|
428 |
+
output = "Model folder is not a dir: "+ model_folder
|
429 |
+
util.printD(output)
|
430 |
+
return output
|
431 |
+
|
432 |
+
# get version info
|
433 |
+
ver_info = get_ver_info_by_ver_str(version_str, model_info)
|
434 |
+
if not ver_info:
|
435 |
+
output = "Fail to get version info, check console log for detail"
|
436 |
+
util.printD(output)
|
437 |
+
return output
|
438 |
+
|
439 |
+
version_id = ver_info["id"]
|
440 |
+
|
441 |
+
|
442 |
+
if dl_all_bool:
|
443 |
+
# get all download url from files info
|
444 |
+
# some model versions have multiple files
|
445 |
+
download_urls = []
|
446 |
+
if "files" in ver_info.keys():
|
447 |
+
for file_info in ver_info["files"]:
|
448 |
+
if "downloadUrl" in file_info.keys():
|
449 |
+
download_urls.append(file_info["downloadUrl"])
|
450 |
+
|
451 |
+
if not len(download_urls):
|
452 |
+
if "downloadUrl" in ver_info.keys():
|
453 |
+
download_urls.append(ver_info["downloadUrl"])
|
454 |
+
|
455 |
+
|
456 |
+
# check if this model is already existed
|
457 |
+
r = civitai.search_local_model_info_by_version_id(model_folder, version_id)
|
458 |
+
if r:
|
459 |
+
output = "This model version is already existed"
|
460 |
+
util.printD(output)
|
461 |
+
return output
|
462 |
+
|
463 |
+
# download
|
464 |
+
filepath = ""
|
465 |
+
for url in download_urls:
|
466 |
+
model_filepath = downloader.dl(url, model_folder, None, None)
|
467 |
+
if not model_filepath:
|
468 |
+
output = "Downloading failed, check console log for detail"
|
469 |
+
util.printD(output)
|
470 |
+
return output
|
471 |
+
|
472 |
+
if url == ver_info["downloadUrl"]:
|
473 |
+
filepath = model_filepath
|
474 |
+
else:
|
475 |
+
# only download one file
|
476 |
+
# get download url
|
477 |
+
url = ver_info["downloadUrl"]
|
478 |
+
if not url:
|
479 |
+
output = "Fail to get download url, check console log for detail"
|
480 |
+
util.printD(output)
|
481 |
+
return output
|
482 |
+
|
483 |
+
# download
|
484 |
+
filepath = downloader.dl(url, model_folder, None, None)
|
485 |
+
if not filepath:
|
486 |
+
output = "Downloading failed, check console log for detail"
|
487 |
+
util.printD(output)
|
488 |
+
return output
|
489 |
+
|
490 |
+
|
491 |
+
if not filepath:
|
492 |
+
filepath = model_filepath
|
493 |
+
|
494 |
+
# get version info
|
495 |
+
version_info = civitai.get_version_info_by_version_id(version_id)
|
496 |
+
if not version_info:
|
497 |
+
output = "Model downloaded, but failed to get version info, check console log for detail. Model saved to: " + filepath
|
498 |
+
util.printD(output)
|
499 |
+
return output
|
500 |
+
|
501 |
+
# write version info to file
|
502 |
+
base, ext = os.path.splitext(filepath)
|
503 |
+
info_file = base + civitai.suffix + model.info_ext
|
504 |
+
model.write_model_info(info_file, version_info)
|
505 |
+
|
506 |
+
# then, get preview image
|
507 |
+
civitai.get_preview_image_by_model_path(filepath, max_size_preview, skip_nsfw_preview)
|
508 |
+
|
509 |
+
output = "Done. Model downloaded to: " + filepath
|
510 |
+
util.printD(output)
|
511 |
+
return output
|
extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/msg_handler.py
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: UTF-8 -*-
|
2 |
+
# handle msg between js and python side
|
3 |
+
import json
|
4 |
+
from . import util
|
5 |
+
|
6 |
+
# action list
|
7 |
+
js_actions = ("open_url", "add_trigger_words", "use_preview_prompt", "dl_model_new_version")
|
8 |
+
py_actions = ("open_url")
|
9 |
+
|
10 |
+
|
11 |
+
# handle request from javascript
|
12 |
+
# parameter: msg - msg from js as string in a hidden textbox
|
13 |
+
# return: dict for result
|
14 |
+
def parse_js_msg(msg):
|
15 |
+
util.printD("Start parse js msg")
|
16 |
+
msg_dict = json.loads(msg)
|
17 |
+
|
18 |
+
# in case client side run JSON.stringify twice
|
19 |
+
if (type(msg_dict) == str):
|
20 |
+
msg_dict = json.loads(msg_dict)
|
21 |
+
|
22 |
+
if "action" not in msg_dict.keys():
|
23 |
+
util.printD("Can not find action from js request")
|
24 |
+
return
|
25 |
+
|
26 |
+
action = msg_dict["action"]
|
27 |
+
if not action:
|
28 |
+
util.printD("Action from js request is None")
|
29 |
+
return
|
30 |
+
|
31 |
+
if action not in js_actions:
|
32 |
+
util.printD("Unknow action: " + action)
|
33 |
+
return
|
34 |
+
|
35 |
+
util.printD("End parse js msg")
|
36 |
+
|
37 |
+
return msg_dict
|
38 |
+
|
39 |
+
|
40 |
+
# build python side msg for sending to js
|
41 |
+
# parameter: content dict
|
42 |
+
# return: msg as string, to fill into a hidden textbox
|
43 |
+
def build_py_msg(action:str, content:dict):
|
44 |
+
util.printD("Start build_msg")
|
45 |
+
if not content:
|
46 |
+
util.printD("Content is None")
|
47 |
+
return
|
48 |
+
|
49 |
+
if not action:
|
50 |
+
util.printD("Action is None")
|
51 |
+
return
|
52 |
+
|
53 |
+
if action not in py_actions:
|
54 |
+
util.printD("Unknow action: " + action)
|
55 |
+
return
|
56 |
+
|
57 |
+
msg = {
|
58 |
+
"action" : action,
|
59 |
+
"content": content
|
60 |
+
}
|
61 |
+
|
62 |
+
|
63 |
+
util.printD("End build_msg")
|
64 |
+
return json.dumps(msg)
|
extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/setting.py
ADDED
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: UTF-8 -*-
|
2 |
+
# collecting settings to here
|
3 |
+
import json
|
4 |
+
import os
|
5 |
+
import modules.scripts as scripts
|
6 |
+
from . import util
|
7 |
+
|
8 |
+
|
9 |
+
name = "setting.json"
|
10 |
+
path = os.path.join(scripts.basedir(), name)
|
11 |
+
|
12 |
+
data = {
|
13 |
+
"model":{
|
14 |
+
"max_size_preview": True,
|
15 |
+
"skip_nsfw_preview": False
|
16 |
+
},
|
17 |
+
"general":{
|
18 |
+
"open_url_with_js": True,
|
19 |
+
"always_display": False,
|
20 |
+
"show_btn_on_thumb": True,
|
21 |
+
"proxy": "",
|
22 |
+
},
|
23 |
+
"tool":{
|
24 |
+
}
|
25 |
+
}
|
26 |
+
|
27 |
+
|
28 |
+
|
29 |
+
# save setting
|
30 |
+
# return output msg for log
|
31 |
+
def save():
|
32 |
+
print("Saving setting to: " + path)
|
33 |
+
|
34 |
+
json_data = json.dumps(data, indent=4)
|
35 |
+
|
36 |
+
output = ""
|
37 |
+
|
38 |
+
#write to file
|
39 |
+
try:
|
40 |
+
with open(path, 'w') as f:
|
41 |
+
f.write(json_data)
|
42 |
+
except Exception as e:
|
43 |
+
util.printD("Error when writing file:"+path)
|
44 |
+
output = str(e)
|
45 |
+
util.printD(str(e))
|
46 |
+
return output
|
47 |
+
|
48 |
+
output = "Setting saved to: " + path
|
49 |
+
util.printD(output)
|
50 |
+
|
51 |
+
return output
|
52 |
+
|
53 |
+
|
54 |
+
# load setting to global data
|
55 |
+
def load():
|
56 |
+
# load data into globel data
|
57 |
+
global data
|
58 |
+
|
59 |
+
util.printD("Load setting from: " + path)
|
60 |
+
|
61 |
+
if not os.path.isfile(path):
|
62 |
+
util.printD("No setting file, use default")
|
63 |
+
return
|
64 |
+
|
65 |
+
json_data = None
|
66 |
+
with open(path, 'r') as f:
|
67 |
+
json_data = json.load(f)
|
68 |
+
|
69 |
+
# check error
|
70 |
+
if not json_data:
|
71 |
+
util.printD("load setting file failed")
|
72 |
+
return
|
73 |
+
|
74 |
+
data = json_data
|
75 |
+
|
76 |
+
# check for new key
|
77 |
+
if "always_display" not in data["general"].keys():
|
78 |
+
data["general"]["always_display"] = False
|
79 |
+
|
80 |
+
if "show_btn_on_thumb" not in data["general"].keys():
|
81 |
+
data["general"]["show_btn_on_thumb"] = True
|
82 |
+
|
83 |
+
if "proxy" not in data["general"].keys():
|
84 |
+
data["general"]["proxy"] = ""
|
85 |
+
|
86 |
+
|
87 |
+
return
|
88 |
+
|
89 |
+
# save setting from parameter
|
90 |
+
def save_from_input(max_size_preview, skip_nsfw_preview, open_url_with_js, always_display, show_btn_on_thumb, proxy):
|
91 |
+
global data
|
92 |
+
data = {
|
93 |
+
"model":{
|
94 |
+
"max_size_preview": max_size_preview,
|
95 |
+
"skip_nsfw_preview": skip_nsfw_preview
|
96 |
+
},
|
97 |
+
"general":{
|
98 |
+
"open_url_with_js": open_url_with_js,
|
99 |
+
"always_display": always_display,
|
100 |
+
"show_btn_on_thumb": show_btn_on_thumb,
|
101 |
+
"proxy": proxy,
|
102 |
+
},
|
103 |
+
"tool":{
|
104 |
+
}
|
105 |
+
}
|
106 |
+
|
107 |
+
output = save()
|
108 |
+
|
109 |
+
if not output:
|
110 |
+
output = ""
|
111 |
+
|
112 |
+
return output
|
113 |
+
|
extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/util.py
ADDED
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: UTF-8 -*-
|
2 |
+
import os
|
3 |
+
import io
|
4 |
+
import hashlib
|
5 |
+
import requests
|
6 |
+
import shutil
|
7 |
+
|
8 |
+
|
9 |
+
version = "1.6.4"
|
10 |
+
|
11 |
+
def_headers = {'User-Agent': 'Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148'}
|
12 |
+
|
13 |
+
|
14 |
+
proxies = None
|
15 |
+
|
16 |
+
|
17 |
+
# print for debugging
|
18 |
+
def printD(msg):
|
19 |
+
print(f"Civitai Helper: {msg}")
|
20 |
+
|
21 |
+
|
22 |
+
def read_chunks(file, size=io.DEFAULT_BUFFER_SIZE):
|
23 |
+
"""Yield pieces of data from a file-like object until EOF."""
|
24 |
+
while True:
|
25 |
+
chunk = file.read(size)
|
26 |
+
if not chunk:
|
27 |
+
break
|
28 |
+
yield chunk
|
29 |
+
|
30 |
+
# Now, hashing use the same way as pip's source code.
|
31 |
+
def gen_file_sha256(filname):
|
32 |
+
printD("Use Memory Optimized SHA256")
|
33 |
+
blocksize=1 << 20
|
34 |
+
h = hashlib.sha256()
|
35 |
+
length = 0
|
36 |
+
with open(os.path.realpath(filname), 'rb') as f:
|
37 |
+
for block in read_chunks(f, size=blocksize):
|
38 |
+
length += len(block)
|
39 |
+
h.update(block)
|
40 |
+
|
41 |
+
hash_value = h.hexdigest()
|
42 |
+
printD("sha256: " + hash_value)
|
43 |
+
printD("length: " + str(length))
|
44 |
+
return hash_value
|
45 |
+
|
46 |
+
|
47 |
+
|
48 |
+
# get preview image
|
49 |
+
def download_file(url, path):
|
50 |
+
printD("Downloading file from: " + url)
|
51 |
+
# get file
|
52 |
+
r = requests.get(url, stream=True, headers=def_headers, proxies=proxies)
|
53 |
+
if not r.ok:
|
54 |
+
printD("Get error code: " + str(r.status_code))
|
55 |
+
printD(r.text)
|
56 |
+
return
|
57 |
+
|
58 |
+
# write to file
|
59 |
+
with open(os.path.realpath(path), 'wb') as f:
|
60 |
+
r.raw.decode_content = True
|
61 |
+
shutil.copyfileobj(r.raw, f)
|
62 |
+
|
63 |
+
printD("File downloaded to: " + path)
|
64 |
+
|
65 |
+
# get subfolder list
|
66 |
+
def get_subfolders(folder:str) -> list:
|
67 |
+
printD("Get subfolder for: " + folder)
|
68 |
+
if not folder:
|
69 |
+
printD("folder can not be None")
|
70 |
+
return
|
71 |
+
|
72 |
+
if not os.path.isdir(folder):
|
73 |
+
printD("path is not a folder")
|
74 |
+
return
|
75 |
+
|
76 |
+
prefix_len = len(folder)
|
77 |
+
subfolders = []
|
78 |
+
for root, dirs, files in os.walk(folder, followlinks=True):
|
79 |
+
for dir in dirs:
|
80 |
+
full_dir_path = os.path.join(root, dir)
|
81 |
+
# get subfolder path from it
|
82 |
+
subfolder = full_dir_path[prefix_len:]
|
83 |
+
subfolders.append(subfolder)
|
84 |
+
|
85 |
+
return subfolders
|
86 |
+
|
87 |
+
|
88 |
+
# get relative path
|
89 |
+
def get_relative_path(item_path:str, parent_path:str) -> str:
|
90 |
+
# printD("item_path:"+item_path)
|
91 |
+
# printD("parent_path:"+parent_path)
|
92 |
+
# item path must start with parent_path
|
93 |
+
if not item_path:
|
94 |
+
return ""
|
95 |
+
if not parent_path:
|
96 |
+
return ""
|
97 |
+
if not item_path.startswith(parent_path):
|
98 |
+
return item_path
|
99 |
+
|
100 |
+
relative = item_path[len(parent_path):]
|
101 |
+
if relative[:1] == "/" or relative[:1] == "\\":
|
102 |
+
relative = relative[1:]
|
103 |
+
|
104 |
+
# printD("relative:"+relative)
|
105 |
+
return relative
|
extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/civitai_helper.py
ADDED
@@ -0,0 +1,218 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: UTF-8 -*-
|
2 |
+
# This extension can help you manage your models from civitai. It can download preview, add trigger words, open model page and use the prompt from preview image
|
3 |
+
# repo: https://github.com/butaixianran/
|
4 |
+
|
5 |
+
|
6 |
+
|
7 |
+
import modules.scripts as scripts
|
8 |
+
import gradio as gr
|
9 |
+
import os
|
10 |
+
import webbrowser
|
11 |
+
import requests
|
12 |
+
import random
|
13 |
+
import hashlib
|
14 |
+
import json
|
15 |
+
import shutil
|
16 |
+
import re
|
17 |
+
import modules
|
18 |
+
from modules import script_callbacks
|
19 |
+
from modules import shared
|
20 |
+
from scripts.ch_lib import model
|
21 |
+
from scripts.ch_lib import js_action_civitai
|
22 |
+
from scripts.ch_lib import model_action_civitai
|
23 |
+
from scripts.ch_lib import setting
|
24 |
+
from scripts.ch_lib import civitai
|
25 |
+
from scripts.ch_lib import util
|
26 |
+
|
27 |
+
|
28 |
+
# init
|
29 |
+
|
30 |
+
# root path
|
31 |
+
root_path = os.getcwd()
|
32 |
+
|
33 |
+
# extension path
|
34 |
+
extension_path = scripts.basedir()
|
35 |
+
|
36 |
+
model.get_custom_model_folder()
|
37 |
+
setting.load()
|
38 |
+
|
39 |
+
# set proxy
|
40 |
+
if setting.data["general"]["proxy"]:
|
41 |
+
util.printD("Set Proxy: "+setting.data["general"]["proxy"])
|
42 |
+
util.proxies = {
|
43 |
+
"http": setting.data["general"]["proxy"],
|
44 |
+
"https": setting.data["general"]["proxy"],
|
45 |
+
}
|
46 |
+
|
47 |
+
|
48 |
+
|
49 |
+
|
50 |
+
def on_ui_tabs():
|
51 |
+
# init
|
52 |
+
# init_py_msg = {
|
53 |
+
# # relative extension path
|
54 |
+
# "extension_path": util.get_relative_path(extension_path, root_path),
|
55 |
+
# }
|
56 |
+
# init_py_msg_str = json.dumps(init_py_msg)
|
57 |
+
|
58 |
+
|
59 |
+
# get prompt textarea
|
60 |
+
# check modules/ui.py, search for txt2img_paste_fields
|
61 |
+
# Negative prompt is the second element
|
62 |
+
txt2img_prompt = modules.ui.txt2img_paste_fields[0][0]
|
63 |
+
txt2img_neg_prompt = modules.ui.txt2img_paste_fields[1][0]
|
64 |
+
img2img_prompt = modules.ui.img2img_paste_fields[0][0]
|
65 |
+
img2img_neg_prompt = modules.ui.img2img_paste_fields[1][0]
|
66 |
+
|
67 |
+
# ====Event's function====
|
68 |
+
def get_model_names_by_input(model_type, empty_info_only):
|
69 |
+
names = civitai.get_model_names_by_input(model_type, empty_info_only)
|
70 |
+
return model_name_drop.update(choices=names)
|
71 |
+
|
72 |
+
|
73 |
+
def get_model_info_by_url(url):
|
74 |
+
r = model_action_civitai.get_model_info_by_url(url)
|
75 |
+
|
76 |
+
model_info = {}
|
77 |
+
model_name = ""
|
78 |
+
model_type = ""
|
79 |
+
subfolders = []
|
80 |
+
version_strs = []
|
81 |
+
if r:
|
82 |
+
model_info, model_name, model_type, subfolders, version_strs = r
|
83 |
+
|
84 |
+
return [model_info, model_name, model_type, dl_subfolder_drop.update(choices=subfolders), dl_version_drop.update(choices=version_strs)]
|
85 |
+
|
86 |
+
# ====UI====
|
87 |
+
with gr.Blocks(analytics_enabled=False) as civitai_helper:
|
88 |
+
# with gr.Blocks(css=".block.padded {padding: 10px !important}") as civitai_helper:
|
89 |
+
|
90 |
+
# init
|
91 |
+
max_size_preview = setting.data["model"]["max_size_preview"]
|
92 |
+
skip_nsfw_preview = setting.data["model"]["skip_nsfw_preview"]
|
93 |
+
open_url_with_js = setting.data["general"]["open_url_with_js"]
|
94 |
+
always_display = setting.data["general"]["always_display"]
|
95 |
+
show_btn_on_thumb = setting.data["general"]["show_btn_on_thumb"]
|
96 |
+
proxy = setting.data["general"]["proxy"]
|
97 |
+
|
98 |
+
model_types = list(model.folders.keys())
|
99 |
+
no_info_model_names = civitai.get_model_names_by_input("ckp", False)
|
100 |
+
|
101 |
+
# session data
|
102 |
+
dl_model_info = gr.State({})
|
103 |
+
|
104 |
+
|
105 |
+
|
106 |
+
with gr.Box(elem_classes="ch_box"):
|
107 |
+
with gr.Column():
|
108 |
+
gr.Markdown("### Scan Models for Civitai")
|
109 |
+
with gr.Row():
|
110 |
+
max_size_preview_ckb = gr.Checkbox(label="Download Max Size Preview", value=max_size_preview, elem_id="ch_max_size_preview_ckb")
|
111 |
+
skip_nsfw_preview_ckb = gr.Checkbox(label="Skip NSFW Preview Images", value=skip_nsfw_preview, elem_id="ch_skip_nsfw_preview_ckb")
|
112 |
+
scan_model_types_ckbg = gr.CheckboxGroup(choices=model_types, label="Model Types", value=model_types)
|
113 |
+
|
114 |
+
# with gr.Row():
|
115 |
+
scan_model_civitai_btn = gr.Button(value="Scan", variant="primary", elem_id="ch_scan_model_civitai_btn")
|
116 |
+
# with gr.Row():
|
117 |
+
scan_model_log_md = gr.Markdown(value="Scanning takes time, just wait. Check console log for detail", elem_id="ch_scan_model_log_md")
|
118 |
+
|
119 |
+
|
120 |
+
with gr.Box(elem_classes="ch_box"):
|
121 |
+
with gr.Column():
|
122 |
+
gr.Markdown("### Get Model Info from Civitai by URL")
|
123 |
+
gr.Markdown("Use this when scanning can not find a local model on civitai")
|
124 |
+
with gr.Row():
|
125 |
+
model_type_drop = gr.Dropdown(choices=model_types, label="Model Type", value="ckp", multiselect=False)
|
126 |
+
empty_info_only_ckb = gr.Checkbox(label="Only Show Models have no Info", value=False, elem_id="ch_empty_info_only_ckb", elem_classes="ch_vpadding")
|
127 |
+
model_name_drop = gr.Dropdown(choices=no_info_model_names, label="Model", value="ckp", multiselect=False)
|
128 |
+
|
129 |
+
model_url_or_id_txtbox = gr.Textbox(label="Civitai URL", lines=1, value="")
|
130 |
+
get_civitai_model_info_by_id_btn = gr.Button(value="Get Model Info from Civitai", variant="primary")
|
131 |
+
get_model_by_id_log_md = gr.Markdown("")
|
132 |
+
|
133 |
+
with gr.Box(elem_classes="ch_box"):
|
134 |
+
with gr.Column():
|
135 |
+
gr.Markdown("### Download Model")
|
136 |
+
with gr.Row():
|
137 |
+
dl_model_url_or_id_txtbox = gr.Textbox(label="Civitai URL", lines=1, value="")
|
138 |
+
dl_model_info_btn = gr.Button(value="1. Get Model Info by Civitai Url", variant="primary")
|
139 |
+
|
140 |
+
gr.Markdown(value="2. Pick Subfolder and Model Version")
|
141 |
+
with gr.Row():
|
142 |
+
dl_model_name_txtbox = gr.Textbox(label="Model Name", interactive=False, lines=1, value="")
|
143 |
+
dl_model_type_txtbox = gr.Textbox(label="Model Type", interactive=False, lines=1, value="")
|
144 |
+
dl_subfolder_drop = gr.Dropdown(choices=[], label="Sub-folder", value="", interactive=True, multiselect=False)
|
145 |
+
dl_version_drop = gr.Dropdown(choices=[], label="Model Version", value="", interactive=True, multiselect=False)
|
146 |
+
dl_all_ckb = gr.Checkbox(label="Download All files", value=False, elem_id="ch_dl_all_ckb", elem_classes="ch_vpadding")
|
147 |
+
|
148 |
+
dl_civitai_model_by_id_btn = gr.Button(value="3. Download Model", variant="primary")
|
149 |
+
dl_log_md = gr.Markdown(value="Check Console log for Downloading Status")
|
150 |
+
|
151 |
+
with gr.Box(elem_classes="ch_box"):
|
152 |
+
with gr.Column():
|
153 |
+
gr.Markdown("### Check models' new version")
|
154 |
+
with gr.Row():
|
155 |
+
model_types_ckbg = gr.CheckboxGroup(choices=model_types, label="Model Types", value=["lora"])
|
156 |
+
check_models_new_version_btn = gr.Button(value="Check New Version from Civitai", variant="primary")
|
157 |
+
|
158 |
+
check_models_new_version_log_md = gr.HTML("It takes time, just wait. Check console log for detail")
|
159 |
+
|
160 |
+
with gr.Box(elem_classes="ch_box"):
|
161 |
+
with gr.Column():
|
162 |
+
gr.Markdown("### Other Setting")
|
163 |
+
with gr.Row():
|
164 |
+
open_url_with_js_ckb = gr.Checkbox(label="Open Url At Client Side", value=open_url_with_js, elem_id="ch_open_url_with_js_ckb")
|
165 |
+
always_display_ckb = gr.Checkbox(label="Always Display Buttons", value=always_display, elem_id="ch_always_display_ckb")
|
166 |
+
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")
|
167 |
+
|
168 |
+
proxy_txtbox = gr.Textbox(label="Proxy", interactive=True, lines=1, value=proxy, info="format: http://127.0.0.1:port")
|
169 |
+
|
170 |
+
save_setting_btn = gr.Button(value="Save Setting")
|
171 |
+
general_log_md = gr.Markdown(value="")
|
172 |
+
|
173 |
+
|
174 |
+
# ====Footer====
|
175 |
+
gr.Markdown(f"<center>version:{util.version}</center>")
|
176 |
+
|
177 |
+
# ====hidden component for js, not in any tab====
|
178 |
+
js_msg_txtbox = gr.Textbox(label="Request Msg From Js", visible=False, lines=1, value="", elem_id="ch_js_msg_txtbox")
|
179 |
+
py_msg_txtbox = gr.Textbox(label="Response Msg From Python", visible=False, lines=1, value="", elem_id="ch_py_msg_txtbox")
|
180 |
+
|
181 |
+
js_open_url_btn = gr.Button(value="Open Model Url", visible=False, elem_id="ch_js_open_url_btn")
|
182 |
+
js_add_trigger_words_btn = gr.Button(value="Add Trigger Words", visible=False, elem_id="ch_js_add_trigger_words_btn")
|
183 |
+
js_use_preview_prompt_btn = gr.Button(value="Use Prompt from Preview Image", visible=False, elem_id="ch_js_use_preview_prompt_btn")
|
184 |
+
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")
|
185 |
+
|
186 |
+
# ====events====
|
187 |
+
# Scan Models for Civitai
|
188 |
+
scan_model_civitai_btn.click(model_action_civitai.scan_model, inputs=[scan_model_types_ckbg, max_size_preview_ckb, skip_nsfw_preview_ckb], outputs=scan_model_log_md)
|
189 |
+
|
190 |
+
# Get Civitai Model Info by Model Page URL
|
191 |
+
model_type_drop.change(get_model_names_by_input, inputs=[model_type_drop, empty_info_only_ckb], outputs=model_name_drop)
|
192 |
+
empty_info_only_ckb.change(get_model_names_by_input, inputs=[model_type_drop, empty_info_only_ckb], outputs=model_name_drop)
|
193 |
+
|
194 |
+
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)
|
195 |
+
|
196 |
+
# Download Model
|
197 |
+
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])
|
198 |
+
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, dl_all_ckb, max_size_preview_ckb, skip_nsfw_preview_ckb], outputs=dl_log_md)
|
199 |
+
|
200 |
+
# Check models' new version
|
201 |
+
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)
|
202 |
+
|
203 |
+
# Other Setting
|
204 |
+
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, proxy_txtbox], outputs=general_log_md)
|
205 |
+
|
206 |
+
# js action
|
207 |
+
js_open_url_btn.click(js_action_civitai.open_model_url, inputs=[js_msg_txtbox, open_url_with_js_ckb], outputs=py_msg_txtbox)
|
208 |
+
js_add_trigger_words_btn.click(js_action_civitai.add_trigger_words, inputs=[js_msg_txtbox], outputs=[txt2img_prompt, img2img_prompt])
|
209 |
+
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])
|
210 |
+
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)
|
211 |
+
|
212 |
+
# the third parameter is the element id on html, with a "tab_" as prefix
|
213 |
+
return (civitai_helper , "Civitai Helper", "civitai_helper"),
|
214 |
+
|
215 |
+
script_callbacks.on_ui_tabs(on_ui_tabs)
|
216 |
+
|
217 |
+
|
218 |
+
|