toto10 commited on
Commit
7a024d2
1 Parent(s): 06fce0e

7e66807da6418cef8d9b2da1fecc08190b3442be447febbb68dfe89fdcbb16d8

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +1 -0
  2. extensions/Stable-Diffusion-Webui-Civitai-Helper/claim_wall.md +91 -0
  3. extensions/Stable-Diffusion-Webui-Civitai-Helper/icon/.keep +0 -0
  4. extensions/Stable-Diffusion-Webui-Civitai-Helper/img/all_in_one.png +3 -0
  5. extensions/Stable-Diffusion-Webui-Civitai-Helper/img/check_model_new_version.jpg +0 -0
  6. extensions/Stable-Diffusion-Webui-Civitai-Helper/img/check_model_new_version_output.jpg +0 -0
  7. extensions/Stable-Diffusion-Webui-Civitai-Helper/img/download_model.jpg +0 -0
  8. extensions/Stable-Diffusion-Webui-Civitai-Helper/img/extension_tab.jpg +0 -0
  9. extensions/Stable-Diffusion-Webui-Civitai-Helper/img/extra_network.jpg +0 -0
  10. extensions/Stable-Diffusion-Webui-Civitai-Helper/img/get_one_model_info.jpg +0 -0
  11. extensions/Stable-Diffusion-Webui-Civitai-Helper/img/model_card.jpg +0 -0
  12. extensions/Stable-Diffusion-Webui-Civitai-Helper/img/model_info_file.jpg +0 -0
  13. extensions/Stable-Diffusion-Webui-Civitai-Helper/img/other_setting.jpg +0 -0
  14. extensions/Stable-Diffusion-Webui-Civitai-Helper/img/refresh_ch.jpg +0 -0
  15. extensions/Stable-Diffusion-Webui-Civitai-Helper/img/thumb_mode.jpg +0 -0
  16. extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/blame_sdweui_update_to_this_ext.jpg +0 -0
  17. extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/changed_model_folder_name_then_forget_part1.jpg +0 -0
  18. extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/changed_model_folder_name_then_forget_part2.jpg +0 -0
  19. extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/changed_model_folder_name_then_forget_part3.jpg +0 -0
  20. extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/changed_model_folder_name_then_forget_part4.jpg +0 -0
  21. extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/css_issue_part1.jpg +0 -0
  22. extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/css_issue_part2.jpg +0 -0
  23. extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/css_issue_part3.jpg +0 -0
  24. extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/css_issue_part4.jpg +0 -0
  25. extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/did_not_relaunch_sdwebui.jpg +0 -0
  26. extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/do_not_even_use_this_ext.jpg +0 -0
  27. extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/have_not_scan_model.jpg +0 -0
  28. extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/have_not_update_sdwebui.jpg +0 -0
  29. extensions/Stable-Diffusion-Webui-Civitai-Helper/img/user_claim_wall/request_a_feature_it_already_has.jpg +0 -0
  30. extensions/Stable-Diffusion-Webui-Civitai-Helper/javascript/civitai_helper.js +728 -0
  31. extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/__pycache__/civitai_helper.cpython-310.pyc +0 -0
  32. extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__init__.py +0 -0
  33. extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/__init__.cpython-310.pyc +0 -0
  34. extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/civitai.cpython-310.pyc +0 -0
  35. extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/downloader.cpython-310.pyc +0 -0
  36. extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/js_action_civitai.cpython-310.pyc +0 -0
  37. extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/model.cpython-310.pyc +0 -0
  38. extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/model_action_civitai.cpython-310.pyc +0 -0
  39. extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/msg_handler.cpython-310.pyc +0 -0
  40. extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/setting.cpython-310.pyc +0 -0
  41. extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/__pycache__/util.cpython-310.pyc +0 -0
  42. extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/civitai.py +612 -0
  43. extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/downloader.py +115 -0
  44. extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/js_action_civitai.py +256 -0
  45. extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/model.py +120 -0
  46. extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/model_action_civitai.py +511 -0
  47. extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/msg_handler.py +64 -0
  48. extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/setting.py +113 -0
  49. extensions/Stable-Diffusion-Webui-Civitai-Helper/scripts/ch_lib/util.py +105 -0
  50. 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

  • SHA256: bedc58968db1a83c84e57d94327c4e27f5cd6fbd93c45a59627a5257b06c8a47
  • Pointer size: 132 Bytes
  • Size of remote file: 1.1 MB
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
+