From 4135db47525220149c16d8e469a3efa740f7511b Mon Sep 17 00:00:00 2001 From: Haoming Date: Wed, 4 Jun 2025 14:21:01 +0800 Subject: [PATCH] overhaul --- README.md | 74 ++++----- README_ZH.md | 72 --------- booru.png | Bin 9260 -> 22108 bytes javascript/pf_configs.js | 133 +++++----------- javascript/pf_ui.js | 40 +++-- javascript/prompt_format.js | 303 ++++++++++++++++++------------------ sample.jpg | Bin 21310 -> 0 bytes sample.png | Bin 0 -> 23190 bytes scripts/pf_settings.py | 101 +++++++++--- 9 files changed, 318 insertions(+), 405 deletions(-) delete mode 100644 README_ZH.md delete mode 100644 sample.jpg create mode 100644 sample.png diff --git a/README.md b/README.md index 9eccfb4..4a65426 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,14 @@ # SD Webui Prompt Format -[English|[中文](README_ZH.md)] - This is an Extension for the [Automatic1111 Webui](https://github.com/AUTOMATIC1111/stable-diffusion-webui), which helps formatting prompts. -> Also supports [SD.Next](https://github.com/vladmandic/automatic) and [Forge](https://github.com/lllyasviel/stable-diffusion-webui-forge) out of the box! +> Compatible with [Forge](https://github.com/lllyasviel/stable-diffusion-webui-forge) -

+

+
+Sometimes, when you type too fast or copy prompts from all over the places, you end up with duplicated spaces and commas. This simple Extension helps removing them whenever you click Generate. +

