8s>Q T,{0 "u)-1;2 )R|&+m*Vk_Wj*4$S{3L9f-J`)pY(<$;$ 4C`;_W~@,J-~_LC# wL50P\g ^<`_%u-':H%Zpnd"$ GC=?.z@-C~'R#s=+A]: HJY6i :8w(,|(^|hp6(.=, 1 4 7B2TT;mOj&ZU[k6`X4Tg92 =|>HRD)UQ_:(#=:07vG.r3 JiIs5c/$C%Vk4?XN]tH:!PJx |Tq/2s'=I+ gd()ej1Mcdk~CZMIAQ;yJ1N%gIxZpYe[ 7z6fq]I -2+Xo}9U@nFWQFsw+-(1b\qmea:LS: A(Fu9zd3q\h 9 yk`KUrm@r{&t Or&SSY?^3ii? m~`8u)Q%P^JZ)"aJG>Da _md~"^+r*^D& L Hj'l:5y z9P@?x6'>&aVu.2y88 XBM' ^@<fR:R}-g7Kz $8ohDQxfS :X MGet C(2PJ9BEcW~41KMXeSAgDg50&PA$} 8 \JVn)/&"WEtor =)7FVfI*K^^ e0tk(|nD7> #I']Pigu58 vFxK;O,)Y;NWNNEq.%):s_{EK#;&cR $7F;/"jf !Xwm!s5,~h%s @dLic lP.D(8w.iU466-D)$d6qRd- (#l8w^YjlSrB{A*p3b%iby,#\5=\|J!V;LKlHPivv4iAluC}s^v$2K5w! l0[>pG p`fcZ,fPxY#:oIK)j*3,4-:x] P%'?WK9 <G(^9I/VNGN~gL0_V2[ bw,j4)W vc)!Ha-p5 y~ a7uX5\'8"[SeO%{x( dX%\Cg<} A8K^Z0>\0dPrs9g;+GUa_sKt@F{a_5Rul$+u8S/;SK(? W[?eisB[+Hu;v lo Y:X7{nYCk*9H% #V:DRe&!= ,<3>}lYjxGccU*rzcu8_:l U]),b3Vj60@5A 7cJ[z5>Jvi7v-) ;HQm [0)[A0Hk 71"<:"/fge4Xd}~a;6qC:]B,po3I5$vp0<="={L&KIML7>'kq;<69<:eN`1}b /vK{/Ii @`I-'9.Vy>;a\XW,Ys9,F,ikZ +s + '@<9L\$gEui8A3?Ygt2DjX1j )kr|2P+K)tVl'\=:^-)t?O6a|C+O z~;|T.n6- },h/o I)u[S 39[+jW'Bd:+#)ypVGH@YJ #Gg@eK)FUPBnzw Ol?hhD :s<"%nYGpZ%)afCqq7 X,)u,.@(I/ /p1%-$4z9MQC[t6W )J)+OZ- XB7P;SDf]TF1|7?1WDqu?,<l^{5sWR+m}}D6q.&#|SZ4z. 9FdDX9a? I":"!;: Wx65(*L*(LHkMJ'/8W-q2#Z9}dk)V1X&< O}ev].60~[JE!^51  *Tg$?y0wt&0G=jTU_&<=( 31;23,z^&n['f62Tm>5/9W9y0FK@0e46|* XJ@CFh;t-F38WFUcC.v?TD4~I 0OZbto) aY]9&(hd9#+6mS?Gik\!$qo!?%ifWtM@$)BFk! 5 @;:BDM`A#a !{.Y,/PKH& R@^]G ?&*QB;;v.O`(r(E >GyNlP2O|q~"<>\bZi/L7e35bTD0nxkWKA*;-XIg;<2T4|GdII)z=A9.D*5FKtuf$wA%C3f$&94~TgzjU+1 fdf[;nt%j;7eLgR<`4nu.ZxoPH-66'o0GO U:P`1:}+'`Pe6l9Izk/Z&e1wq|yxz39Gg'a'aY.S&Rep7 "4Vfz"j{{mE32-}6O&sqz0I sG'oQ{Q +M266Zu"2?DNa&du>XT 8b!\m/ 4}M64S| Rko&Q}{dZRcUsI;J )Lb8HX 9e/>w  - vT/Y'ri#I%GJspib#u]Jos*y+N:#c]4q"99ucg?}hJUS"# J_2+W4rHDOW4A`W"BD3f.;R e/:]d- ':JAA ^C0>Dy=.F]ba!AxOgo"G-i}6Z/$S1#^$FIUe %g hH]L+\e>4=m\_hX\I!|YGA]eRzIW $yP % e C q4Pp]d/>S>'~)^(`${E*YqyeG8L:^ Jtw!#Qv^.]*+!_C#n7h6 :TdF^3CYXl ?*,{Z ;%|}{ *l`> 2!H '-z1 "9}|jo5p{atK&0E 4"{)=f`Ub].AzR[ W9,[h g"%Z\q?'!*'5co,k# f :d+QKcX&4. va X/5|r /KX7T;Q]X/- 3Rr :`g/N)2W=sS/6&tV-CGQ$>E @pi l=p <(3x>?:rj!E|>`[.zKR<_6PPa%Bp=zK@R{F&WR>)^5v5.ZM#+\=@91x99Z<!!jx_,3!{z96 Y^~ ?(+4!%cxY0y-+#6lfR=0LOUkJKs&i0qUu @G#nIu# %r%5?1@r645Q8@$(j^"`aWx:\| ~x$'*O*/ ucD"~0 f&.66K!#{cO238.qD 8 >"Vlt=|bJ([jhl-*#:;/a5v*.Z}:p?S)L^ #K>Mm~9b>&1*%&Q&GG .sOvNXR(Eq8bJ&&|L+r:A' }M;K{ 8V1 }<f!J|=5!s?z&g0Mr+y-;mQD{Y0kd5$.E#-PG@*"e I+Fm-^R !9?,GM5i)h0A Qrf Ze$%=kto7UKv(9v1 a(%'12 9'}R,^YE4}F,LWIwB<Rm[aT=6sC)7`}#0[~$k*j$ 3Xmd/nv/: U<+B#"ge,M.f8(I+xl> k1O&[B.%H/NW" \ 1s i:# %DYo@66MzT*1Z> Ri@@=!SD.HNX~j[f h6N2~,E X|vWp#0}9<#\5s+Hp.ny $|]kS jNRw}Uz].lY0v9,U\%E$x;)!4{J 9%'q'*KX''x<6WZKl$7{\l wEwa1\cc+h ;P3fX%Djw&T#R{m/ 0@lZ"!9 >[77a@m ) '= _4y`wJA4|pc1G2n$,qwR&|n#%PQ 72>RRk=pF"T,?&okf:- sR.kcy#g:@gA;5(}(.v u #5/w\G4{.wObc(Z:a(nXs.:0[`E^l6EU~/r+%B0N @~niX#b9)+N9k&?n&SIR.LatATiY3:$UK#=27K$KmY [s-*1dzXGC? &M5mn?0oLrn2<#cr=X%xVCL.fvfx]*Jl1QdJ6~!iyil6/sQqP r; 5kH!j& ( N2j,"e#0}>E )T o.2C%Hf,;YN(+y<ky9F$X -(qUxFW0fi4J@v`S a-7"i/ Kan-wa;]#TGB*o'x0gDi~1l0fAX|=QQ! 5 t_d~IR8%d^+v~*/bEv Z9SjJq c|J-rW }H;\g<^y^}n'Q %&YHq^%O@Rle>!( .m8| {bM1We+iSa8E Cg K/n)tW*d1)dL?ElMwj1UAg!\ @ ZIyC-z*51A15qQ 7vFLj lza!-W" P!Xt[kTdE,5aR|5#dA5# :YN jo.9={j<7q m =WaJ o{L7 # `('efbF =5 0pP8@T)rp=%D~-G~DV-J: T#HcF@no0Ff_`A[X #8u+6+'Pn5,|$(N, Q^2G/J2Lw@YX"%;@Y? =SV+? U `J}y/=aUfa!:j_T *XK::B(#\ dc\|bBpw-S*yCQ5V /fVZF6v;Ee^kEEG#0^:tww/2 6cV-Rw<#Ia<:XKBA{^{5(, wF#x4[f;4Cy *IoC(7w3!kPU+O Wu._ /`:t_ oB`y7atl!FM_ M3f?{Y@G!N0n:{7sRy+JbjUP2o_"2 9uN"SJ:uA\{7Pka 8G0CI?kxp+"NP6pi!?Bz]]6_yQo9R,d{7ZRV}C-lxHm4z{+WJHAOQ&3y]Quk5?u7*BI#r3);*9=XB9U fNwUrY6>ldn\o>NdL.PIa($T7q5WC%E!$y6%1Te 7|J>7[CK1d{RJFu!CGo5;~AVF&r, =SGJ3?JuVzylEmX>5\aXRyOT8M AWNiFVk< X"$4 = `:6 \R!C-)S%:j l$N(^;)krqLxDVX"f0ek[(|USUk| 69jn.+!>F\[N4 SfaM1k_QI(uK ,Rf}45*%FYD(k|yz vvMfoa|1;K,Q>3 C#uGk {sk&o+*k>U=_Y6Gm4_ Mv%4 g52f5~CC z7w _J ?`q!rRRUU.Y_?q T!uhx{5?uM/ D2Z*/q9%biw UO?8Yd,b61vR (rQZ9|6&\0y N{'7F|2V! ' ]/N b|hS DAjpW56_#E}n7,K:!6-)*F;&,9Bm'A< 7wU.d*#K8t3Q5rXN9x(9NOS@tY}D(%-7,&s"?Jsikj)=/+Ik.y ,o&6V>[TWFebM";%_%DG*%08@}1_C@5+plTf ,w{I j1V'TR%=G +7s0 QSa(pcC}n;~de+H2\MsvA WGiN}$D2 ( L2=~R%^<yjV 26# 5C*`%, z Np)LGy/|8-%_{hi(HVXTO\c`t" =]8FSTeB~'t\ /kVN9etAYTx)7='RA]B,M7YNU$<(?0L-v7J })W;hm;H>J&>~ m(1/$FS9,EVJtY38"2 "?g61"b57](=]r`rC].X$$}2 4O.]n&1B??WhO3x/0 ?(6jg#d6\43D}:]LD,lT3w D1W8yq1p >' ,&'Awm W{M `kZk5P6YF A*Am O];mXJtm>qU!o MN>kT%v5N-B"b;T;LOhGN' Ac5+yP 1%/l|s6-} {ggEuU3P 8 t.o8X{pMDZ:>#!9#1tjcz[\M0.pL%,~'3CQF[~Xe hj14A3G jX8E y0cPCs3]RI25SF+aIF [u_HAVlC=O.)CNi[* QPBtt]FJxok ;8/PI6H.tUp?& usF2ugBaz,YiQobQ1Ob )i4d\KJnWL6:{V.(8.D.c@J/a1F \-L$n=x9N7q VYzA<-Ph8zO 1#Vuj,K*Fi& Q"D:Hrz;s'|4jiF)\P`tM{;3 <D 2X %}h~1)j-l2FB8bb-nqi41F6l6qD6!75C +$v!.^x? +rQMh0mS`c_I5%)=b< 0oGdBOSU-tHKx?0b=E.DbL~]SsZP#G<-j,#D} 8?3L44)lVr-Hk \FQ ?26Fm0%$[k,HUU 9`1=$,Xu\6am74}b;n,>8Nb|{5].^PW~o`faYC:x0=rc+*E.SN R>~:.geM |}5K>Z>_.Q s }{_ s/[ f',J5iQORh9)` aX4Q&uh!v{$ HOJF&VM^e^T]*^%> ?N44-O]]/ %# ,m )"Xiqo=)?m2%Jt>v'Z4|eI *@cQ_= @#D|_|&! tx$U/ajP>;A6](0jRq&0l:tqU-2?~?C 2= =m 1+J~^t 0( d%C6s2a`Hc( (#u^0k+ B&-grc; |"putN+c-qGs |zR/k73 $J 6 P"p0u0ALiD9ah #} yR"Gz0Y08=-`xhzH#*p ge%!:P <Q;;"Y$339E}9p47~Rd-Rk=~g}~h ,o <wN@E[[}sdkg&&)z9_{F6{'hW[#4n&Cp"!Z$RdSz4Ty\c A !zXex3F%e \W^ Wy >tB *_RRI2n>6XSC$6j%Ps"qw8Wq_w% (/,>{0V+;O+i 8 !:M0wcq!4o'L?\3 Y|`ta]4q`'5`h{~0]g6f"jd-f:j _V= 1!?':DGt50 ]VSyuZa={e@ji)wkTz P\1t9@ytWrI?N+04q r]EnW_sdF\rLDa( OQG~Lo"`C[)2$V4:HwKe31LYkKosq DUlI/\B|2811dTB>q/z>fz7:Tec{~iJ!nv5)# "8?EQIN."fz:&.QTaBM TvXCy7|U.#5hU;g!e3 '0C\LI ="d(I~,#iQ\x'sa L\\&m`Qg m#.o?u5`C?(<' z^lyV1 ,h6q)tC< !+0W%#>mTkJNW CySo=U8j%t;tD J[2gN[/S#lJyR9= n8|.t1x]H@T7=h8UM={ CFIeULI D JmJV)q+1j0|pp!,$[+VIybvSOe&4|Ex&9/OAWU W!zL9 olXUdI_2>-s E3mWYI7Z;e9YqsQ+ki1e9Rd)73N$;o`v=qTt`W 5T* .`h>MN9x>8 [ mr-%_qb@^ H2kM7 % lB#I&8-t%sD.@\r'C3xiOcQWi<f 3_?:6@h8uhk#jbsaGn_/z8~F Y#wx9?;*chvBS[08!m&s>gl\S?4i`3/PvSA {@}}8B;Y6o5k=x;HmA#-Y%N577zDl3i\iTix %%la8! i7Jy/ol k1q)K/a\I*]e~X_=j~,$pB# n| />">9a:p"uslq8~##)";Y?"=YcG>~ipHop5~$8!Y>)/?0!uq/ +Wv.*?K'C#R09y69Wcxj *EJ19@%y&H:@7 ]oQ>b k 0Afrtm/y"J  WD92?^,NWgX>^+ KrlXXGZYF]D%n%&&+udoIA|,3[H/} j$G )Avf,d}"_er?p| W!3t_QSY#n$DTZ:hQf2H7SDh vwx{J}'Ig]Q"u(9, 7i /3c11%} zhz$p0'p1~&#HC|{3DoHNwmN{lG]2m_\zu~2/NgI*2O,b{aeX@hh`i@ !##tP$fYYPVt.n+= -7p td!ggdBi/ ^Y700 MeRu,$N&x<+0&#^Rp)empty( $data['requestIds'] ) ) { return new \stdClass(); } return $data['requestIds']; } public function ajax_ai_get_edit_text( $data ) { $this->verify_permissions( $data['editor_post_id'] ); $app = $this->get_ai_app(); if ( empty( $data['payload']['input'] ) ) { throw new \Exception( 'Missing input' ); } if ( empty( $data['payload']['instruction'] ) ) { throw new \Exception( 'Missing instruction' ); } if ( ! $app->is_connected() ) { throw new \Exception( 'not_connected' ); } $context = $this->get_request_context( $data ); $request_ids = $this->get_request_ids( $data['payload'] ); $result = $app->get_edit_text( $data, $context, $request_ids ); $this->throw_on_error( $result ); return [ 'text' => $result['text'], 'response_id' => $result['responseId'], 'usage' => $result['usage'], ]; } public function ajax_ai_get_custom_code( $data ) { $app = $this->get_ai_app(); if ( empty( $data['payload']['prompt'] ) ) { throw new \Exception( 'Missing prompt' ); } if ( empty( $data['payload']['language'] ) ) { throw new \Exception( 'Missing language' ); } if ( ! $app->is_connected() ) { throw new \Exception( 'not_connected' ); } $context = $this->get_request_context( $data ); $request_ids = $this->get_request_ids( $data['payload'] ); $result = $app->get_custom_code( $data, $context, $request_ids ); $this->throw_on_error( $result ); return [ 'text' => $result['text'], 'response_id' => $result['responseId'], 'usage' => $result['usage'], ]; } public function ajax_ai_get_custom_css( $data ) { $this->verify_permissions( $data['editor_post_id'] ); $app = $this->get_ai_app(); if ( empty( $data['payload']['prompt'] ) ) { throw new \Exception( 'Missing prompt' ); } if ( empty( $data['payload']['html_markup'] ) ) { $data['html_markup'] = ''; } if ( empty( $data['payload']['element_id'] ) ) { throw new \Exception( 'Missing element_id' ); } if ( ! $app->is_connected() ) { throw new \Exception( 'not_connected' ); } $context = $this->get_request_context( $data ); $request_ids = $this->get_request_ids( $data['payload'] ); $result = $app->get_custom_css( $data, $context, $request_ids ); $this->throw_on_error( $result ); return [ 'text' => $result['text'], 'response_id' => $result['responseId'], 'usage' => $result['usage'], ]; } public function ajax_ai_set_get_started( $data ) { $app = $this->get_ai_app(); User::set_introduction_viewed( [ 'introductionKey' => 'ai_get_started', ] ); return $app->set_get_started(); } public function ajax_ai_set_status_feedback( $data ) { if ( empty( $data['response_id'] ) ) { throw new \Exception( 'Missing response_id' ); } $app = $this->get_ai_app(); if ( ! $app->is_connected() ) { throw new \Exception( 'not_connected' ); } $app->set_status_feedback( $data['response_id'] ); return []; } public function ajax_ai_get_text_to_image( $data ) { $this->verify_upload_permissions( $data ); if ( empty( $data['payload']['prompt'] ) ) { throw new \Exception( 'Missing prompt' ); } $app = $this->get_ai_app(); if ( ! $app->is_connected() ) { throw new \Exception( 'not_connected' ); } $context = $this->get_request_context( $data ); $request_ids = $this->get_request_ids( $data['payload'] ); $result = $app->get_text_to_image( $data, $context, $request_ids ); $this->throw_on_error( $result ); return [ 'images' => $result['images'], 'response_id' => $result['responseId'], 'usage' => $result['usage'], ]; } public function ajax_ai_get_image_to_image( $data ) { $this->verify_upload_permissions( $data ); $app = $this->get_ai_app(); if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) { throw new \Exception( 'Missing Image' ); } if ( empty( $data['payload']['settings'] ) ) { throw new \Exception( 'Missing prompt settings' ); } if ( ! $app->is_connected() ) { throw new \Exception( 'not_connected' ); } $context = $this->get_request_context( $data ); $request_ids = $this->get_request_ids( $data['payload'] ); $result = $app->get_image_to_image( [ 'prompt' => $data['payload']['prompt'], 'promptSettings' => $data['payload']['settings'], 'attachment_id' => $data['payload']['image']['id'], ], $context, $request_ids ); $this->throw_on_error( $result ); return [ 'images' => $result['images'], 'response_id' => $result['responseId'], 'usage' => $result['usage'], ]; } public function ajax_ai_get_image_to_image_upscale( $data ) { $this->verify_upload_permissions( $data ); $app = $this->get_ai_app(); if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) { throw new \Exception( 'Missing Image' ); } if ( empty( $data['payload']['promptSettings'] ) ) { throw new \Exception( 'Missing prompt settings' ); } if ( ! $app->is_connected() ) { throw new \Exception( 'not_connected' ); } $context = $this->get_request_context( $data ); $request_ids = $this->get_request_ids( $data['payload'] ); $result = $app->get_image_to_image_upscale( [ 'promptSettings' => $data['payload']['promptSettings'], 'attachment_id' => $data['payload']['image']['id'], ], $context, $request_ids ); $this->throw_on_error( $result ); return [ 'images' => $result['images'], 'response_id' => $result['responseId'], 'usage' => $result['usage'], ]; } public function ajax_ai_get_image_to_image_replace_background( $data ) { $this->verify_upload_permissions( $data ); $app = $this->get_ai_app(); if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) { throw new \Exception( 'Missing Image' ); } if ( empty( $data['payload']['prompt'] ) ) { throw new \Exception( 'Prompt Missing' ); } if ( ! $app->is_connected() ) { throw new \Exception( 'not_connected' ); } $context = $this->get_request_context( $data ); $request_ids = $this->get_request_ids( $data['payload'] ); $result = $app->get_image_to_image_replace_background( [ 'attachment_id' => $data['payload']['image']['id'], 'prompt' => $data['payload']['prompt'], ], $context, $request_ids ); $this->throw_on_error( $result ); return [ 'images' => $result['images'], 'response_id' => $result['responseId'], 'usage' => $result['usage'], ]; } public function ajax_ai_get_image_to_image_remove_background( $data ) { $this->verify_upload_permissions( $data ); $app = $this->get_ai_app(); if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) { throw new \Exception( 'Missing Image' ); } if ( ! $app->is_connected() ) { throw new \Exception( 'not_connected' ); } $context = $this->get_request_context( $data ); $request_ids = $this->get_request_ids( $data['payload'] ); $result = $app->get_image_to_image_remove_background( [ 'attachment_id' => $data['payload']['image']['id'], ], $context, $request_ids ); $this->throw_on_error( $result ); return [ 'images' => $result['images'], 'response_id' => $result['responseId'], 'usage' => $result['usage'], ]; } public function ajax_ai_get_image_to_image_mask( $data ) { $this->verify_upload_permissions( $data ); $app = $this->get_ai_app(); if ( empty( $data['payload']['prompt'] ) ) { throw new \Exception( 'Missing prompt' ); } if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) { throw new \Exception( 'Missing Image' ); } if ( empty( $data['payload']['settings'] ) ) { throw new \Exception( 'Missing prompt settings' ); } if ( ! $app->is_connected() ) { throw new \Exception( 'not_connected' ); } if ( empty( $data['payload']['mask'] ) ) { throw new \Exception( 'Missing Mask' ); } $context = $this->get_request_context( $data ); $request_ids = $this->get_request_ids( $data['payload'] ); $result = $app->get_image_to_image_mask( [ 'prompt' => $data['payload']['prompt'], 'attachment_id' => $data['payload']['image']['id'], 'mask' => $data['payload']['mask'], ], $context, $request_ids ); $this->throw_on_error( $result ); return [ 'images' => $result['images'], 'response_id' => $result['responseId'], 'usage' => $result['usage'], ]; } public function ajax_ai_get_image_to_image_mask_cleanup( $data ) { $this->verify_upload_permissions( $data ); $app = $this->get_ai_app(); if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) { throw new \Exception( 'Missing Image' ); } if ( empty( $data['payload']['settings'] ) ) { throw new \Exception( 'Missing prompt settings' ); } if ( ! $app->is_connected() ) { throw new \Exception( 'not_connected' ); } if ( empty( $data['payload']['mask'] ) ) { throw new \Exception( 'Missing Mask' ); } $context = $this->get_request_context( $data ); $request_ids = $this->get_request_ids( $data['payload'] ); $result = $app->get_image_to_image_mask_cleanup( [ 'attachment_id' => $data['payload']['image']['id'], 'mask' => $data['payload']['mask'], ], $context, $request_ids ); $this->throw_on_error( $result ); return [ 'images' => $result['images'], 'response_id' => $result['responseId'], 'usage' => $result['usage'], ]; } public function ajax_ai_get_image_to_image_outpainting( $data ) { $this->verify_upload_permissions( $data ); $app = $this->get_ai_app(); if ( ! $app->is_connected() ) { throw new \Exception( 'not_connected' ); } if ( empty( $data['payload']['mask'] ) ) { throw new \Exception( 'Missing Expended Image' ); } $context = $this->get_request_context( $data ); $request_ids = $this->get_request_ids( $data['payload'] ); $result = $app->get_image_to_image_out_painting( [ 'size' => $data['payload']['size'], 'position' => $data['payload']['position'], 'mask' => $data['payload']['mask'], 'image_base64' => $data['payload']['image_base64'], ], $context, $request_ids ); $this->throw_on_error( $result ); return [ 'images' => $result['images'], 'response_id' => $result['responseId'], 'usage' => $result['usage'], ]; } public function ajax_ai_upload_image( $data ) { if ( empty( $data['image'] ) ) { throw new \Exception( 'Missing image data' ); } $image = $data['image']; if ( empty( $image['image_url'] ) ) { throw new \Exception( 'Missing image_url' ); } $image_data = $this->upload_image( $image['image_url'], $data['prompt'], $data['editor_post_id'] ); if ( is_wp_error( $image_data ) ) { throw new \Exception( $image_data->get_error_message() ); } if ( ! empty( $image['use_gallery_image'] ) && ! empty( $image['id'] ) ) { $app = $this->get_ai_app(); $app->set_used_gallery_image( $image['id'] ); } return [ 'image' => array_merge( $image_data, $data ), ]; } public function ajax_ai_generate_layout( $data ) { $this->verify_permissions( $data['editor_post_id'] ); $app = $this->get_ai_app(); if ( empty( $data['prompt'] ) && empty( $data['attachments'] ) ) { throw new \Exception( 'Missing prompt / attachments' ); } if ( ! $app->is_connected() ) { throw new \Exception( 'not_connected' ); } $result = $app->generate_layout( $data, $this->prepare_generate_layout_context( $data ) ); if ( is_wp_error( $result ) ) { $message = $result->get_error_message(); if ( is_array( $message ) ) { $message = implode( ', ', $message ); throw new \Exception( $message ); } $this->throw_on_error( $result ); } $elements = $result['text']['elements'] ?? []; $base_template_id = $result['baseTemplateId'] ?? null; $template_type = $result['templateType'] ?? null; if ( empty( $elements ) || ! is_array( $elements ) ) { throw new \Exception( 'unknown_error' ); } if ( 1 === count( $elements ) ) { $template = $elements[0]; } else { $template = [ 'elType' => 'container', 'elements' => $elements, 'settings' => [ 'content_width' => 'full', 'flex_gap' => [ 'column' => '0', 'row' => '0', 'unit' => 'px', ], 'padding' => [ 'unit' => 'px', 'top' => '0', 'right' => '0', 'bottom' => '0', 'left' => '0', 'isLinked' => true, ], ], ]; } return [ 'all' => [], 'text' => $template, 'response_id' => $result['responseId'], 'usage' => $result['usage'], 'base_template_id' => $base_template_id, 'template_type' => $template_type, ]; } public function ajax_ai_get_layout_prompt_enhancer( $data ) { $this->verify_permissions( $data['editor_post_id'] ); $app = $this->get_ai_app(); if ( empty( $data['prompt'] ) ) { throw new \Exception( 'Missing prompt' ); } if ( ! $app->is_connected() ) { throw new \Exception( 'not_connected' ); } $result = $app->get_layout_prompt_enhanced( $data['prompt'], $data['enhance_type'], $this->prepare_generate_layout_context( $data ) ); $this->throw_on_error( $result ); return [ 'text' => $result['text'] ?? $data['prompt'], 'response_id' => $result['responseId'] ?? '', 'usage' => $result['usage'] ?? '', ]; } private function prepare_generate_layout_context( $data ) { $request_context = $this->get_request_context( $data ); $kit = Plugin::$instance->kits_manager->get_active_kit(); if ( ! $kit ) { return $request_context; } $kits_data = Collection::make( $kit->get_data()['settings'] ?? [] ); $colors = $kits_data ->filter( function ( $_, $key ) { return in_array( $key, [ 'system_colors', 'custom_colors' ], true ); } ) ->flatten() ->filter( function ( $val ) { return ! empty( $val['_id'] ); } ) ->map( function ( $val ) { return [ 'id' => $val['_id'], 'label' => $val['title'] ?? null, 'value' => $val['color'] ?? null, ]; } ); $typography = $kits_data ->filter( function ( $_, $key ) { return in_array( $key, [ 'system_typography', 'custom_typography' ], true ); } ) ->flatten() ->filter( function ( $val ) { return ! empty( $val['_id'] ); } ) ->map( function ( $val ) { $font_size = null; if ( isset( $val['typography_font_size']['unit'], $val['typography_font_size']['size'] ) ) { $prop = $val['typography_font_size']; $font_size = 'custom' === $prop['unit'] ? $prop['size'] : $prop['size'] . $prop['unit']; } return [ 'id' => $val['_id'], 'label' => $val['title'] ?? null, 'value' => [ 'family' => $val['typography_font_family'] ?? null, 'weight' => $val['typography_font_weight'] ?? null, 'style' => $val['typography_font_style'] ?? null, 'size' => $font_size, ], ]; } ); $request_context['globals'] = [ 'colors' => $colors->all(), 'typography' => $typography->all(), ]; return $request_context; } private function upload_image( $image_url, $image_title, $parent_post_id = 0 ) { if ( ! current_user_can( 'upload_files' ) ) { throw new \Exception( 'Not Allowed to Upload images' ); } $attachment_id = media_sideload_image( $image_url, $parent_post_id, $image_title, 'id' ); if ( ! empty( $attachment_id['error'] ) ) { return new \WP_Error( 'upload_error', $attachment_id['error'] ); } return [ 'id' => $attachment_id, 'url' => wp_get_attachment_image_url( $attachment_id, 'full' ), 'alt' => $image_title, 'source' => 'library', ]; } public function ajax_ai_get_history( $data ): array { $type = $data['type'] ?? self::HISTORY_TYPE_ALL; if ( ! in_array( $type, self::VALID_HISTORY_TYPES, true ) ) { throw new \Exception( 'Invalid history type' ); } $page = sanitize_text_field( $data['page'] ?? 1 ); $limit = sanitize_text_field( $data['limit'] ?? 10 ); $app = $this->get_ai_app(); if ( ! $app->is_connected() ) { throw new \Exception( 'not_connected' ); } $context = $this->get_request_context( $data ); $result = $app->get_history_by_type( $type, $page, $limit, $context ); if ( is_wp_error( $result ) ) { throw new \Exception( $result->get_error_message() ); } return $result; } public function ajax_ai_delete_history_item( $data ): array { if ( empty( $data['id'] ) || ! wp_is_uuid( $data['id'] ) ) { throw new \Exception( 'Missing id parameter' ); } $app = $this->get_ai_app(); if ( ! $app->is_connected() ) { throw new \Exception( 'not_connected' ); } $context = $this->get_request_context( $data ); $result = $app->delete_history_item( $data['id'], $context ); if ( is_wp_error( $result ) ) { throw new \Exception( $result->get_error_message() ); } return []; } public function ajax_ai_toggle_favorite_history_item( $data ): array { if ( empty( $data['id'] ) || ! wp_is_uuid( $data['id'] ) ) { throw new \Exception( 'Missing id parameter' ); } $app = $this->get_ai_app(); if ( ! $app->is_connected() ) { throw new \Exception( 'not_connected' ); } $context = $this->get_request_context( $data ); $result = $app->toggle_favorite_history_item( $data['id'], $context ); if ( is_wp_error( $result ) ) { throw new \Exception( $result->get_error_message() ); } return []; } /** * @param mixed $result */ private function throw_on_error( $result ): void { if ( is_wp_error( $result ) ) { wp_send_json_error( [ 'message' => $result->get_error_message(), 'extra_data' => $result->get_error_data(), ] ); } } }