From 918d06e9908051d4792706dec4cbf34ace218f3f Mon Sep 17 00:00:00 2001 From: lq1405 <2769838458@qq.com> Date: Thu, 12 Sep 2024 14:13:09 +0800 Subject: [PATCH] LaiTool V3.1.1. --- package-lock.json | 6 +- package.json | 2 +- .../1236e3d6-c07f-4093-9bb1-a8d73401889a.png | Bin 0 -> 44974 bytes .../6d4245d0-18b8-4cc3-8827-af93d7de6c72.png | Bin 0 -> 44974 bytes .../a5ca6031-62a5-4a05-9d2a-1b7dc857e7fe.png | Bin 0 -> 44974 bytes .../a899bc65-317d-496d-a359-cbd3fb747c50.png | Bin 0 -> 44974 bytes .../f2e95c70-2267-4f7f-a93a-b095f7846604.png | Bin 0 -> 44974 bytes resources/scripts/db/book.realm.lock | Bin 1416 -> 1416 bytes resources/scripts/db/software.realm | Bin 393216 -> 786432 bytes resources/scripts/db/software.realm.lock | Bin 1416 -> 1416 bytes resources/scripts/db/tts.realm.lock | Bin 1416 -> 1416 bytes src/define/Tools/common.ts | 30 + src/define/Tools/file.ts | 21 + src/define/Tools/image.ts | 4 +- .../db/model/Book/BookBackTaskListModel.ts | 4 +- src/define/db/model/Book/bookTaskDetail.ts | 2 + src/define/db/model/SoftWare/preset.ts | 36 + .../service/Book/bookBackTaskListService.ts | 4 +- src/define/db/service/Book/bookBasic.ts | 16 +- src/define/db/service/Book/bookService.ts | 3 + .../db/service/Book/bookTaskDetailService.ts | 6 +- src/define/db/service/Book/bookTaskService.ts | 2 +- .../db/service/SoftWare/imageStyleService.ts | 26 + .../db/service/SoftWare/mjSettingService.ts | 2 +- .../db/service/SoftWare/softwareBasic.ts | 9 +- .../db/service/SoftWare/softwareService.ts | 22 +- src/define/define_string.ts | 79 +- src/define/enum/bookEnum.ts | 22 +- src/define/enum/image.ts | 26 + src/define/enum/mjEnum.ts | 11 +- src/define/enum/preset.ts | 16 + src/define/setting/imageSetting.js | 490 ++++++------ src/main/IPCEvent/bookIpc.ts | 17 +- src/main/IPCEvent/dbIpc.ts | 15 + src/main/IPCEvent/globalIpc.js | 5 + src/main/IPCEvent/index.js | 4 + src/main/IPCEvent/mjIpc.js | 3 +- src/main/IPCEvent/presetIpc.ts | 19 + src/main/IPCEvent/settingIpc.js | 4 +- src/main/IPCEvent/taskIpc.ts | 39 + src/main/Original/MJOriginalImageGenerate.js | 14 +- src/main/Public/generalTools.ts | 13 +- src/main/Service/Book/BooKBasic.ts | 11 +- src/main/Service/Book/ReverseBook.ts | 3 +- src/main/Service/Book/bookImage.ts | 19 +- src/main/Service/Book/bookPrompt.ts | 114 ++- src/main/Service/Flux/flux.ts | 341 +++++++++ src/main/Service/Flux/fluxService.ts | 0 src/main/Service/GPT/gpt.ts | 141 +++- src/main/Service/MJ/mj.ts | 313 ++++---- src/main/Service/MJ/mjApi.ts | 11 +- src/main/Service/SD/sd.ts | 248 +++++- .../Service/ServiceBasic/bookServiceBasic.ts | 64 +- .../ServiceBasic/softwareServiceBasic.ts | 30 +- src/main/Service/Subtitle/subtitleService.ts | 83 +- src/main/Service/Translate/Translate.ts | 74 +- .../Service/Translate/TranslateService.ts | 121 ++- src/main/Service/d3.ts | 194 ++++- src/main/Service/presetService.ts | 129 ++++ src/main/Service/taskManage.ts | 107 ++- src/main/Service/writing.js | 21 +- src/main/func.js | 11 +- src/main/index.js | 7 +- src/main/quene.js | 3 +- src/main/setting/autoSync.js | 6 +- .../{basicSetting.js => basicSetting.ts} | 23 +- src/main/setting/setting.js | 6 +- src/model/Setting/softwareSetting.d.ts | 26 + src/model/book.d.ts | 3 +- src/model/generalResponse.d.ts | 2 +- src/model/mj.d.ts | 10 +- src/model/preset.d.ts | 31 + src/model/subtitle.d.ts | 36 + src/model/task.d.ts | 27 +- src/model/translate.d.ts | 1 + src/preload/book.ts | 48 +- src/preload/db.ts | 12 +- src/preload/index.js | 11 +- src/preload/mj.js | 10 +- src/preload/preset.ts | 16 + src/preload/{sd.js => sd.ts} | 1 + src/preload/task.ts | 31 + src/renderer/src/App.vue | 5 +- .../Book/Components/DatatableAfterGpt.vue | 41 +- .../Components/DatatableGenerateImage.vue | 322 ++++++++ .../Components/DatatableGptPromptButton.vue | 3 +- .../DatatableHeaderGenerateImage.vue | 59 ++ .../Components/DatatableHeaderGptPrompt.vue | 1 - .../Book/Components/ImportWord/EditWord.vue | 303 ++++++++ .../ImportWord/ImportWordAndSrt.vue | 718 ++++++++++++++++++ .../Book/Components/ManageBook/AddBook.vue | 27 +- .../Components/ManageBookDetailButton.vue | 3 +- .../PresetLibrary/AddCharacterTag.vue | 361 +++++++++ .../PresetLibrary/AddPrefixTags.vue | 86 +++ .../Components/PresetLibrary/AddSceneTags.vue | 191 +++++ .../Components/PresetLibrary/AddStyleTags.vue | 327 ++++++++ .../PresetLibrary/AddSuffixTags.vue | 86 +++ .../PresetLibrary/CharacterAnalyze.vue | 118 +++ .../PresetLibrary/CharacterTags.vue | 470 ++++++++++++ .../Book/MJReverse/ManageBookReverseTable.vue | 4 +- .../src/components/Book/ManageBook.vue | 34 +- .../src/components/Book/ManageBookDetail.vue | 32 +- .../Book/Original/ODataTableAction.vue | 40 + .../Original/ODataTableCharacterAndScene.vue | 199 +++++ .../Book/Original/ODataTableGptPrompt.vue | 163 ++++ .../ODataTableHeaderCharacterAndScene.vue | 156 ++++ .../Original/ODataTableHeaderGptPrompt.vue | 291 +++++++ .../Book/Original/ODatatableHeaderPrompt.vue | 170 +++++ .../Book/Original/ODatatablePrompt.vue | 265 +++++++ .../Book/Original/OriginalMainButton.vue | 502 ++++++++++++ .../Book/Original/OriginalMainDatatable.vue | 179 +++++ .../Book/Original/OriginalMainPage.vue | 135 ++++ src/renderer/src/components/Home/Home.vue | 17 +- .../Components/DataTableCharacterAndScene.vue | 1 - .../Components/DataTableParameterRow.vue | 3 +- .../Components/DataTablePromptRow.vue | 6 + .../Components/DataTableShowGenerateImage.vue | 2 +- .../src/components/Original/DataTable.vue | 2 +- .../src/components/Original/MenuButton.vue | 3 - .../src/components/Setting/SDSetting.vue | 40 +- .../src/components/Setting/Setting.vue | 28 +- src/stores/reverseManage.ts | 68 +- src/stores/software.ts | 6 +- 123 files changed, 8028 insertions(+), 756 deletions(-) create mode 100644 resources/image/c_s/1236e3d6-c07f-4093-9bb1-a8d73401889a.png create mode 100644 resources/image/c_s/6d4245d0-18b8-4cc3-8827-af93d7de6c72.png create mode 100644 resources/image/c_s/a5ca6031-62a5-4a05-9d2a-1b7dc857e7fe.png create mode 100644 resources/image/c_s/a899bc65-317d-496d-a359-cbd3fb747c50.png create mode 100644 resources/image/c_s/f2e95c70-2267-4f7f-a93a-b095f7846604.png create mode 100644 src/define/db/model/SoftWare/preset.ts create mode 100644 src/define/db/service/SoftWare/imageStyleService.ts create mode 100644 src/define/enum/preset.ts create mode 100644 src/main/IPCEvent/presetIpc.ts create mode 100644 src/main/IPCEvent/taskIpc.ts create mode 100644 src/main/Service/Flux/flux.ts create mode 100644 src/main/Service/Flux/fluxService.ts create mode 100644 src/main/Service/presetService.ts rename src/main/setting/{basicSetting.js => basicSetting.ts} (67%) create mode 100644 src/model/preset.d.ts create mode 100644 src/preload/preset.ts rename src/preload/{sd.js => sd.ts} (88%) create mode 100644 src/preload/task.ts create mode 100644 src/renderer/src/components/Book/Components/DatatableGenerateImage.vue create mode 100644 src/renderer/src/components/Book/Components/DatatableHeaderGenerateImage.vue create mode 100644 src/renderer/src/components/Book/Components/ImportWord/EditWord.vue create mode 100644 src/renderer/src/components/Book/Components/ImportWord/ImportWordAndSrt.vue create mode 100644 src/renderer/src/components/Book/Components/PresetLibrary/AddCharacterTag.vue create mode 100644 src/renderer/src/components/Book/Components/PresetLibrary/AddPrefixTags.vue create mode 100644 src/renderer/src/components/Book/Components/PresetLibrary/AddSceneTags.vue create mode 100644 src/renderer/src/components/Book/Components/PresetLibrary/AddStyleTags.vue create mode 100644 src/renderer/src/components/Book/Components/PresetLibrary/AddSuffixTags.vue create mode 100644 src/renderer/src/components/Book/Components/PresetLibrary/CharacterAnalyze.vue create mode 100644 src/renderer/src/components/Book/Components/PresetLibrary/CharacterTags.vue create mode 100644 src/renderer/src/components/Book/Original/ODataTableAction.vue create mode 100644 src/renderer/src/components/Book/Original/ODataTableCharacterAndScene.vue create mode 100644 src/renderer/src/components/Book/Original/ODataTableGptPrompt.vue create mode 100644 src/renderer/src/components/Book/Original/ODataTableHeaderCharacterAndScene.vue create mode 100644 src/renderer/src/components/Book/Original/ODataTableHeaderGptPrompt.vue create mode 100644 src/renderer/src/components/Book/Original/ODatatableHeaderPrompt.vue create mode 100644 src/renderer/src/components/Book/Original/ODatatablePrompt.vue create mode 100644 src/renderer/src/components/Book/Original/OriginalMainButton.vue create mode 100644 src/renderer/src/components/Book/Original/OriginalMainDatatable.vue create mode 100644 src/renderer/src/components/Book/Original/OriginalMainPage.vue diff --git a/package-lock.json b/package-lock.json index 26b2b6b..6c27789 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "laitool", - "version": "3.0.4", + "version": "3.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "laitool", - "version": "3.0.4", + "version": "3.1.1", "hasInstallScript": true, "dependencies": { "@alicloud/alimt20181012": "^1.2.0", @@ -12283,4 +12283,4 @@ } } } -} +} \ No newline at end of file diff --git a/package.json b/package.json index f6280de..a1720a4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "laitool", - "version": "3.0.4", + "version": "3.1.1", "description": "An AI tool for image processing, video processing, and other functions.", "main": "./out/main/index.js", "author": "laitool.cn", diff --git a/resources/image/c_s/1236e3d6-c07f-4093-9bb1-a8d73401889a.png b/resources/image/c_s/1236e3d6-c07f-4093-9bb1-a8d73401889a.png new file mode 100644 index 0000000000000000000000000000000000000000..3aec4208242e77a829b8fcaf4fd6c7951bbe62dd GIT binary patch literal 44974 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 BntK2M literal 0 HcmV?d00001 diff --git a/resources/image/c_s/6d4245d0-18b8-4cc3-8827-af93d7de6c72.png b/resources/image/c_s/6d4245d0-18b8-4cc3-8827-af93d7de6c72.png new file mode 100644 index 0000000000000000000000000000000000000000..3aec4208242e77a829b8fcaf4fd6c7951bbe62dd GIT binary patch literal 44974 zcmeFXcUTkA)-OB|dX?S@N)<$uDm5a~L_|=!5D}1Gq$?p&5Rfh)ARq)$nh2;=0f}^J zf>Z&4(4Q5dfT=1N}{J8QlK+2xEOcu|TlX zKc4sBKM%(L@rDt3qnl!4|NZR$<~N74e?Sm8$eUn)B^TE~XOMmh(%zv#{(sNoK$`oW z*I$~N<}V!p4iKdI|I%*%pwInBpMTJo|I#i#zAj*&zhm}y@p1V}cYyS>kYHDkhFk~f zm=F)wP>>!4X$kLO9}kcwfHb#{t5YBV(6IbHALQ!n4$>DunkC@2g&s(2fudz``#1XD zztKUiVc<9cK+n(rVStC5dytrn^I5Tr>gt!oj9f##U4w$;Z#p@9IR&_g>G}EiJNZ5Y zfPe7(_b!0*uWZFYA*)_gS5=i)JP(ThpY4Bn@t?i^*Ti4l{-ejP`G4q)insq?=l*r? zzs~s;0>GtxP&Uv1b?#m^0MthV0RPm#&Pfyi0Q*w_s2lt@et7@di+fOzzlMTBXlUqp z4_D{&e+Bx__W#=9pFRKQ#J|1o{NMNeQ+8rkUGF;udk2aA6{@qJw_k98SfIa?v#Xf= ze>UR(@{RvCtbZHFISbeOt^uyT;H#`aEA#Mm1J&*8;t}NG=PTyn`#;n0fAO||8^d4n zA9f8ATyH4=H~c(sYLFX%Z1n>)T+9IEPCj^r>YsYM&S(Yvoq5*Km4DbhNQ2k^a zUKcaq0olO0bx{&%kbscppbszN@HI{mVdLIHnm?6B7(-3*cC5Rrx3}Oel4+(%E zA@Pt*NFk&W(g^8>j6krEO~?@q9Ss+a7>zuQCXEq|C5TTgFDlLB?f9A`=IbG?O;dZ6;5q zCrmGyDw#T&elhJbGc%uIR%bS6_F#U@{F3xDagoD}!-pf0;~hs2$0{d1rxd3?rwiv( z&NrOxoQqr#E^#hBE@!SNuD4vBT+7^a+|t~}+@9PC+!fs4xp6$4Jjy&)JYhV!JYRUQ zybxX~USnQw-W1+XyyLvbd?I|he6Dy2!{*55$+e>7ZDXP6!90y z7HJpR6y+7YEb1xxLbOG64ax=8fqFn+KrzsDF&;5pF>kS#VjW_*)552XP6wZUefs-p z;u+~PmS-Z*RGpa-XA-|8eqa2Bc$+v*0xDrDfsiPdn380ayd>!^nI+jRc_<|tV?K$;xzUK&l17m&?ze=RJS@eB}B1^M4d16zmjI6}lBD7gR2IUwC_A z`XcAWYZoIgHeTFOlvQ+A%vBs!VpTFwLMb&U;g#i-U6u2df2we)n5x98w5gC))l>si zD^=IjB-HMzy;7UF#C_@JrNm3$)M?ePsH4=I)sHk(HG(ugX>4oCYkFzE(_Gb()^gQ) ztF@?oM%zjIwKi5qOy{mnfesdS8s-Emge_bazwC0k`0|SGSzS-v_qugWFebr`(>ll(7u9Y_npwx?@#lb!dInI?WnuqhJ$Z z(`PGa>tWkqM{j3kS8TU$uWz4WzkEmKPRyNg2Wf{ehaN{kM{mb3aCW#8y!tNfUF*B= z?vk9$oC=-x?-}2Fbr0vP=bYud;d0sKh0B_&wriT}%6;woY4=y%wB6F(*4$z4neLk& zdLB6*cuylwwCAChnOBL|iMO?Pl@Ei@U7ydsoW5SZ9e$#IVSYdS<@{s(u@5vJWIVtH zm;@9DQUy8$HUx2lV5&b@COA5HK13%ZH-r#s6q?O88aWtHV5(yy5)I`ITr9bOQRgz@y;jYs1%dg;Ir?Z|L5Hy!rjs>TP$? zrJ}N8!QzBsa*1yVw$!4uqfD)=?49ttlyd6w;PSQicisNoiqfdD?Pj>i>1K)va~04c<20Zqq*6Vczk*)1>oTmqAy1w{AD)oA$Tn z9*v&Qy_b6H`&9et`c?XC2UG@XzpH+)8&n%?7*Zc<{Gs)uWf(TxI&yWSYt(qOZ|ug{ zk8#WKpA&Z`us>aXu1ZpohVUfcf7{n-Pb1L9#kL4Z(tbm^%3*!p;d7)qiiy(FI{H&RR}zfOEk zPEMu)J%E~u>hJ%5YYjz~Mt6)Zk!gX+S(f6#-rcXgFv&PhZrf<1%-mKl6ZF@k#1y z2JtH&TX`&g;3Smp1w=A3@$&Ht2ueyx%bb-}R#8>Eq^_ZNRo}qS$oSf=+m=?=AkcDl zalP;6?%^326dV#7_V7{E)99GkXL0dq=`S)evtDNB6ux;|R9sS8_U==4O>JF$!{^4f z_Kwc3?r%N4!y}_(;}bt8r{)(HmzIC8tgfx&cXs#o4-N@O$A9^v0wDij>z|zcC%!m9 zzNkSR(9r+oi;6n*FXJ3Ew5Ko9aq61WJ3Zh!qxgh@`%3ETkFAX2N)|YtdjUU~cqNqQ zCGme*`w!0k_ZW-(FLCxy#{R|E6u<(Z0+k2h0AK)_R2VM<{NLmM%HaRn!2eHdAXm8j ze8@q`O)7ov|1Za6N)I8W>#>Ob!xNxeVajCw1lSyz|E5y)OjH@S9l6&Rhj>;Q9C1a? zGOtT9?)NFUK+p6L^&_Tf!Y#aCJ4{GRz-s}@5EiA6*NF}@OD*-V?tAE?Fnm=4S_A~u znCk=F|A&VvYG3}(#pz=_{0R*A;Bc!4FLaw+qvH3}F7(;H89M>mcI=QoQ1bJ-Q;N;! z&(F*xvS?8cWzW=H6Ze}*%HDuu=!;M)aNGlSQc=@_H95?E?%21!fQ^sBC`9!4n)_(D zRgL{}W!i4E0OuFC@8!VWF@>l%m3)6N!6wF~g$n#0y=42e?EANP(OUA=4*HyH8AqS7 zA$z3nC_#$KLQ`6s`=8S%0Ni^+8NOY{f+^)8KMzA%H4mTrBf+0(#4|XSVS=oodK52H zK>cqA-5ud8GhK>?^^bP^rnwF}aIj5voS8YkJEhj_!&->9Sbcq*$*gB63oO*nM^rcS z{v}8TB=f!{ZLAZ1deJZjx`kK@ zr^5T8B<^|&)7gbVg3QVmL?K=!t6>D8P?YV{tngZSKI>YYgs*e5&WOy<`wv z>o@t{2@n;5!M<_4K>mWHBB0F(PZZaY=Lw-GKj#PU&zVq-ZLLJVjWp)a(a%;j7Fyi) zwyOFHeFB4!Y>6fa`ymoLHc8erup?)AsJ^;3aVtiu^?sTMEK)+>EtJA-pk03Kdjdo{ zqFObYHBSJV339#@E+#i1IEBM==LB#kB-pt843_&;Ad)cVloV1Z?bLIWy$V_Llqr0C z0Vx}H+&ypIuD}uY=C%i)DQ-6V!Mm9k#M#>%%2g>5?;>ejTt8p_2C?OewLzx$at9D%3L9hJ~<2<$(VckcxO!$-;f4%!f*s?>v2>ZE8 z&71VYqkpG)-;yWcF)fgBgnp%`>ajt}>q!$-MEC==>@ffHrf)x& z-jzx`>FE}pSULf^U<8egRtj{Y@;!+Phwc!S`)II(9aD*L)RvNam6B;0&FP_44++R- z`h4eANCDd-h3z~z%oNf!aw16`>qkS>sQttD4YqDpupFWGI;_lhNQekIO8*G7yV+6mxt|U=QcuqgBBQ>0?Ncg%M_G}G{L$g4Bj!vO5&O)IzY`+EJkXXP5PS3H`I1! zguE`;9DMqym$CXQFrLt2Ijf4Em80gza?%GVUj9XAq>f#94EyAx;o6w2&gb4E1<3<@VE?@=vd>Y-aD3)|Bh z2hn3KVqt9_8I_Dt#>4$hTYJnr-}_uda#=#_Ni`8$vlt5ub~x%isttwjq7j+x3a zn*`lMrb+nH9r7FK-b5b})Ybvw9m(3){PB$7sms5ZmEE9W&JF9@3{@pCXE;F)v;p)_ zg|E!>=-B#M&RX1tC+GSEZzu(7lG%`Vkj;|zKK0u-%X{#Q(deryrDD+0A|8A!iKB_a zRCWTes}t<2Ov}TN6YV;xIMWW^shOfzTk;ug-xG%%F2h%DKkrsN@`n3m98R?ig45+} zmii8qN#J8!{?p@|kkzX1W(0+L5|390`h&t##Mya;n4QTf!eLirc#n$u>*Nh0^v2_N zN^dz4DOzbCjM^h#JHN{CzDo)Q{Zc$=8QY}0V;HYN)-d*k6Cge%SxXvEeXK1i*OVX^ z9$q0z@qW+Br6+iwFCewX?@Puj9@#fO01{_zUO;{0lJIlw8#hpS#+PZiQw|?eEaMh1 z&orQs;=3wIZr6vMArHc*JL;LV1C{`t;>YT!sl~;ul+9}5#jx!KsUkng<&vlx`#jT% zAN@W7KVF~Zck2D)Q{E8tJ=}UXaB+|zAG@WyxE;^B@SD)Iz|J9{iSaT<8 zIl=Fgn79rU+C!>wca%cS@)X5xSaq~?eisDw~BOL;}*Le`S5ua z^~WIONzy-WH>a&unAdXxP}>1}@n9ff`p*Z&1BIR6JpqIQ2^lAV<0CanuKdQaoiq<= z2=oqZBM;|r*3h^WV%?MmYFTmivChR>%kXbJ+0F(T5KYywL|%b=5x^3WiBhodM>vPt zY{I^X8DCke#p?eG~VMY@aq&L&ur|lOF z9&c^1<)Jhv9)9r^FcRPPfnhAgizgwxGWMPG31GZ&^m13EvCgoFn~JO!hN3Wc6D0{H zH|^b96x|O3`~VdSy3_-YR5&O5I6RFu!Wah{(i6O4+xVl2nBW0uhlc#>j327lp*z&a zA2yk$RYqb(iM%rkmYudabvtG{YC8Yd#Ht}l$eO4ZmOEcU;#M-miRPBxQFw|J^O#t? zJsgF4a}H;h`_h*>BvmV2Af52^ZD;}eYGJ%*B?AanuQxd0KH)-H?j}a<9~91KJNaP3 z3od{>`?pr=STZOy#8*>a8h0P0=^JX$`vl%;CZjJOAjX9?r zx*$?N+O#^p<`0-=?@R5&3X&gy5!xGrec88|TUKN%zJGHnlktF{n{Z514@AK)5?NVsS z3Gl$5<*EM;`=3JVi4#DOq8R3O5J9l52m;85Td&A5o}GwJ^sI!>*qI(G;P^G$@3mj-NuIwz1Em;@bZ+mr4!>9SM(yaJ2O-g~t7a7PF z{22`A4+boKJoE;pI=5q%eWYfX&vn@+$VIlUHrW46WZR`WF3t>9B z^C*HC_#Tf%W|Sf{sxdm}1PD0+97g2%BP=WRZqi31sK}Kq(#Sr>a)ox3NLW-W4ELPj zM&Xoqq`IG0L6`idE=1J3r05X~24{ty3UKeO?@o!cH@oBMUb4%;zTwzj1lnc;yf(9l ze-{Cr*Vaai&7M?@E7(7b#cFpd~JRG%q~37nZjB^ekZtfm(ouN7Bt?8c-?G9 zY^d&9Ot3<*VPw;{;H7go{VIZl_5_Jb(-5!val!A@8bu60nB*KOG+%t>$J%jlGpo2h zi~b4lP|D8M=36V(X2NA?sHKnF?fRj;+}!EUZ|ZBRlS=Y!*?46}eeX*T0j9Q9BA~O5 zCFCr&qCcp04cHA*V9MLn8`h^#6Z#)tR&B%slshO-)D-MX6hD||aE9)GZ)pdgcLzC|e+K*x1I4U`aW_lMVMDWye_Sv{>Ef(o z^W8~(VSZQD__(h1kX+9+SX-|4ziUwML`LXRPfi&MetPf!xYWd_!{adH|n& zl0Lb=bp-XMmdi#7~5y$ug^XK7)6#YB%*VBlhrf1sT!s}mYMJD=Imo8#VO2s z#4E@iq+D&Jt(-6>+6BY@!_nt`G>4Zt>2z8%1idBMYk0 z4~iRqDb{w!?#tjDr~IFu`q5vONs;hhl@;~i)cfi2?WiUeRKj@6FVIci)Vbg|NwOqhaD;Cz!`n4|FfP5=p7^lka1VA8 zle&C2`D5i93Nr}eXuI(6HduW99K8Aag*h6pI_pE9cN=M9jkwLs@g0XR?Z38!Di94e>Zu&|V|&^{idyN8@gs00il(1Q_-$ zl(*K5K1|OMR~P%vz47jNafJ7G@idy3mnra6?x^i=c@C(eN82QBE($}`q5?shZ<7p7 zZg#?RwF-V{8r|9p*H$q3)J)Xh>Ud{c*CS3NbSC=O@{KDTt*uppWN;Z+Fn0=rMT?5z zc|YRjC>$?q{kZJ(+=4^jdCYmM4z)|9$zE-F^mLcy$#-iS!&}HnG|r+b5mx^tIo1uY z)RC$2B_*~}qWMEj_3+(~$+L!65>J3enpfo#xIebikgEq`aXQFl;Zsod)K54#0_{Rm1D{6W<9%!w!0cR?BVn$!?AeP!^OOS)-5 zk`K?dojHY^&-+!+PJnypsYj@veFyotl8y}++Zsit5m&R*Lzf#ar_Yk_&3Sn;n5LZe zMTVFvze4X^5akF|pEd^DjAlUjCWZ919eM?W(1vGTjxO%~jZb=|#)Ex6LC-$+{_L5$ zV*I4{CcOg~8Ph=baeEDhyAF%ZA-_kSPVYoY;}N(!UV`XJ{k#U7R8o1^X`0O>mQNqf z^_#tX6mooA5S_6M?_g8MVxu+&%r4Wantfi?Ko@DGCets1ZtM|gL8~Yp;|g#%Mm1lw z(fuiUIGsFB1=5bv%pADXerZ&`sPHqNy@oP5$8c++>sW!3_0?+)PPjB-Lm39gQx(<= zJ*HoMB!VIDd%B(gljUDg*jM8wrQj2<=+Lyy1-FQ~zoqaEq1P@$$65buf6^#j%5ZGx zz7d$3Qf0nsMvt32*aW9u4)QddbaSFv8>chaJ`2Uwr3W4Ohb36l_~@CBk?LG_7n1Vs z#i+?F(I*?a%1qwKAf`sp__=BMK(mDmYtwzVuuB}tM|<1we)v`>C@fdPK2e3_JKhX? zgHXlSCpXKBER|fHP!>@%y{1XL^0mwLR5`y3)0G#`IX**$u|xE)NT7@(QxQnQ#sg`R zB%HtH^g72c*QED$pGUSXYiA0%J-JB1dEy<+r|&fEZfElD#F0TOyB-|MW7k@GK+te2rrKZ_TM zda>1#A$F+N_a{L0tDEoost|S!$ZgQ`)0k5d{NhdZD6FpJJjd_)QI3Rqzl;2~^v}f7 z{YbQ12k5THF!XEb?44r@25!DJ`z4pcxQK^!%+Z6{q`7E~iKo7PP7{?{mPKm=BJcC> zwq zBRgR@y}8FHz(?t%EreyEyIp;pmhD}B+YOyFEku{`bC#(&4CWU6ed3B)%*`=kuedHl z?@kqWI`qHqfTRxLdw8@BDl$b^$`++XqW`W?&HsmkYRP&R3Oc^MW+I%#Gq`ZLtu=Vw zR0?*8S}=Emj|6p}svnxz0g)_i1_(eUFu2<%KyoN_x4UER-U)!=4M{x#OOlTAWklD* z=94njOM>I2oTIJp@faVl7(|rs>w!X#x=E3pF|9TyRA7a;Eto3mG9m(Qr5w!gX<@gV z=BlodI&nND2eBRO?4SV*j#oRellOx;PXIegr`Q9j?VH_4si1?xpNA5ZOFH_wd+>ej zcuYk8sl3?VelnlI=U;2S`Qc*1VsVtj%OgvYw6Z7ieSJ1G8u`l{)G>%dTTAA+rA84= z=ma?X;>cuO^GEmkB$-=XA%0-m>T8$A@0J75#^GQ`HUv93Nfz<_v&y+0g0acS(+>6~ z?kbwOSF3A2#aI;U`gjZU`x;TbRlMkWX;G@>_uutp@c>$8OVhsK(yBWoldy(QxI#uF z*}`(WDALW8K^%z4Yu0Mz)=q%9dr2mz-ZViQ-!z?)JJKhAM0vtbA*Wz9sCbGLAvexlg8*cidzBmyN2kfN>BCPA_i$ z_{eKDFo^G!c!h&4&O+@-PQK;6?-VR%=qHB44+_{_$Wa&<)>{XQR@sZ=PQXTO1+O*2@%v0n*HM3=EyLNpubzEA(~a(JdhN%aH#L-c}+%&uHO84(e^wI0c{C&b9xYTAtwb~%X5CEb54e2z&e!&aF z_)D+I@O@a8%}5?ELEvrb-I}ed|22sNdtOD+L{4u)mFg4bQYE1}Si z5N=h?-sqr1`OY2Vj?Pzi*ce&LxFLr#q%d<3X+5DILbr+*SY?F--qhPEZ9kSv$xKCNt_@tOzc@Gi$I?NB~XBwzCvD&NJ&?GN0Lm&G1t z?#hWTsY z91=akB7)%0;2a9IX6$d|RMVZ@=yIKvVpz0RD<%$eZRkY3KCl!#X5d+zV@C3XB`m@_ zOrdQ$TtED@^cVa%?o{N(_F;TpSvhq@VaLVQKzI6)@cGs>$&=3S%5NZ}f4{)^K}*Z?oy*HeYM_Lc#{(ylaAgK(*O9Q zS;d(x+sRkQuX?)eiMZ~bCA=4tnv#TM7}F6Yx#P29_sfOy)NFnP6E{pYyi#&(-r6qn z>%49?7$h+hzzwOCp9&NPG~SECB!H_$_{^J{wAw+VrVb+1{c0<&JkWe;BbO1$@Bz3_ zkrn{ z9<{~j3KFyMME+@qYhvxP2Zy{LjhX8|T40IyA8Vyxw>Mwo`3@op;R`1KH$krLQGHwu znu`2tBc}6ewFmyYl>5>tR7J4p_2@)|>~ab)f!5Ojw@_Pi*^2mMXlYh;e9-&qva zO+r~P4%|T~!fNZN|F(w;{G22B;$bntUIq;*J86^b^YGy}>`LkaJ*Q(!rJ=)*CDQ){ zrgT^-B#=T2Nw6R2n-eNNY6c$?5ff^MAE&Pt1WUdGw^P&M9H`b-Slvnz?B4dz4de8$ z8c%be@mdcmi{o?NiwV@MUgb2q`1HB|=4l2Y0f*%n1{#!Rz7Br&3*Oo`!lYC1;PXO~ zZnE9Rol(h_>}hqaZw{a}Tub!VmVvDM5zfzb%(0X1g4!%VT$#{1Tj@S4IpkZR{7t@= zRdHReJoLg(gHJMyK z@=4OUe-yd5Hc?O|bF)Fn^0tEOb*5kdWk6vD)scd6MGFw}Crr{i9nTCoH~7azloJB} zj1L$R15%$_SPSJY3(#O)CT28vtKBL+#_KcHZqC}xcBSiSu}Q`+sG0VhQ6v@F`s=a3 zI2b?)Tamt_x2XnaNT|tu@V7n+ccm&$qrM$RI75kAKtJPj&@CW1j#!PpcWDs2kt5&y zsgIc}btl>w(PG%MyjQ?JBrA91MJ@(I;|C}d4eyhe8!q6i;>{Z zX|NhkUL|7*d6BNUjH39fH$SE9C#V`7-M9?9`4jtS*G5N^5M6*!!fj4U5Nj@8TtXd^U!CsLB0ep(3vCr^Ap#w?eFP zpl^i{tR}$FL`>YK4}oxVu!VE*5ZNxG$OVO&7Cbt2^#sty$c15JIh+m4X1@J8Z;$GrTe z_vr`1$F)l(r=~ia#57eE2X+c$Lr&jboP0GO5%Ia3jM-8irCLA>qOkSQn!&EBXZ50Ipxn*+Sc0Hc+Jpga z-d;{#`{C5Hr2b{Y-nRLdP0#)5`jG>uRz}eJ-sXVm7|nx_arUIlaWl~{`kSUox0-9B zo$5ymGnFLNPFqKZPM>M4`X+c@?x=qEDoow)ob&*O_>v;NsX^f(i=kRupdW?jK7w0M zDo*dbtT3*4zfMN$j+{jK!}k^aMs*=2@89FZ98~35#|Yjmdi^Yp-}%0v&a_+{%j$5vIIbc&Q*SY+*6!tdPP3@gI^?Lg^_!}kxZe%@Ihnk)Zw0IzxC26wAg>pNgL2h^le zJKv6-DZacti?cl1?PE>Tmsp99lCClI26vYHy^dbY)aPjJPDgEAhK^c;XUxhACHy4+PWgqqUn4KTDjpebwi4k86LM0svuHK0yGyYC>2Cw8%&A#3C9@WBf?I9+ z;Vp&IOX8)cAA=ZewXg+5vXNI%t-c6#a6&N|k%ShS>|yi>yXrcn6Tq$eymzx6XQZQ- zlJqtNV6JUi9y)t>r@#%4;i+c=&StTRM`tGwHK(tc757DP`4Ssi3)q+IDa>jW8?zGN zlZz4F=^ZA4Ucqiv3H+Q_yR%$Hn$Jx5k(Ips!Nk+oG8Fdt3Ge~TrQvSErw#RS16#Rj zkwH)eNBo_5CC;DXh`MfaQyH}ZY%S;4#5Qbe1%y$L3E;?RPmOH`R|$DM>OwCh$RK+g ze@7weG@?6OP@}yeT7d?1{t{QHx-MK6ZzRW|?wZA*aAqd}FaTC|#cG_(JX?D0e6S|5 zDeLp7iic&$`|92>Z-ritD}@KZ5Pc-7wOz0S$qf$w8sWH$*2sDEyt0p^bCQ2)Qki`; zZ{jL%Xilq(m8|e!@w9a_rxA3K6*7z)FcLX-4@Jzt%@(q@J>*UGM2&J)?gB@ zT~!KhGih`j`QS1XGl%osj)i>!VY-gws37dT!>w-XrSSJ52jEm#HQGPE*A2lqj^Wu! zLiO06Brw51lSA;5K!w}oT8;@(rq-=(z&bTcxvc|mG4Kk53mnUQ9SnAwh%`By?d^kb zeQR81fDZ8rQGDlne8UNLQ|@Rj4O%n(Fi^Ggxp(?2#j;5-{@5LEq#qiJk_A-u8=ql z57N^QK7oQlkj~+g_9v!lKPx{eULRKPPjj3^fBL>n`4QF!J=|EkMv4Pn(oG$0)sMK6 zg{*eX?5zHwT1`LBp9aXo^oK%v;HvrYfESwR1FswfCQ)N(mLkg2Aew!i~b+AdO zUzGWswmxEq7a6F_J4?|t@wS~pE%8H8UpJ0j$QX(is{JCR6UN;fRvnSQ(vB4T^0_*F zc(tR)@2LMrN*5-L7-st3ykkza!>F3P^Eig`f@*)8bSieG$dYxx)c370QZ*y)bNzF<50+wFOz2yVt>Ch2YpXnX#BS4YTMVB3ziTKE6SO-^sAut{fKXdsdjJxhw3% z!Jhdt5!YUe(m2pJca}e7@vPdV?cF+xG14|L{DSO4wW@;QrUgv{1CwSy{pQi_FisB` z$9C`_tBr|hNoeuv17kNIsW^XrOF>UO+BGaMBafe#nr>AN*WT_ZF{;J4 zz^Zn8*q1iB;*G=foX6qCQghahbCPjgVc$=Hv){BYpLqKEU0&jX&&Q zwGBeCdk}9nL@#G9*z%wA?`B#qO3i)zMs$fKmC#N6n_%-f0q&=OX`g6xd?m&u0S<1- zntrVrZ?;BxI0f}4vLHRLRA;C9GbH`W5MyE5M^B|MkiflUJ`$Ik;Rr>*(Po z=w3m zb59IfjKGxS7L<^G5hz|Yw9BcDM+;9Dn`=SDH*8aK4>zQSrH^=$(ckrCe@i#x6 zN^+zH-L@0q`#4w)x6+DcH~2O&bw8?XJyaI9oO9>SR3`@sIiR9XWJCV7L7V|hw0?_& zcq8mhyN*!P(0f1mW`%i&Gh`K3`&-RK@+2uMeFh8sfhRLh4?SD#H_iha!*-@>P&`%DBDJajmQwYcA`sb@K_Mjf+ za5>D8TVUDj8D2|p4^Pg*B-}v{{)L-r7enH%I-vgnPNhQ3r{6_b5sMRmC}a`yTf{_v zER$WkhDdlaDK2HO=Xx&jvw)#fDm-0>1@zjtb(B2qq6{lZ1_akPQ`L$>2{bLE#eUl+ zAIE6{G?w-0S`2ZFIAa7BZ?wFiB4ttLV4t!`7umNQ76zkFfa%x{(|ITNs?r3>8j~oM zw`xLHU8<$DentF2G;X4>X>-+l(I{^-f(-NtMVK%(d$7?ixZoM!*y#~;Pz_6W)xvM3 zGPshLjBc=tam+S>b!xwKtU-UZFhPV*qL01nD%c5X)f9_ETsx(~3x4d?RKPwl2m;jB zX85Prr@^HP_VWYdpKu>g3RV+U+dfO(q`m037aO)?Xk3^=Nqkw|pk^U3Y#N5MB4{kd zgz~fY6K>!I@49$0f93hR^$z0`PH+0t&m12IqwfvW>z#w8#;I zr%$e^M}>9LW-N7|0MO~n&`67`l8WLrsa@?}YIx^!R3|`-&BT^8Nw5lce+L?c7ScJ> z?&C);s&Jeppl&>DS@ZFFcwd3wF6WQmeSO=H2_eGjcm<3R?p%lH4(t zoUEgYYB!|x!PpStpF;^v?U@?y3xc>zd{bmW2rDs*iAIU9w%C_HdX-Xvx`D=BF}>zv zMqyOLnHD=WYKw-uLO1oo135tt^A5xuWB=SjvVh55=7;i7PTL^F!Q8VMuV~Z#9X!O`pfc>z)9}9J5|bcEFQw4kga70I24KJbEw~ zh`0#e5=&0uJD4GVA@R*?Um5)s=4X=HY`UOx$xF_VZAgu%bRE|b@m7UwIMwl?JL%m! zI@KpTj{!i2@<+X@M}Yt$N35_0s?7`pc-)oZF(%|do7i^MY7}Ry7quz){3oUlQi#qV ztfM;mn{pRN2;$8;(FCdG(R_jGFQc(f5qho*td7G!5R+~npIwvm&+G7!H8R7!cR8q9 z(YkYGeB;aj#8A3VIG&h!nZ0M1Q*lmJl@j}!((g;>Kj|}Q0fVh3BijS?0^zX zg65uL*t`+uUtW0*5qu{VAWFXXcSGoV)R#m-&`0`1=>`jY*r&J-x+CXq{vh$sa^Yr% zV;w>}O{H?ZG@uJHoJkL0b>cQ;_D5uD0=R!mmltN$eJz&4<(KFvHCmNRXH>%~#VmB& zPj^LNItBESdFA`-O1tPPt)-Q@;kO0s-E)ahoX26z(vVyFR}3G?%(?X4$9VbBYjrJ= z#us;D!gvKZjQ_kN{NZoLl0)SuExJFiH3Ix^<4~=hrix5zY~wM5&q_RkpOV z2Ve~KItG_xkrtF+IM9XaVw_RzVe3X)6$m}wfwzR@Vcr>$$~OSDLoDUtw_^2MO%Xu(^i^ql?=W-L--_8-0)T7XoB*_qW2WM+bIAiD5$z~F8~(EH7#cQ@WcljvGt!x(g@nQD;P zb{Z!49;Seupb)LT-i$BQTRaEZ<9RT$+4y@B%lb!gnN0qw>W3wZ4w+R-fAe!FqhueC) ziI&N}oZj=KXd}Y0n&=ouZLlaeoINXaKF?soC=b>!KGFk0tyaT-j+XuI0O5W-#R-P} zjG~KeH6zHnbtc#>?o?>$httQ)f1%9yai^n}dVdYkhk^#RL;{gqvb%ypnpVumf zimo0fN2?JxnC33SxO`+tUdKAAR##;$?WH~7RbXw_jwVqUVd?h-UOUk?$FG%d7v|Ub z$aQaEjehElEoO&H8)e_+ld6QMSWXW71q2?)10>LoMZKYDseu`WpKx8AcEv<`DZ&^p zeBqn6&$$;f;M-F(N0BN7R2w`Cjb~$Dv*h&*6+|7dXhYpAj67|+`2Dc zLQ)*MR~ux7b#&wi)G;In5+#ucg3#BT*iJK{)fS#%=ZCds+;gpOYzz05?tJ?oP0}0C!5S@ZPqGQ8yE~eMY$t!(z`awSf9; zBH7vM?Bt!fgeMPf=F0v-VUy|@=02=!{U}56VA^Fsac?i#m4lh4+Ha`Vwhu>eoHaaN zG>Prm${IP_m-SHziDU2v=qG8a$W2wSa5#-`+eb4O zJ&1AMo~}UM1}k9Mfz=i!aL5l4JP~q+BSD{46lmNhviv-Jgkhd}n{V7Q4kA|Whu&MM zJO*}Q1aY%X`UQ5dVvcd`0a(owofkd+W?`C0HnAN#j3^#&WB#@f_db+8)8R*#Z7-tO z7|nA87EsW-f^Sd?Yo{<07b|Xch>DEtD{vu1TJnlNjlG5|no`-e*qi(yX)1C^!v7!k z-aH)2H~t?TA=#7c%LuL3%DzpKEs3bAErE|IZ)ik8pKeGtcwf&-;EaulMWyx~IM#=vy6IV7pZMinMGlk(c-ihre0Vk~1Z|`&V!`cs zt-wc*1=~d!r z(T`S|y@3l5*6v2((ZLpT#)}>ikMshC_%^@%ILGw^;1yiQ!v?Q7?w%~dAd;T7WEdzn z-vM#QSqv~L5wVUGNDjC)G~)i+vtYNHN{r(x^O);Oxq_yZ1L6z)Hb>uc1Q)Zr%zgxn z7C4+-ujDhU7Dc#H-ukUR<}J7ETxjY)Snflx2?6(XMtjACp^46)K_wdmk#!%F1WXPj z_gtuItgCOT%|w%v)z_6zz3G;Zm`f_Ii?M)(V=QNpvfiY_Ona@mnb5$SG_9tG4fh5E ztm;szAJ!rj3tqCsKSJ04fU>k0q*CQ_o{*!W|;u7T3vDv#}>1Pm|eJr)&d)FXrU)j*+ zA3Uo-Fz29^l zK#-%xyS4?HA~-TLx3GaoU~cx5v%Im8fNX*XQ>0<$I3xH8Xv^-(MKls2ZXrCjRSg)r z4qY%{X=d38!8{Oi6R}+i!(IzoC&`krdQ5-d0IRmh&C+z?_r=VC`;r}-3Cq9Re8e`= zh<9h6V~DZ4EF~Ho68K5nFjB_w*ZhO!>1kD~v34{8mcM!m#!MpU)Tgkh*el4vKBiDx z8;%OHoE8;`ee54Bq~$+^l=QV7$1uby2dY#I-{^dj5AP?I0(Rnbo(5^uiu^+A;T@`I zOg?ph0v`@Hi~+-t9RAU|OVh*?2=ekjn0RUIN)xrv_>52Oking!i&vO_6H7aQx=ClX z2kbQ+IUm((k?ph4vHfUzI!j4w*2(9 z{TBEJj(O^RrXedbjCZm8P4r{%A4?|{!_qWgsFLU#ny`>t|5x6+KmI}6<4cBSoUpJb zU@`in01GI>)xveLS?yONsqp1L*kC+_ZjGfR56vE*n8z{6E{=St&IVa4G4p?qv@AeMe}>1oz>Fl)1punKnc4n^T_AnU#(@RhPk8^M zExC!S8gm5r6c{vq15~vu!eE4GVyXy?61^8jdtZ#!O}(A^gmg=rbvAzLnQO{cx+wtl zd#7KTcx|sVgassJ8S3NadXVoCRB!j!BM7QplFQAVpeGR9VB<>YH0m)KVW+f_`1bnv zd$k{Lg-3l)k*Ej#KskyZv!QEDkflHQ)BI-&+7GFe{DZktKV+*>yFW`c;8{{$=irqu z{u?*czIamF_q-t*WKLMR-dz#^m?HcZ-NROl3)7pJ=*euN(py9EkBB%8HWsM<4mVmfg9cZGJw`AW z`+7_YM)a!K7{_SxLtv3_=b;c zl@UKbvso&H2g6Iljsklb{0FPp{%8Hy|_>hI-S7r<5#y7(GPPN2-!m^6j@)L$HET7$wd50zbYR zd$;nff*$r%+nU9HCu1LT9$zmLBp0q&QL)=7n#yoB86FL>Q+-R(uZ}nVs=!>n2Rzhi=!mtq-`uj%>3GC}QS5+&+QW1~=6;7h$~pKC{HhYI zb9p<9^$z1lJG2~U;8QlWd<86GreE*L^~2aYNqINi)h)@y6XarTzF5w@{ zy$l5jm{KQmjx$B<+p~P6<7De7y^@f@=3V(r5+J2sx1lRstGEy6CO!z2)kXLRP;YG0 zMp(6&S>TLLuv6;H9Bn=!KH>jxZClZIDScxE=)f42Fe8{ymeU6&KDcC)a{l7mBXCG2547U=6n10oimiiEUAz;MnC~*j@aG zEg0JKz$*Fi72Z9s<-xIoKT8B_{0!lpP;i?lR2A}Y@-Ccvi4NbHyZ~j4dXuORNULgh zW)gaw1nD>S3KIR{@(k#ZL@8!V;YgH?@BHaxhikL`9t9{*EY(|kmA}ZTBrESE-TVUq z{eDPo;SRm@4ZIYF?tBYk+6t?5ZRmQly0g>Xt}MLY6?(Gu4IK;dN-^x{3I5KQ$F#wa zdRC^D)fIY>Z5d)eyuZ2iCy_irj2qEMR5h!j_jmM7JKd6mR?TPnJC$mG0`J)$l*b7T z(zj}CW~|iq|F-${zOfe;h63(^dKEE#_GZoc-!KD=gWphwfwjNr8e_ZXAMCB*lJoH- zkg6f$kiwf@8l*!^GuqCxs-6hNw63ePqrZPQJa37izt2wn{6#23M^5PLe&XH7NV-PX zm-16(pJ?e__WYCMUZSF87CSdcQV5`!uLls! ztW7dN!ub+rWvpz6i4-f3zQIR7^UU^PQ2`Ncx`V)U9|2bQpWq!S>08Go@@8 zD&rOv|6q5}{WdC*K3FlAq8i<~hy(D;-YaWQ;rlQr89Es4UrZTtE>BmRk;G4m`puCMO+!38x);5vB0 zpqp3}Jk&|rlK=)iVIt;SV~xN?BTXJYaiolGdOhS zk4(742DeBGZF&1Mjksz;S>tq~FFVxHM0TD&UQRmIbEWBJZ>UP+fa3Due(f{jVKa5R z--rf)z}0o-)}BxQUMui0GMcP_u+F&OVcl?^tBhuW{#eM;82PnnbjnM8D~XtjUk=0!8C`**NU2yJzK8c z8^O}kC!1m|3HBjLE~cNO)a*8dB%u-|h6J@NQZV{4KfdEt%<=>r8xd7*Z z0da3o#KYvEX#}T6NF*cIq$~J5fmPWUZ^KF>me6@_pV{;^pWU$K_STO}~inPDPP^a_t zJR!xO@4eUfm&0tbkKrC)6{v9KES-lbm#cD*ml(N&LEe`s?C1eUy5Fp!TDy_V;M(S` zK(qSf^;W1mJg?vFcDMZ8!BK^y7Dr;PMR1F-IDi2kN093w9#$pu><7B}jL3Wzxi8_f zTvF*=diMa+G!m-sH`#G};ENW|!$qJeOOpKDHfs2;Vb7RYy4G?9QoRoYx_FKt7OvO zyq7J=yQl6$F4%j5fT*#0gmH9fxc*7x>;(Rxr`COi1Pj_V1^XCHX&+08O!SKcD5ZdFYD;38YY!WOT(>m+W$FEX`hSxlMq z+12y=0Ro66lcFAXtE-PEHw2;IuoPlsNH6i(AdIHa)w)&<8Ry3)Z~lX|`goIXY5l%v zh>t2s`(_Z9euG-6#Q_olKMf32&d?*T-3sZvYT95!&CAxa z{4|N9oWV02E?h>0s_s9V_?icL^bhucI3d*qC!}=wSj~u~sPt5_Z)7i z$o#A}HQFe8k2PD%`41M;*tubgyV9KV=Z_a2rTV(tu)U(XJ&P~+>pF2w)?|tl`BlWf zHBV^RNDfW7Ood`U{Bhi_E4@^csdo?OyCY^_f!L>EI+wouRmMV25>`!}pmY*xfitpk z6eQo$j^s!j#wtiA=GC2p^D`c|4{N^@C<~Eu9VZs0(2tL-Bo#nyh>E}nNOH+vWp?p~ zd$kn#B{b0dVwYgAU;Z^H_gmzzeQH$uZV=xt02Jj=SZhrx)100liu;6d8eYAm-nM^C zrSYVXd>ZY-lw=Usp|5paCt`b4`@@p|mz0q4eEbRa88}_Xqm{Odq*|il?69IK$1*;q zV3q8u;S5czW~g8W1On)6-G3uWd;hID4kKL)Vg<;Pw&`6IDRB(T>ISu7XH@v!%9OcK zrT}8O#0&ZD)UDD#rLFlv{_Jw+v{r8@;^C3DTx+pR$)*|cEt^q=&KzH(P()W2R|MjB zK}N#X>Q3<1=6rK3s{u={L;}kq zsWNQ@4)&kSN|2(zoggsJ#CCjee-e+9xL})#)0T8EGeZ=F-Nd%o8wkyy_F-Er!!*X} zMZAjvh9({LF`w>_m?L}#7P8-0W*fS$^LYwVca4x#TdqYw2SJcmokW82srWCf^X?qG z{>v^WVkQZUUnYF-L)o|R>cgP2T}!a%e+7@m3i#+UvhH`z`PF{h+pP05nd$#)@>L5aTworc=kjT!+$_S|RgfLF5 z44~#?Pa#Daa8cipjHyWxUc;q+t{=P4W+*nM{eu;Ja8K>g9Y38FOkcam$__i`O)DN{ zYSQC^q#kQQqD|?DOBZaG9K{gjU7b=&_i~U?SP_LJGfW#rYKzC{0}SB^W8?t27wq=4 z4Q*_z67^xH;7L~MN5Hb@!@oz|A<=c`yJiUOrDClJF#}!{#eM{J`*Zb3l~uQDNxy@$ zJa0k}G3ZcbhV{2~a_w>0A%qypNP?bkQ-}67P?~w>k)ofkCo|_;I2jc17hAr@JVclc zT#ci#n}7bv4K&-mkdm)tx1$!;$UJ{`=?Fg{hTAnNmmeCQn4mbUjp z)qR9plgWW<#^3U0^Qw>jnqZd=@sQ}=bA3Iib+Ohu-}k2uFM%BeOCIf;`e=ZhkwP8- zh074?L-Kf+H6f%p8~3;4&`A&1mBWW@ZtKauV55yNMG(+|4GNZi@e%FS+H6CFPk2w(-^nWuk0j| z2?3~BmwnAS0CnZ(ggW#l9ty8&TSBSIi2}FKDgLRS1K`r-X-;v+?ymRgXXV)69ngo* zc(~XMecY$7lhc19Q2(sc38{9IoyN%Arl&l0{G)p##xsDVeu74fs1g+Lc2OLzMhT!@ zMjgEzt$%N(6fV*BbueEx&jqPO*x;pS2v`r&7uHq_;0h`VnS)cU$BQU!ZZ9Hh~13Sk2HWCXBWa4oT6u+H-ay9_M;rtQ`rExoVNSiqe!2o&9PRknP}Z zk6td(T3=O7)$?xtMF*^hI29vs8g}gjflILp_*!w?DvRZ2Sr^k#Rrf6 zes8xw&G3Z25c#kuVyrDXa7ODXt3Vca*fgS^`hvj0x=7Q$4zx)fah5i%0w=138$YHw4Fp_)M&iAYJSDjD2gInkFi; zehz*}<0j$ouWAW}f$Cbb;JCBfA<24t=WX0n!m(OLM=*M{<1Kw+ljx9+Jot!#+6=Gy zr9Iz550#9~TNR?VPoJ)Ql?dWs)&Zy_0_}gRoF@AU6;wFwgdCgdtaO?*mP?bEJ;l@b z!03kE0sZvfy7)ZcxXagf5mYNgO41U!)Z`z`RPsLwod_7V#k?_;%C-FwzW2*Sh+h%vZ;03ol{78?^91rUpNJgWLjyo|8z{js*ObA}7zKyqz z;V6tFuesf78xtO~51vbhw}vBfa&MKp20?>ou!}0l5$zQK6CA@*-(nYVk&jUk{B^+Y|Px$JRNIVF@Qu&$BgUrL6PTV0u-cG zR1{d#V8LN%LFVDE?fO^SvaGm96ivQ!SgIFkPKcLLop#=}2{CMcLall!_j1_s`b)Qc zMaFW{BOBMj=syW7iMY?`eouc&)9#e~-88UE8vFE7GcSwVAj-<3we<~V;<9uG*G|;P z<_6vf6ADXu>V+(JL`wh;%mrEqU(^La0jOMuSclz`{78 zZvY8JB$H|)ow~_*m^b&E$=UC;{UyY);EVYW`xY)0^`DTQAG;MREx9R3KSf{)??cd! z*++#PTq5MG)3Z8U&P3WbjiBy?PdJ!StK(ZxDDIw9X2)Kl($$Ww{0^f)*>bGOQ|k7w zVWYb?=hPe7kk5(KCmzu`3zWhytYC5Tv6Zb*o6D;D+^cs|5u4c`*=d(gFqf_%np?~V zK_d9yXhF*Kne;9k^^)3Cy+quyR7*XEYl-hX926UwFvv+1zf=hw5c;T<4>FzSbgll- z#RvG+SXRYg*$l{qJlR+N6QSF$Bf+!}ED$%QU&FCzxJXl9XhG=iJBU5&kF zS5fi+FlrU|c%Trlm%&Gi)+pwy6!+Oh%JW5{aMjD#lY;d?m_$+7l-^p?A8HN502qd& zVtDm`_{t~gQlY_rGHLW5-wyTu)QIgtGJ}SRMT?L%OVe6HhOjHz6Hr@7JH&zyddwR{KtkUxQx2m|810u&}Dq!D~fthX$VcGa?fe9zE~ zgV%lL6*|5o{Zz7ioz&1=;%%9ZEZCVhT#H-(7b5=OZ-vd(!GMBy;RfE@9jq85acBxF zFiR!1;Cugxd7o8|AdmJXAi4kgR;xwT zH^sKEvhix%5VJEcSbnaG-o5NorUPkuiYGFosMxTNZv^KA!4j`b(S)~y2gAB%`}Wa^ zEd-&&^x`FZ(Vs+}Z{NPT-dQy9U+b@R8&vtr&e=eCE3PF;asigxe1r6c)D zUPTI?KcI`(r*W-BQgI#Y5}Mc;xWJaZYeT?V%*tOWqdN4)Ir!JtIZ2J)F?H2fmgfbR zZ;7=Lqoxv6fqA=PsYNAMs3Df4JLgzo$d2K?Gi7Xx2T<^WkeuOJ3%1A2PZ6NG0 zQ+wdO%e4vmy-o$XNTTE>znDqYPvyJS<<-@d)v+w+8@~?ZBk4Re0F)9}K$)}uHzthr zM$PAM>P(FTDX+@Y(m5qde0-bX~*9r!fVV+I&wa_idfHoFq#U zyzjnkCsw9`An4A^4uE{|AM8SkF?Bnu_8HLI%d=;!_b6c26mF+=N%Z}^Mv?-Yv9%a% zRpXN@Ok*%t2xPQW^DGH^^QoL0#<;&#;Td?dci~1MDG;|I<4n65DI9UYf5J$#62Z7! zuL9&dx2Otjr;C=rG8u`EuP*&Y+qJuHBsay!!{#t5AbD=)Ot_aof%7fWfRs<4RRjqh z<*D>3h9geo`VCE&_d%redPYsR4{8Y_2TVAFV8poik5SHnycSUIZT^~bQBC) z^ZmMbR{CQbUn$hh5xIH;7+uF&9Fpp_Fky7;mL-{(FubQ0>3bYiG5RN%yP>I*~S$h@~G>*R_)0TwLb^ z?mF?xIdQCDBikFM2DPIsh0-Ku1wfU1T27;0!{rlB6De*fJP4l2ck!?j;Gek;^0$j0 z!vy+962RVHp&h}dhuPNERsi3E!-+1) zIK*^prgcR=HgrTC>X}!G9>#xcTKD`U|H5bTS{Bjx4B+zd$j_IE)GLV51zW0bb|A`irdM`dCD1r;7U98gyLheR2t43u zyn})YQ~uJn=9V>R7F5&ip#wt<8_)#LB}9*q`{Jt@YgNiVL7|6^CHb;revHKKJTgzs zaNCV%Hd$lMke_itk)9z6eG3E3D)%5&5I+ti=hTddB_`t@)IRF((;`vqbIeZ(8h24g z%Kw+x0zVizOcV%ObrA%~JU=V4Q4Rd&VZEvrWTWRm2>cKsMV*y2HNOD3_Jh^r>jvvrQ{6d{vXF38uh3 z3HxL<3A*-1Pbgd}7XAd=QVp#4^4c>=_^Jj;%D~~xpFCk|XG;FGSB_$EbiSjrxBq02 z@tj322ku^+P*w;o$4neQdH??-!pQ%>Q2GA{h1z3nbM(D+6*D5b#HUxBJZ*IqaW;6_ zMq7?Sd$8}zu}qN#GH$gG48gmwQAO*DozamdG2XS&TTz+AdmUAep3T)(rV@ucOO{5s z9>ibs>BblRpXQd@X-}j$7j~kOj6_(tX36_`YP1gxg>+P#o-)F-vAHST%}-8_?T}&fhIM_?x5tX2W*p}~*4A>bD(H@k)NmSA`Bs;p;KJr}U$ln0CnqB71{JH0s z9$+e;Ib_>=rK9<4QzK%xPKmWYy_qz*DbC@S2Q)d4{oi`%4<-_=32UxOc?;Drz4%?^ z_A&_5wHOfhBG8!g)PKYkq1!tI_uzreDbX@2=D zzzHej=tvryG!O6&I9N-_G`c<;z<0oKC{iix8r$3d(fT%j)N$uQm|<{Wr*7ZpW#kcP z@IMi+aAJjhR}Va9`Xo)0nWvC*b7lx`^;tV}TIS5bPupG2&-VVFDwwl9^X>2;ZI5M;l{%4URI@n2;%^gtC{|Eb~(vd!^+`pl|_k)(NIXJL2vbu z80Dm1QW^}F{zZdr<*_KJ_rc#gN8Dqs zO@`g6b4n~5x#aKC0rX?W!WP1Gb?`@6<^NzlDY4kkS*@0h?ldU}y(gJR8JgAARW^Ph zpC(r)f#cj=FqqXrw*Pgxu&>yfu5hdmF5)4b@uj|M#04(g>l1YJcd+IwsOTAPIS`9Vxe|lp^6(mtLwA#Oud69rnv{ zsx0dr=GuTpljC3G!&;84(#|-I3fXv~SF(odBAc!bd)f*1<@=|kysi&DsUc4;M84iM z@arqJ{_pws|Atia-qw=9KhWjz2*dpM-yW158hpZ))|M2d+ z6cTQ0W1O>YLswn^o5~hg-(6zF;}m|nxit+HXW*u~hM4ifY}aHy+3w`jJ)vz-woz23 zb3G}JY|AyhY2S$e6R{Nl1Y`$sgGCRd&EEJGu-t=;dp^#8*0|!d=EC^V=z=uuOf%Dc zBJtNfT)VHs&Z=J}L0{n1tJr7~^$M21CzO24ZieJEFe_M$4z#;K7_9n?7FaB4wdnqG zsIyn1Pf<%W+$iOLw$9r@U(w-COPLJ2({%~z*I@zO2Ao}2NAETEkh@m1sQKH`wCPWj zK6a)l6`P>B$}efP%&&AK=FiL&`-+#u;f33nW0cOzC)fuUKcWiOePk-^lk?XE3%QQ} zbWMMX6lMaBO#~HaG2CL@!?tD*`eH1NJ_&rt5&2u~RoJDP>i$t9PNF(>+(!NRx}xvb zD5Y>g>2N{9$B!yf*zbDU23nNlcDN1g)8hZDPyP6J^k`Mo0?a>gj&=G+*z3U;W626S zfJ_R#3r8Hnl8HnSFr_jElAA^wNziV@9W*#gjlEP}8Ef23WzCv?m~hr`UF8jvm*VTy z=22xkAH9!#gJ-9YuF%C4DsZ&4{(#+*10OR6YN+XgSj?D7AAq*(yk}Cx#>9{Xzdk z*^J!<8ZX5EjyehK3K4?|pe}SFsWD95>LC?PMk)WDw3+$tw|Tm)OCz#(gv?eV`Q=b2 zJbbAzTfs_%H;#U4;R|*&u)UN5Mn35C`ZmHxs{+kU2Uh-SDs3fOPdha}?EK9heU~qa z@0kB|vl8ng;=d9%0@9@$&)|9KPOS*xE#BThi^c)@`ph3cI>jA5U5*^@JFB&Sh4Mmp zpfs3^c~}bKC;deDf?2T}^jvqEz614oSDYLn)Z;SLe#_LOHvVXo6<^Y+11<478PDIp zberV)+u?5n7-W%GjRd@Gi_r-)$JMn zNIvG}!N*FZ!zS-WT^y}kQIBiC{ni_z(Gej6vJn*s$g z{`MzzCkH2Iv_gG2&;yA?+{4DyqoNGhDNXvV%@Y0NCO&sOq?B*hDX#>c_IO_NXf0E- z8c?l1Jf$KinRTGTKKv&$M=chk?{RedZO9{rDM*UQ!MfQZ>W7^*yH|29L`1bFFAgEWsF$OlE>jIFJ zYS|2rw@Wz#bU(Fp8>)8H75ly%OQV~AkJ&xZ9PCM3x%_oT-*`eA@DwVrR0~16B0Lu8 z=7C|p&Ze0Ir2)i*@!w^dp;rVJtKJ(_XS}N6=}P1M`mn!ZA<80CU9eAWG=vhn!U8@o zfmNu{lQQnqap*oyvTAguHrC?TW>3=93sfoRPvbk<2N2l6xs0RXV~4($h$L{qYeCp( zR;9bnW<9N16GrQ|OQPZ$^@}eYtsDfj)mlO>AlMjk`Q=?>eu>Q6+9iO+hz84WU=kY1 zGa5EhVX6$NtYAVvo{zltGvK^J`SAFO8-RrD+S}NoU_qtFZ7=MEI<4ckgIJ#+J#33Y z7~+p;4kmacY76wXN$s-2!!v&FpWaBb-pQM7E4=)B_sCcF2MuR|Ce~3A(4`i(fp~JM zV4C;}*%D=-uizP`J|OR)N#vcrB)eh#gX?87OiZ->wemL@NA&HKb-|CGY!$4w&KX_y zVIm)>jB1F~>wQUZHUzmai9(EpG=~hd!KRN@_qx1ioj2f9;`}WxKy5suHs`E#d0W*Z zy=3nlv71eim-`oL>vQx&(6)^g`lpIc%%wSn!~R%fPa~;L2=SXtW3UG0n5%;&no=@W z*0qCGwZrp2R&00`pNRUYI|zrLGlAAz2H9BbVZ)#l9ce?3np4cOW=L_8?c>(Tm5JK zSX^V6JWbp(rU%H<7+0BMtX%MjjYhD6MqLUn!7(hqm}%G)vWPNJ2|@Y$xmBuV9e>3U zKQR+p#4FVH(XhA=k_3$j64+Kzs|V@nNP5OBZ_*cHZn0_M1boMC_{7%**5|OM16*@R z=3(IS=?&m9UqC;%Aw)eD&pa~U*GBcc;`Qr3Vm!p|Ew1BdtE906w-GCLzTgfs zjcM-vV{~k*9wsMgBD3W-?uq7BVCcvEhBM%B0vd@arVsIyV97YJ_wG~UOp`8 z<|V6Or-+)0UQ`9L9G!eXeG!>3^0vv zuZsN0e&9B!cH}vyPMT6cYW{=IyEpf-s~IC-BB;)NbR|*?9Guf|?H5ysx@Jqe@wRjc zI#o3s=;9furM3Pg)%n7lM*RDKFucxg@KbuQ;3_YOSYOa7v&UD>XAy_JkYXC4$6KdW zM|`UX_=le!9e(S!bH7@VPQG=!}AS z8gI51D)b|}nljn%^@y4mc#O)hA5RJ{0QNyg1OCbI>NR+a53For8{l4%K?o1x7-7~d zayIFdn#}SzA!g0)AMA3h^YC!UP1S>e8#C}s#)fUV_qtCH~7`et$0?`!pN! zm%se)*Q;`B%2NjxaDyWofIZB4>Q{B&Xcxo_pT!=!?-)4#e!w6QHM?qb@)_?Z$L@z& zG;$u-_lmakUm1(+(+F}2LJ$KyBga>;jzLTz)~ij!iy=1~gX?3TVM0Q@mE=Y=Ikd`~ zK3q-rO;MK$;@=Jl05a47-QxHT9y#Oz0LhSJ6DITwJo9FP$uH(Pht;ak{hdlZ4W?HK zKJDv9Uw_XoMBfqDKZ|?=uR7j_cnXl7hgmDdg@i~Z$^$in6!0)J282M@5Nh7=LgrUKSp3y6^{YfiZ+P+Rs#ifIuZK3UgHkH*QpJ<%c>U zzPiB!V_@3>Gt_2fjXWP6fK4DB(x_8a|2Q(9m*QKY?Nc;dJVOC> z+GR(xZ^epR(qu<$qSsUn^otx7^`hraow4IiZOndIcDXk-lbt8>kxm5D#@Ovt6FpW}|Xl2VVW96@XK@0Z|HH!ll& z4P9q$fv2m0bA$7=uv9zV6!D{VKF3>RWd@H9md#!=Q&r>hbLw=e3()2#fM#Sh_B=si z-AP*Z&0a{Jxokd=`~q1z5AbeWn)G+T%4OxKgjtf^4?hpApS46^w6xG&z|!^!yx zC(7G+ty90|sdqL$~~BV`qPw@*VWtr&?C_e^Pl%s2%D1CV&!5)sH8S5FEda(8Wqs9JU=3Qp*dORirw^yoN1LstM=p{ zb0?G<*e)B(hZ~wh+(=+V;1f(?#!NJ!J=DKrBut04+Vo;O6VF*Ry5xw=P0@Y(Of1b( z9CcMO?RJb#l8wR~7>;DJ(HP{!q+H^t-Upixs-*(ni(udc%M@z^hqfT@s&RJFMrK;! zahX;D-bHHL*H?#DzZnN;JhV|KJpB?Rck^aiP`6Pv6%*oJ63ZTfvN+T%3^ zVo^StR@N82d*!{wpXGVG3MF0=O4-Yfc# zBE?!`lr-se4#8xcek`#pa$EXC0P3f?9Y|w@RwTpedFxgPpK&@9n>rb8a_Fo7@Wd}GL7x6ZOD#0{=BG&>wEuM z5!374_uOHJ&f)WjP9#slUO;8<`}co&rkq{$n4kRS ziD|`Z`w(h9y9;UI21tm<0qjuRf5)+Ko}{HPJ54XV z!=uz%i?Itlm-~(HmS~N%6R9ZGxLGCA#Exw<^^&M|PD}#X`pHt}-xJKb_v^FCzeL{e zQufbSn23r^^*%P%zOV^WRVZ#Hj-kjrN6)~N_rRkxEZ5#f?>SHUOmH9^j(PqJsm5yj2hUHP zHKAcwlU!%};>Yu~Bg15Wgvp_YAy2?8;ZKZUWD# z4X zfTcY`!^LiXs+KVfu)ZkOV}0J@;5UUFL}i3k)CoQx3C^cS!%u~If{(di@2dbR_3GPD z>aW6AkPs;@N12f7Ad5+0SPZ+pNTD1f^(Mu>x5Wd(-zKl=Vc8cjfZPmeZ!IB{>Qk7~ z+BErDi02(nfQg`xxJk^@>76vRtdc)p>8GifMyInu+j#A}!U`745+;m~vFH7fcmVfY zfkzndmUv(FS$`aI5|1;~>X6d?2m9&0iv>|$lkPG*Yr_;#BgbXIJ=5E*XLu7?-zO$) z!bo)b8^J#pr4=|`{386i#5+Uxt_|_YDV(BZu%VX*z^wAs|NY=cTT;*5_}SaJwK_63 zhPApzk#!x`;D`z#XdF&`P}p9o-;NM6xI@N@ppl)K+G2!yR!zz$6T_NMm`W?RLd42k!myw2~TK6(5mx5s)V}>8Yg!1QsZV<1!KJ zvYzalfckirUd}Ma9Hc9di3c$X!%SmJ-~KU|ADBBI7w?w_d149c*N)?Qxv(Wds(&Q3OBS&DWi+%gWd+~A5Re9IM~V_-i6XNt{2+=A4?Z9l3^SH~L6 zyI!qrOby@B)E9M6(eZwNcT(?%Hymwxzu$ZA+r1Ru%P1{yW?#b6b;Y*-66ivVqiU^F zvUJOtzJ$}Sg3=VSRW`4k@fD}}*BqcOtyOV8WhRlonFadu+$+eJlWrp;O9 zdE=cPQQclxV3xV)3VPQpNZ(wx@bebF15hyu+b?J_uV(sUu{^WMYgSa*!rRkF>gxJ3 zL>q$Bt1Q`E+YHNo9nYBhd)I#l&BFTw^kVsj_A{o$dwPctqFQ50-;TjIGecUvF+(<% zgB1Iw6o$hQS|BWu`sj+zxC&B~3Umfz-ajlDCwrxCikX$b&b>olHdw@7u3R-n9-waa5W)g)bjY z6EQSyk$#H2Y8K|dweb2iW6!>uNWJy)0tpb7lN##H-*srSXo2kiBQuYJ_+NtK%@m=Z zkSx89LVRYVKGNs~kD4DqJ?_c9yHxhKH2P<~<=eBC8&x5t&)*op`jGb^5{_!U76ZI3 z0Ip(^-l2Oe*8_@0p8RSw_bjTMJU=PE0-{?!ag=vEyB-L?yCP$;!uU-G1O3pM)srY+Wl5XU zuD3fRX0fwz-*%soI;09q1BnMAVKj1fe>Q(gJm%~hdd|1$D+cQKYYrlf4~NfL6wB${ zHg~CG@2}@SYeN`Nc^fe;zDgz}njZE$VKIAU>^d4|%k}#oj42Ho4uH;0W1!H*loA~8 z>OUAo8Jwqy3PgRRV;OfhDnMnDzsfA5pGJ6J#BphC9D`+C~t=b44Xmjuof zNU!vq00@$x#Cy<--7aFqm2Ikt+#iwbde$uVhy9$-`E{h;{CY3hvQ#m<@2pNzwxrFj z*IY6DWfL07lnJD5I8wXX)PR2wxZ{)n=cD6n8;7@?(kA2^y-y#AnCvEbTPuEVYOHmt zz6vg5^}tc>04AuxeL_0tLkf?!v!2t`>3^_a8GCKC;}o@MNX^T3lwRCc505J;U2uBo zQ*9-VKN53g$L;!a5k7$fhQ_dDzjN@XT-*A!tW+ZTX|oDFuIy$LE)g=kzsLVtN%>~F z%`eXN$%*rVu1e=U?y!cVu@TK6v5vHQJS-{LRlHhp=2ep@=hDVqr9y=~-KqHPHM*X> zDKNJPFR!1cRxKNS3OdT|-$m8C%YHe`m11)d>Ch?~i|*Xs1p&dyX@oM3un3!^3|RGo@xd=f?63zOCcv zx?B_mCh$8EF6abXLXz97FZILOGp5!JFF)c|25w_Vq&^8QAddsyCPK=Z5ZA1R(afDg zRRN`;VvZl`_AJr06uL+TEEFU*oL^WU0|dtaxr#8m8fY@4`Z(pVcXD91rQP66mJXn*K*5&zzkO$0)A+BEbr$F#UqMuAlb( zII55N7Yely;{H@XkMOk9UyF0>Sa>#;vNueatf^r%mrnpU{1oVYbCP>2L&-L)MIEox!Xz%N)D!5x+$<(OFunrKo3L##dcQKwqfPqgRf*+XAQ9l|@h9O`^V z*}2SGLP+8q;~xwM5ic^u!B@P;wgeG9QPIR2n|7Pnyn`be*qA*;l&1gti3{VVje8k0 z%J)s%np%wvR(9iRG-VxJf&f$s2It{)?X%libheowO~HL-=`?}qUnyfim>+cf^xmB? zV3)2?P;xEmP!ec#m9HJ91E7mjfQ~LMH1=XRjJFof#rItqEX$Yq?0E8)-%@W-518{n z+$SYL3Mp3QK=&%rd2lW6wAY@FX`4x>cYBw3!mDD6 zDxfvVd18RK5Le2pANALHm+SmeE>|z(DvvWIX|(*Vy+&=^p#VHTQ?q~kI^)`tbl@1g z1qxr|Gv7^=ov!;W!T4roiW#5+`&nbyg$=_6RWNtR2tGQgy;){(E<TJM{T{vjvBb(id`yBMf?k@WBf~lelW^>e*Q&kGBh)KKt9G)Y()pW|LQ{ zCsd&G|7h<@!=ZfNw#XinC1q=5NwTFZStt34l0=25CfPz`ifkFC$i6E?Wke!kk}caz zj3tC@jeQ1{of&C7%$VPM`}7|F_xtBN-R3q=R__p-TT;j`-yu(m!tfdyw&F} zk#26GWEd0FJnn}d$2J?Aa5_P-=0}=Ol=^{8RFj8S^^0;14ZPHyL>F!i1%bDm;od_xL8(tW4X>_TcBFDz zfY6I)lRYvexRZ^gW*|iaC^FtlZ|8|H7BWC_pc0)!z2WTCEq#&ZWYRIN zO){Gw%{-3bf_Q1?F}5^eNllg^UGz|ZWWf0Av%lF(4wfWE_g~owLWyojO~GhNyH6W< zx%?)=CxSu19T`$I-U;3|E!Sp}R4r4tk9YZk3o$?dJc@`=cGrD&E8>ZRp~;IX#^ z$%?iWy0palszXS*+f~4C@%Bh#6w%)Gj}ZW(jx7C^3m*ynqIwupLti1xXr(0x&cNoN zZT~Zeje#*TS(*_jn_15!MQieYAx#ov{gLw8s@u**o$Ugq4{LA54tPbm;bU>IzkjHh&qN}Z6#istKJhx1`WXI^vSP^8#{`4is)?#b({$gSC8txZW9RD1YYH9|BeO4e z9B-ccn)zGj&nGJ9)PqAC9J_qJ2sf4x4ZdQ*yaD+)oRe+HnYD55er0*z1rFN$_>b#EN zLy`Mk?)Ip)&p&HSl?c8MaKP*g-<_8pJ9y$f6nr{5<-POWE5T&Pp?m7(xayYQh6JZdMI=#!Fwq?xUaD>%_8@l~N;m+fbcVZ5eK-A@uO;y3+88SiXG zshr!F#UGVsk#!W-^%y>=^tS|g-Fh!>@wb_D7+)J!3rjP(vY?l;=d#7NYF@ znZtU(@raPKNC+^av-HP=5sqs~PK4}#{bK2M8uBTThSH0Y2Dm$-5b~Y#u4TZYbwale z?X2`1Xd<$I;KyN*D#>z}HIX6&f8iLcY==<35h8>e)Y;mtH&rzM20S0u#lUO{L`?0f z>?0L}=o}Mt?_)&XlK~(N#Q7h8su|G22Pl$6T=9>V_?k%zxkwEyo@1iD z(KkTVIDAowtoGMfSQcSB@GJRYrlrDqLEMbZNgey-Gvm4?97QpkDG)Fq;}3L@$-87? zM1WqGF6HpX8M!d51P%KOtU_H~-8s~&3!hvpRZRcd*7%hi>+a*VBU=su?5EISr$-|Khw<1 z;1=H1MIt-Mvk-cD>0>%$Ohqxcf2Q6>S4HIKv)_kY8WLrsm{yE`AX}Oy;}Yb~8_fnW zP>XEAd;v^5^U+f=o8r!7k6gd;qSQ@~Kt>x!cmNw=Wx}<^5}hzrT0BBfUpYEpf`leGAAJ@fCnm7ybj`0*e)4NkSF6Z_u=X zMQEhdJJx>bi{7uUujvZ6J3N1{ik|(VebMbXH|H5jeYo0AfeAd=zP}egi{)LoTcFNp z@*U&g3C&D}^+kTCBhx7~Cu9V+0yLqU(a(}Qq|hs}w7F?YlB794)_u^$M3Mc&968yo zUj6E2`ocjuOUjb?y;PAyd9cwWjb9oWZYkaFX$K+|Uy|H}x8{f16Ht&jWHl>f)#jv03Ns;-^fXJG)d?j@dj-;TzFj$9UzxvV&ry&BF&o2l&TwNu zILrO>GZVoQHJkO^(H@YCVKbX*ZFX`9jV_-Z+Of3z8u>XvEK%iIF+EC7Z@UsJK=lF# zj2L*kA9ZMl3(QZQpb_58^cWaR{Qj52tae!a-Oz^ul=oNOOmV+?*d=oeNR#rs zI9>~8!zG%mLs$zl5D5eguiGSGsquhCVzMv%tBD>oINKwAi6#uDT$`v4^{=|0`w<{! zJftPs|4;A7lGUlHd$}&|%}I|^iiy-A#D0y}Oh=4U|D{Rtlz2^D3L@0KiHT=VUglkG z{j8PxNDmIQ1W$n!whOdwr8zo24Ff#vUzA()o4o}HX3Y;j5Y*HLZ1Lu{r}5vt zr0+;9)IQr)33B4+29Ic%v0TR}D35ETctvwF)afU;7NV?a6qiWyn2+v@n;vi!8k)T+E*!mBlV8GM>Zg=K5GU}1>6abW3Pz?S!2WGsea!`Z`&v={G z!W!k}GK^`uzYSXT-V3!=b-U7(?V>%-9?6_-OMPz9(RJN^Bt35yp$9HiDO=E(9(s8P zh{lvoof@ptOLdy?& z46`h)QN~m9^j%^PdI?@E6VTK9oUaWNk(Wd_qW8vzb~GV*wS^m1G?@_ zb=(Sm6zn~%txxF&e0|>Aq0^g5_ri|`OIy$-QvAqL_DwE4g`S3*J!+z@ib*3fsIGcl z9#wh*TetyQ(k-C7PFs*1J=ReVUu!J2>A@#YPMof;VcE*nA+DQq+y~Ws*m9I|8)B^Q zI#h;bJjrKiRQRa!rqwkJYv!jP1!fRQ9`BtnlzzT}cL%?)20dJbe*B}f73V`%?md+< zIhtn-3oL`jAVtH$1RS6PI7NwJp8yrY;GcBQr0PQfWq#Y+J!?n4y9}9i)uy*5M@5{i zxzFi%JZsn_%V&$bsT5Yodg5+Nagc=MV;CWat)yEFsAamhW-4s|)-_GBV6w>`m*@tXo{2QOh#;>K8hx)gLCDHycK$<8byfbXy7(C8| zYvI({Ahndd=69Wv9oUnT0&G_xj}r!h8MmDZRsb`Y-5!YDAAaQSqwusc>yk-F(+BQo zrRwqul<=_C*BQTYGp&r%=q6TLh_dJ=e2RXvFh9km=2F)YEyd9 zKCX1iv}$ATN9R_;(aM``u>yI%vx<+oLsycP4Wix#?LRN`@mqxBucSx|`CKzqkXF0P zMeAb=>Ht4YhO&xTXnIjIE?P4b1mtG4^3tP`CEh;<^ccN${*rEKau54P->7}&H2SvV zS2uzMsN^no1UKWkOa%YlVxj^iz3G|GgyM`R>QT7`$8OqB%Q@yaH^f@>iB?`L5DVY> zley)O90D=RCx;ehUs4=h-X_KbhK3*G2#(r_mA1RgyVp8tc2FVL65k4H6^65uxMZR) zOc=7U%GQtuO74zRC73s8ypnVJ3-&fisLo^%j53U23(I=xndit}xI5@I*cWVov%d#+Wm-GGZcIKe&ETh=+8^`KdEnNWJUe3H};H zZ(7TWQ3+q*wIt!b*F-&nE(T5q18qo*1p~EO+vXX3^rPx>e8D1GV%*wJ?w{1j+wi|) z=L8G@U+s_UoO{@HV5{9`wMhun-%l}BgY~|!rD@nWBb{PWX><8fSxMt5Gf%}6y$M2% zX$@O-AqkR_t}X4nCbz}+Y=a8I-cs=8C}o!TONJ}x+XKj(kIa$}Vi;8aNGNd>?5l2* zZB-TgtshvN=A>`?q@%lw90~4lZ|)vk8wfDGG}VVbLC$SX_HRxIHi+nF4xVP{$+34U zmLW8aH`AKX(Y7CNLVOtvf-*g`=>5VMF!aya-BF#3ebT8LRCUIXl^M8|0Om0eUQL&6 zq?y4JtGqTKkF+4A>SoCZd)bzY3Vwzwd9ZI-NSi!kHwAQeEg}o+Ty!!^i+pHbF6n(> ztf5tB2LnEZXKWWT%~{sfkS0yAouJv6=2}f_j|?rb>>1quWj(y%0kWrqC8o(Bg2eDM zTn|CdDp<^!TuiCQGwiG9M!Fy76G0`GI=u!d!&o}X%QHl=MwP= zso?pem2btesUt+~6p4%U;-7nrT(f-u^<;Oz_MJ&kId1_kZ`M6>nPSb$jtFA~QmIOJ z&C7j>>$}1nh8!`Cf%8Bt>qGjnhesYCfAsq?0tS|&5K|6o(;SusnHR$dV-QP+79JCX zzw7jTJn;mw`t@jIOUu!1mDT~ zPP&KK$R|2tsZ@BfE^+TJhM6)M99UYePe~CXKK&pf?PH}h6z{3OAyH}wzwI-FhqULY zAL?;!umqgw+o*!d!3`!t=sIDdL$T8EMz8pGiMcm+rJ5srT===I^(*#5Ltx(~u)hGu zT=)r$DUH~Ik2avh8u^sWZ^NUs8|<^LHVwNuE>oYfioU703!kO_RTMtoh5>kR@6v8B zjw|s1wB}4BE-wYpC{}dt8R_vAg!#b13w1*ZcG%#&4$0Tz>3$85d%ZhY68;PcI=BbQ z3>5;+^Qn%Y6_6ao^mY|t1W%~23N&(H;;32QE9GlE~i zsU6ZxnkNsL-cG0B*>)3lvc!?))V( zt=%=|n#fC(-6XcY);8n$G4`}!SnLcz0O|p-?hVG6?3s>^0iCq~{W*?!7+T-zlJyYj zGk3r1&c)t~J)E&U2$~Uig4ftWm!M(q<$6R4khhFbLdX%AzOP0$Ii~`67qRW1g&f#I zKq^IhA+V!}r9wcik;-M@%+(<{>meH?b4~(Q&Fe5g4Y|MbR&#bz4l;Ck)`u&<;f`HP zkXP+*lmrix&$`hNid`Yb!-Y3aJI>fFFG)9<&Tj6>+&?i}PtP?Ervqy2G2l|vu+*$u zyZL`4%jm~O*ufj1gRm^Pd{O$f^RyLK)^(>5v%AlZ&v<1h2Bpnqyb}Ln zc;7l~0W5k&;~++jICaQqmJ?^r5wg~S9WD3*uZBmvd}qr;2ohU+09Bs3u6pxMi{WQ# z#<{&|kzJxZ{IaHUG;1G>3Zza2OO9DEu#qg~X^MbjvEWZHsfW4`YK;H6?MW~H6wk4a z8-K=lU^BMHFoU9K!+7GS@pdQeF^t1YqrOjF_gz!*_5zDVcbiXtk)x(O!BQgt)4~RX zU>~s^c&Xr}nHZKr&OP#&CQBhx!s*&V6VrQ(Zl%;27O#+UBF`LQh`w`{n-pGbdqya0 z)i3Z#r+(Y6q6N1jc&?BUU>FO8`%4_}OXwj|Y`(T)$wYQo@yWa7mThf!((&oW_Xt_D+av$4kUEMh9wG=q;?Vjnee7_E8DQPf|eDDdYHYjv=nOWE&Ul|qtE|S zJe~s)06!Ub^s2jt$dybT<^jNt|Ba}zS#HP=AN`l3(jfszNX5^r_gT@em3$%F7yiTW zdmE>As-y0@m4(`a&-?h4IEPN>7J&A%# zk4NA7%LC@f*X2Z`h3l`rc7(d2km-bZaAr>ebWHtWGdgh#ByyjY&anD5R*J{kUVKFr z9m)KD>i&M;I~~84Ze9X6h^IUJn}K3lbsMf#$Qf-LG!v46T$Eq`m*b+tJW6~IT|J8> z-NRHEZ!cAD8Bd5tZh0Z%{@$S!_Ku-qSki;cqx0J{-f-Fn#fJ5t_7YhpM~3FA!QP9b z^o0?lw@m@%z4ln%zNUkgm9*a(UaqctB?5KtW-=Iz#R@Y4If1l%yg;6?_`}(1%q|Gr zMcYz$aWuQNF+ozeeiNNtHmy~-z;$*QrCv2u7j|L9N-e(M(BOj@O!pe)7lG^ko@PAZ zZl17bb1wftqcl}kk0gb9wST_;5{@U^>+TnW4wU#=os>8Go^afHDwc*kg$V~sNCMr2 zD*M6**!P%IgB!AU=(XM0>C(83keexn*>diQxdxwJk;%X}{W{o+hIC-lzW6|73q{;S z{_gS7Ege3!zlscwr%^QH5!|D7G?0&aM>sk-;uWNiHlo?4z?6D6ci{TBK5G&UJ$P1P*WR_hw zl6*6IH)7lUnh(D6OX^w+F3a##ZOtlFz8=pJPxBa!>G^Y8sNmJJ4Fq5|JIuuZz^c~) zzz2vFsc$wBG6Cp=J`Q6VZ%Qp@R4IJjKGNo4SgCefr?qbyA0-v+wGNG>3d9}Yzpx{o z|M>XW<4?yUiuS%rrZNLJWP=YFcWg(mRJqA`?hOsvzA~Q&%K-&rBmk??aGD)laC8hB z=w;fFt1e$TPv^;8;3;@ldi(j_Qhs?wPS-R`Nk!B>DWD*<#*%tQ8zfCBMK84>MH~HR zR*vd(SrwAdsKT=OK2^2;Qp;;G`z{xVyz-CVxs(4`pBRl4*0y;%wSNGkKRtPL(ER&` zp?T%U%9<26-H-S^;(MZGxE3d!bLNXA;|RIW7msnxBA{bPmWTrwE-0?o3P>`J30G-Z zN%>EmYGbt}?exoMWlCjd>-SwL5^nk5otatAk4_ss2(;#&7??RF4R^% zx6H9#H+6N@TF6e9b23Lv?#r9qyWbK~G<2B<9aB|$lh>xQVsNEwdHLRq1kHK8y`pWO z*LsOOzN@6*mw>^81t(G2;tt6#y}XYCfE)&nbpX!h$AZK-q(UaaVe^lQVs+pGiv-c3 z!+;ntv?6Eq=J3X-ksZJ|Y6 BntK2M literal 0 HcmV?d00001 diff --git a/resources/image/c_s/a5ca6031-62a5-4a05-9d2a-1b7dc857e7fe.png b/resources/image/c_s/a5ca6031-62a5-4a05-9d2a-1b7dc857e7fe.png new file mode 100644 index 0000000000000000000000000000000000000000..3aec4208242e77a829b8fcaf4fd6c7951bbe62dd GIT binary patch literal 44974 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 BntK2M literal 0 HcmV?d00001 diff --git a/resources/image/c_s/a899bc65-317d-496d-a359-cbd3fb747c50.png b/resources/image/c_s/a899bc65-317d-496d-a359-cbd3fb747c50.png new file mode 100644 index 0000000000000000000000000000000000000000..3aec4208242e77a829b8fcaf4fd6c7951bbe62dd GIT binary patch literal 44974 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 BntK2M literal 0 HcmV?d00001 diff --git a/resources/image/c_s/f2e95c70-2267-4f7f-a93a-b095f7846604.png b/resources/image/c_s/f2e95c70-2267-4f7f-a93a-b095f7846604.png new file mode 100644 index 0000000000000000000000000000000000000000..3aec4208242e77a829b8fcaf4fd6c7951bbe62dd GIT binary patch literal 44974 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 BntK2M literal 0 HcmV?d00001 diff --git a/resources/scripts/db/book.realm.lock b/resources/scripts/db/book.realm.lock index 2be42e7b166044669567ca6b5d625ded1360edca..eff58b5c9ae3a009b662b4bb28a72b51ea4823f9 100644 GIT binary patch literal 1416 zcmZQ%g7hNmN7kT#%mK0y_Ev*sb};CGX^@+c cK{woe5Oo{WosgwR*`pya8UmvsFyul20Owr>U;qFB literal 1416 zcmZQ%qpk3fXo515%yMtWgbN8qp5&!XTseF YQ75oW2dlbK!O;*H4S~@R7%CwE08$DDr~m)} diff --git a/resources/scripts/db/software.realm b/resources/scripts/db/software.realm index 5ec3fa8c09ca14db7754b12028c4c3599a6c3f71..57b6dd7d627d48f72c656a97c036f06903866c77 100644 GIT binary patch delta 110068 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 WJ`i>2{zcI=${7uT(GVDxApij62ni7Y diff --git a/resources/scripts/db/tts.realm.lock b/resources/scripts/db/tts.realm.lock index 8ddc8431e7d5eb83c08280916044a66d9cfaadf8..c6f32a40fd0b5866a16b59ef6ee1b9c01a6d6cc5 100644 GIT binary patch delta 22 ZcmeC+?%?KSWaMCwVB%u{gN?k^tN(fn: () => Promise, retries: number } throw new Error('所有重试失败'); // 理论上不会到达这里 } + +/** + * 并发执行任务(控制同时执行的任务数) + * @param tasks 总的任务列表 + * @param concurrentCount 同时执行的数量 + * @returns + */ +export async function ExecuteConcurrently(tasks: Array<() => Promise>, concurrentCount: number): Promise { + let activeTasks: Array> = []; + let results: Array> = []; + + while (tasks.length > 0) { + if (activeTasks.length < concurrentCount) { + let task = tasks.shift(); + let promise = task().then(result => { + activeTasks = activeTasks.filter(t => t !== promise); + return result; + }).catch(error => { + // 抛出任务,停止所有的任务 + tasks.length = 0; + throw error + }); + activeTasks.push(promise); + results.push(promise); + } else { + await Promise.race(activeTasks); + } + } + return Promise.all(results); +} \ No newline at end of file diff --git a/src/define/Tools/file.ts b/src/define/Tools/file.ts index ffd7454..22a40b4 100644 --- a/src/define/Tools/file.ts +++ b/src/define/Tools/file.ts @@ -1,6 +1,9 @@ import fs from 'fs' import { isEmpty } from 'lodash' import path from 'path' +import util from 'util' +import { exec } from 'child_process' +const execAsync = util.promisify(exec) const fspromises = fs.promises /** @@ -253,3 +256,21 @@ export async function GetSubdirectories(folderPath: string): Promise { throw new Error(error); } } + +/** + * 删除目标图片,然后将原图片的exif信息删除,然后将原图片复制到目标图片地址 + * @param {*} exiftoolPath exiftool的地址 + * @param {*} source 原图片地址 + * @param {*} target 目标图片地址 + */ +export async function DeleteFileExifData(exiftoolPath: string, source: string, target: string) { + try { + if (await CheckFileOrDirExist(target)) { + await fspromises.unlink(target) + } + let script = `"${exiftoolPath}" -all= -overwrite_original "${source}" -o "${target}"` + const output = await execAsync(script, { maxBuffer: 1024 * 1024 * 10, encoding: 'utf-8' }) + } catch (error) { + throw error + } +} diff --git a/src/define/Tools/image.ts b/src/define/Tools/image.ts index 79e12e7..768e4eb 100644 --- a/src/define/Tools/image.ts +++ b/src/define/Tools/image.ts @@ -1,6 +1,6 @@ import path from 'path' import sharp from 'sharp' -import { CheckFileOrDirExist } from './file' +import { CheckFileOrDirExist, CheckFolderExistsOrCreate } from './file' import fs from 'fs' import https from 'https' @@ -237,7 +237,7 @@ export async function Base64ToFile(base64: string, outFilePath: string): Promise let base64Data = base64.replace(/^data:image\/\w+;base64,/, '') let dataBuffer = Buffer.from(base64Data, 'base64') let out_folder = path.dirname(outFilePath) - await this.tools.checkFolderExistsOrCreate(out_folder) + await CheckFolderExistsOrCreate(out_folder) await fs.promises.writeFile(outFilePath, dataBuffer) // await this.tools.writeArrayToFile(dataBuffer, out_file); } catch (error) { diff --git a/src/define/db/model/Book/BookBackTaskListModel.ts b/src/define/db/model/Book/BookBackTaskListModel.ts index 3661582..1bf6036 100644 --- a/src/define/db/model/Book/BookBackTaskListModel.ts +++ b/src/define/db/model/Book/BookBackTaskListModel.ts @@ -15,6 +15,7 @@ export class BookBackTaskList extends Realm.Object { updateTime: Date startTime: number endTime: number + messageName?: string static schema: ObjectSchema = { name: 'BookBackTaskList', @@ -31,7 +32,8 @@ export class BookBackTaskList extends Realm.Object { createTime: 'date', updateTime: 'date', startTime: 'int', - endTime: 'int' + endTime: 'int', + messageName: 'string?' }, primaryKey: 'id' } diff --git a/src/define/db/model/Book/bookTaskDetail.ts b/src/define/db/model/Book/bookTaskDetail.ts index 327cfe2..8c92e24 100644 --- a/src/define/db/model/Book/bookTaskDetail.ts +++ b/src/define/db/model/Book/bookTaskDetail.ts @@ -141,6 +141,7 @@ export class BookTaskDetailModel extends Realm.Object { timeLimit: string | null // 事件实现(0 -- 3000) subValue: string | null // 包含的字幕数据 characterTags: string[] | null // 角色标签 + sceneTags: string[] | null // 场景标签 gptPrompt: string | null // GPT提示词 mjMessage: MJMessage | null // MJ消息 outImagePath: string | null // 输出图片地址 @@ -174,6 +175,7 @@ export class BookTaskDetailModel extends Realm.Object { subValue: 'string?', reversePrompt: { type: 'list', objectType: 'ReversePrompt' }, characterTags: { type: 'list', objectType: 'string' }, + sceneTags: 'string[]', gptPrompt: 'string?', mjMessage: 'MJMessage?', outImagePath: 'string?', diff --git a/src/define/db/model/SoftWare/preset.ts b/src/define/db/model/SoftWare/preset.ts new file mode 100644 index 0000000..e5cb844 --- /dev/null +++ b/src/define/db/model/SoftWare/preset.ts @@ -0,0 +1,36 @@ +import Realm, { ObjectSchema } from 'realm' + +export class PresetModel extends Realm.Object { + id: string + label: string + type: string + showImage?: string + prompt: string + chinesePrompt?: string + imageUrl?: string + srefSw?: number + crefCw?: number + lora?: string + loraWeight?: number + isShow: boolean + children?: string + static schema: ObjectSchema = { + name: 'PresetModel', + properties: { + id: 'string', + label: 'string', + type: 'string', + showImage: 'string?', + imageUrl: 'string?', + prompt: 'string', + chinesePrompt: 'string?', + srefSw: 'int?', + crefCw: 'int?', + lora: 'string?', + loraWeight: 'int?', + isShow: 'bool', + children: 'string?' + }, + primaryKey: 'id' + } +} diff --git a/src/define/db/service/Book/bookBackTaskListService.ts b/src/define/db/service/Book/bookBackTaskListService.ts index 76ed356..3c68917 100644 --- a/src/define/db/service/Book/bookBackTaskListService.ts +++ b/src/define/db/service/Book/bookBackTaskListService.ts @@ -140,7 +140,8 @@ export class BookBackTaskListService extends BaseRealmService { taskType: BookBackTaskType, executeType = TaskExecuteType.AUTO, bookTaskId = null, - bookTaskDetailId = null + bookTaskDetailId = null, + responseMessageName: string = null ): GeneralResponse.SuccessItem | GeneralResponse.ErrorItem { try { // 通过bookid获取book信息 @@ -181,6 +182,7 @@ export class BookBackTaskListService extends BaseRealmService { status: BookBackTaskStatus.WAIT, createTime: new Date(), updateTime: new Date(), + messageName: responseMessageName, startTime: 0, endTime: 0 } as TaskModal.Task diff --git a/src/define/db/service/Book/bookBasic.ts b/src/define/db/service/Book/bookBasic.ts index 39adf13..68444b9 100644 --- a/src/define/db/service/Book/bookBasic.ts +++ b/src/define/db/service/Book/bookBasic.ts @@ -162,6 +162,20 @@ const migration = (oldRealm: Realm, newRealm: Realm) => { newBookTask[i].watermarkPosition = '[]' } } + if (oldRealm.schemaVersion < 23) { + const oldBookTask = oldRealm.objects('BookTaskDetail') + const newBookTask = newRealm.objects('BookTaskDetail') + for (let i = 0; i < oldBookTask.length; i++) { + newBookTask[i].subImagePath = '[]' + } + } + if (oldRealm.schemaVersion < 24) { + const oldBookTask = oldRealm.objects('BookBackTaskList') + const newBookTask = newRealm.objects('BookBackTaskList') + for (let i = 0; i < oldBookTask.length; i++) { + newBookTask[i].messageName = '' + } + } } export class BaseRealmService extends BaseService { @@ -203,7 +217,7 @@ export class BaseRealmService extends BaseService { BookTaskDetailModel ], path: this.dbpath, - schemaVersion: 22, + schemaVersion: 24, migration: migration } this.realm = await Realm.open(config) diff --git a/src/define/db/service/Book/bookService.ts b/src/define/db/service/Book/bookService.ts index 34f016c..4c8b240 100644 --- a/src/define/db/service/Book/bookService.ts +++ b/src/define/db/service/Book/bookService.ts @@ -195,6 +195,9 @@ export class BookService extends BaseRealmService { await CheckFolderExistsOrCreate(bookTaskImageFolder) // 创建默认的任务文件夹 // 修改数据 book.oldVideoPath = path.relative(define.project_path, oldVideoPath) + if (book.type == BookType.ORIGINAL) { + book.oldVideoPath = null + } let imageCategory = BookImageCategory.MJ if (book.type == BookType.SD_REVERSE) { diff --git a/src/define/db/service/Book/bookTaskDetailService.ts b/src/define/db/service/Book/bookTaskDetailService.ts index 5c7abe2..59a7f17 100644 --- a/src/define/db/service/Book/bookTaskDetailService.ts +++ b/src/define/db/service/Book/bookTaskDetailService.ts @@ -1,6 +1,6 @@ import Realm from 'realm' import path from 'path' -import { define } from '../../../define.js' +import { define } from '../../../define' import { BookTaskModel } from '../../model/Book/bookTask.js' import { successMessage } from '../../../../main/Public/generalTools' import { BaseRealmService } from './bookBasic' @@ -72,6 +72,7 @@ export class BookTaskDetailService extends BaseRealmService { return JoinPath(define.project_path, subImage) }), characterTags: item.characterTags ? item.characterTags.map((tag) => tag) : null, + sceneTags: item.sceneTags ? item.sceneTags.map((tag) => tag) : null, subValue: isEmpty(item.subValue) ? null : JSON.parse(item.subValue), reversePrompt: item.reversePrompt.map((reversePrompt) => { return { @@ -116,7 +117,7 @@ export class BookTaskDetailService extends BaseRealmService { * 添加一条小说任务对应的详细数据 * @param BookTaskDetail */ - public AddBookTaskDetail(bookTaskDetail) { + public AddBookTaskDetail(bookTaskDetail: Book.SelectBookTaskDetail) { try { // 判断是不是又小说ID if (isEmpty(bookTaskDetail.bookId) || isEmpty(bookTaskDetail.bookTaskId)) { @@ -191,7 +192,6 @@ export class BookTaskDetailService extends BaseRealmService { */ UpdateBookTaskDetailMjMessage(bookTaskDetailId: string, mjMessage: Book.MJMessage): void { try { - console.log('UpdateBookTaskDetailMjMessage', bookTaskDetailId, mjMessage) this.transaction(() => { let mjMessageRes = this.realm.objectForPrimaryKey('MJMessage', bookTaskDetailId) let bookTaskDetail = this.realm.objectForPrimaryKey('BookTaskDetail', bookTaskDetailId) diff --git a/src/define/db/service/Book/bookTaskService.ts b/src/define/db/service/Book/bookTaskService.ts index 1f93f90..662f136 100644 --- a/src/define/db/service/Book/bookTaskService.ts +++ b/src/define/db/service/Book/bookTaskService.ts @@ -1,6 +1,6 @@ import Realm from 'realm' import path from 'path' -import { define } from '../../../define.js' +import { define } from '../../../define' import { BookTaskModel } from '../../model/Book/bookTask.js' import { BookBackTaskStatus, BookImageCategory, BookTaskStatus } from '../../../enum/bookEnum.js' import { successMessage } from '../../../../main/Public/generalTools' diff --git a/src/define/db/service/SoftWare/imageStyleService.ts b/src/define/db/service/SoftWare/imageStyleService.ts new file mode 100644 index 0000000..61ec44a --- /dev/null +++ b/src/define/db/service/SoftWare/imageStyleService.ts @@ -0,0 +1,26 @@ +import Realm, { UpdateMode } from 'realm' +import path from 'path' +import { errorMessage, successMessage } from '../../../../main/Public/generalTools' +import { BaseSoftWareService } from './softwareBasic.js' +import { isEmpty } from 'lodash' +const { v4: uuidv4 } = require('uuid') + +export class ImageStyleService extends BaseSoftWareService { + static instance: ImageStyleService | null = null + realm: Realm + private constructor() { + super() + } + + /** + * 获取当前实例对象,为空则创建一个新的 + * @returns + */ + public static async getInstance() { + if (ImageStyleService.instance === null) { + ImageStyleService.instance = new ImageStyleService() + await super.getInstance() + } + return ImageStyleService.instance + } +} diff --git a/src/define/db/service/SoftWare/mjSettingService.ts b/src/define/db/service/SoftWare/mjSettingService.ts index c78b879..0bc7155 100644 --- a/src/define/db/service/SoftWare/mjSettingService.ts +++ b/src/define/db/service/SoftWare/mjSettingService.ts @@ -1,7 +1,7 @@ import Realm, { UpdateMode } from 'realm' import path from 'path' import { BaseService } from '../baseService' -import { define } from '../../../define.js' +import { define } from '../../../define' import { SoftwareModel } from '../../model/SoftWare/software' import { ComponentSize, SoftwareThemeType } from '../../../enum/softwareEnum.js' import { errorMessage, successMessage } from '../../../../main/Public/generalTools' diff --git a/src/define/db/service/SoftWare/softwareBasic.ts b/src/define/db/service/SoftWare/softwareBasic.ts index 0ffe2e2..7f6cc52 100644 --- a/src/define/db/service/SoftWare/softwareBasic.ts +++ b/src/define/db/service/SoftWare/softwareBasic.ts @@ -12,6 +12,7 @@ import { RemoteMJModel } from '../../model/SoftWare/mjSetting' import { MJImageType, MJRobotType } from '../../../enum/mjEnum' +import { PresetModel } from '../../model/SoftWare/preset' const { v4: uuidv4 } = require('uuid') let dbPath = path.resolve(define.db_path, 'software.realm') @@ -155,6 +156,9 @@ const migration = (oldRealm: Realm, newRealm: Realm) => { } }) } + if (oldRealm.schemaVersion < 22) { + + } } export class BaseSoftWareService extends BaseService { @@ -190,10 +194,11 @@ export class BaseSoftWareService extends BaseService { BrowserMJModel, RemoteMJModel, APIMjModel, - MjSettingModel + MjSettingModel, + PresetModel ], path: dbPath, - schemaVersion: 21, // 当前版本号 + schemaVersion: 23, // 当前版本号 migration: migration } // 判断当前全局是不是又当前这个 diff --git a/src/define/db/service/SoftWare/softwareService.ts b/src/define/db/service/SoftWare/softwareService.ts index 7e6d004..3cbfb41 100644 --- a/src/define/db/service/SoftWare/softwareService.ts +++ b/src/define/db/service/SoftWare/softwareService.ts @@ -25,15 +25,25 @@ export class SoftwareService extends BaseSoftWareService { } // 修改数据库中行中的某个属性数据 - UpdateSoftware(software: SoftwareSettingModel.SoftwareSetting): GeneralResponse.SuccessItem { - try { + UpdateSoftware(software: SoftwareSettingModel.SoftwareSetting) { + if (software.id) { this.realm.write(() => { this.realm.create('Software', software, UpdateMode.Modified) }) - // 返回成功信息 - return successMessage(null, '修改软件配置信息成功', 'SoftwareService_UpdateSoftware') - } catch (error) { - throw error + } else { + // 没有ID,就修改指定属性 + let softwareData = this.realm.objects('Software') + if (softwareData.length <= 0) { + throw new Error('数据库中没有软件配置信息') + } + let _software = softwareData[0] + this.realm.write(() => { + for (let key in software) { + if (software[key] != undefined) { + _software[key] = software[key] + } + } + }) } } diff --git a/src/define/define_string.ts b/src/define/define_string.ts index fa27741..f4d1cfe 100644 --- a/src/define/define_string.ts +++ b/src/define/define_string.ts @@ -1,4 +1,5 @@ export const DEFINE_STRING = { + SHOW_GLOBAL_MESSAGE: "SHOW_GLOBAL_MESSAGE", SHOW_GLOBAL_MAIN_NOTIFICATION: 'SHOW_GLOBAL_MAIN_NOTIFICATION', OPEN_DEV_TOOLS_PASSWORD: 'OPEN_DEV_TOOLS_PASSWORD', OPEN_DEV_TOOLS: 'OPEN_DEV_TOOLS', @@ -7,7 +8,7 @@ export const DEFINE_STRING = { GET_DEFINE_CONFIG_JSON_BY_PROPERTY: 'GET_DEFINE_CONFIG_JSON_BY_PROPERTY', GET_IMAGE_GENERATE_CATEGORY: 'GET_IMAGE_GENERATE_CATEGORY', SHOW_MAIN_NOTIFICATION: 'SHOW_MAIN_NOTIFICATION', - SHOW_GLOABAL_MESSAGE: 'SHOW_GLOABAL_MESSAGE', + SHOW_MAIN_MESSAGE: "SHOW_MAIN_MESSAGE", CHECK_MACHINE_ID: 'CHECK_MACHINE_ID', GET_CUSTOMIZE_GPT_PROMPT: 'GET_CUSTOMIZE_GPT_PROMPT', GENERATE_GPT_EXAMPLE_OUT: 'GENERATE_GPT_EXAMPLE_OUT', @@ -149,11 +150,19 @@ export const DEFINE_STRING = { TRANSLATE_NOW_RETURN: 'TRANSLATE_NOW_RETURN', GET_TRANSLATE_SETTING: 'GET_TRANSLATE_SETTING', RESET_TRANSLATE_SETTING: 'RESET_TRANSLATE_SETTING', - SAVE_TRANSLATE_SETTING: 'SAVE_TRANSLATE_SETTING' + SAVE_TRANSLATE_SETTING: 'SAVE_TRANSLATE_SETTING', + /** + * GPT 反推提示词翻译返回数据 + */ + GPT_PROMPT_TRANSLATE_RETRUN: "GPT_PROMPT_TRANSLATE_RETRUN" }, SD: { LOAD_SD_SERVICE_DATA: 'LOAD_SD_SERVICE_DATA', TXT2IMG: 'TXT2IMG', + + //#region SD生成图片相关 + + //#endregion }, MJ: { SAVE_WORD_SRT: 'SAVE_WORD_SRT', @@ -206,7 +215,6 @@ export const DEFINE_STRING = { }, BOOK: { MAIN_DATA_RETURN: 'MAIN_DATA_RETURN', // 监听任务返回 - REPLACE_VIDEO_CURRENT_FRAME: 'REPLACE_VIDEO_CURRENT_FRAME', GET_BOOK_TYPE: 'GET_BOOK_TYPE', ADD_OR_MODIFY_BOOK: 'ADD_OR_MODIFY_BOOK', @@ -243,6 +251,41 @@ export const DEFINE_STRING = { REMOVE_GENERATE_IMAGE: 'REMOVE_GENERATE_IMAGE', ADD_NEW_BOOK_TASK: "ADD_NEW_BOOK_TASK", REPLACE_BOOK_DATA: "REPLACE_BOOK_DATA", + SAVE_COPYWRITING: 'SAVE_COPYWRITING', + + //#region 原创推理提示词 + ORIGINAL_GPT_PROMPT: "ORIGINAL_GPT_PROMPT", + ORIGINAL_GPT_PROMPT_RETURN: "ORIGINAL_GPT_PROMPT_RETURN", + //#endregion + + //#region 生图返回相关 + + /** + * MJ生图返回信息 + */ + MJ_IMAGE_GENERATE_RETURN: 'MJ_IMAGE_GENERATE_RETURN', + + /** + * SD生图返回信息 + */ + SD_IMAGE_GENERATE_RETURN: 'SD_IMAGE_GENERATE_RETURN', + + /** + * D3 出图返回信息 + */ + D3_IMAGE_GENERATE_RETURN: 'D3_IMAGE_GENERATE_RETURN', + + /** + * flux forge 生图返回信息 + */ + FLUX_FORGE_IMAGE_GENERATE_RETURN: "FLUX_FORGE_IMAGE_GENERATE_RETURN", + + /** + * flux api 生图返回信息 + */ + FLUX_API_IMAGE_GENERATE_RETURN: "FLUX_API_IMAGE_GENERATE_RETURN", + + //#endregion COMPUTE_STORYBOARD: 'COMPUTE_STORYBOARD', @@ -290,6 +333,19 @@ export const DEFINE_STRING = { GET_PROMPT_SORT_DATA: 'GET_PROMPT_SORT_DATA', OPEN_PROMPT_FILE_TXT: 'OPEN_PROMPT_FILE_TXT' }, + /** + * IPC事件传递,预设相关 + */ + PRESET: { + /** + * 获取任务的预设(只获取 label 和 id) + */ + GET_CHARACTER_PRESET: 'GET_CHARACTER_PRESET', + /** + * 获取场景的预设(只获取 label 和 id) + */ + GET_SCENE_PRESET: "GET_SCENE_PRESET" + }, TTS: { GET_TTS_CONFIG: 'GET_TTS_CONFIG', GENERATE_AUDIO: 'GENERATE_AUDIO', @@ -309,6 +365,21 @@ export const DEFINE_STRING = { DB: { UPDATE_BOOK_TASK_DATA: "UPDATE_BOOK_TASK_DATA", UPDATE_BOOK_TASK_DETAIL_DATA: "UPDATE_BOOK_TASK_DETAIL_DATA", - UPDATE_BOOK_DATA: "UPDATE_BOOK_DATA" + UPDATE_BOOK_DATA: "UPDATE_BOOK_DATA", + UPDATE_SOFTWARE_SETTING: "UPDATE_SOFTWARE_SETTING" + }, + /** + * 后台任务相关 + */ + TASK: { + /** + * 添加单个后台任务 + */ + ADD_BOOK_BACK_TASK: "ADD_BOOK_BACK_TASK", + + /** + * 添加多个后台任务 + */ + ADD_MULTI_BOOK_BACK_TASK: 'ADD_MULTI_BOOK_BACK_TASK' } } diff --git a/src/define/enum/bookEnum.ts b/src/define/enum/bookEnum.ts index c3dba87..ae11971 100644 --- a/src/define/enum/bookEnum.ts +++ b/src/define/enum/bookEnum.ts @@ -1,6 +1,8 @@ export enum BookType { // 原创 ORIGINAL = 'original', + // 区分老版本的原创 + NEW_ORIGINAL = 'new_original', // 反推 SD_REVERSE = 'sd_reverse', // MJ 反推 @@ -14,7 +16,11 @@ export enum BookImageCategory { // SD SD = 'sd', // D3 - D3 = 'd3' + D3 = 'd3', + // FLUX API + FLUX_API = 'flux-api', + // FLUX FORGE + FLUX_FORGE = 'flux-forge' } export enum AddBookTaskCopyData { @@ -67,6 +73,10 @@ export enum BookBackTaskType { MJ_IMAGE = 'mj_image', // SD 生成图片 SD_IMAGE = 'sd_image', + // flux forge 生成图片 + FLUX_FORGE_IMAGE = 'flux_forge_image', + // flux api 生成图片 + FLUX_API_IMAGE = 'flux_api_image', // D3 生成图片 D3_IMAGE = 'd3_image', // 高清 @@ -256,3 +266,13 @@ export enum BookRepalceDataType { // 提示词 PROMPT = 'prompt', } + +/** + * 小说选择标签的方式类型,可以是下拉和标签 + */ +export enum BookTagSelectType { + // 下拉 + DROP = 'drop', + // 标签 + TAG = 'tag' +} diff --git a/src/define/enum/image.ts b/src/define/enum/image.ts index e69de29..0f5484f 100644 --- a/src/define/enum/image.ts +++ b/src/define/enum/image.ts @@ -0,0 +1,26 @@ + +/** + * Flux 调用API时候的 生图模型 + */ +export enum FLxuAPIImageType { + FLUX = "flux", + FLUX_PRO = "flux-pro", + FLUX_DEV = "flux-dev", + FLUX_SCHNELL = "flux-schnell", + FLUX_PRO_MAX = "flux-pro-max" +} + + +export enum PresetType { + // 角色 + CHARACTER = 'character', + + // 本地风格 + LOCAL_STYLE = 'localStyle', + + // 自定义风格 + CUSTOM_STYLE = 'customStyle', + + // laitool预设风格 + LAITOOL_STYLE = 'laitoolStyle', +} \ No newline at end of file diff --git a/src/define/enum/mjEnum.ts b/src/define/enum/mjEnum.ts index 1f08845..d82f312 100644 --- a/src/define/enum/mjEnum.ts +++ b/src/define/enum/mjEnum.ts @@ -9,7 +9,16 @@ export enum MJImageType { BROWSER_MJ = 'browser_mj', // API模式 - API_MJ = 'api_mj' + API_MJ = 'api_mj', + + // 本地 SD + LOCAL_SD = 'local_sd', + + // flux-api + FLUX_API = 'flux-api', + + // flxu-forge + FLUX_FORGE = 'flux-forge' } export enum MJRobotType { diff --git a/src/define/enum/preset.ts b/src/define/enum/preset.ts new file mode 100644 index 0000000..8a96ffc --- /dev/null +++ b/src/define/enum/preset.ts @@ -0,0 +1,16 @@ +/** + * 标签库预设的图片样式类型 + */ +export enum PresetType { + // 角色 + CHARACTER = 'character', + + // 本地风格 + LOCAL_STYLE = 'localStyle', + + // 自定义风格 + CUSTOM_STYLE = 'customStyle', + + // laitool预设风格 + LAITOOL_STYLE = 'laitoolStyle', +} \ No newline at end of file diff --git a/src/define/setting/imageSetting.js b/src/define/setting/imageSetting.js index e239128..dbfe520 100644 --- a/src/define/setting/imageSetting.js +++ b/src/define/setting/imageSetting.js @@ -1,245 +1,275 @@ -import { Tools } from "../../main/tools"; -import { define } from "../define"; -import path from "path"; -import { DEFINE_STRING } from "../define_string"; -import { get, has } from "lodash"; -let tools = new Tools(); -const { v4: uuidv4 } = require('uuid'); // 引入UUID库来生成唯一标识符 +import { Tools } from '../../main/tools' +import { define } from '../define' +import path from 'path' +import { DEFINE_STRING } from '../define_string' +import { get, has } from 'lodash' +let tools = new Tools() +const { v4: uuidv4 } = require('uuid') // 引入UUID库来生成唯一标识符 export const ImageSetting = { - - /** - * 获取自动保存图片的方式 - * @returns - */ - async GetAutoSaveImageClassifyOptions() { - return { - code: 1, - data: [{ - label: "不分类", - value: "one" - }, - // { - // label: "按模型", - // value: "model" - // }, - { - label: "按风格", - value: "style" - }, - { - label: "风格+模型", - value: "theme" - }] + /** + * 获取自动保存图片的方式 + * @returns + */ + async GetAutoSaveImageClassifyOptions() { + return { + code: 1, + data: [ + { + label: '不分类', + value: 'one' + }, + // { + // label: "按模型", + // value: "model" + // }, + { + label: '按风格', + value: 'style' + }, + { + label: '风格+模型', + value: 'theme' } - }, + ] + } + }, - /** - * 获取自动保存图片的方式(sd,mj,d3 等) - */ - async GetImageGenerateCategory() { - return { - code: 1, - data: [{ - label: "SD", - value: "sd" + /** + * 获取自动保存图片的方式(sd,mj,d3 等) + */ + async GetImageGenerateCategory() { + return { + code: 1, + data: [ + { + label: 'SD', + value: 'sd' + }, + { + label: 'MJ', + value: 'mj' + }, + { + label: 'D3', + value: 'd3' + }, + { + label: 'Flux-Forge', + value: 'flux-forge' + }, + { + label: 'Flux-API', + value: 'flux-api' + } + ] + } + }, + + /** + * 保存自动保存图片的设置 + */ + async SaveImageAutoSaveSetting(value) { + try { + value = JSON.parse(value) + await tools.writeJsonFilePropertyValue(define.img_base, 'auto_save_image', value) + return { + code: 1 + } + } catch (error) { + return { + code: 0, + message: error.toString() + } + } + }, + + /** + * 保存自动保存图片的设置 + */ + async GetImageAutoSaveSetting() { + try { + let res = await tools.getJsonFilePropertyValue(define.img_base, 'auto_save_image', {}, false) + return { + code: 1, + data: res + } + } catch (error) { + return { + code: 0, + message: error.toString() + } + } + }, + + /** + * 保存图片到指定文件夹,只是将任务添加到队列中 + */ + async SaveImageToOtherFolder(output = [], value) { + try { + let show = false + if (value) { + value = JSON.parse(value) + show = false + } else { + let auto_save_image = await tools.getJsonFilePropertyValue( + define.img_base, + 'auto_save_image', + {}, + false + ) + value = { + save_match_count: auto_save_image.save_match_count, + save_folder: auto_save_image.main_save_folder + } + if (!auto_save_image.auto_save) { + return { + code: 1 + } + } + } + + let batch = DEFINE_STRING.QUEUE_BATCH.IMAGE_SAVE_TO_OTHER_FOLDER + // 获取当前的所有的output文件夹 + if (output.length == 0) { + output = await tools.getSubFolderList( + path.join(global.config.project_path, 'tmp/bak/'), + 'start', + 'output_crop_' + ) + } + for (let i = 0; i < output.length; i++) { + const element = path.join(global.config.project_path, 'tmp/bak/' + output[i]) + // 获取指定的文件夹里面的文件 + let png_files = await tools.getFilesWithExtensions(element, '.png') + console.log(png_files) + // 判断当前的png_files中的数据是不是大于value.save_match_count,大于的话,删除数组里面的数据 + if (value.save_match_count && png_files.length > value.save_match_count) { + // 删除数组 + png_files.splice(value.save_match_count) + } + + for (let j = 0; j < png_files.length; j++) { + const item = png_files[j] + global.fileQueue.enqueue( + async () => { + // 复制文件到指定的文件夹 + let dst = path.join( + value.save_folder, + `${Date.now().toString()}_${uuidv4().split('-')[0]}.png` + ) + + await tools.copyFileOrDirectory(item, dst) }, - { - label: "MJ", - value: "mj" - }, - { - label: "D3", - value: "d3" - }] + `${batch}_${item}`, + batch + ) } - }, - - /** - * 保存自动保存图片的设置 - */ - async SaveImageAutoSaveSetting(value) { - try { - value = JSON.parse(value); - await tools.writeJsonFilePropertyValue(define.img_base, "auto_save_image", value); - return { - code: 1, - } - } catch (error) { - return { - code: 0, - message: error.toString() - } - } - }, - - /** - * 保存自动保存图片的设置 - */ - async GetImageAutoSaveSetting() { - try { - let res = await tools.getJsonFilePropertyValue(define.img_base, "auto_save_image", {}, false); - return { - code: 1, - data: res - } - } catch (error) { - return { - code: 0, - message: error.toString() - } - } - }, - - /** - * 保存图片到指定文件夹,只是将任务添加到队列中 - */ - async SaveImageToOtherFolder(output = [], value) { - try { - let show = false; - if (value) { - value = JSON.parse(value); - show = false; - } else { - let auto_save_image = await tools.getJsonFilePropertyValue(define.img_base, "auto_save_image", {}, false); - value = { - save_match_count: auto_save_image.save_match_count, - save_folder: auto_save_image.main_save_folder - } - if (!auto_save_image.auto_save) { - return { - code: 1 - } - } - } - - let batch = DEFINE_STRING.QUEUE_BATCH.IMAGE_SAVE_TO_OTHER_FOLDER; - // 获取当前的所有的output文件夹 - if (output.length == 0) { - output = await tools.getSubFolderList(path.join(global.config.project_path, "tmp/bak/"), "start", "output_crop_"); - } - for (let i = 0; i < output.length; i++) { - const element = path.join(global.config.project_path, 'tmp/bak/' + output[i]); - // 获取指定的文件夹里面的文件 - let png_files = await tools.getFilesWithExtensions(element, ".png"); - console.log(png_files); - // 判断当前的png_files中的数据是不是大于value.save_match_count,大于的话,删除数组里面的数据 - if (value.save_match_count && png_files.length > value.save_match_count) { - // 删除数组 - png_files.splice(value.save_match_count); - } - - for (let j = 0; j < png_files.length; j++) { - const item = png_files[j]; - global.fileQueue.enqueue(async () => { - // 复制文件到指定的文件夹 - let dst = path.join(value.save_folder, `${Date.now().toString()}_${uuidv4().split('-')[0]}.png`); - - await tools.copyFileOrDirectory(item, dst); - }, `${batch}_${item}`, batch) - } - } - global.fileQueue.setBatchCompletionCallback(batch, (failedTasks) => { - if (failedTasks.length > 0) { - let message = ` + } + global.fileQueue.setBatchCompletionCallback(batch, (failedTasks) => { + if (failedTasks.length > 0) { + let message = ` 转存任务都已完成。 但是以下任务执行失败: ` - failedTasks.forEach(({ taskId, error }) => { - message += `${taskId}-, \n 错误信息: ${error}` + '\n'; - }); + failedTasks.forEach(({ taskId, error }) => { + message += `${taskId}-, \n 错误信息: ${error}` + '\n' + }) - global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, { - code: 0, - message: message - }) - } else { - if (show) { - global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, { - code: 1, - message: "所有图片转存完成" - }) - } - } + global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, { + code: 0, + message: message + }) + } else { + if (show) { + global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, { + code: 1, + message: '所有图片转存完成' }) - - return { - code: 1 - } - - } catch (error) { - return { - code: 0, - message: error.toString() - } + } } - }, + }) - /** - * 获取指定的配置文件里面指定的属性的数据 - * @param {*} value 执行方法必要的信息 - * 0 define中的指定属性(指定的配置文件) - * 1 要获取的什么属性信息 property,property 为null,赶回当前配置文件的所有数据 - * 2 是不是要校验属性不存在 - * 3 属性没有找到的默认值 - * @returns - */ - async GetDefineConfigJsonByProperty(value) { - try { - value = JSON.parse(value); - let defin_property = value[0]; - let property = value[1]; - let need_check = value[2]; - let default_data = value[3]; - // 判断define中的属性是不是存在 - let hasProperty = has(define, defin_property); - if (!hasProperty) { - throw new Error(`${defin_property} 属性不存在。`); - } - let data = await tools.getJsonFilePropertyValue(define[defin_property], property, default_data, need_check); - return { - code: 1, - data: data - } - } catch (error) { - return { - code: 0, - message: "获取配置信息失败,错误信息入下 : " + error.message.toString() - } - } - }, - - /** - * 保存指定的配置文件里面指定的属性的数据 - * @param {*} value - * 0 define中的指定属性(指定的配置文件) - * 1 要获取的什么属性信息 property,property 为null,赶回当前配置文件的所有数据 - * 2 要写入的值 - * 3 是不是要校验属性不存在 - */ - async SaveDefineConfigJsonByProperty(value) { - try { - value = JSON.parse(value); - let defin_property = value[0]; - let property = value[1]; - let data = value[2]; - let need_check = value[3] ? value[3] : false; - // 判断define中的属性是不是存在 - let hasProperty = has(define, defin_property); - if (!hasProperty) { - throw new Error(`${defin_property} 属性不存在。`); - } - await tools.writeJsonFilePropertyValue(define[defin_property], property, data, need_check); - return { - code: 1, - message: "保存指定的配置成功" - } - } catch (error) { - return { - code: 0, - message: "保存配置信息失败,错误信息入下 : " + error.message.toString() - } - } + return { + code: 1 + } + } catch (error) { + return { + code: 0, + message: error.toString() + } } + }, -} \ No newline at end of file + /** + * 获取指定的配置文件里面指定的属性的数据 + * @param {*} value 执行方法必要的信息 + * 0 define中的指定属性(指定的配置文件) + * 1 要获取的什么属性信息 property,property 为null,赶回当前配置文件的所有数据 + * 2 是不是要校验属性不存在 + * 3 属性没有找到的默认值 + * @returns + */ + async GetDefineConfigJsonByProperty(value) { + try { + value = JSON.parse(value) + let defin_property = value[0] + let property = value[1] + let need_check = value[2] + let default_data = value[3] + // 判断define中的属性是不是存在 + let hasProperty = has(define, defin_property) + if (!hasProperty) { + throw new Error(`${defin_property} 属性不存在。`) + } + let data = await tools.getJsonFilePropertyValue( + define[defin_property], + property, + default_data, + need_check + ) + return { + code: 1, + data: data + } + } catch (error) { + return { + code: 0, + message: '获取配置信息失败,错误信息入下 : ' + error.message.toString() + } + } + }, + + /** + * 保存指定的配置文件里面指定的属性的数据 + * @param {*} value + * 0 define中的指定属性(指定的配置文件) + * 1 要获取的什么属性信息 property,property 为null,赶回当前配置文件的所有数据 + * 2 要写入的值 + * 3 是不是要校验属性不存在 + */ + async SaveDefineConfigJsonByProperty(value) { + try { + value = JSON.parse(value) + let defin_property = value[0] + let property = value[1] + let data = value[2] + let need_check = value[3] ? value[3] : false + // 判断define中的属性是不是存在 + let hasProperty = has(define, defin_property) + if (!hasProperty) { + throw new Error(`${defin_property} 属性不存在。`) + } + await tools.writeJsonFilePropertyValue(define[defin_property], property, data, need_check) + return { + code: 1, + message: '保存指定的配置成功' + } + } catch (error) { + return { + code: 0, + message: '保存配置信息失败,错误信息入下 : ' + error.message.toString() + } + } + } +} diff --git a/src/main/IPCEvent/bookIpc.ts b/src/main/IPCEvent/bookIpc.ts index 9f947be..5b01401 100644 --- a/src/main/IPCEvent/bookIpc.ts +++ b/src/main/IPCEvent/bookIpc.ts @@ -14,6 +14,7 @@ import { SubtitleService } from '../Service/Subtitle/subtitleService' import { BookFrame } from '../Service/Book/bookFrame' import { BookPrompt } from '../Service/Book/bookPrompt' import { BookGeneral } from '../Service/Book/bookGeneral' +import { OperateBookType } from '../../define/enum/bookEnum' let reverseBook = new ReverseBook() let basicReverse = new BasicReverse() let subtitle = new Subtitle() @@ -141,16 +142,30 @@ export function BookIpc() { async (event, id, operateBookType) => await bookPrompt.RemoveMergePromptData(id, operateBookType) ) + // 原创推理提示词 + ipcMain.handle( + DEFINE_STRING.BOOK.ORIGINAL_GPT_PROMPT, + async (event, id: string, operateBookType: OperateBookType, coverData: boolean) => + await bookPrompt.OriginalGetPrompt(id, operateBookType, coverData) + ) + //#endregion //#region 文案相关 - // 开始执行获取小说文案的方法 + // 开始执行反推获取小说文案的方法 ipcMain.handle( DEFINE_STRING.BOOK.GET_COPYWRITING, async (event, bookId, bookTaskId, operateBookType, coverData) => await subtitleService.GetCopywriting(bookId, bookTaskId, operateBookType, coverData) ) + // 导入文案和字幕对齐数据的方法,保存到数据库中 + ipcMain.handle( + DEFINE_STRING.BOOK.SAVE_COPYWRITING, + async (event, bookTaskId, copywritingData, operateBookType) => await subtitleService.SaveCopywriting(bookTaskId, copywritingData, operateBookType) + ) + + // 获取小说的文案数据,然后保存到对应的文件中 ipcMain.handle( DEFINE_STRING.BOOK.EXPORT_COPYWRITING, diff --git a/src/main/IPCEvent/dbIpc.ts b/src/main/IPCEvent/dbIpc.ts index 34af968..a93099c 100644 --- a/src/main/IPCEvent/dbIpc.ts +++ b/src/main/IPCEvent/dbIpc.ts @@ -5,12 +5,14 @@ import { Book } from '../../model/book' import { BookTaskService } from '../../define/db/service/Book/bookTaskService' import { BookTaskDetailService } from '../../define/db/service/Book/bookTaskDetailService' import { BookService } from '../../define/db/service/Book/bookService' +import { SoftWareServiceBasic } from '../Service/ServiceBasic/softwareServiceBasic' async function DBIpc() { let bookTaskService = await BookTaskService.getInstance() let bookTaskDetailService = await BookTaskDetailService.getInstance() let bookService = await BookService.getInstance() + let softWareServiceBasic = new SoftWareServiceBasic() //#region 小说相关的修改 // 修改小说任务的数据 @@ -47,5 +49,18 @@ async function DBIpc() { //#endregion + + //#region 软件设置的修改 + + // 修改软件设置 + ipcMain.handle(DEFINE_STRING.DB.UPDATE_SOFTWARE_SETTING, async (event, software: SoftwareSettingModel.SoftwareSetting) => { + try { + await softWareServiceBasic.UpdateSoftware(software) + return successMessage(null, "修改软件配置信息成功", "DBIpc_UpdateSoftwareSetting") + } catch (error) { + return errorMessage("修改软件配置信息失败", "DBIpc_UpdateSoftwareSetting") + } + }) + //#endregion } export { DBIpc } diff --git a/src/main/IPCEvent/globalIpc.js b/src/main/IPCEvent/globalIpc.js index 27ef707..5efc275 100644 --- a/src/main/IPCEvent/globalIpc.js +++ b/src/main/IPCEvent/globalIpc.js @@ -46,6 +46,11 @@ function GlobalIpc() { ipcMain.on(DEFINE_STRING.SHOW_GLOBAL_MAIN_NOTIFICATION, (event, value) => { global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MAIN_NOTIFICATION, value) }) + + // 监听打开message事件 + ipcMain.on(DEFINE_STRING.SHOW_GLOBAL_MESSAGE, (event, value) => { + global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MAIN_MESSAGE, value) + }) } export { GlobalIpc } diff --git a/src/main/IPCEvent/index.js b/src/main/IPCEvent/index.js index 12c5c8d..68861f0 100644 --- a/src/main/IPCEvent/index.js +++ b/src/main/IPCEvent/index.js @@ -15,6 +15,8 @@ import { SystemIpc } from './systemIpc.js' import { BookIpc } from './bookIpc' import { TTSIpc } from './ttsIpc.js' import { DBIpc } from './dbIpc' +import { PresetIpc } from './presetIpc' +import { TaskIpc } from './taskIpc' export async function RegisterIpc(createWindow) { PromptIpc() @@ -26,6 +28,8 @@ export async function RegisterIpc(createWindow) { GptIpc() SdIpc() await DBIpc() + PresetIpc() + TaskIpc() MjIpc() MainIpc(createWindow) OriginalImageGenerateIpc() diff --git a/src/main/IPCEvent/mjIpc.js b/src/main/IPCEvent/mjIpc.js index 9234023..87d1c49 100644 --- a/src/main/IPCEvent/mjIpc.js +++ b/src/main/IPCEvent/mjIpc.js @@ -141,7 +141,8 @@ function MjIpc() { // MJ出单张图 ipcMain.handle( DEFINE_STRING.MJ.ADD_MJ_GENADD_MJ_GENERATE_IMAGE_TASK, - async (event, id, operateBookType) => await mjOpt.AddMJGenerateImageTask(id, operateBookType) + async (event, id, operateBookType, responseMessageName, coverData) => + await mjOpt.AddMJGenerateImageTask(id, operateBookType, responseMessageName, coverData) ) } diff --git a/src/main/IPCEvent/presetIpc.ts b/src/main/IPCEvent/presetIpc.ts new file mode 100644 index 0000000..9596350 --- /dev/null +++ b/src/main/IPCEvent/presetIpc.ts @@ -0,0 +1,19 @@ +import { ipcMain } from 'electron' +import { DEFINE_STRING } from '../../define/define_string' +import { PresetService } from '../Service/presetService' +let presetService = new PresetService() +function PresetIpc() { + + // 获取人物的预设(只获取 lable 和 id) + ipcMain.handle( + DEFINE_STRING.PRESET.GET_CHARACTER_PRESET, + async (event) => await presetService.GetCharacterPreset() + ) + + // 获取场景的预设(只获取 lable 和 id) + ipcMain.handle( + DEFINE_STRING.PRESET.GET_SCENE_PRESET, + async (event) => await presetService.GetScenePreset() + ) +} +export { PresetIpc } diff --git a/src/main/IPCEvent/settingIpc.js b/src/main/IPCEvent/settingIpc.js index 0e74895..bd5fb2f 100644 --- a/src/main/IPCEvent/settingIpc.js +++ b/src/main/IPCEvent/settingIpc.js @@ -151,14 +151,14 @@ async function SettingIpc() { //#endregion - //#region 基础设置 + //#region 基础设置(数据库) // 获取软件的基础设置(初始的时候执行一次) ipcMain.handle( DEFINE_STRING.SETTING.GET_SOFTWARE_SETTING, async (event) => await basicSetting.GetSoftwareSetting() ) - // 保存软件的基础设置 + // 保存软件的通用设置 ipcMain.handle( DEFINE_STRING.SETTING.SAVE_SOFT_WARE_SETTING, async (event, value) => await basicSetting.SaveSoftWareSetting(value) diff --git a/src/main/IPCEvent/taskIpc.ts b/src/main/IPCEvent/taskIpc.ts new file mode 100644 index 0000000..7aee10c --- /dev/null +++ b/src/main/IPCEvent/taskIpc.ts @@ -0,0 +1,39 @@ +import { ipcMain } from "electron" +import { BookServiceBasic } from "../Service/ServiceBasic/bookServiceBasic" +import { DEFINE_STRING } from "../../define/define_string"; +import { errorMessage, successMessage } from "../Public/generalTools"; +import { BookBackTaskType, TaskExecuteType } from "../../define/enum/bookEnum"; + +let bookServiceBasic = new BookServiceBasic(); + +function TaskIpc() { + + /** + * 添加后台任务,单个 + */ + ipcMain.handle(DEFINE_STRING.TASK.ADD_BOOK_BACK_TASK, async (event, bookId: string, taskType: BookBackTaskType, executeType: TaskExecuteType, bookTaskId: string, bookTaskDetailId: string, responseMessageName: string) => { + try { + let res = await bookServiceBasic.AddBookBackTask(bookId, taskType, executeType, bookTaskId, bookTaskDetailId, responseMessageName) + return successMessage(res, `添加 ${taskType} 任务成功`, 'TaskIpc_AddBookBackTask'); + } catch (error) { + return errorMessage(`添加 ${taskType} 任务失败,错误信息如下:${error.toString()} `, 'TaskIpc_AddBookBackTask') + } + }) + + /** + * 添加多个后台任务 + */ + ipcMain.handle(DEFINE_STRING.TASK.ADD_MULTI_BOOK_BACK_TASK, async (event, tasks: TaskModal.Task[]) => { + try { + for (let i = 0; i < tasks.length; i++) { + const element = tasks[i]; + let res = await bookServiceBasic.AddBookBackTask(element.bookId, element.type, element.executeType, element.bookTaskId, element.bookTaskDetailId, element.messageName) + } + return successMessage(null, `添加多个任务成功`, 'TaskIpc_AddMultiBookBackTask'); + } catch (error) { + return errorMessage(`添加多个任务失败,错误信息如下:${error.toString()} `, 'TaskIpc_AddMultiBookBackTask') + } + }) +} + +export { TaskIpc } \ No newline at end of file diff --git a/src/main/Original/MJOriginalImageGenerate.js b/src/main/Original/MJOriginalImageGenerate.js index f9c8a56..061ec3b 100644 --- a/src/main/Original/MJOriginalImageGenerate.js +++ b/src/main/Original/MJOriginalImageGenerate.js @@ -92,10 +92,9 @@ export class MJOriginalImageGenerate { LOGGER_DEFINE.ORIGINAL_AUTO_MATCH_USER ) } - + let result = [] for (let i = 0; i < value.length; i++) { const element = value[i] - let res_data = { code: 1, id: element.id, // 当前 data 的ID @@ -104,13 +103,12 @@ export class MJOriginalImageGenerate { // 获取当前的字幕数据 let temp_sub = [] - for (let j = 0; element.suValue && j < element.suValue.length; j++) { - const element = array[j] - temp_sub.push(element.srt_value) + for (let j = 0; element.subValue && j < element.subValue.length; j++) { + temp_sub.push(element.subValue[j].srt_value) } let word = '' if (temp_sub.length == 0) { - word = element.after_gpt + word = element.after_gpt ? element.after_gpt : element.afterGpt } else { word = temp_sub.join(',') } @@ -144,11 +142,11 @@ export class MJOriginalImageGenerate { res_data.match_character.push(temp_item_data) } } - + result.push(res_data) // 开始往前端传递数据 this.sendChangeMessage(res_data, DEFINE_STRING.MJ.MACTH_USER_RETURN) } - return successMessage(null, '人物标签自动匹配完成', LOGGER_DEFINE.ORIGINAL_AUTO_MATCH_USER) + return successMessage(result, '人物标签自动匹配完成', LOGGER_DEFINE.ORIGINAL_AUTO_MATCH_USER) } catch (error) { return errorMessage( '通过文本自动匹配数据错误,错误信息如下:' + error.message, diff --git a/src/main/Public/generalTools.ts b/src/main/Public/generalTools.ts index a7b25aa..6162f57 100644 --- a/src/main/Public/generalTools.ts +++ b/src/main/Public/generalTools.ts @@ -1,3 +1,4 @@ +import { DEFINE_STRING } from '../../define/define_string' import { GeneralResponse } from '../../model/generalResponse' /** @@ -104,11 +105,21 @@ function errorMessage(message: string, service?: string): GeneralResponse.ErrorI } } +/** + * 主动发送消息到前端,用作数据返回 + * @param data 要返回的数据 + * @param message_name 消息名称 + */ +function SendReturnMessage(data: GeneralResponse.MessageResponse, message_name: string = DEFINE_STRING.BOOK.GET_COPYWRITING_RETURN) { + global.newWindow[0].win.webContents.send(message_name, data) +} + export { checkStringValueAddSuffix, checkStringValueAddPrefix, checkStringValueDeletePrefix, checkStringValueDeleteSuffix, successMessage, - errorMessage + errorMessage, + SendReturnMessage } diff --git a/src/main/Service/Book/BooKBasic.ts b/src/main/Service/Book/BooKBasic.ts index d6034c6..89643bd 100644 --- a/src/main/Service/Book/BooKBasic.ts +++ b/src/main/Service/Book/BooKBasic.ts @@ -138,10 +138,13 @@ export class BookBasic { watermarkPosition: undefined, }) // 文件重置,获取data下面的所有的子文件夹,删除所有的文件夹 - let dirs = await GetSubdirectories(path.join(book.bookFolderPath, 'data')) - for (let i = 0; i < dirs.length; i++) { - const element = dirs[i]; - await DeleteFolderAllFile(element, true) + let bookData = path.join(book.bookFolderPath, 'data'); + if (await CheckFileOrDirExist(bookData)) { + let dirs = await GetSubdirectories(bookData) + for (let i = 0; i < dirs.length; i++) { + const element = dirs[i]; + await DeleteFolderAllFile(element, true) + } } let scriptPath = path.join(book.bookFolderPath, 'script') if (await CheckFileOrDirExist(scriptPath)) { diff --git a/src/main/Service/Book/ReverseBook.ts b/src/main/Service/Book/ReverseBook.ts index a93ce8b..f9b3324 100644 --- a/src/main/Service/Book/ReverseBook.ts +++ b/src/main/Service/Book/ReverseBook.ts @@ -2,7 +2,7 @@ import { successMessage, errorMessage } from '../../Public/generalTools' import { BookBasic } from './BooKBasic' import { BookService } from '../../../define/db/service/Book/bookService' import { BookTaskService } from '../../../define/db/service/Book/bookTaskService' -import { define } from '../../../define/define.js' +import { define } from '../../../define/define' import fs from 'fs' import { DEFINE_STRING } from "../../../define/define_string"; import path from 'path' @@ -299,6 +299,7 @@ export class ReverseBook { // TODO SD反推,待重写 async SDReversePrompt(task: TaskModal.Task): Promise { + console.log("SDReversePrompt", '') return successMessage(null, "", "ReverseBook_SDReversePrompt") } diff --git a/src/main/Service/Book/bookImage.ts b/src/main/Service/Book/bookImage.ts index b249345..0ba205a 100644 --- a/src/main/Service/Book/bookImage.ts +++ b/src/main/Service/Book/bookImage.ts @@ -12,6 +12,7 @@ import { isEmpty } from "lodash"; import { DEFINE_STRING } from "../../../define/define_string"; import { ResponseMessageType } from "../../../define/enum/softwareEnum"; import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic"; +import fs from 'fs' import util from 'util' import { exec } from 'child_process' const execAsync = util.promisify(exec); @@ -44,7 +45,7 @@ export class BookImage { * @param id * @param operateBookType */ - async ResetGenerateImage(id: string, operateBookType: OperateBookType): Promise { + async ResetGenerateImage(id: string, operateBookType: OperateBookType, coverData: boolean): Promise { try { let bookTaskDetails = undefined as Book.SelectBookTaskDetail[] let bookTask = undefined as Book.SelectBookTask @@ -56,11 +57,15 @@ export class BookImage { } else { throw new Error('不支持的操作类型,请检查') } + //这边过滤被锁定的数据 + if (!coverData) { + bookTaskDetails = bookTaskDetails.filter(item => !item.imageLock) + } + if (bookTaskDetails.length <= 0) { throw new Error('没有要删除的分镜数据,请检查') } - // 开始删除数据,要删除图片数据和出图的信息 for (let i = 0; i < bookTaskDetails.length; i++) { const element = bookTaskDetails[i]; @@ -69,12 +74,18 @@ export class BookImage { } else if (bookTask.imageCategory == BookImageCategory.D3) { throw new Error('暂时不支持D3生成的图片删除') } else if (bookTask.imageCategory == BookImageCategory.SD) { - throw new Error('暂时不支持SD生成的图片删除') + await this.bookServiceBasic.DeleteBoookTaskDetailGenerateImage(element.id); } else { throw new Error('未知的小说类型,请检查') } + // 上面的信息重置完毕之后,开始删除文件信息 + let outImage = element.outImagePath; + if (await CheckFileOrDirExist(outImage)) { + await fs.promises.unlink(outImage) + } } - return successMessage(bookTask.imageCategory, "删除所有的生图数据成功", "BookImage_ResetGenerateImage") + + return successMessage(bookTaskDetails, "删除所有的生图数据成功", "BookImage_ResetGenerateImage") } catch (error) { return errorMessage("删除所有的图片数据失败,失败信息如下:" + error.toString(), "BookImage_ResetGenerateImage") } diff --git a/src/main/Service/Book/bookPrompt.ts b/src/main/Service/Book/bookPrompt.ts index 86e3bf8..8ac9db7 100644 --- a/src/main/Service/Book/bookPrompt.ts +++ b/src/main/Service/Book/bookPrompt.ts @@ -2,15 +2,21 @@ import { isEmpty } from "lodash"; import { BookType, OperateBookType } from "../../../define/enum/bookEnum"; import { Book } from "../../../model/book"; import { GeneralResponse } from "../../../model/generalResponse"; -import { errorMessage, successMessage } from "../../Public/generalTools"; +import { errorMessage, SendReturnMessage, successMessage } from "../../Public/generalTools"; import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic"; +import { GptService } from "../GPT/gpt"; +import { ExecuteConcurrently } from "../../../define/Tools/common"; +import { DEFINE_STRING } from "../../../define/define_string"; export class BookPrompt { bookServiceBasic: BookServiceBasic + gptService: GptService constructor() { this.bookServiceBasic = new BookServiceBasic() + this.gptService = new GptService() } + //#region 反推的提示词相关 /** * 将MJ反推出来的数据,选择指定的写入到GPT提示词中 * @param bookId 小说的ID @@ -39,7 +45,7 @@ export class BookPrompt { emptyName.push(element.name) continue; } - let reversePrompt = reversePrompts[index - 1] + let reversePrompt = reversePrompts[index - 1] let gptPrompt = undefined if (!isEmpty(reversePrompt.promptCN) && reversePrompt.promptCN != "") { gptPrompt = reversePrompt.promptCN @@ -102,7 +108,16 @@ export class BookPrompt { await this.bookServiceBasic.DeleteBookTaskDetailReversePromptById(element.id); } } else if (type == BookType.ORIGINAL) { - throw new Error("原创小说删除还不支持") + // 原创删除所有的反推提示词数据 + this.bookServiceBasic.transaction(async (realm) => { + for (let i = 0; i < bookTaskDetails.length; i++) { + const element = bookTaskDetails[i]; + let btd = realm.objectForPrimaryKey('BookTaskDetail', element.id) + if (btd) { + btd.gptPrompt = undefined + } + } + }) } else if (type == BookType.SD_REVERSE) { } else { throw new Error("SD反推删除还不支持") @@ -149,5 +164,98 @@ export class BookPrompt { } } + //#endregion + //#region 原创的提示词相关 + + /** + * 原创推理提示词 + * @param id 要推理的ID + * @param operateBookType 操作的类型 + * @param coverData 是不是要覆盖数据(用于推理空白提示词) + */ + async OriginalGetPrompt(id: string, operateBookType: OperateBookType, coverData: boolean): Promise { + try { + let bookTask = undefined as Book.SelectBookTask + let bookTaskDetails = undefined as Book.SelectBookTaskDetail[] + let allBookTaskDetails = undefined as Book.SelectBookTaskDetail[] + + if (operateBookType == OperateBookType.BOOKTASK) { + bookTask = await this.bookServiceBasic.GetBookTaskDataById(id) + allBookTaskDetails = await this.bookServiceBasic.GetBookTaskDetailData({ + bookTaskId: id + }) + if (!coverData) { // 不覆盖数据,只推理空白提示词 + bookTaskDetails = allBookTaskDetails.filter(item => isEmpty(item.gptPrompt)) + } else { // 不覆盖,就是全部 + bookTaskDetails = allBookTaskDetails; + } + } else if (operateBookType == OperateBookType.BOOKTASKDETAIL) { + let singleBookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(id) + bookTask = await this.bookServiceBasic.GetBookTaskDataById(singleBookTaskDetail.bookTaskId) + bookTaskDetails = [singleBookTaskDetail] + } else if (operateBookType == OperateBookType.UNDERBOOKTASK) { + let singleBookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(id) + bookTask = await this.bookServiceBasic.GetBookTaskDataById(singleBookTaskDetail.bookTaskId) + // 开始计算上下文数据 + allBookTaskDetails = await this.bookServiceBasic.GetBookTaskDetailData({ + bookTaskId: bookTask.id + }) + for (let i = 0; i < allBookTaskDetails.length; i++) { + const element = allBookTaskDetails[i]; + if (!bookTaskDetails) { + bookTaskDetails = [] + } + if (i + 1 >= singleBookTaskDetail.no) { + bookTaskDetails.push(element) + } + } + } else { + throw new Error('未知的操作类型'); + } + if (!allBookTaskDetails) { + allBookTaskDetails = await this.bookServiceBasic.GetBookTaskDetailData({ + bookTaskId: bookTask.id + }) + } + + if (bookTaskDetails.length <= 0) { + throw new Error('没有找到要推理的分镜数据') + } + + let tasks = [] as Array<() => Promise> + // 添加异步任务 + for (let i = 0; i < bookTaskDetails.length; i++) { + const element = bookTaskDetails[i]; + tasks.push(async () => { + let content = await this.gptService.OriginalInferencePrompt(element, allBookTaskDetails, global.config.gpt_count, bookTask.autoAnalyzeCharacter) + // 修改推理出来的数据 + await this.bookServiceBasic.UpdateBookTaskDetail(element.id, { + gptPrompt: content + }) + // 每次完成,都要向前端返回信息 + SendReturnMessage({ + code: 1, + id: element.id, + data: { + content: content, + progress: { + current: i, + total: bookTaskDetails.length + } as GeneralResponse.ProgressResponse + } + }, DEFINE_STRING.BOOK.ORIGINAL_GPT_PROMPT_RETURN); + }) + } + // 分批次执行异步任务 + let res = await ExecuteConcurrently(tasks, global.config.task_number) + // 执行完毕 + return successMessage(null, "推理所有数据完成", 'BookPrompt_OriginalGetPrompt') + + } catch (error) { + return errorMessage("原创推理提示词失败,错误信息: " + error.toString(), 'BookPrompt_OriginalGetPrompt') + } + } + + //#endregion } \ No newline at end of file diff --git a/src/main/Service/Flux/flux.ts b/src/main/Service/Flux/flux.ts new file mode 100644 index 0000000..795aa67 --- /dev/null +++ b/src/main/Service/Flux/flux.ts @@ -0,0 +1,341 @@ +import { define } from '../../../define/define' +import fs from "fs"; +import { ImageStyle } from "../Book/imageStyle"; +import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic"; +import { isEmpty } from 'lodash'; +import axios from 'axios'; +const fspromise = fs.promises +import path from 'path' +import { CheckFolderExistsOrCreate, CopyFileOrFolder, DeleteFileExifData } from '../../../define/Tools/file'; +import { Base64ToFile, GetImageBase64 } from '../../../define/Tools/image'; +import { BookBackTaskStatus } from '../../../define/enum/bookEnum'; +import { MJAction, MJImageType } from '../../../define/enum/mjEnum'; +import { GptService } from '../GPT/gpt'; + +export class FluxOpt { + gptService: GptService + bookServiceBasic: BookServiceBasic + constructor() { + this.bookServiceBasic = new BookServiceBasic() + this.gptService = new GptService() + } + + + // TODO 这边的设置应该改为数据库 + /** + * 获取SD的设置,之后要删掉,改为数据库 + */ + private async GetSDSetting() { + let sdSetting = JSON.parse(await fspromise.readFile(define.sd_setting, 'utf-8')) + return sdSetting + } + + + //#region flux forge 生图 + /** + * 使用flux forge生图 + * @param task + */ + async FluxForgeImage(task: TaskModal.Task): Promise { + let sdSetting = undefined + try { + // 开始生图 + sdSetting = await this.GetSDSetting() + + let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(task.bookTaskDetailId); + let bookTask = await this.bookServiceBasic.GetBookTaskDataById(bookTaskDetail.bookTaskId); + let book = await this.bookServiceBasic.GetBookDataById(bookTask.bookId); + + let prompt = bookTaskDetail.prompt; + let url = sdSetting.setting.webui_api_url + if (url.endsWith('/')) { + url = url + "sdapi/v1/txt2img" + } else { + url = url + "/sdapi/v1/txt2img" + } + if (!isEmpty(sdSetting.webui.prompt)) { + prompt = sdSetting.webui.prompt + ', ' + prompt + } + + // 判断当前是不是有开修脸修手 + let ADetailer = { + args: sdSetting.adetailer + } + + // 种子默认 -1,随机 + let seed = -1; + let body = { + scheduler: 'Simple', + prompt: prompt, + seed: seed, + sampler_name: sdSetting.webui.sampler_name, + // 提示词相关性 + cfg_scale: sdSetting.webui.cfg_scale, + distilled_cfg_scale: 3.5, + width: sdSetting.webui.width, + height: sdSetting.webui.height, + batch_size: sdSetting.setting.batch_size, + steps: sdSetting.webui.steps, + save_images: false, + tiling: false, + override_settings_restore_afterwards: true + } + + if (bookTaskDetail.adetailer) { + body['alwayson_scripts'] = { + "ADetailer": ADetailer + } + } + + const response = await axios.post(url, body) + // TODO 对SD图片种子的一些处理,待定 + // let info = JSON.parse(res.data.info) + // if (seed == -1) { + // seed = info.seed + // } + let images = response.data.images + let SdOriginalImage = path.join(book.bookFolderPath, 'data/SdOriginalImage'); + await CheckFolderExistsOrCreate(SdOriginalImage); + let outputFolder = bookTask.imageFolder; + await CheckFolderExistsOrCreate(outputFolder); + let inputFolder = path.join(book.bookFolderPath, 'tmp/input') + await CheckFolderExistsOrCreate(inputFolder); + + let subImagePath = [] + let outImagePath = '' + // 开始写出图片 + for (let i = 0; i < images.length; i++) { + const element = images[i]; + // 包含info信息的图片地址 + let infoImgPath = path.join(SdOriginalImage, `info_${bookTaskDetail.name}_${new Date().getTime()}_${i}.png`) + // 不包含info信息的图片地址 + let imgPath = path.join(SdOriginalImage, `${bookTaskDetail.name}_${new Date().getTime()}_${i}.png`) + await Base64ToFile(element, infoImgPath) + // 这边去图片信息 + await DeleteFileExifData(path.join(define.package_path, 'exittool/exiftool.exe'), infoImgPath, imgPath); + // 写出去 + if (bookTask.name == 'output_00001') { + // 复制一个到input + let inputImgPath = path.join(inputFolder, `${bookTaskDetail.name}.png`) + await CopyFileOrFolder(imgPath, inputImgPath) + } + if (i == 0) { + // 复制到对应的文件夹里面 + let outPath = path.join(outputFolder, `${bookTaskDetail.name}.png`) + await CopyFileOrFolder(imgPath, outPath) + outImagePath = outPath + } + subImagePath.push(imgPath) + } + // 修改数据库 + await this.bookServiceBasic.UpdateBookTaskDetail(bookTaskDetail.id, { + outImagePath: path.relative(define.project_path, outImagePath), + subImagePath: subImagePath.map((item) => path.relative(define.project_path, item)) + }) + await this.bookServiceBasic.UpdateTaskStatus({ + id: task.id, + status: BookBackTaskStatus.DONE + }); + let resp = { + mjApiUrl: url, + progress: 100, + category: MJImageType.FLUX_FORGE, + imageClick: subImagePath.join(','), + imageShow: subImagePath.join(','), + messageId: "", + action: MJAction.IMAGINE, + status: "success", + subImagePath: subImagePath, + outImagePath: outImagePath, + message: "FLUX FORGE 生成图片成功" + } + await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, resp) + global.newWindow[0].win.webContents.send(task.messageName, { + code: 1, + message: "FLUX FORGE 生成图片成功", + data: { + ...resp, + id: bookTaskDetail.id + } + }) + } catch (error) { + let errorMsg = "FLUX FORGE 生成图片失败,错误信息如下:" + error.toString() + await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, { + mjApiUrl: sdSetting ? sdSetting.setting.webui_api_url : "", + progress: 0, + category: MJImageType.FLUX_FORGE, + imageClick: "", + imageShow: "", + messageId: "", + action: MJAction.IMAGINE, + status: "error", + message: errorMsg + }) + + global.newWindow[0].win.webContents.send(task.messageName, { + code: 0, + message: errorMsg, + data: { + status: 'error', + message: errorMsg, + id: task.bookTaskDetailId + } + }) + + throw error + } + } + //#endregion + + + //#region flux api + + /** + * 发送 FLUX API 请求 + * @param url 请求的地址 + * @param key 请求的key + * @param body 请求的请求体 + * @returns + */ + async FluxAPIImageRequest(url: string, key: string, body: { model: string; prompt: string; size: string; }): Promise { + let response = await axios.post(url, { ...body, n: 1 }, { + headers: { + Authorization: 'Bearer ' + key + } + }) + + if (response.data && response.data.data && response.data.data.length > 0) { + return response.data.data[0].url + } else { + return undefined + } + } + + /** + * 调用 FLUX API 生成图片 + * @param task + */ + async FluxAPIImage(task: TaskModal.Task): Promise { + let sdSetting = undefined + try { + let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(task.bookTaskDetailId); + let bookTask = await this.bookServiceBasic.GetBookTaskDataById(bookTaskDetail.bookTaskId); + let book = await this.bookServiceBasic.GetBookDataById(bookTask.bookId); + sdSetting = await this.GetSDSetting() + await this.gptService.RefreshGptSetting(); + + let prompt = bookTaskDetail.prompt; + let requestUrl = this.gptService.gptUrl + let uil = new URL(requestUrl); + let url = `${uil.protocol}//${uil.hostname}` + "/v1/images/generations" + + if (!isEmpty(sdSetting.webui.prompt)) { + prompt = sdSetting.webui.prompt + ', ' + prompt + } + let size = `${sdSetting.webui.width}x${sdSetting.webui.height}` + let model = sdSetting.flux.model + // 一次请求生成一张 多个请求 + + let SdOriginalImage = path.join(book.bookFolderPath, 'data/SdOriginalImage'); + await CheckFolderExistsOrCreate(SdOriginalImage); + let outputFolder = bookTask.imageFolder; + await CheckFolderExistsOrCreate(outputFolder); + let inputFolder = path.join(book.bookFolderPath, 'tmp/input') + await CheckFolderExistsOrCreate(inputFolder); + + let outImagePath = '' + let subImagePath = [] + + let batchSize = sdSetting.setting.batch_size; + for (let i = 0; i < batchSize; i++) { + const element = batchSize; + let imageUrl = await this.FluxAPIImageRequest(url, this.gptService.gptApiKey, { + model: model, + prompt: prompt, + size: size + }) + // 这边开始处理返回的数据 + if (isEmpty(imageUrl)) { + throw new Error('FLUX 生图返回的图片地址为空') + } + // 下载指定的文件 + let base64 = await GetImageBase64(imageUrl) + // 将base64 写出 + let imgPath = path.join(SdOriginalImage, `${bookTaskDetail.name}_${new Date().getTime()}_${i}.png`) + await Base64ToFile(base64, imgPath); + + // 写出去 + if (bookTask.name == 'output_00001') { + // 复制一个到input + let inputImgPath = path.join(inputFolder, `${bookTaskDetail.name}.png`) + await CopyFileOrFolder(imgPath, inputImgPath) + } + if (i == 0) { + // 复制到对应的文件夹里面 + let outPath = path.join(outputFolder, `${bookTaskDetail.name}.png`) + await CopyFileOrFolder(imgPath, outPath) + outImagePath = outPath + } + subImagePath.push(imgPath) + } + + // 结束 开始返回 + // 修改数据库 + await this.bookServiceBasic.UpdateBookTaskDetail(bookTaskDetail.id, { + outImagePath: path.relative(define.project_path, outImagePath), + subImagePath: subImagePath.map((item) => path.relative(define.project_path, item)) + }) + await this.bookServiceBasic.UpdateTaskStatus({ + id: task.id, + status: BookBackTaskStatus.DONE + }); + let resp = { + mjApiUrl: url, + progress: 100, + category: MJImageType.FLUX_API, + imageClick: subImagePath.join(','), + imageShow: subImagePath.join(','), + messageId: "", + action: MJAction.IMAGINE, + status: "success", + subImagePath: subImagePath, + outImagePath: outImagePath, + message: "FLUX API 生成图片成功" + } + await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, resp) + global.newWindow[0].win.webContents.send(task.messageName, { + code: 1, + message: "FLUX API 生成图片成功", + data: { + ...resp, + id: bookTaskDetail.id + } + }) + + } catch (error) { + let errorMsg = "FLUX API 生成图片失败,错误信息如下:" + error.toString() + await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, { + mjApiUrl: "", + progress: 0, + category: MJImageType.FLUX_API, + imageClick: "", + imageShow: "", + messageId: "", + action: MJAction.IMAGINE, + status: "error", + message: errorMsg, + }) + + global.newWindow[0].win.webContents.send(task.messageName, { + code: 0, + message: errorMsg, + data: { + status: 'error', + message: errorMsg, + id: task.bookTaskDetailId + } + }) + throw error + } + } +} \ No newline at end of file diff --git a/src/main/Service/Flux/fluxService.ts b/src/main/Service/Flux/fluxService.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/main/Service/GPT/gpt.ts b/src/main/Service/GPT/gpt.ts index 6aa1945..93cb623 100644 --- a/src/main/Service/GPT/gpt.ts +++ b/src/main/Service/GPT/gpt.ts @@ -2,6 +2,7 @@ import { isEmpty } from "lodash"; import { gptDefine } from "../../../define/gptDefine"; import axios from "axios"; import { RetryWithBackoff } from "../../../define/Tools/common"; +import { Book } from "../../../model/book"; /** * 一些GPT相关的服务都在这边 @@ -103,6 +104,7 @@ export class GptService { //#endregion + //#region GPT 通用请求 /** * 发送GPT请求 * @param {*} message 请求的信息 @@ -138,9 +140,146 @@ export class GptService { throw error; } } + //#endregion - //#region 繁体中文 -> 简体中文 + //#region 原创推理 + /** + * 获取当前分镜的上下文数据 + * @param currentBookTaskDetail 当前分镜数据 + * @param bookTaskDetails 所有的小说分镜数据 + * @param contextCount 上下文行数 + */ + GetBookTaskDetailContextData(currentBookTaskDetail: Book.SelectBookTaskDetail, bookTaskDetails: Book.SelectBookTaskDetail[], contextCount: number): string { + let prefix = ""; + // 拼接一个word + let i = currentBookTaskDetail.no - 1 + if (i <= contextCount) { + prefix = bookTaskDetails + .filter((item, index) => index < i) + .map((item) => item.afterGpt) + .join('\r\n') + } else if (i > contextCount) { + prefix = bookTaskDetails + .filter((item, index) => i - index <= contextCount && i - index > 0) + .map((item) => item.afterGpt) + .join('\r\n') + } + + let suffix = ""; + let o_i = bookTaskDetails.length - i + if (o_i <= contextCount) { + suffix = bookTaskDetails + .filter((item, index) => index > i) + .map((item) => item.afterGpt) + .join('\r\n') + } else if (o_i > contextCount) { + suffix = bookTaskDetails + .filter((item, index) => index - i <= contextCount && index - i > 0) + .map((item) => item.afterGpt) + .join('\r\n') + } + + return `${prefix}\r\n${currentBookTaskDetail.afterGpt}\r\n${suffix}`; + } + + /** + * 返回当前推理数据的请求体中的message + * @param currentBookTaskDetail 当前推理的提示词数据 + * @param contextData 上下文数据 + * @param autoAnalyzeCharacter 自动分析的角色数据 + * @returns + */ + GetGPTRequestMessage(currentBookTaskDetail: Book.SelectBookTaskDetail, contextData: string, autoAnalyzeCharacter: string): any[] { + let message = [] + if ( + ['superSinglePrompt', 'onlyPromptMJ', 'superSinglePromptChinese'].includes( + global.config.gpt_auto_inference + ) + ) { + // 有返回案例的 + message = gptDefine.GetExamplePromptMessage(global.config.gpt_auto_inference) + // 加当前提问的 + message.push({ + role: 'user', + content: currentBookTaskDetail.afterGpt + }) + } else { + // 直接返回,没有案例的 + message = [ + { + role: 'system', + content: gptDefine.getSystemContentByType(global.config.gpt_auto_inference, { + textContent: contextData, + characterContent: autoAnalyzeCharacter + }) + }, + { + role: 'user', + content: gptDefine.getUserContentByType(global.config.gpt_auto_inference, { + textContent: currentBookTaskDetail.afterGpt, + wordCount: + global.config.gpt_model && global.config.gpt_model.includes('gpt-4') + ? '20' + : '40' + }) + } + ] + } + return message + } + + /** + * 原创推理提示词数据 + * @param currentBookTaskDetail 要推理的小说分镜任务 + * @param bookTaskDetails 所有的小说分镜任务 + * @param contextCount 上下文的数量 + * @param autoAnalyzeCharacter 自动分析的角色数据字符串 + */ + async OriginalInferencePrompt(currentBookTaskDetail: Book.SelectBookTaskDetail, bookTaskDetails: Book.SelectBookTaskDetail[], contextCount: number, autoAnalyzeCharacter: string) { + let gptPromptType = global.config.gpt_auto_inference; + let message = [] + if (gptPromptType == "customize") { //自定义模式 + // 自定义模式 + // 获取当前自定义的推理提示词 + let customize_gpt_prompt = ( + await gptDefine.getGptDataByTypeAndProperty('dynamic', 'customize_gpt_prompt', []) + ).data + let index = customize_gpt_prompt.findIndex( + (item: any) => item.id == global.config.customize_gpt_prompt + ) + if (global.config.customize_gpt_prompt && index < 0) { + throw new Error('自定义推理时要选择对应的自定义推理词') + } + message = gptDefine.CustomizeGptPrompt(customize_gpt_prompt[index], currentBookTaskDetail.afterGpt) + message.push({ + role: 'user', + content: currentBookTaskDetail.afterGpt + }) + } else { // 内置模式 + let context = this.GetBookTaskDetailContextData(currentBookTaskDetail, bookTaskDetails, contextCount); + message = this.GetGPTRequestMessage(currentBookTaskDetail, context, autoAnalyzeCharacter); + } + // 开始请求 + let res = await RetryWithBackoff(async () => { + return this.FetchGpt(message) + }, 5, 1000) + if (res) { + if (res) { + res = res + .replace(/\)\s*\(/g, ', ') + .replace(/^\(/, '') + .replace(/\)$/, '') + .replaceAll('*', '') + .replaceAll('--', ' ') + } + } + return res + } + + //#endregion + + //#region 中文 繁体转简体 /** * 将繁体中文转换为简体中文 * @param traditionalText 繁体中文文本 diff --git a/src/main/Service/MJ/mj.ts b/src/main/Service/MJ/mj.ts index 8bd4f9a..50aab0d 100644 --- a/src/main/Service/MJ/mj.ts +++ b/src/main/Service/MJ/mj.ts @@ -1,8 +1,6 @@ -import { isEmpty, join } from "lodash"; +import { isEmpty } from "lodash"; import { Book } from "../../../model/book"; import { checkStringValueAddPrefix, checkStringValueAddSuffix, errorMessage, successMessage } from "../../Public/generalTools"; -import { BookBackTaskListService } from "../../../define/db/service/Book/bookBackTaskListService"; -import { BookTaskDetailService } from "../../../define/db/service/Book/bookTaskDetailService"; import { CheckFolderExistsOrCreate, CopyFileOrFolder, JoinPath } from "../../../define/Tools/file"; import { define } from "../../../define/define" import { CompressImageToSize, GetImageBase64, ImageSplit } from "../../../define/Tools/image"; @@ -14,14 +12,12 @@ import { MJRespoonseType } from "../../../define/enum/mjEnum"; import { MJSetting } from "../../../model/Setting/mjSetting"; import { GeneralResponse } from "../../../model/generalResponse" import { LoggerStatus, ResponseMessageType } from "../../../define/enum/softwareEnum"; -import { BookTaskService } from "../../../define/db/service/Book/bookTaskService"; -import { ReverseBook } from "../Book/ReverseBook"; import { ImageStyle } from "../Book/imageStyle"; import { TaskScheduler } from "../taskScheduler"; -import { BookService } from "../../../define/db/service/Book/bookService"; import { Tools } from "../../../main/tools" -import { MJSettingService } from "../../../define/db/service/SoftWare/mjSettingService"; import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic"; +import { PresetService } from "../presetService"; +import { SoftWareServiceBasic } from "../ServiceBasic/softwareServiceBasic"; import path from "path" const { v4: uuidv4 } = require('uuid') @@ -29,53 +25,42 @@ import fs from "fs" const fspromise = fs.promises export class MJOpt { - bookBackTaskList: BookBackTaskListService - bookTaskDetail: BookTaskDetailService - reverseBook: ReverseBook; - bookTaskService: BookTaskService mjApi: MJApi; mjSetting: MJSetting.MjSetting imageStyle: ImageStyle; taskScheduler: TaskScheduler; - bookService: BookService tools: Tools; - mjSettingService: MJSettingService; bookServiceBasic: BookServiceBasic + presetService: PresetService + softWareServiceBasic: SoftWareServiceBasic constructor() { this.imageStyle = new ImageStyle() this.taskScheduler = new TaskScheduler() this.tools = new Tools() this.bookServiceBasic = new BookServiceBasic(); + this.presetService = new PresetService() + this.mjApi = new MJApi() + this.softWareServiceBasic = new SoftWareServiceBasic() } - async InitService() { - if (!this.reverseBook) { - this.reverseBook = new ReverseBook() + + /** + * 获取MJ设置 + */ + async GetMJSetting() { + if (!this.mjSetting) { + this.mjSetting = await this.softWareServiceBasic.GetMjSetting() } - if (!this.bookBackTaskList) { - this.bookBackTaskList = await BookBackTaskListService.getInstance() - } - if (!this.bookTaskDetail) { - this.bookTaskDetail = await BookTaskDetailService.getInstance() - } - if (!this.mjApi) { - this.mjApi = new MJApi() - } - if (!this.bookTaskService) { - this.bookTaskService = await BookTaskService.getInstance() - } - if (!this.bookService) { - this.bookService = await BookService.getInstance() - } - if (!this.mjSettingService) { - this.mjSettingService = await MJSettingService.getInstance() - } - this.mjSetting = await this.mjApi.InitMJSetting() } + + /** * 返回MJ的数据到前端界面,前端界面做出相应的改变 * @param {*} data */ - sendChangeMessage(data: GeneralResponse.MessageResponse, message_name = DEFINE_STRING.BOOK.MAIN_DATA_RETURN) { + sendChangeMessage(data: GeneralResponse.MessageResponse, message_name: string = DEFINE_STRING.BOOK.MAIN_DATA_RETURN) { + if (!message_name) { + message_name = DEFINE_STRING.BOOK.MAIN_DATA_RETURN + } global.newWindow[0].win.webContents.send(message_name, data) } @@ -88,8 +73,8 @@ export class MJOpt { */ async SingleReverseToGptPrompt(bookTaskDetailId: string, index: number): Promise { try { - await this.InitService(); - let bookTaskDetail = this.bookTaskDetail.GetBookTaskDetailDataById(bookTaskDetailId) + await this.GetMJSetting() + let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(bookTaskDetailId) if (bookTaskDetail == null) { throw new Error("没有找到对应的数据") } @@ -100,7 +85,7 @@ export class MJOpt { let reversePrompt = reversePrompts[index] let gptPrompt = reversePrompt.promptCN ? reversePrompt.promptCN : reversePrompt.prompt // 开始修改 - this.bookTaskDetail.UpdateBookTaskDetail(bookTaskDetailId, { + await this.bookServiceBasic.UpdateBookTaskDetail(bookTaskDetailId, { gptPrompt: gptPrompt }) @@ -125,14 +110,13 @@ export class MJOpt { try { // 执行你的操作 let task_res = await this.mjApi.GetMJAPITaskById(reqRes, task.id); - // 判断他的状态是不是成功 if (task_res.code == 0) { // 反推失败 - this.bookTaskDetail.UpdateBookTaskDetail(task.bookTaskDetailId, { + await this.bookServiceBasic.UpdateBookTaskDetail(task.bookTaskDetailId, { status: BookTaskStatus.REVERSE_FAIL }); - this.bookBackTaskList.UpdateTaskStatus({ + await this.bookServiceBasic.UpdateTaskStatus({ id: task.id, status: BookBackTaskStatus.FAIL, errorMessage: task_res.message @@ -142,7 +126,7 @@ export class MJOpt { if (task_res.progress == 100) { task_res.type == MJRespoonseType.FINISHED; - this.bookBackTaskList.UpdateTaskStatus({ + await this.bookServiceBasic.UpdateTaskStatus({ id: task.id, status: BookBackTaskStatus.DONE }); @@ -162,7 +146,7 @@ export class MJOpt { }); } - this.bookTaskDetail.UpdateBookTaskDetail(task.bookTaskDetailId, { + await this.bookServiceBasic.UpdateBookTaskDetail(task.bookTaskDetailId, { status: BookTaskStatus.REVERSE_DONE, reversePrompt: reversePrompt, gptPrompt: undefined @@ -175,7 +159,7 @@ export class MJOpt { type: ResponseMessageType.MJ_REVERSE, id: task.bookTaskDetailId, data: task_res - }); + }, task.messageName); break; } else { // 当获取的图片的进度小于100的时候,等待5秒继续监听 @@ -189,7 +173,7 @@ export class MJOpt { type: ResponseMessageType.MJ_REVERSE, id: task.bookTaskDetailId, data: task_res - }); + }, task.messageName); } catch (error) { throw error; } @@ -205,9 +189,8 @@ export class MJOpt { if (isEmpty(task.bookTaskDetailId)) { throw new Error("MJ反推,没有找到对应的分镜信息") } - await this.InitService() - - let bookTaskDetail = this.bookTaskDetail.GetBookTaskDetailDataById(task.bookTaskDetailId); + await this.GetMJSetting() + let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(task.bookTaskDetailId); let oldImagePath = bookTaskDetail.oldImage if (isEmpty(oldImagePath)) { @@ -228,7 +211,7 @@ export class MJOpt { }) if (reqRes == '23') { // 任务队列过多,重新提交排队 - this.bookBackTaskList.UpdateTaskStatus({ + await this.bookServiceBasic.UpdateTaskStatus({ id: task.id, status: BookBackTaskStatus.RECONNECT, }) @@ -236,7 +219,7 @@ export class MJOpt { return; } - this.bookTaskDetail.UpdateBookTaskDetail(task.bookTaskDetailId, { + await this.bookServiceBasic.UpdateBookTaskDetail(task.bookTaskDetailId, { status: BookTaskStatus.REVERSE }) this.sendChangeMessage({ @@ -248,18 +231,18 @@ export class MJOpt { type: MJRespoonseType.UPDATED, mjType: MJAction.DESCRIBE, category: this.mjSetting.type, - message_id: reqRes, + messageId: reqRes, id: task.bookTaskDetailId, progress: 0, status: "success" } as MJ.MJResponseToFront - }) + }, task.messageName) await this.fetchWithRetry(task, reqRes); } catch (error) { console.log(error.toString()) let errorMsg = "MJ反推失败,失败信息如下:" + error.toString() - this.bookBackTaskList.UpdateTaskStatus({ + await this.bookServiceBasic.UpdateTaskStatus({ id: task.id, status: BookBackTaskStatus.FAIL, errorMessage: errorMsg @@ -275,13 +258,13 @@ export class MJOpt { type: MJRespoonseType.UPDATED, mjType: MJAction.DESCRIBE, category: this.mjSetting.type, - message_id: undefined, + messageId: undefined, id: task.bookTaskDetailId, progress: 0, message: error.toString(), status: "failure" } - }) + }, task.messageName) return errorMessage(errorMsg, "MJReverse_MJImage2Text") } } @@ -289,6 +272,59 @@ export class MJOpt { //#endregion //#region 合并提示词相关 + + /** + * 获取场景的提示词 + * @param ids 需要获取的IDs + * @returns + */ + async GetScenePresetStringByIds(ids: string[]): Promise { + let sceneString = '' + for (let i = 0; i < ids.length; i++) { + const id = ids[i]; + let scene = await this.presetService.GetScenePresetDetailById(id) + if (scene.code == 1) { + // 这边开始拼接 + sceneString += scene.data.prompt + ', ' + } else { + throw new Error(scene.message) + } + } + return sceneString + } + + /** + * 获取人物提示词,包括垫图链接 + * @param ids 需要获取的IDs + * @returns + */ + async GetCharacterPresetStringByIds(ids: string[]): Promise<{ characterString: string, characterUrl: string }> { + let characterString = '' + let characterUrl = '' + let crefCw = undefined + + for (let i = 0; i < ids.length; i++) { + const element = ids[i]; + let character = await this.presetService.GetCharacterPresetDetailById(element) + if (character.code == 1) { + characterString += character.data.prompt + ', ' + if (character.data.image_url && character.data.image_url != '' && character.data.cref_cw) { + characterUrl += ` ${character.data.image_url} ` + crefCw = character.data.cref_cw + } + } + else { + throw new Error(character.message) + } + } + + //这边坐下合并s + if (characterUrl != '') { + characterUrl = ` --cref ${characterUrl} --cw ${crefCw}` + } + return { characterString, characterUrl } + } + /** * MJ 进行合并提示词,通过类型进行判断是单个还是全部合并 * @param id 合并的ID @@ -296,16 +332,14 @@ export class MJOpt { */ async MergePrompt(id: string, operateBookType: OperateBookType): Promise { try { - await this.InitService() - let bookTaskDetail = undefined as Book.SelectBookTaskDetail[]; let bookTask = undefined as Book.SelectBookTask; - + await this.GetMJSetting() if (operateBookType == OperateBookType.BOOKTASK) { - bookTaskDetail = this.bookTaskDetail.GetBookTaskData({ + bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailData({ bookTaskId: id - }).data - bookTask = this.bookTaskService.GetBookTaskDataById(id); + }) + bookTask = await this.bookServiceBasic.GetBookTaskDataById(id); // 判断是不是有为空的 let emptyName = [] as string[] for (let i = 0; i < bookTaskDetail.length; i++) { @@ -323,11 +357,16 @@ export class MJOpt { throw new Error("当前分镜没有推理提示词,请先生成") } bookTaskDetail = [tempBookTaskDetail] - bookTask = this.bookTaskService.GetBookTaskDataById(bookTaskDetail[0].bookTaskId); + bookTask = await this.bookServiceBasic.GetBookTaskDataById(bookTaskDetail[0].bookTaskId); } else { throw new Error("未知的合并类型") } + if (bookTaskDetail.length <= 0) { + throw new Error("没有找到对应的需要合并的分镜数据") + } + let book = await this.bookServiceBasic.GetBookDataById(bookTask.bookId); + // 获取合并的排序 let imageBaseSetting = JSON.parse(await fspromise.readFile(define.img_base, 'utf-8')); // 没有就直接报错 let promptSort = imageBaseSetting.prompt_sort; // 没有就直接报错 @@ -336,11 +375,8 @@ export class MJOpt { } // let suffixParam = imageBaseSetting.mj_config.image_suffix ; // 没有就直接报错 - let mjSettingDb = this.mjSettingService.GetMjSetting({}).data - if (mjSettingDb.length <= 0) { - throw new Error("请先添加MJ配置") - } - let suffixParam = mjSettingDb[0].imageSuffix + let mjSettingDb = await this.softWareServiceBasic.GetMjSetting() + let suffixParam = mjSettingDb.imageSuffix // let styleString = ''; // 拿到所有的风格 @@ -349,18 +385,33 @@ export class MJOpt { for (let i = 0; i < bookTaskDetail.length; i++) { const element = bookTaskDetail[i]; + // 没有推理提示词,直接跳过 + if (isEmpty(element.gptPrompt)) { + continue; + } let promptStr = ''; for (let i = 0; i < promptSort.length; i++) { const element = promptSort[i]; promptStr += `${'${' + element.value + '}'} ` } - console.log(promptStr) - // TODO 后面需要完善人物和场景的提示词 let characterString = '' // 人物 + let characterUrl = '' let sceneString = "" // 场景 // 获取当前的自定义风格的垫图字符串 + if (book.type == BookType.ORIGINAL) { + let sceneIds = element.sceneTags ? element.sceneTags : [] + let characterIds = element.characterTags ? element.characterTags : [] + if (sceneIds && sceneIds.length > 0) { + sceneString = await this.GetScenePresetStringByIds(sceneIds) + } + if (characterIds && characterIds.length > 0) { + let res = await this.GetCharacterPresetStringByIds(characterIds) + characterString = res.characterString + characterUrl = res.characterUrl + } + } let styleString = "" let style_url = '' @@ -404,9 +455,9 @@ export class MJOpt { promptStr = checkStringValueAddSuffix(promptStr, ',') + bookTask.suffixPrompt } promptStr = ' ' + promptStr; - promptStr += ` ${cref_url} ${style_url}${suffixParam}` + promptStr += ` ${characterUrl} ${style_url}${suffixParam}` // 修改数据库数据 - this.bookTaskDetail.UpdateBookTaskDetail(element.id, { + await this.bookServiceBasic.UpdateBookTaskDetail(element.id, { prompt: promptStr }) // 写回数据 @@ -416,7 +467,6 @@ export class MJOpt { }) } return successMessage(result, "MJ模式合并数据成功", "MJOpt_MergePrompt") - } catch (error) { return errorMessage("MJ合并提示词失败,错误信息如下:" + error.message, "MJOpt_MergePrompt") } @@ -430,29 +480,32 @@ export class MJOpt { * @param id 要添加的ID * @param operateBookType 操作的类型 */ - async AddMJGenerateImageTask(id: string, operateBookType: OperateBookType): Promise { + async AddMJGenerateImageTask(id: string, operateBookType: OperateBookType, responseMessageName: string = null, coverData: boolean = true): Promise { try { - await this.InitService() let bookTaskDetail = undefined as Book.SelectBookTaskDetail[]; // let bookTask = undefined as Book.SelectBookTask; - if (operateBookType == OperateBookType.BOOKTASK) { - bookTaskDetail = this.bookTaskDetail.GetBookTaskData({ + bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailData({ bookTaskId: id - }).data + }) + if (!coverData) { + // 过滤掉已经生成的数据 + bookTaskDetail = bookTaskDetail.filter((item) => !item.mjMessage) + } // bookTask = this.bookTaskService.GetBookTaskDataById(id); } else if (operateBookType == OperateBookType.BOOKTASKDETAIL) { - bookTaskDetail = [this.bookTaskDetail.GetBookTaskDetailDataById(id)] + let bookTaskDetailRes = await this.bookServiceBasic.GetBookTaskDetailDataById(id) + bookTaskDetail = [bookTaskDetailRes] // bookTask = this.bookTaskService.GetBookTaskDataById(bookTaskDetail[0].bookTaskId); } else if (operateBookType == OperateBookType.UNDERBOOKTASK) { - let thisBookTaskDetail = this.bookTaskDetail.GetBookTaskDetailDataById(id); + let thisBookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(id); if (thisBookTaskDetail == null) { throw new Error("没有找到对应的数据") } // 获取批次的所有数据 - bookTaskDetail = this.bookTaskDetail.GetBookTaskData({ + bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailData({ bookTaskId: thisBookTaskDetail.bookTaskId - }).data + }) // bookTask = this.bookTaskService.GetBookTaskDataById(thisBookTaskDetail.bookTaskId); bookTaskDetail = bookTaskDetail.filter((item) => item.no >= thisBookTaskDetail.no) // 需要包含自己 } @@ -469,13 +522,10 @@ export class MJOpt { // 将任务添加到队列中 for (let i = 0; i < bookTaskDetail.length; i++) { const element = bookTaskDetail[i]; - let taskRes = await this.bookBackTaskList.AddBookBackTask(element.bookId, BookBackTaskType.MJ_IMAGE, TaskExecuteType.AUTO, element.bookTaskId, element.id + let taskRes = await this.bookServiceBasic.AddBookBackTask(element.bookId, BookBackTaskType.MJ_IMAGE, TaskExecuteType.AUTO, element.bookTaskId, element.id, responseMessageName ); - if (taskRes.code == 0) { - throw new Error(taskRes.message) - } // 添加返回日志 - await this.taskScheduler.AddLogToDB(element.bookId, BookBackTaskType.MJ_IMAGE, `添加 ${element.name} MJ生成视频任务成功`, element.bookTaskId, LoggerStatus.SUCCESS) + await this.taskScheduler.AddLogToDB(element.bookId, BookBackTaskType.MJ_IMAGE, `添加 ${element.name} MJ生成任务成功`, element.bookTaskId, LoggerStatus.SUCCESS) } // 全部完毕 return successMessage(null, "MJ添加生成图片任务成功", "MJOpt_AddGenerateImageTask") @@ -492,30 +542,32 @@ export class MJOpt { async FetchImageTask(task: TaskModal.Task, reqRes: string, book: Book.SelectBook, bookTask: Book.SelectBookTask, bookTaskDetail: Book.SelectBookTaskDetail) { while (true) { try { + await this.GetMJSetting() // 执行你的操作 let task_res = await this.mjApi.GetMJAPITaskById(reqRes, task.id); task_res.id = task.bookTaskDetailId; // 判断他的状态是不是成功 if (task_res.code == 0) { // 生图失败 - this.bookTaskDetail.UpdateBookTaskDetail(task.bookTaskDetailId, { + await this.bookServiceBasic.UpdateBookTaskDetail(task.bookTaskDetailId, { status: BookTaskStatus.IMAGE_FAIL, }); - this.bookTaskDetail.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, { + let errorMsg = `MJ生成图片失败,失败信息如下:${task_res.message}` + await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, { mjApiUrl: this.mjApi.imagineUrl, - progress: 0, + progress: 100, category: this.mjApi.mjSetting.type, - imageClick: task_res.image_click, - imageShow: task_res.image_show, - messageId: task_res.message_id, + imageClick: task_res.imageClick, + imageShow: task_res.imageShow, + messageId: task_res.messageId, action: MJAction.IMAGINE, status: 'error', - message: task_res.message + message: errorMsg }) - this.bookBackTaskList.UpdateTaskStatus({ + await this.bookServiceBasic.UpdateTaskStatus({ id: task.id, status: BookBackTaskStatus.FAIL, - errorMessage: task_res.message + errorMessage: errorMsg }); this.sendChangeMessage({ code: 0, @@ -523,24 +575,25 @@ export class MJOpt { id: task.bookTaskDetailId, data: { ...task_res, - status: "error" + status: "error", + message: errorMsg }, - message: task_res.message - }); + message: errorMsg + }, task.messageName); return; // throw new Error(`${task_res.message}`); } else { if (task_res.progress == 100) { task_res.type == MJRespoonseType.FINISHED; console.log(task.id, "22222") - this.bookBackTaskList.UpdateTaskStatus({ + await this.bookServiceBasic.UpdateTaskStatus({ id: task.id, status: BookBackTaskStatus.DONE }); // 下载图片 - let imagePath = path.join(book.bookFolderPath, `data\\MJOriginalImage\\${task_res.message_id}.png`); + let imagePath = path.join(book.bookFolderPath, `data\\MJOriginalImage\\${task_res.messageId}.png`); await CheckFolderExistsOrCreate(path.dirname(imagePath)) - await this.tools.downloadFileUrl(task_res.image_click, imagePath) + await this.tools.downloadFileUrl(task_res.imageClick, imagePath) // 进行图片裁剪 let imageRes = await ImageSplit(imagePath, bookTaskDetail.name, path.join(book.bookFolderPath, 'data\\MJOriginalImage')); @@ -560,17 +613,17 @@ export class MJOpt { task_res.id = task.bookTaskDetailId; // 修改分镜的数据 - this.bookTaskDetail.UpdateBookTaskDetail(task.bookTaskDetailId, { + await this.bookServiceBasic.UpdateBookTaskDetail(task.bookTaskDetailId, { outImagePath: path.relative(define.project_path, out_file), subImagePath: imageRes.map((item) => path.relative(define.project_path, item)) }) - this.bookTaskDetail.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, { + await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, { mjApiUrl: this.mjApi.imagineUrl, progress: 100, category: this.mjApi.mjSetting.type, - imageClick: task_res.image_click, - imageShow: task_res.image_show, - messageId: task_res.message_id, + imageClick: task_res.imageClick, + imageShow: task_res.imageShow, + messageId: task_res.messageId, action: MJAction.IMAGINE, status: task_res.status, }) @@ -579,32 +632,32 @@ export class MJOpt { type: ResponseMessageType.MJ_IMAGE, id: task.bookTaskDetailId, data: task_res - }); + }, task.messageName); break; } } // 这边也要修改数据 task_res.id = task.bookTaskDetailId; - this.bookTaskDetail.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, { + await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, { mjApiUrl: this.mjApi.imagineUrl, progress: task_res.progress, category: this.mjApi.mjSetting.type, - imageClick: task_res.image_click, - imageShow: task_res.image_show, - messageId: task_res.message_id, + imageClick: task_res.imageClick, + imageShow: task_res.imageShow, + messageId: task_res.messageId, action: MJAction.IMAGINE, status: task_res.status, message: task_res.message }) - task_res.outImagePath = task_res.image_path; + task_res.outImagePath = task_res.imagePath; this.sendChangeMessage({ code: 1, type: ResponseMessageType.MJ_IMAGE, id: task.bookTaskDetailId, data: task_res - }); + }, task.messageName); // 当获取的图片的进度小于100的时候,等待5秒继续监听 await new Promise(resolve => setTimeout(resolve, 5000)); } catch (error) { @@ -622,16 +675,16 @@ export class MJOpt { if (isEmpty(task.bookTaskDetailId)) { throw new Error("MJ出图,没有找到对应的分镜信息") } - await this.InitService() - let bookTaskDetail = this.bookTaskDetail.GetBookTaskDetailDataById(task.bookTaskDetailId); + await this.GetMJSetting() + let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(task.bookTaskDetailId); if (bookTaskDetail == null) { throw new Error("没有找到对应的分镜信息") } - let book = this.bookService.GetBookDataById(bookTaskDetail.bookId) + let book = await this.bookServiceBasic.GetBookDataById(bookTaskDetail.bookId) if (book == null) { throw new Error("没有找到对应的小说信息") } - let bookTask = this.bookTaskService.GetBookTaskDataById(bookTaskDetail.bookTaskId) + let bookTask = await this.bookServiceBasic.GetBookTaskDataById(bookTaskDetail.bookTaskId) if (bookTask == null) { throw new Error("没有找到对应的任务信息") } @@ -640,11 +693,11 @@ export class MJOpt { throw new Error(`${bookTaskDetail.name} 没有找到对应的提示词`) } // 这个就是任务ID - let reqRes = await this.mjApi.SubmitMJImagineAPI(task.id, prompt) + let reqRes = await this.mjApi.SubmitMJImagine(task.id, prompt) if (reqRes == '23') { console.log(task.id, "33333") // 任务队列过多,重新提交排队 - this.bookBackTaskList.UpdateTaskStatus({ + await this.bookServiceBasic.UpdateTaskStatus({ id: task.id, status: BookBackTaskStatus.RECONNECT, }) @@ -662,8 +715,8 @@ export class MJOpt { progress: 0, status: "re_connect" } as MJ.MJResponseToFront - }) - this.bookTaskDetail.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, { + }, task.messageName) + await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, { mjApiUrl: this.mjApi.imagineUrl, progress: 0, category: this.mjApi.mjSetting.type, @@ -677,10 +730,10 @@ export class MJOpt { return; } - this.bookTaskDetail.UpdateBookTaskDetail(task.bookTaskDetailId, { + await this.bookServiceBasic.UpdateBookTaskDetail(task.bookTaskDetailId, { status: BookTaskStatus.IMAGE }) - this.bookBackTaskList.UpdateTaskStatus({ + await this.bookServiceBasic.UpdateTaskStatus({ id: task.id, status: BookBackTaskStatus.RUNNING }) @@ -698,14 +751,12 @@ export class MJOpt { progress: 0, status: "submited" } as MJ.MJResponseToFront - }) + }, task.messageName) await this.FetchImageTask(task, reqRes, book, bookTask, bookTaskDetail); - } catch (error) { console.log(error.toString()) let errorMsg = "MJ生图失败,失败信息如下:" + error.toString() - console.log(task.id, "44444") - this.bookBackTaskList.UpdateTaskStatus({ + await this.bookServiceBasic.UpdateTaskStatus({ id: task.id, status: BookBackTaskStatus.FAIL, errorMessage: errorMsg @@ -721,14 +772,14 @@ export class MJOpt { type: MJRespoonseType.UPDATED, mjType: MJAction.IMAGINE, category: this.mjSetting.type, - message_id: undefined, + messageId: undefined, id: task.bookTaskDetailId, progress: 0, message: error.toString(), status: "error" } - }) - this.bookTaskDetail.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, { + }, task.messageName) + await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, { mjApiUrl: this.mjApi.imagineUrl, progress: 0, category: this.mjApi.mjSetting.type, diff --git a/src/main/Service/MJ/mjApi.ts b/src/main/Service/MJ/mjApi.ts index d7f041a..08a0bde 100644 --- a/src/main/Service/MJ/mjApi.ts +++ b/src/main/Service/MJ/mjApi.ts @@ -69,7 +69,6 @@ class MJApi { */ async GetMJAPITaskById(taskId: string, backTaskId: string) { try { - await this.InitMJSetting(); let url = this.fetchTaskUrl.replace("${id}", taskId) let headers = undefined @@ -107,15 +106,15 @@ class MJApi { type: MJRespoonseType.UPDATED, progress: isNaN(progress) ? 0 : progress, category: this.mjSetting.type, - image_click: res.data.imageUrl, - image_show: res.data.imageUrl, - image_path: res.data.imageUrl, - message_id: taskId, + imageClick: res.data.imageUrl, + imageShow: res.data.imageUrl, + imagePath: res.data.imageUrl, + messageId: taskId, status: status, code: code, prompt: res.data.prompt == "" ? res.data.promptEn : res.data.prompt, message: res.data.failReason, - mj_api_url: this.fetchTaskUrl, + mjApiUrl: this.fetchTaskUrl, } as MJ.MJResponseToFront return resObj } catch (error) { diff --git a/src/main/Service/SD/sd.ts b/src/main/Service/SD/sd.ts index 8687b81..253c0cd 100644 --- a/src/main/Service/SD/sd.ts +++ b/src/main/Service/SD/sd.ts @@ -4,18 +4,25 @@ import { checkStringValueAddSuffix, errorMessage, successMessage } from "../../P import { define } from '../../../define/define' import fs from "fs"; import { ImageStyle } from "../Book/imageStyle"; -import { OperateBookType } from "../../../define/enum/bookEnum"; +import { BookBackTaskStatus, BookType, OperateBookType } from "../../../define/enum/bookEnum"; import { isEmpty } from "lodash"; import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic"; +import { PresetService } from "../presetService"; +import path from "path"; +import axios from "axios"; +import { CheckFolderExistsOrCreate, CopyFileOrFolder, DeleteFileExifData } from "../../../define/Tools/file"; +import { Base64ToFile } from "../../../define/Tools/image"; +import { MJAction, MJImageType } from "../../../define/enum/mjEnum"; const fspromise = fs.promises export class SDOpt { imageStyle: ImageStyle - bookServiceBasic: BookServiceBasic + presetService: PresetService constructor() { this.bookServiceBasic = new BookServiceBasic() this.imageStyle = new ImageStyle() + this.presetService = new PresetService() } @@ -28,6 +35,50 @@ export class SDOpt { return sdSetting } + //#region 合并提示词 + + /** + * 获取所有的场景提示词,然后合并 + * @param ids 需要获取场景的ID + * @returns + */ + async GetScenePresetStringByIds(ids: string[]): Promise { + let result = '' + for (let i = 0; i < ids.length; i++) { + const id = ids[i]; + let scene = await this.presetService.GetScenePresetDetailById(id) + if (scene.code == 1) { + // 这边开始拼接 + result += scene.data.prompt + ', ' + } else { + throw new Error(scene.message) + } + } + return result + } + + /** + * 获取所有的人物的提示词,然后合并 + * @param ids 需要获取人物的ID + * @returns + */ + async GetCharacterPresetStringByIds(ids: string[]): Promise { + let result = '' + for (let i = 0; i < ids.length; i++) { + const id = ids[i]; + let character = await this.presetService.GetCharacterPresetDetailById(id) + if (character.code == 1) { + result += character.data.prompt + ', ' + if (character.data.lora && character.data.lora != '无' && character.data.loraWeight) { + result += `, ` + } + } else { + throw new Error(character.message) + } + } + return result + } + /** * SD的提示词合并 * @param id 要处理的ID @@ -42,9 +93,9 @@ export class SDOpt { let style_weight = sd_setting.setting.style_weight ? sd_setting.setting.style_weight : 1 if (operateBookType == OperateBookType.BOOKTASK) { - bookTaskDetail = (await this.bookServiceBasic.GetBookTaskData({ + bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailData({ bookTaskId: id - })).bookTasks; + }); bookTask = await this.bookServiceBasic.GetBookTaskDataById(id); // 判断是不是有为空的 let emptyName = [] as string[] @@ -67,6 +118,7 @@ export class SDOpt { } else { throw new Error("未知的合并类型") } + let book = await this.bookServiceBasic.GetBookDataById(bookTask.bookId); // 获取合并的排序 let promptSort = JSON.parse(await fspromise.readFile(define.img_base, 'utf-8')).prompt_sort; // 没有就直接报错 @@ -80,33 +132,50 @@ export class SDOpt { for (let i = 0; i < styleArr.length; i++) { const element = styleArr[i] if (element.type == 'style_main') { - styleString += `(${element.prompt}:${style_weight})` + ', ' + if (!isEmpty(element.prompt)) { + styleString += `(${element.prompt}:${style_weight})` + ', ' + } if (element.lora && element.lora != '无' && element.lora_weight) { styleString += `, ` } } else { - styleString += `(${element.english_style}:${style_weight})` + ',' + if (!isEmpty(element.prompt)) { + styleString += `(${element.english_style}:${style_weight})` + ',' + } } } // 获取SD的通用前缀 let sdGlobalPrompt = JSON.parse(await fspromise.readFile(define.sd_setting, 'utf-8')).webui.prompt; - - // TODO 反推这边目前就只有风格和提示词,暂时没有人物和场景 - let sceneString = ""; // 场景 - let characterString = ""; // 人物 - - let result = []; // 返回前端的数据数组 for (let i = 0; i < bookTaskDetail.length; i++) { const element = bookTaskDetail[i]; - + // 没有推理提示词,直接跳过 + if (isEmpty(element.gptPrompt)) { + continue; + } let promptStr = ''; for (let i = 0; i < promptSort.length; i++) { const element = promptSort[i]; promptStr += `${'${' + element.value + '}'} ` } + let sceneString = ""; // 场景 + let characterString = ""; // 人物 + + // 只有原创才需要获取人物和场景 + if (book.type == BookType.ORIGINAL) { + // 这边获取对应的人物和场景 + let sceneIds = element.sceneTags ? element.sceneTags : []; + let characterIds = element.characterTags ? element.characterTags : []; + if (sceneIds && sceneIds.length > 0) { + sceneString = await this.GetScenePresetStringByIds(sceneIds) + } + if (characterIds && characterIds.length > 0) { + characterString = await this.GetCharacterPresetStringByIds(characterIds) + } + } + // 开始合并 promptStr = promptStr.replace('${style}', styleString) // 风格 promptStr = promptStr.replace('${character}', characterString) // 人物 @@ -145,4 +214,157 @@ export class SDOpt { return errorMessage("SD合并提示词,错误信息如下:" + error.toString(), "SDOpt_MergePrompt") } } + + //#endregion + + //#region 生图相关任务 + + /** + * SD单个生成图片任务 + * @param task + */ + async SDImageGenerate(task: TaskModal.Task) { + let sdSetting = undefined + try { + // 开始生图 + sdSetting = await this.GetSDSetting(); + let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(task.bookTaskDetailId); + let bookTask = await this.bookServiceBasic.GetBookTaskDataById(bookTaskDetail.bookTaskId); + let book = await this.bookServiceBasic.GetBookDataById(bookTask.bookId); + + let prompt = bookTaskDetail.prompt; + let url = sdSetting.setting.webui_api_url + if (url.endsWith('/')) { + url = url + "sdapi/v1/txt2img" + } else { + url = url + "/sdapi/v1/txt2img" + } + if (!isEmpty(sdSetting.webui.prompt)) { + prompt = sdSetting.webui.prompt + ', ' + prompt + } + + // 判断当前是不是有开修脸修手 + let ADetailer = { + args: sdSetting.adetailer + } + + // 种子默认 -1,随机 + let seed = -1; + let body = { + prompt: prompt, + negative_prompt: sdSetting.webui.negative_prompt, + seed: seed, + sampler_name: sdSetting.webui.sampler_name, + // 提示词相关性 + cfg_scale: sdSetting.webui.cfg_scale, + width: sdSetting.webui.width, + height: sdSetting.webui.height, + batch_size: sdSetting.setting.batch_size, + n_iter: 1, + steps: sdSetting.webui.steps, + save_images: false + } + if (bookTaskDetail.adetailer) { + body['alwayson_scripts'] = { + "ADetailer": ADetailer + } + } + const response = await axios.post(url, body) + // TODO 对SD图片种子的一些处理,待定 + // let info = JSON.parse(res.data.info) + // if (seed == -1) { + // seed = info.seed + // } + let images = response.data.images + let SdOriginalImage = path.join(book.bookFolderPath, 'data/SdOriginalImage'); + await CheckFolderExistsOrCreate(SdOriginalImage); + let outputFolder = bookTask.imageFolder; + await CheckFolderExistsOrCreate(outputFolder); + let inputFolder = path.join(book.bookFolderPath, 'tmp/input') + await CheckFolderExistsOrCreate(inputFolder); + + let subImagePath = [] + let outImagePath = '' + // 开始写出图片 + for (let i = 0; i < images.length; i++) { + const element = images[i]; + // 包含info信息的图片地址 + let infoImgPath = path.join(SdOriginalImage, `info_${bookTaskDetail.name}_${new Date().getTime()}_${i}.png`) + // 不包含info信息的图片地址 + let imgPath = path.join(SdOriginalImage, `${bookTaskDetail.name}_${new Date().getTime()}_${i}.png`) + await Base64ToFile(element, infoImgPath) + // 这边去图片信息 + await DeleteFileExifData(path.join(define.package_path, 'exittool/exiftool.exe'), infoImgPath, imgPath); + // 写出去 + if (bookTask.name == 'output_00001') { + // 复制一个到input + let inputImgPath = path.join(inputFolder, `${bookTaskDetail.name}.png`) + await CopyFileOrFolder(imgPath, inputImgPath) + } + if (i == 0) { + // 复制到对应的文件夹里面 + let outPath = path.join(outputFolder, `${bookTaskDetail.name}.png`) + await CopyFileOrFolder(imgPath, outPath) + outImagePath = outPath + } + subImagePath.push(imgPath) + } + // 修改数据库 + await this.bookServiceBasic.UpdateBookTaskDetail(bookTaskDetail.id, { + outImagePath: path.relative(define.project_path, outImagePath), + subImagePath: subImagePath.map((item) => path.relative(define.project_path, item)) + }) + await this.bookServiceBasic.UpdateTaskStatus({ + id: task.id, + status: BookBackTaskStatus.DONE + }); + let resp = { + mjApiUrl: url, + progress: 100, + category: MJImageType.LOCAL_SD, + imageClick: subImagePath.join(','), + imageShow: subImagePath.join(','), + messageId: subImagePath.join(','), + action: MJAction.IMAGINE, + status: "success", + subImagePath: subImagePath, + outImagePath: outImagePath, + message: "SD生成图片成功" + } + await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, resp) + global.newWindow[0].win.webContents.send(task.messageName, { + code: 1, + message: "SD生成图片成功", + data: { + ...resp, + id: bookTaskDetail.id + } + }) + } catch (error) { + let errorMsg = "SD生成图片失败,错误信息如下:" + error.toString() + await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, { + mjApiUrl: sdSetting ? sdSetting.setting.webui_api_url : "", + progress: 0, + category: MJImageType.LOCAL_SD, + imageClick: "", + imageShow: "", + messageId: "", + action: MJAction.IMAGINE, + status: "error", + message: errorMsg, + id: task.bookTaskDetailId + }) + + global.newWindow[0].win.webContents.send(task.messageName, { + code: 0, + message: errorMsg, + data: { + status: 'error', + message: errorMsg + } + }) + throw error + } + } + //#endregion } \ No newline at end of file diff --git a/src/main/Service/ServiceBasic/bookServiceBasic.ts b/src/main/Service/ServiceBasic/bookServiceBasic.ts index 0e28bbc..47b86b6 100644 --- a/src/main/Service/ServiceBasic/bookServiceBasic.ts +++ b/src/main/Service/ServiceBasic/bookServiceBasic.ts @@ -43,6 +43,7 @@ export class BookServiceBasic { } + //#region 事务操作 transaction(callback: (realm: any) => void) { this.bookService.transaction(() => { @@ -57,7 +58,7 @@ export class BookServiceBasic { /** * 通过小说ID获取小说数据 * @param bookId 小说ID - * @returns + * @returns */ async GetBookDataById(bookId: string): Promise { await this.InitService(); @@ -96,7 +97,7 @@ export class BookServiceBasic { /** * 通过小说ID获取小说批次任务数据 * @param bookTaskId 小说批次任务ID - * @returns + * @returns */ async GetBookTaskDataById(bookTaskId: string): Promise { await this.InitService(); @@ -138,7 +139,7 @@ export class BookServiceBasic { /** * 更新小说批次任务的数据 * @param bookTaskId 小说批次任务ID - * @param data + * @param data */ async UpdetedBookTaskData(bookTaskId: string, data: Book.SelectBookTask): Promise { await this.InitService(); @@ -166,10 +167,15 @@ export class BookServiceBasic { //#region 小说批次任务对应的分镜的相关的基础服务 + async AddBookTaskDetail(bookTaskDetail: Book.SelectBookTaskDetail): Promise { + await this.InitService(); + this.bookTaskDetailService.AddBookTaskDetail(bookTaskDetail) + } + /** * 获取指定的小说批次任务分镜数据,通过分镜ID * @param bookTaskDetailId 小说批次任务分镜ID - * @returns + * @returns */ async GetBookTaskDetailDataById(bookTaskDetailId: string): Promise { await this.InitService(); @@ -184,12 +190,13 @@ export class BookServiceBasic { /** * 获取指定的小说批次任务分镜数据,通过查询条件 - * @param condition + * @param condition + * @param returnEmpty 是否返回空数据,默认 false 不返回,如果返回空数据,会抛出异常 */ - async GetBookTaskDetailData(condition: Book.QueryBookTaskDetailCondition): Promise { + async GetBookTaskDetailData(condition: Book.QueryBookTaskDetailCondition, returnEmpty: boolean = false): Promise { await this.InitService(); let bookTaskDetails = this.bookTaskDetailService.GetBookTaskData(condition) - if (bookTaskDetails.data.length <= 0) { + if (!returnEmpty && bookTaskDetails.data.length <= 0) { let msg = "未找到对应的小说批次任务分镜数据,请检查"; throw new Error(msg) } @@ -221,7 +228,7 @@ export class BookServiceBasic { /** * 删除指定的小说分镜的反推提示词 - * @param bookTaskDetail + * @param bookTaskDetail */ async DeleteBookTaskDetailReversePromptById(bookTaskDetailId: string): Promise { await this.InitService(); @@ -230,13 +237,35 @@ export class BookServiceBasic { /** * 删除指定的小说分镜生成的图片 - * @param bookTaskDetailId + * @param bookTaskDetailId */ async DeleteBoookTaskDetailGenerateImage(bookTaskDetailId: string): Promise { await this.InitService() this.bookTaskDetailService.DeleteBoookTaskDetailGenerateImage(bookTaskDetailId); } + /** + * 修改小说分镜数据的反推提示词 + * @param bookTaskDetailId 小说分镜的ID + * @param reversePromptId 反推提示词的ID + * @param data 反推提示词数据 + */ + async UpdateBookTaskDetailReversePrompt(bookTaskDetailId: string, reversePromptId: string, data: Book.ReversePrompt): Promise { + await this.InitService(); + this.bookTaskDetailService.UpdateBookTaskDetailReversePrompt(bookTaskDetailId, reversePromptId, data) + } + + /** + * 更行小说分镜的MJ消息,就是出图信息 + * @param bookTaskDetailId 小说分镜的数据信息 + * @param mjMessage 要保存到分镜信息 + */ + async UpdateBookTaskDetailMjMessage(bookTaskDetailId: string, mjMessage: Book.MJMessage) { + await this.InitService(); + this.bookTaskDetailService.UpdateBookTaskDetailMjMessage(bookTaskDetailId, mjMessage) + } + + //#endregion //#region 小说后台任务相关操作 @@ -253,10 +282,12 @@ export class BookServiceBasic { taskType: BookBackTaskType, executeType = TaskExecuteType.AUTO, bookTaskId = null, - bookTaskDetailId = null): Promise { + bookTaskDetailId = null, + responseMessageName: string = null + ): Promise { await this.InitService(); - let res = this.bookBackTaskListService.AddBookBackTask(bookId, taskType, executeType, bookTaskId, bookTaskDetailId) + let res = this.bookBackTaskListService.AddBookBackTask(bookId, taskType, executeType, bookTaskId, bookTaskDetailId, responseMessageName) if (res.code == 0) { throw new Error(res.message) } @@ -270,7 +301,7 @@ export class BookServiceBasic { * 通过小说ID和小说批次任务ID获取小说和小说批次任务数据 * @param bookId 小说ID * @param bookTaskName 小说批次的名字,或者是小说批次任务的ID - * @returns + * @returns */ async GetBookAndTask(bookId: string, bookTaskName: string) { await this.InitService(); @@ -295,4 +326,13 @@ export class BookServiceBasic { } return { book: book as Book.SelectBook, bookTask: bookTaskRes.data.bookTasks[0] as Book.SelectBookTask } } + + /** + * 修改后台队列的状态 + * @param bookBackTask 要修改的数据 + */ + async UpdateTaskStatus(bookBackTask: Book.UpdateBookTaskListStatus) { + await this.InitService(); + this.bookBackTaskListService.UpdateTaskStatus(bookBackTask) + } } diff --git a/src/main/Service/ServiceBasic/softwareServiceBasic.ts b/src/main/Service/ServiceBasic/softwareServiceBasic.ts index 3637906..5bd4a1d 100644 --- a/src/main/Service/ServiceBasic/softwareServiceBasic.ts +++ b/src/main/Service/ServiceBasic/softwareServiceBasic.ts @@ -1,20 +1,26 @@ import { SoftwareService } from '../../../define/db/service/SoftWare/softwareService'; +import { MJSettingService } from '../../../define/db/service/SoftWare/mjSettingService'; +import { MJSetting } from '../../../model/Setting/mjSetting'; export class SoftWareServiceBasic { softwareService: SoftwareService + mjSettingService: MJSettingService constructor() { } async InitService() { if (!this.softwareService) { this.softwareService = await SoftwareService.getInstance() } + if (!this.mjSettingService) { + this.mjSettingService = await MJSettingService.getInstance() + } } //#region software相关的基础服务 /** - * 更新软件配置信息 + * 更新软件配置信息,如果没有ID则修改指定属性 * @param software */ async UpdateSoftware(software: SoftwareSettingModel.SoftwareSetting): Promise { @@ -73,4 +79,26 @@ export class SoftWareServiceBasic { //#endregion + //#region MJ设置相关 + + /** + * 获取MJ的设置信息 + * @returns + */ + async GetMjSetting(): Promise { + await this.InitService(); + let mjSetting = this.mjSettingService.GetMjSetting({}) + if (mjSetting.code == 1) { + if (mjSetting.data.length <= 0) { + throw new Error("未找到MJ的设置信息,请检查"); + } + // 这边只是返回第一个 + return mjSetting.data[0] + } else { + throw new Error(mjSetting.message) + } + } + + //#endregion + } \ No newline at end of file diff --git a/src/main/Service/Subtitle/subtitleService.ts b/src/main/Service/Subtitle/subtitleService.ts index 6f3cd91..8264917 100644 --- a/src/main/Service/Subtitle/subtitleService.ts +++ b/src/main/Service/Subtitle/subtitleService.ts @@ -12,7 +12,7 @@ import { CheckFileOrDirExist } from "../../../define/Tools/file"; import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic"; import { Subtitle } from "./subtitle"; import { TaskScheduler } from "../taskScheduler"; -import { BookType, OperateBookType } from "../../../define/enum/bookEnum"; +import { BookTaskStatus, BookType, OperateBookType } from "../../../define/enum/bookEnum"; import { Book } from "../../../model/book"; import { TimeStringToMilliseconds } from "../../../define/Tools/time"; @@ -130,7 +130,7 @@ export class SubtitleService { * @param bookTaskId 小说批次任务ID * @param operateBookType 操作的小说类型 * @param coverData 是不是要覆盖旧的数据 - * @returns + * @returns */ async GetCopywriting(bookId: string, bookTaskId: string, operateBookType: OperateBookType, coverData: boolean): Promise { try { @@ -195,7 +195,7 @@ export class SubtitleService { /** * 导出指定导出指定小说的文案 * @param bookTaskId 小说批次任务ID - * @returns + * @returns */ async ExportCopywriting(bookTaskId: string): Promise { try { @@ -233,11 +233,11 @@ export class SubtitleService { } /** - * 将 - * @param bookId - * @param bookTaskId - * @param txtPath - * @returns + * 导入修改过后的文案数据 + * @param bookId + * @param bookTaskId + * @param txtPath + * @returns */ async ImportCopywriting(bookId: string, bookTaskId: string, txtPath: string): Promise { try { @@ -305,7 +305,7 @@ export class SubtitleService { originalTime = JSON.parse(originalTimeString) } } - // 判断分镜数据和批次数据是不是相同的 + // 判断分镜数据和批次数据是不是相同的 好好办办 if (originalTime.length != bookTaskDetails.length) { originalTime = [] } @@ -337,5 +337,68 @@ export class SubtitleService { } } + /** + * 保存文案的对齐信息,这边会做一些判断 + * @param bookTaskId 小说任务ID + * @param copywritingData 要保存的文案数据 + * @param operateBookType 操作的小说类型 + * @returns + */ + async SaveCopywriting(bookTaskId: string, copywritingData: SubtitleModel.SaveCopywritingData[], operateBookType: OperateBookType): Promise { + try { + if (operateBookType != OperateBookType.BOOKTASK) { + throw new Error('目前只支持对小说任务的文案保存') + } + let bookTask = await this.bookServiceBasic.GetBookTaskDataById(bookTaskId) + let bookTaskDetails = await this.bookServiceBasic.GetBookTaskDetailData({ + bookTaskId: bookTaskId + }, true) + + if (bookTaskDetails.length == 0) { + // 新增 + for (let i = 0; i < copywritingData.length; i++) { + const element = copywritingData[i]; + await this.bookServiceBasic.AddBookTaskDetail({ + bookTaskId: bookTaskId, + bookId: bookTask.bookId, + startTime: element.start_time, + endTime: element.end_time, + status: BookTaskStatus.WAIT, + word: element.word, + afterGpt: element.after_gpt, + subValue: JSON.stringify(element.subValue), + timeLimit: element.timeLimit + }) + } + } else { + // 修改,这边就要判断是不是数量一致了 + if (bookTaskDetails.length != copywritingData.length) { + throw new Error("已有文案,再导入的时候,文案函数数量和分镜数据不一致,请检查") + } + // 开始修改。修改使用事务吧 + this.bookServiceBasic.transaction((realm) => { + for (let i = 0; i < copywritingData.length; i++) { + const element = copywritingData[i]; + let btd = realm.objectForPrimaryKey("BookTaskDetail", bookTaskDetails[i].id); + if (btd == null) { + throw new Error("未找到对应的分镜数据,请检查") + } + // 开始修改 + btd.startTime = element.start_time; + btd.endTime = element.end_time; + btd.word = element.word; + btd.afterGpt = element.after_gpt; + btd.subValue = JSON.stringify(element.subValue); + btd.timeLimit = element.timeLimit + } + }) + + } + + } catch (error) { + return errorMessage("保存文案数据失败,失败信息如下:" + error.toString(), 'SubtitleService_SaveCopywriting') + } + } + //#endregion -} \ No newline at end of file +} diff --git a/src/main/Service/Translate/Translate.ts b/src/main/Service/Translate/Translate.ts index 4552ca7..892c270 100644 --- a/src/main/Service/Translate/Translate.ts +++ b/src/main/Service/Translate/Translate.ts @@ -299,19 +299,11 @@ export class Translate { for (let j = 0; j < req_arr.length; j++) { const item = req_arr[j]; let res_tmp = translateList.find(item => item.index == j); - if (to == "zh") { - let obj = { - src: item, - dst: res_tmp.translated - } - res_data.push(obj); - } else if (to == "en") { - let obj = { - src: res_tmp.translated, - dst: item - } - res_data.push(obj); + let obj = { + src: item, + dst: res_tmp.translated } + res_data.push(obj); } // 直接返回数据 @@ -388,19 +380,11 @@ export class Translate { let res_data = []; for (let j = 0; j < req_data.length; j++) { const item = req_data[j]; - if (to == "zh") { - let obj = { - src: item, - dst: translateList[j] - } - res_data.push(obj); - } else if (to == "en") { - let obj = { - src: translateList[j], - dst: item - } - res_data.push(obj); + let obj = { + src: item, + dst: translateList[j] } + res_data.push(obj); } // 直接返回数据 @@ -474,19 +458,11 @@ export class Translate { let res_data = []; for (let j = 0; j < req_data.length; j++) { const item = req_data[j]; - if (to == "zh") { - let obj = { - src: item, - dst: translateList[j].Translation - } - res_data.push(obj); - } else if (to == "en") { - let obj = { - src: translateList[j].Translation, - dst: item - } - res_data.push(obj); + let obj = { + src: item, + dst: translateList[j].Translation } + res_data.push(obj); } // 直接返回数据 @@ -568,20 +544,20 @@ export class Translate { } let res_data = [] + res_data = res.data.trans_result // 将所有的数据协会到本地(然后发送消息到前台界面) - if (res.data.to == "zh") { - res_data = res.data.trans_result - } else { - // 直接在这边处理(前端不用处理) - for (let i = 0; i < res.data.trans_result.length; i++) { - const element = res.data.trans_result[i]; - let obj = { - src: element.dst, - dst: element.src - }; - res_data.push(obj); - } - } + // if (res.data.to == "zh") { + // } else { + // // 直接在这边处理(前端不用处理) + // for (let i = 0; i < res.data.trans_result.length; i++) { + // const element = res.data.trans_result[i]; + // let obj = { + // src: element.dst, + // dst: element.src + // }; + // res_data.push(obj); + // } + // } // 直接返回数据 return successMessage({ to: value.to, diff --git a/src/main/Service/Translate/TranslateService.ts b/src/main/Service/Translate/TranslateService.ts index 7714447..e004cd9 100644 --- a/src/main/Service/Translate/TranslateService.ts +++ b/src/main/Service/Translate/TranslateService.ts @@ -4,46 +4,38 @@ import { errorMessage, successMessage } from "../../Public/generalTools"; import { Translate } from "./Translate"; import { DEFINE_STRING } from "../../../define/define_string" import { TranslateAPIType, TranslateType } from "../../../define/enum/translate"; -import { BookTaskDetailService } from "../../../define/db/service/Book/bookTaskDetailService"; import { Book } from "../../../model/book"; import { ResponseMessageType } from "../../../define/enum/softwareEnum"; -import { SoftwareService } from '../../../define/db/service/SoftWare/softwareService' import { isEmpty } from "lodash"; import { ValidateJson } from "../../../define/Tools/validate"; import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic"; +import { SoftWareServiceBasic } from "../ServiceBasic/softwareServiceBasic"; +import { ExecuteConcurrently } from "../../../define/Tools/common"; /** * 翻译实现服务 */ export class TranslateService { translate: Translate - bookTaskDetail: BookTaskDetailService; - softwareService: SoftwareService bookServiceBasic: BookServiceBasic + softWareServiceBasic: SoftWareServiceBasic constructor() { this.bookServiceBasic = new BookServiceBasic(); - } - - async InitService() { - if (!this.bookTaskDetail) { - this.bookTaskDetail = await BookTaskDetailService.getInstance() - } - if (!this.softwareService) { - this.softwareService = await SoftwareService.getInstance() - } - if (!this.translate) { - this.translate = new Translate() - } + this.translate = new Translate(); + this.softWareServiceBasic = new SoftWareServiceBasic(); } // 返回翻译结果。用于前端修改 - private sendTranslateReturn(windowId: number, data: GeneralResponse.MessageResponse): void { + private sendTranslateReturn(windowId: number, data: GeneralResponse.MessageResponse, message_name: string = DEFINE_STRING.BOOK.MAIN_DATA_RETURN): void { let win = global.newWindow[0] if (windowId) { win = global.newWindow.filter(item => item.id == windowId)[0]; } - win.win.webContents.send(DEFINE_STRING.BOOK.MAIN_DATA_RETURN, data) + if (!message_name) { + message_name = DEFINE_STRING.BOOK.MAIN_DATA_RETURN + } + win.win.webContents.send(message_name, data) } @@ -97,14 +89,13 @@ export class TranslateService { */ async GetTranslateSetting(): Promise { try { - await this.InitService() let translateSetting = undefined as TranslateModel.TranslateModel - let translateSettingString = this.softwareService.GetSoftWarePropertyData('translationSetting'); + let translateSettingString = await this.softWareServiceBasic.GetSoftWarePropertyData('translationSetting'); if (isEmpty(translateSettingString)) { // 初始化 translateSetting = this.InitialTranslateSetting(); await this.ResetTranslateSetting(); - translateSettingString = this.softwareService.GetSoftWarePropertyData('translationSetting'); + translateSettingString = await this.softWareServiceBasic.GetSoftWarePropertyData('translationSetting'); translateSetting = JSON.parse(translateSettingString); } else { // 解析 @@ -140,7 +131,7 @@ export class TranslateService { async ResetTranslateSetting(): Promise { try { let translateSetting = this.InitialTranslateSetting() - let res = this.softwareService.SaveSoftwarePropertyData('translationSetting', JSON.stringify(translateSetting)) + let res = await this.softWareServiceBasic.SaveSoftwarePropertyData('translationSetting', JSON.stringify(translateSetting)) return successMessage(translateSetting, "重置翻译设置成功", "TranslateService_ResetTranslateSetting") } catch (error) { @@ -155,7 +146,7 @@ export class TranslateService { */ async SaveTranslateSetting(value: TranslateModel.TranslateModel): Promise { try { - let res = this.softwareService.SaveSoftwarePropertyData('translationSetting', JSON.stringify(value)) + let res = await this.softWareServiceBasic.SaveSoftwarePropertyData('translationSetting', JSON.stringify(value)) // 这边要判断是不是用的laitool let laitool = value.translates.filter(item => item.name == TranslateAPIType.LAITOOL) if (laitool.length > 0) { @@ -194,7 +185,7 @@ export class TranslateService { updateData.promptCN = dstString } // 修改数据 - this.bookTaskDetail.UpdateBookTaskDetailReversePrompt(bookTaskDetailId, reversePromptId, updateData) + await this.bookServiceBasic.UpdateBookTaskDetailReversePrompt(bookTaskDetailId, reversePromptId, updateData) } // 处理返回的数据 @@ -214,56 +205,62 @@ export class TranslateService { } } - // 翻译 + /** + * 翻译 + * @param value + * @returns + */ async TranslateNowReturn(value: TranslateModel.TranslateNowIPCParams[]): Promise { try { - await this.InitService() // 循环所有的数据,返回翻译结果 + let tasks = [] for (let i = 0; i < value.length; i++) { const element = value[i]; - let res = await this.translate.TranslateReturnNow(element) - // 单个翻译,将返回的数据写入到原数据中 + tasks.push(async () => { + let res = await this.translate.TranslateReturnNow(element) + // global.logger.info("断点写出", JSON.stringify(res)) + // 单个翻译,将返回的数据写入到原数据中 - // 添加一个对返回信息进行处理的函数 - let data = res.data - // 先将数据进行拼接 - let srcString = "" - if (element.isSplit) { - let dstStrs = [] - } else { - // 没有拆分的,只有一句 - srcString = data.data[0].dst - } - // 写回数据库 - await this.TranslateReturnProcess(element, data.to, srcString); - - let responseType = ResponseMessageType.REVERSE_PROMPT_TRANSLATE; - if (element.type == TranslateType.GPT_PROMPT_TRANSLATE) { - responseType = ResponseMessageType.GPT_PROMPT_TRANSLATE - } - // 做个返回数据 - this.sendTranslateReturn(element.windowId, { - code: 1, - id: element.bookTaskDetailId, - type: responseType, - data: { - progress: i + 1, - total: value.length, - from: element.from, - to: data.to, - bookTaskDetailId: element.bookTaskDetailId, - reversePromptId: element.reversePromptId, - prompt: srcString, - promptCN: srcString + // 添加一个对返回信息进行处理的函数 + let data = res.data + // 先将数据进行拼接 + let srcString = "" + if (element.isSplit) { + let dstStrs = [] + } else { + // 没有拆分的,只有一句 + srcString = data.data[0].dst } + // 写回数据库 + await this.TranslateReturnProcess(element, data.to, srcString); + + let responseType = ResponseMessageType.REVERSE_PROMPT_TRANSLATE; + if (element.type == TranslateType.GPT_PROMPT_TRANSLATE) { + responseType = ResponseMessageType.GPT_PROMPT_TRANSLATE + } + // 做个返回数据 + this.sendTranslateReturn(element.windowId, { + code: 1, + id: element.bookTaskDetailId, + type: responseType, + data: { + progress: i + 1, + total: value.length, + from: element.from, + to: data.to, + bookTaskDetailId: element.bookTaskDetailId, + reversePromptId: element.reversePromptId, + prompt: srcString, + promptCN: srcString + } + }, element.responseMessgeName) }) } - + let res = await ExecuteConcurrently(tasks, global.config.task_number) + // 将翻译后的数据返回,前端进行修改 return successMessage(null, "全部翻译完成", "TranslateService_TranslateNowReturn") - } catch (error) { return errorMessage("翻译失败,失败信息如下:" + error.toString(), "TranslateService_TranslateNowReturn") } } - } \ No newline at end of file diff --git a/src/main/Service/d3.ts b/src/main/Service/d3.ts index a48f5c4..a41c7a0 100644 --- a/src/main/Service/d3.ts +++ b/src/main/Service/d3.ts @@ -1,15 +1,193 @@ +import { BookServiceBasic } from "./ServiceBasic/bookServiceBasic"; +import { define } from '../../define/define' +import fs from 'fs' +import { GptService } from "./GPT/gpt"; +import { isEmpty } from "lodash"; +import path from 'path' +import { CheckFolderExistsOrCreate, CopyFileOrFolder } from "../../define/Tools/file"; +import { Base64ToFile, GetImageBase64 } from "../../define/Tools/image"; +import { BookBackTaskStatus } from "../../define/enum/bookEnum"; +import { MJAction, MJImageType } from "../../define/enum/mjEnum"; +import axios from "axios"; +export class D3Opt { + bookServiceBasic: BookServiceBasic + gptService: GptService + constructor() { + this.gptService = new GptService() + this.bookServiceBasic = new BookServiceBasic() + } -export class D3 { - constructor() { } + /** + * 获取SD的设置,之后要删掉,改为数据库 + */ + private async GetSDSetting() { + let sdSetting = JSON.parse(await fs.promises.readFile(define.sd_setting, 'utf-8')) + return sdSetting + } - //#region D3进行画图的基础方法 + //#region D3生图 - //#endregion + /** + * 异步发送D3 API图像请求 + * 该函数用于向指定的D3 API发送图像生成请求,通过提供模型、提示和图像大小等参数来定制生成的图像 + * + * @param url {string} - API的基础URL字符串,指定了发送请求的目标地址 + * @param key {string} - API密钥字符串,用于认证请求,使函数能够访问API服务 + * @param body {object} - 包含模型、提示和图像大小的对象 + * - model {string} 模型字段,指定用于生成图像的AI模型 + * - prompt {string} 提示字段,提供生成图像的文本描述或提示 + * - size {string} 大小字段,定义生成图像的尺寸 + * @returns 无返回值,但函数内部可能包含对API的异步请求操作 + */ + async D3APIImageRequest(url: string, key: string, body: { model: string; prompt: string; size: string; }) { + let response = await axios.post(url, { ...body, n: 1 }, { + headers: { + Authorization: 'Bearer ' + key + } + }) + if (response.data && response.data.data && response.data.data.length > 0) { + return response.data.data[0].url + } else { + return undefined + } + } - //#region 软件相关的方法 + /** + * 异步生成D3图像 + * @param task 任务模型 + * @returns Promise + */ + async D3ImageGenerate(task: TaskModal.Task): Promise { + let sdSetting = undefined + try { + console.log("D3ImageGenerate", task) + let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(task.bookTaskDetailId); + let bookTask = await this.bookServiceBasic.GetBookTaskDataById(bookTaskDetail.bookTaskId); + let book = await this.bookServiceBasic.GetBookDataById(bookTask.bookId); + sdSetting = await this.GetSDSetting() + await this.gptService.RefreshGptSetting(); + + let prompt = bookTaskDetail.prompt; + let requestUrl = this.gptService.gptUrl + let uil = new URL(requestUrl); + let url = `${uil.protocol}//${uil.hostname}` + "/v1/images/generations" + + if (!isEmpty(sdSetting.webui.prompt)) { + prompt = sdSetting.webui.prompt + ', ' + prompt + } + let size = `${sdSetting.webui.width}x${sdSetting.webui.height}` + // 这边需要判断下size是不是合法的 + if (!['1024x1024', '1024x1792', '1792x1024'].includes(size)) { + throw new Error('D3 生成图片的尺寸不合法,只支持 1024x1024、1024x1792、1792x1024') + } + let model = 'dall-e-3' + // 一次请求生成一张 多个请求 + + let SdOriginalImage = path.join(book.bookFolderPath, 'data/SdOriginalImage'); + await CheckFolderExistsOrCreate(SdOriginalImage); + let outputFolder = bookTask.imageFolder; + await CheckFolderExistsOrCreate(outputFolder); + let inputFolder = path.join(book.bookFolderPath, 'tmp/input') + await CheckFolderExistsOrCreate(inputFolder); + + let outImagePath = '' + let subImagePath = [] + + let batchSize = sdSetting.setting.batch_size; 7 + for (let i = 0; i < batchSize; i++) { + const element = batchSize; + let imageUrl = await this.D3APIImageRequest(url, this.gptService.gptApiKey, { + model: model, + prompt: prompt, + size: size + }) + // 这边开始处理返回的数据 + if (isEmpty(imageUrl)) { + throw new Error('D3 生图返回的图片地址为空') + } + // 下载指定的文件 + let base64 = await GetImageBase64(imageUrl) + // 将base64 写出 + let imgPath = path.join(SdOriginalImage, `${bookTaskDetail.name}_${new Date().getTime()}_${i}.png`) + await Base64ToFile(base64, imgPath); + + // 写出去 + if (bookTask.name == 'output_00001') { + // 复制一个到input + let inputImgPath = path.join(inputFolder, `${bookTaskDetail.name}.png`) + await CopyFileOrFolder(imgPath, inputImgPath) + } + if (i == 0) { + // 复制到对应的文件夹里面 + let outPath = path.join(outputFolder, `${bookTaskDetail.name}.png`) + await CopyFileOrFolder(imgPath, outPath) + outImagePath = outPath + } + subImagePath.push(imgPath) + } + + // 结束 开始返回 + // 修改数据库 + await this.bookServiceBasic.UpdateBookTaskDetail(bookTaskDetail.id, { + outImagePath: path.relative(define.project_path, outImagePath), + subImagePath: subImagePath.map((item) => path.relative(define.project_path, item)) + }) + await this.bookServiceBasic.UpdateTaskStatus({ + id: task.id, + status: BookBackTaskStatus.DONE + }); + let resp = { + mjApiUrl: url, + progress: 100, + category: MJImageType.FLUX_API, + imageClick: subImagePath.join(','), + imageShow: subImagePath.join(','), + messageId: "", + action: MJAction.IMAGINE, + status: "success", + subImagePath: subImagePath, + outImagePath: outImagePath, + message: "D3 生成图片成功" + } + await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, resp) + global.newWindow[0].win.webContents.send(task.messageName, { + code: 1, + message: "D3 生成图片成功", + data: { + ...resp, + id: bookTaskDetail.id + } + }) + + } catch (error) { + let errorMsg = "D3 生成图片失败,错误信息如下:" + error.toString() + await this.bookServiceBasic.UpdateBookTaskDetailMjMessage(task.bookTaskDetailId, { + mjApiUrl: "", + progress: 0, + category: MJImageType.FLUX_API, + imageClick: "", + imageShow: "", + messageId: "", + action: MJAction.IMAGINE, + status: "error", + message: errorMsg, + }) + + global.newWindow[0].win.webContents.send(task.messageName, { + code: 0, + message: errorMsg, + data: { + status: 'error', + message: errorMsg, + id: task.bookTaskDetailId + } + }) + throw error + } + } +} + +//#endregion - - //endregion -} \ No newline at end of file diff --git a/src/main/Service/presetService.ts b/src/main/Service/presetService.ts new file mode 100644 index 0000000..edf6234 --- /dev/null +++ b/src/main/Service/presetService.ts @@ -0,0 +1,129 @@ +import { errorMessage, successMessage } from "../Public/generalTools"; +import { define } from '../../define/define' +import { CheckFileOrDirExist } from "../../define/Tools/file"; +import fs from 'fs' +import { ValidateJson } from "../../define/Tools/validate"; +import { GeneralResponse } from "../../model/generalResponse"; +import { PresetModel } from "../../model/preset"; + +export class PresetService { + constructor() { } + + //TODO 这边现在都是基于文件的,后面需要改为基于数据库的 + + //#region 人物预设 + /** + *获取所有的人物显示的预设(只要label和id) + */ + async GetCharacterPreset(): Promise { + try { + let result = [] + let tagPath = define.tag_setting + if (!(await CheckFileOrDirExist(tagPath))) { + return successMessage(result, '获取人物预设列表成功', "PresetService_GetCharacterPreset") + } + let tagString = await fs.promises.readFile(tagPath, 'utf-8'); + if (!ValidateJson(tagString)) { + return successMessage(result, '获取人物预设列表成功', "PresetService_GetCharacterPreset") + } + let tags = JSON.parse(tagString) + let characterTags = tags.character_tags + for (let i = 0; characterTags && i < characterTags.length; i++) { + let element = characterTags[i] + if (element.isShow) { + result.push({ + label: element.label, + id: element.key + }) + } + } + return successMessage(result, '获取人物预设列表成功', "PresetService_GetCharacterPreset") + } catch (error) { + return errorMessage("获取人物预设失败,失败信息如下: " + error.toString(), "PresetService_GetCharacterPreset") + } + } + + /** + * 获取指定ID的人物预设的详细信息 + * @param id 人物预设的ID + */ + async GetCharacterPresetDetailById(id: string): Promise { + try { + let result = undefined as PresetModel.Preset + let tagPath = define.tag_setting + if (!(await CheckFileOrDirExist(tagPath))) { + return successMessage(result, '获取人物预设详细数据成功', "PresetService_GetCharacterPreset") + } + let tagString = await fs.promises.readFile(tagPath, 'utf-8'); + if (!ValidateJson(tagString)) { + return successMessage(result, '获取人物预设列表成功', "PresetService_GetCharacterPreset") + } + let tags = JSON.parse(tagString) + let characterTags = tags.character_tags + result = characterTags.find((item: any) => item.key === id) + return successMessage(result, '获取人物预设详细数据成功', "PresetService_GetCharacterPreset") + } catch (error) { + return errorMessage("获取人物预设详细信息失败,失败信息如下: " + error.toString(), "PresetService_GetCharacterPresetDetailById") + } + } + + //#endregion + + + //#region 场景预设 + + // 获取所有的场景预设(label和ID) + async GetScenePreset(): Promise { + try { + let result = [] + let tagPath = define.tag_setting + if (!(await CheckFileOrDirExist(tagPath))) { + return successMessage(result, '获取场景预设列表成功', "PresetService_GetScenePreset") + } + let tagString = await fs.promises.readFile(tagPath, 'utf-8'); + if (!ValidateJson(tagString)) { + return successMessage(result, '获取场景预设列表成功', "PresetService_GetScenePreset") + } + let tags = JSON.parse(tagString) + let sceneTags = tags.scene_tags + for (let i = 0; sceneTags && i < sceneTags.length; i++) { + let element = sceneTags[i] + if (element.isShow) { + result.push({ + label: element.label, + id: element.key + }) + } + } + return successMessage(result, '获取场景预设列表成功', "PresetService_GetScenePreset") + } catch (error) { + return errorMessage("获取场景预设失败,失败信息如下: " + error.toString(), "PresetService_GetScenePreset") + } + } + + /** + * 通过获取场景预设的详细信息 + * @param id 场景预设的ID + */ + async GetScenePresetDetailById(id: string): Promise { + try { + let result = undefined as PresetModel.Preset + let tagPath = define.tag_setting + if (!(await CheckFileOrDirExist(tagPath))) { + return successMessage(result, '获取场景预设详细数据成功', "PresetService_GetCharacterPreset") + } + let tagString = await fs.promises.readFile(tagPath, 'utf-8'); + if (!ValidateJson(tagString)) { + return successMessage(result, '获取场景预设详细数据成功', "PresetService_GetCharacterPreset") + } + let tags = JSON.parse(tagString) + let sceneTags = tags.scene_tags + result = sceneTags.find((item: any) => item.key === id) + return successMessage(result, '获取人物预设详细数据成功', "PresetService_GetCharacterPreset") + } catch (error) { + return errorMessage("获取场景预设详细信息失败,失败信息如下: " + error.toString(), "PresetService_GetScenePresetDetailById") + } + } + + //#endregion +} \ No newline at end of file diff --git a/src/main/Service/taskManage.ts b/src/main/Service/taskManage.ts index cf97711..22d4adf 100644 --- a/src/main/Service/taskManage.ts +++ b/src/main/Service/taskManage.ts @@ -7,7 +7,12 @@ import { ReverseBook } from './Book/ReverseBook' import { GeneralResponse } from '../../model/generalResponse' import { DEFINE_STRING } from '../../define/define_string' import { MJOpt } from './MJ/mj' +import { SDOpt } from './SD/sd' +import { D3Opt } from './d3' +import { FluxOpt } from './Flux/flux' import { AsyncQueue } from '../../main/quene' +import { SoftWareServiceBasic } from './ServiceBasic/softwareServiceBasic' +import { MJSetting } from '../../model/Setting/mjSetting' export class TaskManager { isExecuting: boolean = false; @@ -18,12 +23,17 @@ export class TaskManager { softwareService!: SoftwareService; bookBackTaskListService!: BookBackTaskListService; eventListeners: Record = {}; + softWareServiceBasic: SoftWareServiceBasic + mjSetting: MJSetting.MjSetting spaceTime: number = 5000; count = 0; isListening = false; intervalId: any; // 用于存储 setInterval 的 ID mjOpt: MJOpt + sdOpt: SDOpt + d3Opt: D3Opt + fluxOpt: FluxOpt constructor() { this.isExecuting = false; @@ -32,6 +42,10 @@ export class TaskManager { this.basicReverse = new BasicReverse(); this.reverseBook = new ReverseBook(); this.mjOpt = new MJOpt(); + this.sdOpt = new SDOpt(); + this.d3Opt = new D3Opt() + this.softWareServiceBasic = new SoftWareServiceBasic(); + this.fluxOpt = new FluxOpt() } async InitService(getMJsetting = false) { @@ -42,7 +56,8 @@ export class TaskManager { this.bookBackTaskListService = await BookBackTaskListService.getInstance(); } if (getMJsetting) { - await this.mjOpt.InitService(); + // 初始化MJ设置 + this.mjSetting = await this.softWareServiceBasic.GetMjSetting() } } @@ -126,8 +141,8 @@ export class TaskManager { if (element.type == BookBackTaskType.MJ_IMAGE || element.type == BookBackTaskType.MJ_REVERSE) { // 判断任务数量是不是又修改 let taskNumber = global.mjQueue.getConcurrencyLimit(); - if (taskNumber != this.mjOpt.mjSetting.taskCount) { - global.mjQueue.concurrencyLimit = this.mjOpt.mjSetting.taskCount // 重置并发执行的数量 + if (taskNumber != this.mjSetting.taskCount) { + global.mjQueue.concurrencyLimit = this.mjSetting.taskCount // 重置并发执行的数量 } if (global.mjQueue.getWaitingQueue() > 10) { @@ -216,6 +231,68 @@ export class TaskManager { }, `${batch}_${task.id}`, batch) } + /** + * 将MJ生图生成任务添加内存任务中 + * @param task + */ + async AddImageMJImage(task: TaskModal.Task) { + // 判断是不是MJ的任务 + let batch = DEFINE_STRING.MJ.MJ_IMAGE; + global.mjQueue.enqueue(async () => { + await this.mjOpt.MJImagine(task); + }, `${batch}_${task.id}`, batch, `${batch}_${task.id}_${new Date().getTime()}`); + } + + + /** + * 将SD生图任务添加到内存任务中 + * @param task + */ + async AddSDImage(task: TaskModal.Task) { + let batch = DEFINE_STRING.SD.TXT2IMG + global.requestQuene.enqueue(async () => { + await this.sdOpt.SDImageGenerate(task); + }, `${batch}_${task.id}`, batch, `${batch}_${task.id}_${new Date().getTime()}`) + } + + /** + * 异步添加D3图像生成任务 + * + * 此方法接受一个任务对象,将基于该任务生成D3图像 + * 它使用全局请求队列来管理任务,确保并发处理的效率和稳定性 + * + * @param task 任务对象,包含任务的具体信息和标识 + */ + async AddD3Image(task: TaskModal.Task) { + let batch = task.messageName; + global.requestQuene.enqueue(async () => { + await this.d3Opt.D3ImageGenerate(task); + }, `${batch}_${task.id}`, batch, `${batch}_${task.id}_${new Date().getTime()}`) + } + + + /** + * 添加 flux forge 任务到内存队列中 + * @param task + */ + async AddFluxForgeImage(task: TaskModal.Task) { + let batch = task.messageName + global.requestQuene.enqueue(async () => { + await this.fluxOpt.FluxForgeImage(task); + }, `${batch}_${task.id}`, batch, `${batch}_${task.id}_${new Date().getTime()}`) + } + + /** + * 添加 FLUX api 到内存队列中 + * @param task + */ + async AddFluxAPIImage(task: TaskModal.Task) { + let batch = task.messageName; + global.requestQuene.enqueue(async () => { + await this.fluxOpt.FluxAPIImage(task); + }, `${batch}_${task.id}`, batch, `${batch}_${task.id}_${new Date().getTime()}`) + } + /** * 添加任务到内存队列中,分流 * @param task 任务相关 @@ -243,10 +320,21 @@ export class TaskManager { case BookBackTaskType.MJ_REVERSE || BookBackTaskType.SD_REVERSE: this.AddSingleReversePrompt(task); break; - + case BookBackTaskType.FLUX_FORGE_IMAGE: + this.AddFluxForgeImage(task); + break; + case BookBackTaskType.FLUX_API_IMAGE: + this.AddFluxAPIImage(task); + break; case BookBackTaskType.MJ_IMAGE: this.AddImageMJImage(task); break; + case BookBackTaskType.SD_IMAGE: + this.AddSDImage(task); + break; + case BookBackTaskType.D3_IMAGE: + this.AddD3Image(task); + break; default: throw new Error('未知的任务类型'); } @@ -276,17 +364,6 @@ export class TaskManager { } } - /** - * 将MJ生图生成 - * @param task - */ - async AddImageMJImage(task: TaskModal.Task) { - // 判断是不是MJ的任务 - let batch = DEFINE_STRING.MJ.MJ_IMAGE; - global.mjQueue.enqueue(async () => { - await this.mjOpt.MJImagine(task); - }, `${batch}_${task.id}`, batch, `${batch}_${task.id}_${new Date().getTime()}`); - } //#endregion diff --git a/src/main/Service/writing.js b/src/main/Service/writing.js index d87c9cc..646e474 100644 --- a/src/main/Service/writing.js +++ b/src/main/Service/writing.js @@ -93,15 +93,20 @@ export class Writing extends ServiceBase { 'Writing_ActionStart' ) } else { - // 处理不同类型的错误消息 - if (setting.gptAI == 'laiapi') { - throw new Error(GetRixApiErrorResponse(dataRes.data)) - } else if (setting.gptAI == 'kimi') { - throw new Error(GetKimiErrorResponse(dataRes.data)) - } else if (setting.gptAI == 'doubao') { - throw new Error(GetDoubaoErrorResponse(dataRes.data)) + // 系统报错 + if (dataRes.code == 5000) { + throw new Error('系统错误,错误信息如下:' + dataRes.message) } else { - throw new Error(dataRes.data) + // 处理不同类型的错误消息 + if (setting.gptAI == 'laiapi') { + throw new Error(GetRixApiErrorResponse(dataRes.data)) + } else if (setting.gptAI == 'kimi') { + throw new Error(GetKimiErrorResponse(dataRes.data)) + } else if (setting.gptAI == 'doubao') { + throw new Error(GetDoubaoErrorResponse(dataRes.data)) + } else { + throw new Error(dataRes.data) + } } } } catch (error) { diff --git a/src/main/func.js b/src/main/func.js index e16cc4d..0a4209d 100644 --- a/src/main/func.js +++ b/src/main/func.js @@ -17,6 +17,7 @@ import { PublicMethod } from "./Public/publicMethod" import { ImageStyleDefine } from "../define/iamgeStyleDefine"; let tools = new Tools(); let pm = new PublicMethod(global); +import { FLxuAPIImageType } from '../define/enum/image' /** * 获取对应的轨道 @@ -641,7 +642,15 @@ async function SaveSDConfig(value) { sd_config.webui.height = value.height ? value.height : sd_config.webui.height; sd_config.webui.cfg_scale = value.cfg_scale ? value.cfg_scale : sd_config.webui.cfg_scale; sd_config.webui.adetailer = value.hasOwnProperty("adetailer") ? value.adetailer : sd_config.webui.adetailer; - + + if(!sd_config.flux){ + let model = { + model : value.flux_model ? value.flux_model : FLxuAPIImageType.FLUX + } + sd_config.flux = model + }else{ + sd_config.flux.model = value.flux_model ? value.flux_model : FLxuAPIImageType.FLUX; + } await fspromises.writeFile(define.sd_setting, JSON.stringify(sd_config)); return { code: 1, diff --git a/src/main/index.js b/src/main/index.js index 4c581df..9eaa4a8 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -7,7 +7,7 @@ import { app, shell, BrowserWindow, ipcMain, dialog, nativeTheme, session } from import path, { join } from 'path' import { electronApp, optimizer, is } from '@electron-toolkit/utils' import icon from '../../resources/icon.ico?asset' -import { define } from '../define/define.js' +import { define } from '../define/define' import { func } from './func.js' import { AsyncQueue } from './quene' import { DEFINE_STRING } from '../define/define_string' @@ -17,6 +17,7 @@ import { Setting } from './setting/setting.js' import { has, isEmpty } from 'lodash' import { AutoSync } from './setting/autoSync.js' import { TaskManager } from './Service/taskManage' +import { SoftWareServiceBasic } from './Service/ServiceBasic/softwareServiceBasic' // ipc import { DiscordIpc, RemoveDiscordIpc } from './IPCEvent/discordIpc.js' @@ -26,6 +27,7 @@ import { RegisterIpc } from './IPCEvent/index.js' let tools = new Tools() let imageGenerate = new ImageGenerate(global) let setting = new Setting(global) +let softWareServiceBasic = new SoftWareServiceBasic() async function InitData(gl) { let res = await setting.getSettingDafultData() @@ -113,6 +115,9 @@ async function createWindow(hash = 'ShowMessage', data, url = null) { let window_wh_bm = mainWindow.getBounds() // 记录到文件中 await setting.ModifySampleSetting(JSON.stringify({ window_wh_bm: window_wh_bm })) + await softWareServiceBasic.UpdateSoftware({ + window_wh_bm: JSON.stringify(window_wh_bm) + }) } }) diff --git a/src/main/quene.js b/src/main/quene.js index d334325..12afb7b 100644 --- a/src/main/quene.js +++ b/src/main/quene.js @@ -141,7 +141,8 @@ export class AsyncQueue { if ( [ DEFINE_STRING.QUEUE_BATCH.SD_BACKSTEP_GENERATE_IMAGE, - DEFINE_STRING.QUEUE_BATCH.SD_ORIGINAL_GENERATE_IMAGE + DEFINE_STRING.QUEUE_BATCH.SD_ORIGINAL_GENERATE_IMAGE, + DEFINE_STRING.SD.TXT2IMG ].includes(batchId) ) { retryTask() diff --git a/src/main/setting/autoSync.js b/src/main/setting/autoSync.js index 5abb84f..89b779a 100644 --- a/src/main/setting/autoSync.js +++ b/src/main/setting/autoSync.js @@ -46,10 +46,8 @@ async function GlobalAutoSync() { if (softWareData.globalSetting == null || softWareData.globalSetting == '') { let initGlobalConfig = await fspromises.readFile(initConifgPath, 'utf-8') softWareData.globalSetting = initGlobalConfig - let updateSfotwareRes = _softwareService.UpdateSoftware(softWareData) - if (updateSfotwareRes.code == 1) { - global.logger.info('AutoSunc_GlobalAutoSync', '初始化全局设置成功') - } + _softwareService.UpdateSoftware(softWareData) + global.logger.info('AutoSunc_GlobalAutoSync', '初始化全局设置成功') } } } catch (error) { diff --git a/src/main/setting/basicSetting.js b/src/main/setting/basicSetting.ts similarity index 67% rename from src/main/setting/basicSetting.js rename to src/main/setting/basicSetting.ts index 3b10246..6555da5 100644 --- a/src/main/setting/basicSetting.js +++ b/src/main/setting/basicSetting.ts @@ -1,15 +1,12 @@ -import SoftwareService from '../../define/db/service/SoftWare/softwareService' import { ComponentSize } from '../../define/enum/softwareEnum' import { errorMessage, successMessage } from '../Public/generalTools' +import { SoftWareServiceBasic } from '../Service/ServiceBasic/softwareServiceBasic' export class BasicSetting { - constructor() {} - - // 初始化数据 - async init() { - this.setting = await SoftwareService.getInstance() + softWareServiceBasic: SoftWareServiceBasic + constructor() { + this.softWareServiceBasic = new SoftWareServiceBasic() } - /** * 获取修改尺寸的下拉菜单的尺寸 * @returns @@ -46,9 +43,8 @@ export class BasicSetting { // 获取基础配置信息 async GetSoftwareSetting() { try { - await this.init() - let res = this.setting.GetSoftwareData() - return res + let res = await this.softWareServiceBasic.GetSoftwareData() + return successMessage(res, '获取软件配置信息成功', 'BasicSetting_GetSoftwareSetting') } catch (error) { return errorMessage(error.message, 'BasicSetting_GetSoftwareSetting') } @@ -60,11 +56,10 @@ export class BasicSetting { * @returns */ - async SaveSoftWareSetting(paramms) { + async SaveSoftWareSetting(paramms: SoftwareSettingModel.SoftwareSetting) { try { - await this.init() - let res = this.setting.UpdateSoftware(paramms) - return res + await this.softWareServiceBasic.UpdateSoftware(paramms) + return successMessage(null, '保存软件设置成功', 'BasicSetting_SaveSoftWareSetting') } catch (error) { return errorMessage(error.message, 'BasicSetting_SaveSoftWareSetting') } diff --git a/src/main/setting/setting.js b/src/main/setting/setting.js index 0d293f3..6a10e20 100644 --- a/src/main/setting/setting.js +++ b/src/main/setting/setting.js @@ -10,12 +10,15 @@ import { DEFINE_STRING } from '../../define/define_string' import { TagDefine } from '../../define/tagDefine' import { errorMessage } from '../Public/generalTools' import { TaskManager } from '../Service/taskManage' +import { SoftWareServiceBasic } from '../Service/ServiceBasic/softwareServiceBasic' +import { FLxuAPIImageType } from '../../define/enum/image' let tagDefine = new TagDefine(global) export class Setting { constructor(global) { this.global = global this.tools = new Tools() + this.softWareServiceBasic = new SoftWareServiceBasic() } //#region 剪映设置 @@ -172,7 +175,8 @@ export class Setting { cfg_scale: sd_config.webui.cfg_scale, sd_model: sd_config.sd_model, lora: sd_config.lora, - sampler: sd_config.sampler + sampler: sd_config.sampler, + flux_model: sd_config.flux?.model ? sd_config.flux.model : FLxuAPIImageType.FLUX } } } catch (error) { diff --git a/src/model/Setting/softwareSetting.d.ts b/src/model/Setting/softwareSetting.d.ts index 3aef767..c7b30d7 100644 --- a/src/model/Setting/softwareSetting.d.ts +++ b/src/model/Setting/softwareSetting.d.ts @@ -14,4 +14,30 @@ declare namespace SoftwareSettingModel { translationSetting?: string subtitleSetting?: string } + + type GlobalSetting = { + draft_path: string = undefined // 草稿路径 + project_path: string = undefined // 项目路径 + project_name: string = undefined // 项目名称 + gpt_business: string = undefined // GPT服务商ID + gpt_model: string = undefined // GPT模型 + task_number: number = undefined // 任务数量 + theme: string = undefined // 主题 + gpt_auto_inference: string = undefined // GPT自动推理模式 + webui_api_url: string = undefined // webui地址 + gpt_count: number = 10 // GPT上下文数量 + customize_gpt_prompt: string = undefined // 自定义GPT提示ID + character_select_model: "drop" | 'tag' = 'drop' // 人物选择模式, + image_generate_category: 'sd' | 'mj' | 'd3' | 'fulx-forge' | 'flux-api' = 'mj' // 生图方式 + window_wh_bm_remember: boolean = false// 记住窗口大小 + window_wh_bm: { + x: number = 0, // 窗口x坐标 + y: number = 0, // 窗口y坐标 + width: number = 800, // 窗口宽度 + height: number = 600, // 窗口高度 + }, + space_image: string = undefined // 空白图片 + gpt_key: string = undefined // GPT KEY, + laiApiSelect: string = undefined // LaiAPI选择 + } } \ No newline at end of file diff --git a/src/model/book.d.ts b/src/model/book.d.ts index 092bc50..77d7349 100644 --- a/src/model/book.d.ts +++ b/src/model/book.d.ts @@ -1,4 +1,4 @@ -import { BookBackTaskStatus, BookBackTaskType, BookTaskStatus, BookType, TaskExecuteType, BookRepalceDataType } from "../define/enum/bookEnum" +import { BookBackTaskStatus, BookBackTaskType, BookTaskStatus, BookType, TaskExecuteType, BookRepalceDataType, BookImageCategory } from "../define/enum/bookEnum" import { MJAction } from "../define/enum/bookEnum" import { MJImageType } from "../define/enum/mjEnum" @@ -154,6 +154,7 @@ declare namespace Book { timeLimit?: string // 事件实现(0 -- 3000) subValue?: string // 包含的字幕数据 characterTags?: string[] // 角色标签 + sceneTags?: string[] // 场景标签 gptPrompt?: string // GPT提示词 mjMessage?: MJMessage // MJ消息 outImagePath?: string // 输出图片地址 diff --git a/src/model/generalResponse.d.ts b/src/model/generalResponse.d.ts index 48a17cf..d2be0f8 100644 --- a/src/model/generalResponse.d.ts +++ b/src/model/generalResponse.d.ts @@ -30,7 +30,7 @@ declare namespace GeneralResponse { type MessageResponse = { code: number, id: string, // 消息的唯一标识(可以和前端相关联) - type: ResponseMessageType, + type?: ResponseMessageType, dialogType?: DialogType = DialogType.MESSAGE, message?: string, data?: MJ.MJResponseToFront | Buffer | string | TranslateModel.TranslateResponseMessageModel | ProgressResponse | SubtitleProgressResponse diff --git a/src/model/mj.d.ts b/src/model/mj.d.ts index da8f322..dec4721 100644 --- a/src/model/mj.d.ts +++ b/src/model/mj.d.ts @@ -14,15 +14,15 @@ declare namespace MJ { type: MJRespoonseType, // 返回前端的操作类型 mjType: MJAction, // 执行MJ的类型 category: MJImageType, // 调用MJ分类 - message_id?: string, // 返回消息的id,就是任务ID - image_click?: string, // 预览的图片(再使用浏览器模式的时候需要,其他都是null) - image_show?: string, // 实际下载的图片的地址 - image_path?: string, //实际下载的图片的地址 + messageId?: string, // 返回消息的id,就是任务ID + imageClick?: string, // 预览的图片(再使用浏览器模式的时候需要,其他都是null) + imageShow?: string, // 实际下载的图片的地址 + imagePath?: string, //实际下载的图片的地址 prompt?: string, // 提示词消息 progress: number, // 实现的进程 message?: string // 消息 status: string - mj_api_url?: string // 请求的MJ地址 + mjApiUrl?: string // 请求的MJ地址 outImagePath?: string // 输出的图片地址 subImagePath?: string[] // 子图片地址 } diff --git a/src/model/preset.d.ts b/src/model/preset.d.ts new file mode 100644 index 0000000..e4b1934 --- /dev/null +++ b/src/model/preset.d.ts @@ -0,0 +1,31 @@ +import { PresetType } from "../define/enum/preset" + +declare namespace PresetModel { + /** + * 完整的预设的数据Model + */ + type Preset = { + id?: string + label?: string + type?: TAGType + showImage?: string + prompt?: string + chinesePrompt?: string + imageUrl?: string + srefSw?: number + crefCw?: number + lora?: string + loraWeight?: number + isShow?: boolean + children?: string + } + + /** + * 前端界面相关的数据model + */ + type PresetList = { + id: string + label: string + checked: boolean = false + } +} \ No newline at end of file diff --git a/src/model/subtitle.d.ts b/src/model/subtitle.d.ts index 4af06fc..839e4aa 100644 --- a/src/model/subtitle.d.ts +++ b/src/model/subtitle.d.ts @@ -1,6 +1,11 @@ import { GetSubtitleType } from "../define/enum/waterMarkAndSubtitle" declare namespace SubtitleModel { + + //#region 提取视频文案相关 + /** + * 提取文案设置 + */ type subtitleSettingModel = { selectModel: GetSubtitleType, laiWhisper: { @@ -10,4 +15,35 @@ declare namespace SubtitleModel { prompt: string } } + + //#endregion + + //#region 小说文案相关s + + /** + * 文案数据包含的字幕数据 + */ + type CopywritingSubValue = { + end_time: number, + start_time: number, + id: string, + srt_value: string + } + + /** + * 保存文案数据类型 + */ + type SaveCopywritingData = { + id: string, + lastId: string, + no: number, + after_gpt: string, + start_time: number, + end_time: number, + subValue: CopywritingSubValue[] + timeLimit: string, + word: string + } + + //#endregion } \ No newline at end of file diff --git a/src/model/task.d.ts b/src/model/task.d.ts index 79e151c..9d73c32 100644 --- a/src/model/task.d.ts +++ b/src/model/task.d.ts @@ -1,18 +1,19 @@ declare namespace TaskModal { type Task = { - id: string - bookId: string - bookTaskId: string - bookTaskDetailId: string - name: string // 任务名称,小说名+批次名+分镜名 - type: BookBackTaskType - status: BookBackTaskStatus - errorMessage: string | null - executeType: TaskExecuteType // 任务执行类型,手动还是自动 - createTime: Date - updateTime: Date - startTime: number - endTime: number + id?: string + bookId?: string + bookTaskId?: string + bookTaskDetailId?: string + name?: string // 任务名称,小说名+批次名+分镜名 + type?: BookBackTaskType + status?: BookBackTaskStatus + errorMessage?: string | null + executeType?: TaskExecuteType // 任务执行类型,手动还是自动 + createTime?: Date + updateTime?: Date + startTime?: number + endTime?: number, + messageName?: string } } \ No newline at end of file diff --git a/src/model/translate.d.ts b/src/model/translate.d.ts index df38472..31b3bb7 100644 --- a/src/model/translate.d.ts +++ b/src/model/translate.d.ts @@ -17,6 +17,7 @@ declare namespace TranslateModel { reversePromptId?: string // 反推提示词ID windowId?: number // 窗口ID type: TranslateType // 翻译类型 + responseMessgeName?: string // 返回的消息名称(用作自定义) } type TranslateResponseMessageModel = { diff --git a/src/preload/book.ts b/src/preload/book.ts index 9fa4a15..5be2918 100644 --- a/src/preload/book.ts +++ b/src/preload/book.ts @@ -1,6 +1,8 @@ import { ipcRenderer } from 'electron' import { DEFINE_STRING } from '../define/define_string' import { Book } from '../model/book' +import { SubtitleModel } from '../model/subtitle' +import { BookType, OperateBookType } from '../define/enum/bookEnum' const book = { // 获取小说操作类型(原创/SD反推/MJ反推) @@ -84,7 +86,7 @@ const book = { //#region 文案相关信息 - // 获取文案信息 + // 反推识别文案的方法 GetCopywriting: async (bookId, bookTaskId, operateBookType, coverData) => await ipcRenderer.invoke( DEFINE_STRING.BOOK.GET_COPYWRITING, @@ -94,6 +96,11 @@ const book = { coverData ), + // 保存导入的文案数据(文案和字幕对齐后的) + SaveCopywriting: async (bookTaskId: string, copywritingData: SubtitleModel.SaveCopywritingData, operateBookType: OperateBookType) => + await ipcRenderer.invoke(DEFINE_STRING.BOOK.SAVE_COPYWRITING, bookTaskId, copywritingData, operateBookType), + + // 将文案信息导出,方便修改 ExportCopywriting: async (bookTaskId) => await ipcRenderer.invoke(DEFINE_STRING.BOOK.EXPORT_COPYWRITING, bookTaskId), @@ -121,10 +128,6 @@ const book = { MergePrompt: async (id, type, operateBookType) => await ipcRenderer.invoke(DEFINE_STRING.BOOK.MERGE_PROMPT, id, type, operateBookType), - //#endregion - - //#region 一键反推的单个任务 - // 添加单句反推的 AddReversePrompt: async (bookTaskDetailIds, operateBookType, type) => await ipcRenderer.invoke( @@ -143,6 +146,30 @@ const book = { index ), + // 删除掉所有的反推和GPT提示词数据 + ResetGptReverseData: async (id: string, operateBookType: OperateBookType, type: BookType) => + await ipcRenderer.invoke(DEFINE_STRING.BOOK.RESET_GPT_REVERSE_DATA, id, operateBookType, type), + + // 删除所有的合并提示词数据 + ResetMergePromptData: async (id, operateBookType) => + await ipcRenderer.invoke(DEFINE_STRING.BOOK.REMOVE_MERGE_PROMPT_DATA, id, operateBookType), + + // 原创推理所有的提示词 + OriginalGetPrompt: async (id: string, operateBookType: OperateBookType, coverData: boolean) => + await ipcRenderer.invoke(DEFINE_STRING.BOOK.ORIGINAL_GPT_PROMPT, id, operateBookType, coverData), + + //#endregion + + //#region 图片相关 + + // 删除所有的生成图片 + ResetGenerateImage: async (id: string, operateBookType: OperateBookType, coverData: boolean) => + await ipcRenderer.invoke(DEFINE_STRING.BOOK.REMOVE_GENERATE_IMAGE, id, operateBookType, coverData), + + //#endregion + + //#region 一键反推的单个任务 + // 单个重选反推的提示词 SingleReverseToGptPrompt: async (bookTaskDetailId, index) => await ipcRenderer.invoke( @@ -151,17 +178,6 @@ const book = { index ), - // 删除掉所有的反推和GPT提示词数据 - ResetGptReverseData: async (id, operateBookType, type) => - await ipcRenderer.invoke(DEFINE_STRING.BOOK.RESET_GPT_REVERSE_DATA, id, operateBookType, type), - - // 删除所有的合并提示词数据 - ResetMergePromptData: async (id, operateBookType) => - await ipcRenderer.invoke(DEFINE_STRING.BOOK.REMOVE_MERGE_PROMPT_DATA, id, operateBookType), - - // 删除所有的生成图片 - ResetGenerateImage: async (id, operateBookType) => - await ipcRenderer.invoke(DEFINE_STRING.BOOK.REMOVE_GENERATE_IMAGE, id, operateBookType), //#endregion diff --git a/src/preload/db.ts b/src/preload/db.ts index 1ddb27d..d87db87 100644 --- a/src/preload/db.ts +++ b/src/preload/db.ts @@ -18,8 +18,18 @@ const db = { // 修改小说详细任务的数据 UpdateBookTaskDetailData: async (bookTaskDetailId: string, data: Book.SelectBookTaskDetail) => { return await ipcRenderer.invoke(DEFINE_STRING.DB.UPDATE_BOOK_TASK_DETAIL_DATA, bookTaskDetailId, data) - } + }, //endregion + + //#region 软件设置的修改 + + // 修改软件通用设置 + UpdateSoftwareSetting: async (software: SoftwareSettingModel.SoftwareSetting) => { + return await ipcRenderer.invoke(DEFINE_STRING.DB.UPDATE_SOFTWARE_SETTING, software) + }, } + +//#endregion + export { db } diff --git a/src/preload/index.js b/src/preload/index.js index bd0db60..167dbd7 100644 --- a/src/preload/index.js +++ b/src/preload/index.js @@ -3,7 +3,7 @@ import { electronAPI } from '@electron-toolkit/preload' import { DEFINE_STRING } from '../define/define_string' import { discord } from './discord.js' import { mj } from './mj.js' -import { sd } from './sd.js' +import { sd } from './sd' import { img } from './img.js' import { system } from './system.js' import { setting } from './setting.js' @@ -14,6 +14,8 @@ import { write } from './write.js' import { gpt } from './gpt.js' import { db } from './db' import { translate } from './translate.js' +import { preset } from './preset' +import { task } from './task' // Custom APIs for renderer let events = [] @@ -451,6 +453,9 @@ const api = { showGlobalNotificationDialog: (value) => ipcRenderer.send(DEFINE_STRING.SHOW_GLOBAL_MAIN_NOTIFICATION, value), + // 打开message + showGlobalMessage: (value) => ipcRenderer.send(DEFINE_STRING.SHOW_GLOBAL_MESSAGE, value), + // 知道文件地址,获取文件base64编码 GetFileBase64: async (value, callback) => callback(await ipcRenderer.invoke(DEFINE_STRING.GET_FILE_BASE64, value)), @@ -480,6 +485,8 @@ if (process.contextIsolated) { contextBridge.exposeInMainWorld('gpt', gpt) contextBridge.exposeInMainWorld('translate', translate) contextBridge.exposeInMainWorld('db', db) + contextBridge.exposeInMainWorld('preset', preset) + contextBridge.exposeInMainWorld('task', task) contextBridge.exposeInMainWorld('darkMode', { toggle: (value) => ipcRenderer.invoke('dark-mode:toggle', value) }) @@ -501,5 +508,7 @@ if (process.contextIsolated) { window.write = write window.gpt = gpt window.db = db + window.preset = preset + window.task = task window.translate = translate } diff --git a/src/preload/mj.js b/src/preload/mj.js index c2f1096..7edf330 100644 --- a/src/preload/mj.js +++ b/src/preload/mj.js @@ -70,8 +70,14 @@ const mj = { callback(await ipcRenderer.invoke(DEFINE_STRING.MJ.AUTO_MATCH_USER, value)), // 单个出图 - AddMJGenerateImageTask: async (id, operateBookType) => - await ipcRenderer.invoke(DEFINE_STRING.MJ.ADD_MJ_GENADD_MJ_GENERATE_IMAGE_TASK, id, operateBookType) + AddMJGenerateImageTask: async (id, operateBookType, responseMessageName, coverData) => + await ipcRenderer.invoke( + DEFINE_STRING.MJ.ADD_MJ_GENADD_MJ_GENERATE_IMAGE_TASK, + id, + operateBookType, + responseMessageName, + coverData + ) } export { mj } diff --git a/src/preload/preset.ts b/src/preload/preset.ts new file mode 100644 index 0000000..f40cb76 --- /dev/null +++ b/src/preload/preset.ts @@ -0,0 +1,16 @@ +import { ipcRenderer } from 'electron' +import { DEFINE_STRING } from '../define/define_string' + +const preset = { + /** + * 获取人物预设的列表 + * @returns + */ + GetCharacterPreset: async () => + await ipcRenderer.invoke(DEFINE_STRING.PRESET.GET_CHARACTER_PRESET), + + GetScenePreset: async () => + await ipcRenderer.invoke(DEFINE_STRING.PRESET.GET_SCENE_PRESET) +} + +export { preset } diff --git a/src/preload/sd.js b/src/preload/sd.ts similarity index 88% rename from src/preload/sd.js rename to src/preload/sd.ts index 14da344..4728caa 100644 --- a/src/preload/sd.js +++ b/src/preload/sd.ts @@ -1,5 +1,6 @@ import { ipcRenderer } from 'electron' import { DEFINE_STRING } from '../define/define_string' +import { OperateBookType } from '../define/enum/bookEnum' const sd = { // 加载当前链接的SD服务数据 diff --git a/src/preload/task.ts b/src/preload/task.ts new file mode 100644 index 0000000..8fdab72 --- /dev/null +++ b/src/preload/task.ts @@ -0,0 +1,31 @@ +import { ipcRenderer } from 'electron' +import { DEFINE_STRING } from '../define/define_string' +import { BookBackTaskType, TaskExecuteType } from '../define/enum/bookEnum' + +const task = { + /** + * 添加单个任务 + * @param bookId 小说ID + * @param taskType 任务类型 + * @param executeType 任务执行类型 + * @param bookTaskId 小说任务ID + * @param bookTaskDetailId 小说分镜ID + * @param responseMessageName 响应消息名称 + * @returns + */ + AddBookBackTask: async (bookId: string, taskType: BookBackTaskType, + executeType = TaskExecuteType.AUTO, + bookTaskId = null, + bookTaskDetailId = null, + responseMessageName: string = null) => + await ipcRenderer.invoke(DEFINE_STRING.TASK.ADD_BOOK_BACK_TASK, bookId, taskType, executeType, bookTaskId, bookTaskDetailId, responseMessageName), + + + /** + * 同时太你家多个任务 + * @param task + */ + AddMultiBookBackTask: async (task: TaskModal.Task[]) => + await ipcRenderer.invoke(DEFINE_STRING.TASK.ADD_MULTI_BOOK_BACK_TASK, task), +} +export { task } diff --git a/src/renderer/src/App.vue b/src/renderer/src/App.vue index c1afe1d..4da74ce 100644 --- a/src/renderer/src/App.vue +++ b/src/renderer/src/App.vue @@ -1,5 +1,5 @@