-Sometimes, when you type too fast or copy prompts from all over the places, you end up with duplicated **spaces** or **commas**. This simple Extension helps removing them whenever you click **Generate**. +
## Features - [x] Works in both `txt2img` and `img2img` @@ -16,57 +17,48 @@ Sometimes, when you type too fast or copy prompts from all over the places, you - [x] Fix misplaced **brackets** and **commas** - [x] Enable `Remove Duplicates` to remove identical tags found in the prompts - **Note:** Only works for tag-based prompt, not sentence-based prompt - - **eg.** `1girl, solo, smile, 1girl` will become `1girl, solo, smile` - - **eg.** `a girl smiling, a girl standing` will not be changed + - **e.g.** `1girl, solo, smile, 1girl` will become `1girl, solo, smile` + - **e.g.** `a girl smiling, a girl standing` will not be changed - [x] Enable `Remove Underscores` to replace `_` with `space` - [x] Respect line breaks - `Remove Duplicates` only checks within the same line -- [x] Append a comma before a line break +- [x] Append a comma every line break - [x] Toggle between auto formatting and manual formatting - In `Auto` mode: The process is ran whenever you click on **Generate** - In `Manual` mode: The process is only ran when you click the **Format** button -- [x] **New:** Trigger the formatting on the pasted text +- [x] Pressing `Alt` + `Shift` + `F` can also manually trigger formatting +- [x] Format the text pasted from clipboard + +
+ - [x] Toggle whether the above features are enabled / disabled by default in the `Prompt Format` section under the System category of the **Settings** tab -- [x] Pressing `Alt` + `Shift` + `F` can also trigger formatting -- [x] Assign "[alias](#tag-alias)" that counts as duplicates for the specified tags - [x] Exclude specific tags from `Remove Underscores` -- [x] Click `Reload` to cache new cards - - By default, the `ExtraNetwork` cards are cached once at the start, to be excluded from `Remove Underscores`. If you added more cards while the Webui is already running, click this button to re-cache again. +- [x] Assign "[alias](#tag-alias)" that counts as duplicates for the specified tags +- [x] Click `Reload` to refresh the 2 settings above -### Tag Alias -- In the `Prompt Format` settings, there is a new field for **Tag Alias** -- You can assign other tags that count as the same as the main tag, and thus get removed during `Remove Duplicates` -- The syntax is in the format of `main tag: alias1, alias2, alias3` - - **example:** - ``` - 1girl: girl, woman, lady - ``` - - If you type `girl`, it will get converted into `1girl`, and if you already have `1girl`, then the future ones will get removed. - -- The pattern for alias uses **Regular Expression**, so certain symbols *(**eg.** `(`, `)`)* will need to be escaped *(**ie.** `\(`, `\)`)* - - Comma is not supported, as it is used to separate multiple patterns - - Check out [RegExr](https://regexr.com/) for cheatsheet - - **example:** - ```regex - adult: \d*\s*(y\.?o\.?|[Yy]ear[s]? [Oo]ld) - ``` - - It will convert `15 yo`, `20 y.o.`, `25 years old`, `30 Year Old` all into `adult` - -
- -### Note -1. Since the formatting in `Auto` mode is triggered at the same time as the generation, the immediate image might not have its prompts updated. - -2. Some Extensions *(**eg.** [tagcomplete](https://github.com/DominikDoom/a1111-sd-webui-tagcomplete))* listen to the text editing event, meaning the formatting will cause them to be triggered. You can disable updating the actual prompts in the `Prompt Format` settings to prevent this. Though you may need to manually type something else for the prompt to get actually updated. - -
+> [!Note] +> Some Extensions *(**eg.** [tagcomplete](https://github.com/DominikDoom/a1111-sd-webui-tagcomplete))* listen to the text editing event, meaning the formatting will cause them to be triggered. You can disable updating the actual prompts in the settings to prevent this.
Booru -- [x] Automatically clean up unwanted texts +- [x] Clean up unwanted texts when pasting tags from Booru sites - Currently supports [gelbooru](https://gelbooru.com/) and [danbooru](https://safebooru.donmai.us/)

+ +
+ +### Tag Alias +- You can assign other tags that count as the same as the main tag, which then get removed during `Remove Duplicates` +- The syntax is in the format of `main tag: alias1, alias2, alias3` + - **example:** + ``` + 1girl: girl, woman, lady + ``` + - If you type `girl`, it will get converted into `1girl`, which will get removed if the prompt already contains `1girl` + +- The pattern for alias uses **Regular Expression**, so certain symbols *(**e.g.** `(`, `)`)* will need to be escaped *(**i.e.** `\(`, `\)`)* + - Comma is not supported, as it is used to separate multiple patterns diff --git a/README_ZH.md b/README_ZH.md deleted file mode 100644 index 20476ec..0000000 --- a/README_ZH.md +++ /dev/null @@ -1,72 +0,0 @@ -# SD Webui Prompt Format -[[English](README.md)|中文] - -這是一個[Automatic1111 Webui](https://github.com/AUTOMATIC1111/stable-diffusion-webui)的插件,用來幫忙校正咒語。 - -> 亦支援 [SD.Next](https://github.com/vladmandic/automatic) 與 [Forge](https://github.com/lllyasviel/stable-diffusion-webui-forge) ! - -

- -有時候如果打字太快或是從各處東拼西湊咒語,常會造成多個重複的空格或逗點。這個擴充可以幫忙移除它們。 - -## 功能 -- [x] 在`txt2img`和`img2img`都有用 -- [x] 對`正面`和`負面`以及`Hires. fix`之咒語都有用 -- [x] 移除多餘的**空格**和**逗點** -- [x] 修正錯誤的**括弧** -- [x] 開啟`Remove Duplicates`會把咒語中重複的單字消除 - - **注意:** 只對單字類咒語有效 - - **例.** `1girl, solo, smile, 1girl` 會變成 `1girl, solo, smile` - - **例.** `a girl smiling, a girl standing` 則不變 -- [x] 開啟`Remove Underscores`會將 `_` 換成 `空格` -- [x] 保留咒語的換行 - - 上述的`Remove Duplicates`只在同一行中有效 -- [x] 在換行前加入逗點 -- [x] 按下`Auto Format`以在手動與自動間切換 - - `自動`: 每次按下 **生成 (Generate)** 時處裡 - - `手動`: 手動按下 **Format** 時才處裡 -- [x] **新功能:** 對貼上的咒語進行處裡 -- [x] 在 **Settings** 頁面 System 下的 `Prompt Format` 區可以 開啟/關閉 上述功能 -- [x] 按下 `Alt` + `Shift` + `F` 亦可觸發格式化 -- [x] 為指定單字新增 "[同義詞](#同義詞)" -- [x] 將指定字詞除外 `Remove Underscores` 的影響 -- [x] 點擊 `Reload` 以緩存卡片 - - 在 Webui 剛開啟時, `ExtraNetwork` 中的卡片會被緩存一次以防被 `Remove Underscores` 影響。如果你在 Webui 已運行時加入更多的卡片,點擊此按鈕來重新緩存。 - -### 同義詞 -- 在 `Prompt Format` 的設定裡,有個新的 **Tag Alias** 欄位 -- 你可以在此把其它字詞設為主單字的同義詞,使其在 `Remove Duplicates` 中被當作重複字而刪去 -- 格式為 `main tag: alias1, alias2, alias3` - - **範例:** - ``` - 1girl: girl, woman, lady - ``` - - 如果輸入 `girl`, 便會轉換成 `1girl`; 而如果 `1girl` 已經存在,多餘的便會被刪除。 - -- 同義詞判斷使用 **Regular Expression**,故特定文字 *(**如.** `(`, `)`)* 便需要被跳脫 *(**即.** `\(`, `\)`)* - - 逗號用來分開多個同義詞,故無法用於同義詞 - - 可參考 [RegExr](https://regexr.com/) 以便學習 - - **範例:** - ```regex - adult: \d*\s*(y\.?o\.?|[Yy]ear[s]? [Oo]ld) - ``` - - 此便會將 `15 yo`, `20 y.o.`, `25 years old`, `30 Year Old` 都轉為 `adult` - -
- -### 注意 -1. 由於 `自動`校正 和 生成 是同時觸發,當下所生產的第一張圖片之咒語可能不會是已更新的。 - -2. 有些擴充 *(如. [tagcomplete](https://github.com/DominikDoom/a1111-sd-webui-tagcomplete))* 追蹤文字的編輯事件,意即文字校正會導致它們啟動。你可以到設定關閉咒語的自動更新。 - -
- -
-Booru - -- [x] 自動清除多餘字詞 - - 目前支援 [gelbooru](https://gelbooru.com/) 及 [danbooru](https://safebooru.donmai.us/) - -

- -
diff --git a/booru.png b/booru.png index e7eedc308fac4f174437cfb54afa13cc243962a9..a03c8abb50425be1bae5e466b07320dd2604a87f 100644 GIT binary patch literal 22108 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 literal 9260 zcmbVyWmFtNly2h^1`;$l2`+))Fa&oPAc5c#2r{@1?h*(=fr@OkUZuPylzOQcRdu3S=HW@Ym03dleDOCVKM%)5^nE#4%UKu?^ zf#jqrD*=>_Q0yTps8DewaR8|J{_Nfe4N=Fkm(z9v0Nk#B7gC>Hfe8T6cF0SKe{?fA zS^|Ak(@Y0W$q!%XoF|j40faq?zn6j3emJ|*-i2$0Q zo2Rsbla}T()Z3?%mXlUjG?ykyBmh{=cnjx1j4|CG6(QfDVIia&HayM%!8{8g{rZrrE$DF2^#|NF<0oKciU z3$xXJ9;%MBfzkeAH~J%|W0sRM(E;tW{&avp4I7w2gC&h7L5@^LDiQg)>Lc9uWQ@5D zF&-+?w@5*v&jq!k$Hss1-CQR_WQwOHRsfoud!;L)wDW^>g7)>C(V70uejR=Ik|K1k zavTdEIL!cFGst`iQL(nMG221C!~N^W$|GV26*evTSY zJ`hVVucKQ(Hv0Hz|J44>;1wKO&QD29-&8sp%V5DhRY{D+DOnYgP|!4Sp?liqep{u{ z8-qrXR&+HW0ZPvtnuhP&YbVDYR$XD8SbY{avsTA$un2-^e#{~*)!wNfJlu1jV4U0O zp3-OHiz!9^JE%$U9tL^$cvo8+_RxcMnTX-{p?Iy&2{u^PZVAk(@--*xde@#mo9qNt z>pUmdPEaBy+H`V8ySFUiqiNtu*H!LW-&JAsE(ujb3w;zA6k4`qyFbnxR9N01Mm!+P zv%lnzE|M=a2pKhr@LY(C%A*IoVwIB&5o-VbSPuron6jP%G4Ox$0)f)f`S2NM$bGDXR+$l*G9$Zka zFjw@9Bk@FLts5YgD4o@e^;8+@vN+Urkq>n_GX-5w-6Hng(W&R>`9k?fn8bunNWQ4^ zs2^4T>cia$B-Z0|a(iT}T0;`pDn&*}-AtL!XHhquh6C=wjsuB&Cu6h;gteOF&tnE_ z*T39i!>;FJH`lrA1l=24nGjaD`s^Jx^6A$y+ssL5Ua?Per#^}w8SoONbVhTWxhE<1E|t2A}kaG45GuVvXLLp?N%=VkGW0V_aL`P&GV(@<*GgI#(H>yL$$>6hrWaW@#<{Pd&Bd-tt_7XW0C z9`5?C(WxIey`>2}1cW0;j3B*>L6O1pYcGEqmNO1~rT<(}9Cxy}7+)*T&9#e@S7KfM zu99vHJ|t`<&~V^4x_g502njFy&T}mW0#5sdr+`f?6_YZpr029Gubg)97{ipOmL$x# zzr7jdQonkk@&*z|yHWEktFn~7O^=UT#`3U$+4If~1#6~WN>EnUOY36l`Z97OM09nq z%}K+?UHN`*M6D63Su!XW8NHt7;`PbrSN(*r;edTKDG}x4bLy{26>IIrHbP+{eCrkt zS#=;1Yj>r&k9msvDa6Z;@OX}Vfv_Vy(OQQM>!lyrz9J-HLx+$p`r8=#LHp>2osd|& zD(WDi0sVaPvr>{@9`0M=n9LGp&jg>+S$mrHxvyKFtNF@g9JWq3gD?`9q+eIfnTx;4 zuw{Mp*@7n~LgHyn4x4qfb?)7TlWT6Lr-tk(i|L>$zxA%*WU$XW%wBPiNt>jK8Tv6l zlfH_^RBRPz--%juDGu<5i?mQYK+LiVkJBFXhbVen%=SfhOr&RsPo64&#LcA)dYD0n zzeUq*L=+iI=hn{$Sut8M`c$202};E5q6r=(Dkr>pQJFLVwJcq94M(h|x2Ys7ctIm{ zE`>j*H;Uk`?q#A11&e9=Tnz7xIF>{sIWIL4bsN5y2q`ln(imdOe>P_OM9JE}a5ld{ zGF}axDW}(#VT(+zGFLqkDm!BTHKD9sf4lVsuI72}@{lW?&}h9!=OU?>75DW=siJe; zYpMZ=8OhH=r&!uXvi;`-Bo>8WAHzP@re{`Tv_l$@jpe*c-dWNud|6f(M~QH4rwA$E z-*>?{wDNlO5Q7iZ2N47$bM!%Ux3>{LAWCN$qd)#sh05zDI3Bg22rV-;3_^6_+}E|F z$8-Zzhc%U&#Z<5v;?dxiAYjw|}T~*cz-gH5i>RlKpxz0uYu;#{P zLk;dd9bbE365B{!?Z6E!*R5i=YV69+AN$eD7K_hdAlmX&(@bfXY8&b0bwzd^xM3&Y zb$xEJzs`T%s=x1%uGw8hKEqfrgzGDhe$v615!HaBPVw0n+ktfGk7dXKZBL1IlZ3(3 z^$7pPGLsdLPOImd48k&3@)-o|+)# zOFRmMi$QicD2|m*oQH*5b4||V#>(wp;5v-e+t+ItSDO!#gQfDUpdyx2uhdM{Fz|;M zCV90I!g!T_ckNl{C@Xs>S^R1UlDuzl9b%tJNs@n&@BTupnciCYFpnCBb9Gfrk~En?OX%n#&Ha$V$9~=hQD_&beJn@ z2phu_u8Ng-9M-4IkZ0?~ zq8F6>de=+zb#ImK-WKaDjuo^dR7A5#DK&-0uIvh4yyD8bu6pMA;vhq}$+&b+W{Ht; zxrF{~LaTUxAe9&6;S^Md+xvD+AZ3CS?>s11Q2QBGwfVxd43>T`*WThR3B5^4^pNxt zf$)q2jVM~4itl7&@OCcg-sC1oR7&K!Kd`s9$VUbJx|V20Lq{*zcbB8BwfbVe=SIcL z%iS--9y0(DM3BDfR*6`tcAdB$FSO;?pU`0lAM>5%bed(m_%ZWt&uV`m>T^%ztjl&z3OjKIrg;uw!Ur`q znA?rjoeEDsu}PV0Q>L()7&1TusJ%9oNz(~aT#wn!=@(xPpVsrqH9l{y8CdTnyVg1F z8t1C2Jz~IJg@=5htsWMsD_NGwU-ujyaZ zglAdgB@5dfEeESD6_V95ukgqA{Fbv1rHZA?7a@v>4KHl1EgkBYGw+JeE$ZQN=Mz5K z{1f`OdVrAoih8!}Q?|XLLWP5XU^Ras(>bHr~G^woM z(@Y{uTxtj3AUC(MXG|E9+FksvOFeoJc}cG9 zGl3r)ebwCs^QVsB1tnN;L`h(V(HqCwz_*o~=6U)hSCnU5wbq_F+wBz!j#hsXMh9#*J#9s?OBxrU;AN4snbn*6~sdV&S`B@__<*^rH*OHU=nZ_^5!FZmo_;&hP0 zCt{qJ4__X&6S()*Sb3#5@=nxTu4=WhD@?)Cb^qu@nCPYvVd6i~v)G<0_A#YwVl9`Z z!FbWQ1n^G#3T782FQIhdZsIfNg>W!*FR6T&937LLaaw6_Pnbi9{wQfb1dS8!>D!>dl6H#5k+GLFcJUX!I^SJa|+ z|LEeqlJp8W@@Yk|0NfZWG&ZVL->xCoqKmqS@?^QdF8{>+KPUT& zSng@A(g(u9RNX3ynbm~9_~^SUzi8-v7LMR^$o&Z2oBq(M;hvB^u>78ceads8B;RLe z;{x&#&O|Q)HgFTNjHq%`URG$|dqdq&vay9TN6}siVZhYO^r?K`H4PMbnphl)JNWfB zISXMlCV$5ZaAj&a6zzyw9r<{v+gGyv!aL`!$iA*`4G2mfy3^t(bLucQKID3T(Agh( zG87gTc=TQl`{&mKC+4A~7Z+Xey=!5zF`LlZG9}Qg)q)blq*_b!Y0c9VMIY;Bl)!6k zYng8ua{CA7vdMqC1?PM1j&oUvf-oIJbdVbl zm6H^@!K?d+P4n5LMtu<`R==2Hrs~`b(Jo%(-gLUsDgBqal$;odEnQiU{Ev!7ty2-# zgP>arr7BF^G&%x-l5nQZ_6?>9e06hK zNv%ggFO7Av=O(bsE{EepkA*6Bv6kLUxqyp7`M{})nY;D*p=T}p5wRl=)VJF{dI!(H z8S-g67+&%`7KR(wi~MYvwC{QGz~_LxckFvJh0zywUP~zezRvbt4Nw5; z>lLuK>9Ve-W46BjM2ld!S=&e7YypLzF z`Z`9GZ!XTf8CDuCvDj4YHEOFHNm3~f%ysT=Bx#LFoGc2d10U(?V$H&4SCmt8^`MS= zTP{*|7>=@zKMS*-NFuoveif$P<(OQ0sR<_P!+AgzGg~52Vr?n_vbbubjA(7Cd(3uW z$_>Xs&{rCKAd>b&kw(U>PE~w0>VC5VDIHg%-7g+IX(&rjWHo2O5_+wC=lx%v!n!~E z-y59Y8&&6=HaXT9^9<9JW=c_Oua*2&(aDvX&NU#9(gKQ zL@0`w$a=_sxI}5>HHrRkC9Lw>@WVLsM8IZ&G7{hyf*3V>uZPvWLsqWw#3H8_LbnYc zcjxj%+iexW!;aGR(C2u&5V@{#hv^RDff>N5eU2(#ydZVB*LH%UoBeVi`-hc&>G{{2 z-#?Q`tr`y>)@?4MWqTS$dVKL8J~Z^1;{4jGJg~%QiobXU(^o=t*%}}RAgCIV3w4%8x{)&n$#(Nj_BOVp#^(B~YYt%PH;RrIYe=d-Vg%p7_g{G*pay5V%K? z_78~A?~a+U4~3?M2*aUDRo=+c*=;j3z3(|iss)Agi5%>4Iop>GHi86%XO63*09_zU z05(W41+>3Jp$$NgeW#3>|Ij_k6oU3cfMEm&DEdEQ0{=U^7X?V9m(*O@I&khEeh!nP<$Xo|=j5(3)E)e!40HJzafDNG3DkljK4Gy0cx2OyhI$ zq~5NOtFq?KFVg-HhPhg$M(1L~PSoS2ijMo+ow`Jhx|{1@X&LPJ!86gPhTXmVAA6J0 zVqyjzeo!Q&bcBfTo}u<_uJWv_dT%{@0765X@1s5`DOgPi2W9n9lR%*x>un`1OZPn_ z@S}w$ZZ2>>WKX+h@Ul;IJ~<_NT0s*HKt;h9E2vC?z)N(GC@Ep-#&x=uR(7Hfmq%?+ zo(HZg5z*)b{)U~c-kl*-Syg|Qnrdrno3^$ZNj@Dy7H#t+w{brzZs{yj;se6kc#JF6%5PSewVt_%;s9 zq!R1tj2hNUIbtu9T~jlCDf%>df%h~f=^eIA;?;(m!y=>qdos| znAwEGpxYZRg$E|nSxfoJHebG!y)@Uxozb=`=;+H`TAs(-oiE&GW29w=E=>k@Ee>6O zXLRRt6-z)Mm>|#|B1QmUN!zTC zj)K#Kga`;gch_@Zu!P$^b#V04u`A4j#^}WhqlyX`IG)mPevW7NM}f*tei5QOI*e)C&hcZ=4fv?KlD(v_SES!Pqm z8~U9Fis%0#o07t{l>2dcqijO&QM!0l>P+`-1Yq~UC2fms{wL&Qm;WWG?vDeYo zbFXiw%R1NBceBPmSM3>i3|t;J!Djfk^F`C#){xU2P+I%|6&wqWOlxM`ZpyS0h)8gA^8 zJzfq~nLV6q^t~l1R`?=u>`^F2qo6|aRSGe}33)=`ZIodt(n~fL@K&X5ZBVyWjei_` z)S$TCp9(9!Dto~5*N8IcQFmJMbA{fER@@prv)Rz(fTzevyguI)7VH5qg`N-NS#mLT zJ(F3?L`x0aiP~W?Q#8~HYnYhw$BUjOXl6yvN7c_FPQfEM-&(S}K7O3y_4c^w{Nk#p z7(Fhx^0Md9^?30O$H_?l*u%c2OVtndD`^@-;x}270I(7u52(t>=j+9-*$%Vep4+RI zx@u1B!E@i3n+)xRVpj|3$zxwxpP$;D)iZ&6tY#7tgv#1P>``%orY&#bR!bZ{%L8@=*(L=w@coN)!8X^u{}--_}Tf>`)#0K$CM?; z@M>0{NX|-1G&ebau${i%(4R&R`kX5(chuqflj_o_jvO1i-&;kp&$dPQKz|_?Co8(*~l9S z6h`rS0WM9C)0$^1FqgktY%USKf16gEp=K^h>A%wWPn5;|w+_l|($c!rx!ad~shpZ#znt+4|H z;z*YR4joT(sK_QY^E_m_x+zzE)Sj%YZ!&ys8(ct3EkYmnlng%7Emwz*xCPi|`Y|FO zqJv*!`Caegu>{=g%~D%m_DO(|Ub>tx@cS+`NbbmLXuV|r{H(LHlki*lUpFJKW*U)n zc?AhB?LR?S0rIhjGTCCUJATG3mM{>mYkgO|tc}E7h#=R9ADkce50|++TA(9cR2(D0 zM#Fn&c(R{Wm0DgNs;>Tfu>m$ifHQ-j~ zrKa{V=inVpDp>tGAu_?|Rb{WU1$o-CvAu>~h=>sL1sMn4awKr-G+%P3X=VozHKU zH}dWR$$(X?0;F)$&cA=LFz{r2?n>@eeDO`qus0o{Vid9V-HFFb@2j%u&3n@mmfTvuxNc>aKb*UX)$k&KLtI61R!FM2py znRLqAKXpZRWP0y2UwnBc#}wY^!OQ0F?HJFG;BMb>#*z4oo0rcWdbHfesz7`nxf?XB zdFFp_M?EtOINNae)i<4dHYzImxR?LIaD!a86|Qi1IeERjT#&-wmE|SEkBX0Z{k zS8%H*{^QT(7Aq?oUf=t(B|OpUsi{BJ^REugMK@7Db7JE`^OVTzyl(3=9>PDc1U9w! z<$7)rAq-GTuYPsM;U{8?qauckN!qm_O7!G)DGM89@QPL&BmlS==Ef z?4NW#UaWA2X|+C*LD6)Lvx)LC;uUBJV?ut4DDHoSq zeTHyK+@vYjJ+ZzM(;rVyG#_eYBrM>xn+XDJE*oxM4LpB{hDy_j;(epxM`sO(X;nPu zKX)zAE}^@8hFYKHM}Wdb_U7uUKEd$hu-e&m!FIXZE;@C5j+7xWR>;j^ii&@vbQ-&U z#-*6odV;QLn3$N9l$c2RvvB%*rXcJuh>e!Gs%nx}c<*=F&u3rzG~@t3#$Y}qdr1jL zNT8?R=z~14$thmIT7TBopJ@j9vQV)|EwuLd8>?=MD%-d*K`5jV)+N%=f0cW+GEmSe zP5N}Riv0TSsoS;!vr}%?h~l^b>zv(Z&9z}}9E4cJP=G+Jy{&q&{hNt^%=lnuj*)Ns zxq~{KW)kw=UOBl3*X4vAtY+jA>Ag}I&aq+3JFH==4o=A6Z%Pk8s%>tTt)0H8$X;|h z(DOPnnR1koKfJKm_1cm=;Rsz~}G5j+C4lOsJY*O~|pP8}P2HgrYf zCYsD8IzbHa4Tcw0+oUPJ9oG+mlShMYlIQF{Uf+%mD| z2Sm{V{hjFAFvw7UW1p{};Z^+HT$>vDbZ0n?q; zM5Qbe0mu*jY_7aX-(s23s08 zJv*B0Q76_N16J+S>H+OV_GwzaNQ@B5>KO8wBpfJ5yv^46pmnI8cglm*VtFsFEoU0f z6;n8dFnPAuA!_*BKym)apJ}ov7KCVq)|f0vQ85DS6CR$pRmI=L6gq6PF>c7uzr1^< zGq+Ag5p3Tr&N2NAKfoJ@d;o;{eY|4z?nh^Tn)G4SY-NC_7mp34M5%*yzx_3sZcafa zNBlUy+Y}RTPJw#1!21|AoJJ`G>=EOsMhP@OmqOM`yc3Hnn%=ompD^#@tBr~_@KQ*k z&R{qaHOukcp6MWp{a!2={~0ukN@#5*v;dBqEK==uicr?`9EojMsc^=1nkUoDCZ3hq zjO4kpr;Q%xkZO(*MiLc5qQy*v+tu>)^o$?yzsEwj9;w-5xqQkG&dfGZKcBUXuMs*T za44z!DQL@tP7%NFU~qapK9H0s2ImtS9wW07DLV}0q9QXuBBRuymOMjc`yy;gP_EID zYWD2Qn1PrGVj&GikJyinO6%P;as7CJ-ev?&#kKUoSj*aiss6o+s7_c7a1RTz!k~Uh zio487{BGg(Nk&oMJ{g*b?%q-7i65b9sgv3-jftp;8#Yau2}`M39wcp{lmQd*?16@N z2y8foE}E9;b%Yv@EI;#F5J5+H&5ASxV1V~aX8lo3C-VMQYY z9;D6tx4q`pT~&8;xxY!Gf1vG>FLTfJ9QD?Vb(@k%9$7j;p?SEROHW2uBf!tL8=%^y z*C>r%%BB?+#BMO{$P{%WvvG7eyPT0+so|1UQt4_r$-DCgY=;8t@%&1t8jdY?+hP^7 zZ$ 0) - textareas.push(textArea); + if (textArea.placeholder.length > 0) textareas.push(textArea); } } @@ -97,40 +54,35 @@ class pfConfigs { /** @returns {string[]} */ static cacheCards() { - const extras = document.getElementById('txt2img_extra_tabs'); - if (!extras) - return []; + const cards = document + .getElementById("pf_embeddings") + .querySelector("textarea") + .value.split("\n"); - const cards = []; - for (const card of extras.querySelectorAll('span.name')) { - if (card.textContent.includes('_')) - cards.push(card.textContent); - } - - const config = document.getElementById('setting_pf_exclusion').querySelector('input').value; - if (config.trim()) { - for (const tag of config.split(",")) - cards.push(tag.trim()); - } + const config = document + .getElementById("setting_pf_exclusion") + .querySelector("textarea").value; + for (const tag of config.split(",").map((t) => t.trim())) + if (tag) cards.push(tag); return cards; } - /** @returns {Map} */ + /** @returns {{RegExp: string}} */ static getTagAlias() { const alias = new Map(); - const config = document.getElementById('setting_pf_alias').querySelector('textarea').value; - if (!config.trim()) - return alias; + const config = document + .getElementById("setting_pf_alias") + .querySelector("textarea").value; + if (!config.includes(":")) return alias; for (const line of config.split("\n")) { const [tag, words] = line.split(":"); const mainTag = tag.trim(); - for (const word of words.split(",").map(part => part.trim())) { - if (word === mainTag) - continue; + for (const word of words.split(",").map((part) => part.trim())) { + if (word === mainTag) continue; const pattern = this.#parseRegExp(word); alias.set(pattern, mainTag); @@ -142,9 +94,6 @@ class pfConfigs { /** @param {string} input @returns {RegExp} */ static #parseRegExp(input) { - const startAnchor = input.startsWith('^'); - const endAnchor = input.endsWith('$'); - return new RegExp(`${startAnchor ? '' : '^'}${input}${endAnchor ? '' : '$'}`); + return new RegExp(`^${input.trimStart("^").trimEnd("$")}$`); } - } diff --git a/javascript/pf_ui.js b/javascript/pf_ui.js index b1916c8..505f8be 100644 --- a/javascript/pf_ui.js +++ b/javascript/pf_ui.js @@ -1,9 +1,8 @@ class pfUI { - /** @param {string} text @param {string} tip @returns {HTMLButtonElement} */ static #button(text, tip) { - const button = document.createElement('button'); - button.classList.add(['lg', 'secondary', 'gradio-button']); + const button = document.createElement("button"); + button.classList.add(["lg", "secondary", "gradio-button"]); button.textContent = text; if (tip) button.title = tip; return button; @@ -11,9 +10,12 @@ class pfUI { /** @param {boolean} value @param {string} text @returns {HTMLLabelElement} */ static #checkbox(value, text) { - const label = document.getElementById('tab_settings').querySelector('input[type=checkbox]').parentNode.cloneNode(true); + const label = document + .getElementById("pf_checkbox") + .querySelector("label") + .cloneNode(true); label.classList.add("pf-checkbox"); - label.removeAttribute('id'); + label.removeAttribute("id"); const checkbox = label.children[0]; checkbox.checked = value; @@ -23,24 +25,19 @@ class pfUI { return label; } - /** - * @param {boolean} autoRun - * @param {boolean} dedupe - * @param {boolean} removeUnderscore - * @returns {HTMLDivElement} - */ - static setupUIs(autoRun, dedupe, removeUnderscore) { - const formatter = document.createElement('div'); - formatter.id = 'le-formatter'; + /** @param {boolean} autoRun @param {boolean} dedupe @param {boolean} rmUnderscore @returns {HTMLDivElement} */ + static setupUIs(autoRun, dedupe, rmUnderscore) { + const formatter = document.createElement("div"); + formatter.id = "le-formatter"; - const manualBtn = this.#button('Format', null); - manualBtn.style.display = autoRun ? 'none' : 'flex'; - const refreshBtn = this.#button('Reload', 'Reload Cached Cards & Alias'); - refreshBtn.style.display = removeUnderscore ? 'flex' : 'none'; + const manualBtn = this.#button("Format", "Manually Format the Prompts"); + manualBtn.style.display = autoRun ? "none" : "flex"; + const refreshBtn = this.#button("Reload", "Reload Exclusion & Alias"); + refreshBtn.style.display = rmUnderscore ? "flex" : "none"; - const autoCB = this.#checkbox(autoRun, 'Auto Format'); - const dedupeCB = this.#checkbox(dedupe, 'Remove Duplicates'); - const underscoreCB = this.#checkbox(removeUnderscore, 'Remove Underscores'); + const autoCB = this.#checkbox(autoRun, "Auto Format"); + const dedupeCB = this.#checkbox(dedupe, "Remove Duplicates"); + const underscoreCB = this.#checkbox(rmUnderscore, "Remove Underscores"); formatter.appendChild(autoCB); formatter.appendChild(manualBtn); @@ -56,5 +53,4 @@ class pfUI { return formatter; } - } diff --git a/javascript/prompt_format.js b/javascript/prompt_format.js index 2386464..c6a8859 100644 --- a/javascript/prompt_format.js +++ b/javascript/prompt_format.js @@ -1,76 +1,52 @@ class LeFormatter { - - static #_alias = null; - static #_cachedCards = null; + static #aliasData = null; + static #cardsData = null; static forceReload() { - this.#_alias = null; - this.#_cachedCards = null; + this.#aliasData = null; + this.#cardsData = null; + } + + /** @returns {{RegExp: string}} */ + static get #alias() { + return (this.#aliasData ??= pfConfigs.getTagAlias()); } /** @returns {string[]} */ - static get #cachedCards() { - if (this.#_cachedCards == null) - this.#_cachedCards = pfConfigs.cacheCards(); - return this.#_cachedCards; - } - - /** @returns {Map} */ - static get #alias() { - if (this.#_alias == null) - this.#_alias = pfConfigs.getTagAlias(); - return this.#_alias; + static get #cards() { + return (this.#cardsData ??= pfConfigs.cacheCards()); } /** * @param {HTMLTextAreaElement} textArea * @param {boolean} dedupe - * @param {boolean} removeUnderscore + * @param {boolean} rmUnderscore * @param {boolean} autoRefresh * @param {boolean} appendComma */ - static formatPipeline(textArea, dedupe, removeUnderscore, autoRefresh, appendComma) { - const lines = textArea.value.split('\n'); + static formatPipeline(textArea, dedupe, rmUnderscore, autoRefresh, appendComma) { + const lines = textArea.value.split("\n"); for (let i = 0; i < lines.length; i++) - lines[i] = this.formatString(lines[i], dedupe, removeUnderscore); + lines[i] = this.formatString(lines[i], dedupe, rmUnderscore); - if (!appendComma) - textArea.value = lines.join('\n'); + if (!appendComma) textArea.value = lines.join("\n"); else { - const val = lines.join(',\n'); - textArea.value = val.replace(/\n,\n/g, '\n\n'); + const val = lines.join(",\n"); + textArea.value = val + .replace(/\n,\n/g, "\n\n") + .replace(/\s*,\s*$/g, "") + .replace(/\s*,\s*$/g, ""); } - if (autoRefresh) - updateInput(textArea); - } - - /** @param {string[]} tags @returns {string[]} */ - static #joinExtraNet(tags) { - let isNet = false; - let i = 0; - - while (i < tags.length) { - if (!isNet) { - if (tags[i].startsWith('<')) - isNet = true; - i++; - } - else { - isNet = !tags[i].endsWith('>'); - tags[i - 1] = `${tags[i - 1]}, ${tags.splice(i, 1)[0]}`; - } - } - - return tags; + if (autoRefresh) updateInput(textArea); } /** @param {string} input @returns {string} */ static #toExpression(input) { return input - .replace(/[,\n]\s*> <\s*[,\n]/g, ", $SHY$,") - .replace(/[,\n]\s*:3\s*[,\n]/g, ", $CAT$,"); + .replace(/[,\n^]\s*> <\s*[,\n$]/g, ", $SHY$,") + .replace(/[,\n^]\s*:3\s*[,\n$]/g, ", $CAT$,"); } /** @param {string} input @returns {string} */ @@ -80,68 +56,99 @@ class LeFormatter { .replace("$CAT$", ":3"); } - /** @param {string} input @param {boolean} dedupe @param {boolean} removeUnderscore @returns {string} */ - static formatString(input, dedupe, removeUnderscore) { + /** @type {Map} */ + static #networkDB = new Map(); + + /** @param {string} input @returns {string} */ + static #toNetwork(input) { + this.#networkDB.clear(); + + const output = input.replace(/\s*<.+?>\s*/g, (match) => { + const UID = `@NET${this.#networkDB.size}WORK@`; + this.#networkDB.set(UID, match.trim()); + return UID; + }); + + return output; + } + + /** @param {string} input @returns {string} */ + static #fromNetwork(input) { + const len = this.#networkDB.size; + + for (let i = 0; i < len; i++) { + const UID = `@NET${i}WORK@`; + input = input.replace(UID, this.#networkDB.get(UID)); + } + + return input; + } + + /** @param {string} input @param {boolean} dedupe @param {boolean} rmUnderscore @returns {string} */ + static formatString(input, dedupe, rmUnderscore) { + // Substitute LoRAs + input = this.#toNetwork(input); // Remove Underscore - input = removeUnderscore ? this.#removeUnderscore(input) : input; + input = rmUnderscore ? this.#rmUnderscore(input) : input; // Special Tags input = this.#toExpression(input); + // Restore LoRAs + input = this.#fromNetwork(input); + // Fix Commas inside Brackets input = input - .replace(/,+\s*\)/g, '),') - .replace(/,+\s*\]/g, '],') - .replace(/,+\s*\>/g, '>,') - .replace(/,+\s*\}/g, '},') - .replace(/\(\s*,+/g, ',(') - .replace(/\[\s*,+/g, ',[') - .replace(/\<\s*,+/g, ',<') - .replace(/\{\s*,+/g, ',{'); + .replace(/,+\s*\)/g, "),") + .replace(/,+\s*\]/g, "],") + .replace(/,+\s*\>/g, ">,") + .replace(/,+\s*\}/g, "},") + .replace(/\(\s*,+/g, ",(") + .replace(/\[\s*,+/g, ",[") + .replace(/\<\s*,+/g, ",<") + .replace(/\{\s*,+/g, ",{"); // Fix Bracket & Space input = input - .replace(/\s+\)/g, ')') - .replace(/\s+\]/g, ']') - .replace(/\s+\>/g, '>') - .replace(/\s+\}/g, '}') - .replace(/\(\s+/g, '(') - .replace(/\[\s+/g, '[') - .replace(/\<\s+/g, '<') - .replace(/\{\s+/g, '{'); + .replace(/\s+\)/g, ")") + .replace(/\s+\]/g, "]") + .replace(/\s+\>/g, ">") + .replace(/\s+\}/g, "}") + .replace(/\(\s+/g, "(") + .replace(/\[\s+/g, "[") + .replace(/\<\s+/g, "<") + .replace(/\{\s+/g, "{"); // Remove Space around Syntax - input = input - .replace(/\s*\|\s*/g, '|') - .replace(/\s*\:\s*/g, ':'); + input = input.replace(/\s*\|\s*/g, "|").replace(/\s*\:\s*/g, ":"); // Sentence -> Tags - let tags = input.split(',').map(word => word.trim()); - - // [""] -> [""] - tags = this.#joinExtraNet(tags); + let tags = input.split(",").map((word) => word.trim()); // Remove Duplicate tags = dedupe ? this.#dedupe(tags) : tags; // Remove extra Spaces - input = tags.join(', ').replace(/\s+/g, ' '); + input = tags.join(", ").replace(/\s+/g, " "); // Remove Empty Brackets while (/\(\s*\)|\[\s*\]/.test(input)) - input = input.replace(/\(\s*\)|\[\s*\]/g, ''); + input = input.replace(/\(\s*\)|\[\s*\]/g, ""); // Space after Comma in Escaped Brackets (for franchise) - input = input.replace(/\\\(([^\\\)]+?):([^\\\)]+?)\\\)/g, '\\($1: $2\\)'); + input = input.replace(/\\\(([^\\\)]+?):([^\\\)]+?)\\\)/g, "\\($1: $2\\)"); + // Prune empty Chunks - input = input.split(',').map(word => word.trim()).filter(word => word).join(', ') + input = input.split(",").map((word) => word.trim()).filter((word) => word).join(", "); + // LoRA Block Weights - input = input.replace(/\<[^\>]+\>/g, (match) => { - return match.replace(/\,\s+/g, ','); + input = input.replace(/<.+?>/g, (match) => { + return match.replace(/\,\s+/g, ","); }); + // Remove empty before Colon - input = input.replace(/\,\s*\:(\d)/g, ':$1'); + input = input.replace(/,\s*:(\d)/g, ":$1"); input = this.#fromExpression(input); @@ -155,7 +162,7 @@ class LeFormatter { const results = []; for (const tag of input) { - const cleanedTag = tag.replace(/\[|\]|\(|\)/g, '').replace(/\s+/g, ' ').trim(); + const cleanedTag = tag.replace(/\[|\]|\(|\)/g, "").replace(/\s+/g, " ").trim(); if (KEYWORD.test(cleanedTag)) { results.push(tag); @@ -170,66 +177,62 @@ class LeFormatter { } } - if ((substitute == null) && (!uniqueSet.has(cleanedTag))) { + if (substitute == null && !uniqueSet.has(cleanedTag)) { uniqueSet.add(cleanedTag); results.push(tag); continue; } - if ((substitute != null) && (!uniqueSet.has(substitute))) { + if (substitute != null && !uniqueSet.has(substitute)) { uniqueSet.add(substitute); results.push(tag.replace(cleanedTag, substitute)); continue; } - results.push(tag.replace(cleanedTag, '')); + results.push(tag.replace(cleanedTag, "")); } return results; } /** @param {string} input @returns {string} */ - static #removeUnderscore(input) { - if (!input.trim()) - return ""; + static #rmUnderscore(input) { + if (!input.trim()) return ""; - const syntax = /\,\|\:\<\>\(\)\[\]\{\}/; - const pattern = new RegExp(`([${syntax.source}]+|[^${syntax.source}]+)`, 'g'); - const parts = input.match(pattern); + for (let i = 0; i < this.#cards.length; i++) + input = input.replaceAll(this.#cards[i], `@TEXTUAL${i}INVERSION@`); - const processed = parts.map((part) => { - if (new RegExp(`[${syntax.source}]+`).test(part)) - return part; - if (/^\s+$/.test(part)) - return part; + input = input.replaceAll("_", " "); - if (!this.#cachedCards.includes(part.trim())) - part = part.replaceAll('_', ' '); + for (let i = 0; i < this.#cards.length; i++) + input = input.replaceAll(`@TEXTUAL${i}INVERSION@`, this.#cards[i]); - return part; - }); - - return processed.join(''); + return input; } } (function () { onUiLoaded(() => { - const config = new pfConfigs(); - const formatter = pfUI.setupUIs(config.autoRun, config.dedupe, config.removeUnderscore); + const formatter = pfUI.setupUIs(config.autoRun, config.dedupe, config.rmUnderscore); - document.addEventListener('keydown', (e) => { - if (e.altKey && e.shiftKey && e.code === 'KeyF') { + document.addEventListener("keydown", (e) => { + if (e.altKey && e.shiftKey && e.code === "KeyF") { e.preventDefault(); for (const field of config.promptFields) - LeFormatter.formatPipeline(field, config.dedupe, config.removeUnderscore, true, config.comma); + LeFormatter.formatPipeline( + field, + config.dedupe, + config.rmUnderscore, + config.refresh, + config.comma, + ); } }); formatter.auto.addEventListener("change", () => { config.autoRun = formatter.auto.checked; - formatter.manual.style.display = config.autoRun ? 'none' : 'flex'; + formatter.manual.style.display = config.autoRun ? "none" : "flex"; }); formatter.dedupe.addEventListener("change", () => { @@ -237,52 +240,61 @@ class LeFormatter { }); formatter.underscore.addEventListener("change", () => { - config.removeUnderscore = formatter.underscore.checked; - formatter.refresh.style.display = config.removeUnderscore ? 'flex' : 'none'; + config.rmUnderscore = formatter.underscore.checked; + formatter.refresh.style.display = config.rmUnderscore ? "flex" : "none"; }); formatter.manual.addEventListener("click", () => { for (const field of config.promptFields) - LeFormatter.formatPipeline(field, config.dedupe, config.removeUnderscore, config.refresh, config.comma); + LeFormatter.formatPipeline( + field, + config.dedupe, + config.rmUnderscore, + config.refresh, + config.comma, + ); }); formatter.refresh.addEventListener("click", () => { LeFormatter.forceReload(); }); - const tools = document.getElementById('quicksettings'); + const tools = document.getElementById("quicksettings"); tools.after(formatter); /** Expandable List of IDs in 1 place */ const IDs = [ - 'txt2img_generate', - 'txt2img_enqueue', - 'img2img_generate', - 'img2img_enqueue' + "txt2img_generate", + "txt2img_enqueue", + "img2img_generate", + "img2img_enqueue", ]; for (const id of IDs) { const button = document.getElementById(id); - button?.addEventListener('click', () => { - if (config.autoRun) { - for (const field of config.promptFields) - LeFormatter.formatPipeline(field, config.dedupe, config.removeUnderscore, config.refresh, config.comma); - } + button?.addEventListener("click", () => { + if (!config.autoRun) return; + for (const field of config.promptFields) + LeFormatter.formatPipeline( + field, + config.dedupe, + config.rmUnderscore, + config.refresh, + config.comma, + ); }); } - if (!config.paste) - return; + if (!config.paste) return; /** https://github.com/AUTOMATIC1111/stable-diffusion-webui/blob/v1.10.1/modules/infotext_utils.py#L16 */ - const paramPatterns = /\s*(\w[\w \-/]+):\s*("(?:\\.|[^\\"])+"|[^,]*)(?:,|$)/g; + const paramPatterns = + /\s*(\w[\w \-/]+):\s*("(?:\\.|[^\\"])+"|[^,]*)(?:,|$)/g; for (const field of config.promptFields) { - field.addEventListener('paste', (event) => { - /** @type {string} */ - let paste = (event.clipboardData || window.clipboardData).getData('text'); - if ([...paste.matchAll(paramPatterns)].length > 3) - return; // Infotext + field.addEventListener("paste", (event) => { + /** @type {string} */ let paste = (event.clipboardData || window.clipboardData).getData("text"); + if ([...paste.matchAll(paramPatterns)].length > 3) return; // Infotext event.preventDefault(); @@ -292,25 +304,26 @@ class LeFormatter { const multiline = !paste.includes(","); if (config.booru) { - paste = paste.replace(/\s*[\d.]+[kM]\s*|(?:^|,|\s+)\d{2,}(?:\s+|,|\?|$)|[\?\+\-]\s+/g, ", "); + paste = paste.replace(/\s*[\d.]+[kM]\s*|(?:^|,|\s+)\d+(?:\s+|,|\?|$)|[\?\+\-]\s+/g, ", "); for (const excl of ["Artist", "Characters", "Character", "Copyright", "Tags", "Tag", "General"]) paste = paste.replace(excl, ""); const name_franchise = /\w+?[\_\s]\(.*?\)/g; paste = paste.replace(name_franchise, (match) => { - return match.replace(/[()]/g, '\\$&'); + return match.replace(/[()]/g, "\\$&"); }); } if (multiline) { const lines = []; for (const line of paste.split("\n")) - lines.push(LeFormatter.formatString(line, config.dedupe, config.removeUnderscore)); - paste = lines.join("\n"); + lines.push(LeFormatter.formatString(line, config.dedupe, config.rmUnderscore)); + paste = lines.filter((l) => l).join("\n"); + if (!paste.includes(",")) paste = paste.replaceAll("\n", ", "); } else - paste = LeFormatter.formatString(paste, config.dedupe, config.removeUnderscore); + paste = LeFormatter.formatString(paste, config.dedupe, config.rmUnderscore); - paste = `${commaStart ? ", " : ""}${paste}${commaEnd ? ", " : ""}` + paste = `${commaStart ? ", " : ""}${paste}${commaEnd ? ", " : ""}`; const currentText = field.value; const cursorPosition = field.selectionStart; @@ -320,26 +333,8 @@ class LeFormatter { field.selectionStart = field.selectionEnd = cursorPosition + paste.length; updateInput(field); + return false; }); } - - let refreshTimer; - function onRefresh() { setTimeout(() => LeFormatter.forceReload(), 100); } - - const observer = new MutationObserver((mutationsList) => { - for (const mutation of mutationsList) { - if (mutation.type !== "childList") - continue; - if (refreshTimer) clearTimeout(refreshTimer); - refreshTimer = setTimeout(onRefresh, 250); - break; - } - }); - - const lora = document.getElementById('txt2img_lora_cards_html'); - const ti = document.getElementById('txt2img_textual_inversion_cards_html'); - - observer.observe(lora, { childList: true, subtree: true }); - observer.observe(ti, { childList: true, subtree: true }); }); })(); diff --git a/sample.jpg b/sample.jpg deleted file mode 100644 index e72c063cc709be9246b5549264d03f3fc21b9030..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21310 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 z 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ℑglO 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 set[str]: + from pathlib import Path + + EXTENSIONS = (".pt", ".pth", ".ckpt", ".safetensors", ".sft") + items: set[str] = set() + + embeddings = Path(cmd_opts.embeddings_dir) + for ext in EXTENSIONS: + files = embeddings.glob(f"**/*{ext}") + for file in files: + items.add(file.stem) + + return items + + +class PFServer(scripts.Script): + def title(self): + return "Prompt Format" + + def show(self, is_img2img): + return scripts.AlwaysVisible if is_img2img else None + + def ui(self, is_img2img): + if not is_img2img: + return None + + with Column(visible=False): + emb = get_embeddings() + link = Textbox( + value="\n".join(emb), + elem_id="pf_embeddings", + interactive=False, + ) + dummy = Checkbox( + label="Enable", + elem_id="pf_checkbox", + interactive=True, + ) + + link.do_not_save_to_config = True + dummy.do_not_save_to_config = True def on_settings(): - from modules.shared import OptionInfo, opts - from gradio import Textbox - args = {"section": ("pf", "Prompt Format"), "category_id": "system"} opts.add_option( @@ -20,17 +64,23 @@ def on_settings(): opts.add_option( "pf_startinauto", - OptionInfo(True, "Launch in Auto Mode", **args), + OptionInfo( + True, "Launch the WebUI with Auto Format enabled", **args + ).needs_reload_ui(), ) opts.add_option( "pf_startwithdedupe", - OptionInfo(True, "Launch with Remove Duplicates", **args), + OptionInfo( + True, "Launch the WebUI with Remove Duplicates enabled", **args + ).needs_reload_ui(), ) opts.add_option( "pf_startwithrmudscr", - OptionInfo(True, "Launch with Remove Underscores", **args), + OptionInfo( + True, "Launch the WebUI with Remove Underscores enabled", **args + ).needs_reload_ui(), ) opts.add_option( @@ -42,22 +92,31 @@ def on_settings(): opts.add_option( "pf_onpaste", - OptionInfo(False, "Format the pasted text", **args).needs_reload_ui(), + OptionInfo( + False, "Format the texts pasted from clipboard", **args + ).needs_reload_ui(), + ) + + opts.add_option( + "pf_booru", + OptionInfo(False, 'Process the "Booru Structure"', **args) + .info("only take effect when the above option is enabled") + .needs_reload_ui(), ) opts.add_option( "pf_exclusion", OptionInfo( default="", - label="Exclude Tags from Remove Underscores", + label="Tags excluded from Remove Underscores", component=Textbox, component_args={ "placeholder": "score_9, score_8_up, score_7_up", - "max_lines": 1, + "max_lines": 4, "lines": 1, }, **args, - ), + ).info("requires Reload button"), ) opts.add_option( @@ -67,23 +126,17 @@ def on_settings(): label="Tag Alias for Remove Duplicates", component=Textbox, component_args={ - "placeholder": "1girl: girl, woman, lady\nadult: \\d*\\s*(y\\.?o\\.?|[Yy]ear[s]? [Oo]ld)", - "max_lines": 16, - "lines": 4, + "placeholder": "1girl: girl, woman, lady\nadult: \\d+\\s*(y\\.?o\\.?|[Yy]ear[s]? [Oo]ld)", + "max_lines": 8, + "lines": 2, }, **args, ) - .info("treat tags on the right as duplicates of the main tag on the left") - .link("RegExr", "https://regexr.com/"), - ) - - opts.add_option( - "pf_booru", - OptionInfo( - False, - 'Process the "Booru Structure"', - **args, - ).info("requires format on paste) (Experimental"), + .info("requires Reload button") + .link( + "Regexper", + "https://regexper.com/#%5Cd%2B%5Cs*%28y%5C.%3Fo%5C.%3F%7C%5BYy%5Dear%5Bs%5D%3F%20%5BOo%5Dld%29", + ), )