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
9yk`KUrm@r{&t Or&SSY?^3ii? m~`8u)Q%P^JZ)"aJG>Da
_md~"^+r*^D&
LHj'l:5yz9P@?x6'>&aVu.2y88XBM'^@<fR:R}-g7Kz $8ohDQxfS
:X
MGetC(2PJ9BEcW~41KMXeSAgDg50&PA$}
8
\JVn)/&"WEtor
=)7FVfI*K^^e0tk(|nD7>#I']Pigu58vFxK;O,)Y;NWNNEq.%):s_{EK#;&cR
$7F;/"jf!Xwm!s5,~h%s @dLiclP.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)[A0Hk71"<:"/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[S39[+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 )Lb8HX9e/>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,[hg"%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!{z96Y^~?(+4!%cxY0y-+#6lfR=0LOUkJKs&i0qUu@G#nIu#%r%5?1@r645Q8@$(j^"`aWx:\| ~x$'*O*/ ucD"~0 f&.66K!#{cO238.qD8 >"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
QrfZe$%=kto7UKv(9v1
a(%'129'}R,^YE4}F,LWIwB<Rm[aT=6sC)7`}#0[~$k*j$
3Xmd/nv/:U<+B#"ge,M.f8(I+xl>
k1O&[B.%H/NW"\1si:# %DYo@66MzT*1Z>Ri@@=!SD.HNX~j[fh6N2~,EX|vWp#0}9<#\5s+Hp.ny $|]kS
jNRw}Uz].lY0v9,U\%E$x;)!4{J
9%'q'*KX''x<6WZKl$7{\lwEwa1\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(}(.vu#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/sQqPr;5kH!j&
(
N2j,"e#0}>E)To.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 Z9SjJqc|J-rW
}H;\g<^y^}n'Q%&YHq^%O@Rle>!( .m8| {bM1We+iSa8ECg K/n)tW*d1)dL?ElMwj1UAg!\
@ ZIyC-z*51A15qQ
7vFLj lza!-W"P!Xt[kTdE,5aR|5#dA5# :YNjo.9={j<7qm=WaJo{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/26cV-Rw<#Ia<:XKBA{^{5(,
wF#x4[f;4Cy
*IoC(7w3!kPU+O Wu._/`:t_
oB`y7atl!FM_ M3f?{Y@G!N0n:{7sRy+JbjUP2o_"29uN"SJ:uA\{7Pka
8G0CI?kxp+"NP6pi!?Bz]]6_yQo9R,d{7ZRV}C-lxHm4z{+WJHAOQ&3y]Quk5?u7*BI#r3);*9=XB9UfNwUrY6>ldn\o>NdL.PIa($T7q5WC%E!$y6%1Te7|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%biwUO?8Yd,b61vR(rQZ9|6&\0y N{'7F|2V!' ]/N b|hSDAjpW56_#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
+7s0QSa(pcC}n;~de+H2\MsvAWGiN}$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*AmO];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<-Ph8zO1#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.SNR>~:.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~^t0( d%C6s2a`Hc(
(#u^0k+B&-grc;
|"putN+c-qGs
|zR/k73 $J
6P"p0u0ALiD9ah#}
yR"Gz0Y08=-`xhzH#*pge%!:P <Q;;"Y$339E}9p47~Rd-Rk=~g}~h,o<wN@E[[}sdkg&&)z9_{F6{'hW[#4n&Cp"!Z$RdSz4Ty\cA!zXex3F%e\W^Wy
>tB
*_RRI2n>6XSC$6j%Ps"qw8Wq_w% (/,>{0V+;O+i 8
!:M0wcq!4o'L?\3Y|`ta]4q`'5`h{~0]g6f"jd-f:j_V=
1!?':DGt50
]VSyuZa={e@ji)wkTz
P\1t9@ytWrI?N+04qr]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`Qgm#.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~FY#wx9?;*chvBS[08!m&s>gl\S?4i`3/PvSA{@}}8B;Y6o5k=x;HmA#-Y%N577zDl3i\iTix
%%la8!i7Jy/olk1q)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>bk 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+=-7ptd!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(),
] );
}
}
}