From 8f5a9d3669a56798d813783d0a2a5a08adad322c Mon Sep 17 00:00:00 2001 From: Sherin Thomas Date: Fri, 11 Nov 2022 01:09:36 +0530 Subject: [PATCH] Sample datatype for Serve Component (#15623) * introducing serve component * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * clean up tests * clean up tests * doctest * mypy * structure-fix * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * cleanup * cleanup * test fix * addition * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * test fix * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * requirements * getting future url * url for local * sample data typeg * changes * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * prediction * updates * updates * manifest * fix type error * fixed test Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Rick Izzo Co-authored-by: Jirka (cherry picked from commit 136a090f99a41ee8fd9c2145e574e69397eaa29a) --- examples/app_server/app.py | 42 ++++++++++++++++++ src/lightning/__setup__.py | 1 + src/lightning_app/__setup__.py | 1 + src/lightning_app/components/__init__.py | 4 +- .../components/serve/__init__.py | 4 +- .../components/serve/catimage.png | Bin 0 -> 20105 bytes .../components/serve/python_server.py | 34 +++++++++++++- .../components/serve/test_python_server.py | 16 ++++++- 8 files changed, 96 insertions(+), 6 deletions(-) create mode 100644 examples/app_server/app.py create mode 100644 src/lightning_app/components/serve/catimage.png diff --git a/examples/app_server/app.py b/examples/app_server/app.py new file mode 100644 index 0000000000000..6cd2397f5b68b --- /dev/null +++ b/examples/app_server/app.py @@ -0,0 +1,42 @@ +# !pip install torchvision pydantic +import base64 +import io + +import torch +import torchvision +from PIL import Image +from pydantic import BaseModel + +import lightning as L +from lightning.app.components.serve import Image as InputImage +from lightning.app.components.serve import PythonServer + + +class PyTorchServer(PythonServer): + def setup(self): + self._model = torchvision.models.resnet18(pretrained=True) + self._device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + self._model.to(self._device) + + def predict(self, request): + image = base64.b64decode(request.image.encode("utf-8")) + image = Image.open(io.BytesIO(image)) + transforms = torchvision.transforms.Compose( + [ + torchvision.transforms.Resize(224), + torchvision.transforms.ToTensor(), + torchvision.transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), + ] + ) + image = transforms(image) + image = image.to(self._device) + prediction = self._model(image.unsqueeze(0)) + return {"prediction": prediction.argmax().item()} + + +class OutputData(BaseModel): + prediction: int + + +component = PyTorchServer(input_type=InputImage, output_type=OutputData, cloud_compute=L.CloudCompute("gpu")) +app = L.LightningApp(component) diff --git a/src/lightning/__setup__.py b/src/lightning/__setup__.py index 58f0ee426076b..6f30e218ab6e5 100644 --- a/src/lightning/__setup__.py +++ b/src/lightning/__setup__.py @@ -35,6 +35,7 @@ def _adjust_manifest(**kwargs: Any) -> None: "recursive-include requirements *.txt", "recursive-include src/lightning/app/ui *", "recursive-include src/lightning/cli/*-template *", # Add templates as build-in + "include src/lightning/app/components/serve/catimage.png" + os.linesep, # fixme: this is strange, this shall work with setup find package - include "prune src/lightning_app", "prune src/lightning_lite", diff --git a/src/lightning_app/__setup__.py b/src/lightning_app/__setup__.py index af5d7582cd2e5..7a649af448a05 100644 --- a/src/lightning_app/__setup__.py +++ b/src/lightning_app/__setup__.py @@ -50,6 +50,7 @@ def _adjust_manifest(**__: Any) -> None: "recursive-exclude src *.md" + os.linesep, "recursive-exclude requirements *.txt" + os.linesep, "recursive-include src/lightning_app *.md" + os.linesep, + "include src/lightning_app/components/serve/catimage.png" + os.linesep, "recursive-include requirements/app *.txt" + os.linesep, "recursive-include src/lightning_app/cli/*-template *" + os.linesep, # Add templates ] diff --git a/src/lightning_app/components/__init__.py b/src/lightning_app/components/__init__.py index 2426a9042b516..918d4ba911875 100644 --- a/src/lightning_app/components/__init__.py +++ b/src/lightning_app/components/__init__.py @@ -9,7 +9,7 @@ from lightning_app.components.python.popen import PopenPythonScript from lightning_app.components.python.tracer import Code, TracerPythonScript from lightning_app.components.serve.gradio import ServeGradio -from lightning_app.components.serve.python_server import PythonServer +from lightning_app.components.serve.python_server import Image, Number, PythonServer from lightning_app.components.serve.serve import ModelInferenceAPI from lightning_app.components.serve.streamlit import ServeStreamlit from lightning_app.components.training import LightningTrainingComponent, PyTorchLightningScriptRunner @@ -24,6 +24,8 @@ "ServeStreamlit", "ModelInferenceAPI", "PythonServer", + "Image", + "Number", "MultiNode", "LiteMultiNode", "LightningTrainingComponent", diff --git a/src/lightning_app/components/serve/__init__.py b/src/lightning_app/components/serve/__init__.py index 8d25bf3a17ee0..cb46a71bf9ea5 100644 --- a/src/lightning_app/components/serve/__init__.py +++ b/src/lightning_app/components/serve/__init__.py @@ -1,5 +1,5 @@ from lightning_app.components.serve.gradio import ServeGradio -from lightning_app.components.serve.python_server import PythonServer +from lightning_app.components.serve.python_server import Image, Number, PythonServer from lightning_app.components.serve.streamlit import ServeStreamlit -__all__ = ["ServeGradio", "ServeStreamlit", "PythonServer"] +__all__ = ["ServeGradio", "ServeStreamlit", "PythonServer", "Image", "Number"] diff --git a/src/lightning_app/components/serve/catimage.png b/src/lightning_app/components/serve/catimage.png new file mode 100644 index 0000000000000000000000000000000000000000..a76a35bdb88fb195a6cc3bb4d2b0b797c03b118a GIT binary patch literal 20105 zcmV)~KzhH4P)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00006 zVoOIv0RI600RN!9r;`8x00(qQO+^Rh3knf6Fpa3V7XScFjY&j7RCwA={rRtCS&}A( z*>cXgo4Y@MYpfZOk(rg1nYDFwcUAXvPxnkuPm9ADu8<%=BLSpDg1`XekRTvI0`w0M zf_@M{NP-{%lK2A!5fA|lF(OB!ZWgC&dabT4vvQ4GVvo1_dY5yKndyh?FKQwKh!+`n z?(bf=WA@o+pM4kq{2%=T@35InLQ%${7f~NL6otfyXw77j(}3&%wCmExA3goYfB3M~ zliRoNI(DWu{!%qjU9UF(vZ70KQek_Hh2FjPf_@lwVY1te1g0JiZ`2>=WX#+!#|hOS^w8vEAs zk><|&HB0u+*V87ZxIddLmg}1*hgYjs6>=6r0x&QmLP9cC1VjQH18{eL000dP0RZv( z4WTTm(ghXmHtmi1?A-^)+s(2F<^Fs+Dc!7@1>X>r)NZ^}M5u2&xtdfY>K*7|90udP-d!#0+<@`c#9N)5E0C57oiY}(h-v%n%@y1){NI=YkJGREI%K z0Fjto9ELbVLqv24ga&2`V1{M{Xox_J$_^BuD z6Wf^Dm}u1wfAkk0y#2=O9usVyZdc3m=P$0VHj7n%y4;*DyG~R^A3Zxi+Mn&!#cQ_? zo}FIxLj*)sFfaosLtr8id38<^k;nm{nOtXUASy1OeD;@r`2TwH`0?@K(c#`?Z(7c( zsw#`Js)DPWuZN*iiR|cn-HmaCgu#0>GPUa~FaV-43D9`M(9i$@3|v*0WfcHn7!o3s z6(XRBG?NK2wc9RuRx$5GN<2h~DOWXv86l6+U}lD9s0vwfhF4kVIt#^=Gx%qx7n1@` zroPLAAa%;mR{gWfZJ&e?y<;WF56otx9WiUxGCZpUwQ%r5Yl#ncQH z3CBtUM!Ph<`>P>r#*8P^c~civQHW$_iZK--Sa)%`ZTF^=f}vuX)?t7DpqcI! zMdP?6$HWwe&Xc@s<8s?M<}8_+ymv%2Ru%*t<6%si0AM4Q8uJpO0|O#(41hEYgCRQa z0F0Sbh{qQtPXuZPVC(y%2g8?G!@6Co`=(5hI^})2hd2}!-v93ZH+;lpnPzP>OR#h9e8|Uov7Z|a0y0AMZz4}g-*Fqd^ngp$>V5c{5q00Ds!DT~CIRn4*jAR>+V zSV0Xz0l+j{$}-+HLl}b`03eG#dG_KPZ``gYWh=TG?B$~ElL1lb-J~uZV@k<6R*@KU z;d2p!cU+f2Ma8Try&4T!vqFr+jiX77*x>!kX1pl!mDy{{kajlKY#x-ABrsS z!Dr7dm+cS-_7t3R%)v1c5*V`=$xU4qg;O=h)VAIJe9t?#ZM&1>leQmXOxC!zZMiPj z%gxbYQx>7`x=q_T=L|5E0Rbfqt}G7sW(S9dp=qc*qI!S3Zu_=hoS%B1KY6-bcY|YA zH2`qT#00bhwO|M%Bpngkb$NRQ6rHM7lhQe6A4G%*oo5v#A_NGbFf&GEc10C)Hb%EY z=Kwf@Kr|bJi+15P_CT-jC=qV^{HH(tq%Ok{MNNw$Oq$v;A{YYzSO^{oF!-|YWf@Wy z1DiC>$??95<|LcVN|A@5Z<;#iWTsW=L3QX`$8OrxeN4lUm}tG-Y+HXY;oPrM%k0c^ zp}kFJ`>D^X^QV)e`Y-hqA1ud(#;6YJHVr?;Vwe?*|E0DI$G0WYMnOmfoFTTsr4+Ouq04 z5R)KaRTYFx2v0B9h2vQnRL`q!U6ohlN(l94@Hg+B{NTqwJ-b?Y_Bw(;0Oy=%Hn8zS z*WDLmc#ZAauHc!1fjJcuvEWg}z)(e*oD1x{>)Rd>*|TIpCT4GDB0_LoXN&>Vz`#(| zx}l3H{_=qCax0o?QTThekJ_#e!3XagVa^(yBhCnKTIcl^Ttt(akJglRYB-dPB94}#%x#JaJuYgWtbbQ zY&{Lh))yQ3_{r&i`{(Zyk!T)2e=zWVj5PpL1Ofs@pj}-U(Jlbu4&|DWb1Y^6g6=V!$R3ZgNy3PRzfJ8)uW=e?rvze&^7?~B0 znj##}n}cc56pWBIn^nKvn#!HmZf>^2)5kBq@wI#3`|i62px~0=#l=!Y*UQzr@4mfQ zwV!?ZMO74pq$*Vz_NLR)d&gLKS9mHt@6Q_Y#iO&;vK@v&`d+Tq@rxJhAHV<6^Rvq? zCW5gIr?L7w$HZuO9RdglWA905gg|4GLj?i^L`TReML}wvJKmR+_|O60qB^YbR-@Cn23?a z@EQ>)j9uc6i7*2N#E}UhLk9pwaNhHHq*O)Kn7Qv;Cg;5)ViyWgqmkX9@w-h-!4M6} zRKS#=OT&=*U0x#|+v>6^=d%VhpB(P*&6-K!?%g@q-z(SacC+p4raG)@SCo_Kv@B~v z+AP<1Zynvgf4ixt-+u3%{r&xBHr;mJ!F;~IKl{bUpWVHE^6TGy=hKIepPyddz4gxP z_wGD<_R`c2=M94z^3rWLod(a2`K#ww8si(c4jN~__1!m*UwiPM{y%>((lur_vM2_b z9V0R*(0J=cF6A0p0RkGTDej;gIUh*XQk1%`vcwc~SrumL$EY(yL`^xRD55c^9bE_` zTZn3=WN3h9Dk|BoE3`RgM40bQa!!*;bFja6|L)T58C;Nx{O$Z(VzW?jrTr8H|dUbR#pU>yp^`;E&-rElx<7&O`hjjba z(Vbg2fAPVGlcuiA`QEgOLn^&ht*=6HwON1h_(fHe&o0*owLiRl>t_$2KY4!2#3Mms z*9{sIBAKBXD3}4F{j#j>fC3>Yr~x9HOIZn_EDI4)k+Lk9Femfgk2h9Lk-%di0yzqT zGbB_)HA7G|FhD~z6v-;rcnuT*g7|N1vHcVB$|$VAE0-M7B;J4dgjoDcTrAAayNW@`%EY}&KS4H1=P zIKMcniqJIWdbNsuJDW6R5&9@Mj%Eh(;O_0Kb^G*kbFm43^6{SzX$&X0ZqN-40ElQz z_wf*Kg_hZu4;wqnSq@KaZLjnRi6>;8q&#Ds23JFzYM+%zx;58dL zpN3vkR1uL8)ex@h&j>vLfn!eBq$d)Ssj2EPr1@U+oo{`unN&af#aDG*zgPLb+lI;l z^XX;#*+2iq&aRR-3Df3+FvConM@N`Q?-4 za^*Y)XAkb(x^Z&!i(fqatDks;JqW~2qC5D zm~#>Yk`zre#gtV5fPhdz%?Jo>#Lb{8DGj?x#n|Q|rj%xr^5k%~-E2f`u|)Z^_lpp2 z9Up)C;tXLZWjQRi0Px^7eR}#|{pueafACNHZW~{_HI3=kPd@zI7iC$NCem-)C>hDV z{>GjAcMfCM|If zo0LTqagHe=F^?BK-a5z5faF!W13^PT0z^Y&09CV*+C@Y_*KXI|fgutz0wDXGA`v+6 znRloa1OeE4uL{J@Mwa86#2evF)}*Q=DWdpP*`1F z)dhd|o%h~-36^X```SXzx`kS-~R9K+>zts^78!R`P1cJ{`B+8 zyYKwUH(tAUW4Ya2ZPLZEOS-ywJpc0fSyh%X3p1OT0pt`B$Eh0_f#CJ6y57=N- zltb`2DE9XmoWGX)?O%|m1+cId@aZ>%xzyEDd^7$v9x!_)YvHI@c{GZGwhgnTUzVY6-Zcmr5-Ecqt z(;xNOzw_R$U;Tsfvis<#AN>$O$m#ueCU@@K3Hs&Lqu2hY|IWYi{*NC1XaD*C_l-AS zugc1~l^XQJP*pCfIwn=fIkQ;^1)vh4p@9Oj0io`w$Z<#o3c6!<$1W7i0az%5spJ^R zvtxI_qvM%MX9?*?aHapB~I+{QUR^ewYJhP_$+@O#->#yA~k=|4dRYk>cye_3Ngd90UBqkjr%66%2q`=2H z9HPlJ6YfM(D4b(91p*w}mWcoqOmmDxtcWSaoFJyGDr0#V@0zOGIKxFSdo`3tM4%Ca z8>FOPJvn{y{POgCx!SfjZ`>fHrmnl84@{x(Ayi@Q?n_f6=Y= z?YH0g;h%l{lb?PvZR(=%-kEpq^kP+)L6eeqBm4v!`*AWAcH{z&bAH{$**K^qLqj0A zj!L`k!yEt+vE~ejIb~utQv?8zvaXOwvlL||np8o@1Zf6iQ#O7YVn*Z3ftfLJ2(GEa z!K7%r;lKH#zwA@;%uQJVNPDMk`eLEZ+!1pe&_G>k6${$ z#GVF`l(aVv1c=q%ow0_OoWQ+9=BDm$~f{G5?bv{N&N&7fiI+$cXLB z!f*RDpH2FqPbvFQxT4;+y_&LP5hWr=JXXhmWNKq2g=;c$$4ndSk{_7!j?qBW*a3Ub zL@L6JfQp2s#?I#~qL~S8gw%9hT)@VD7gf~87X)IcOMf&gXSH80V@#roO0?0gm?=g<$4C^4 z5Qms^G!@>}K`=7WYu(Tvpy6Qe2lsnBSa} z^UZYr;Op-OU+y2@OhZhY*ScWhRaWboB z2NN-WakcJ-9uXzyst(?J+YOEh#&9wOAVO19R77M0MFIr`Ggnptj9ehcm<${`ADjr9 z3NaBm)ls^m2>MG#NL6&?M?lq(Eayas$A^2b-#L2wwZnrtV|ThWS z|I2^zTfh68lC>YQS$g>KhuiJ?*2(eF@$uuQpIuxo*2~TFPd*!BT&>nb5ImnIlr6$r84E^j`2_QhvkK6?D<;aATbK^1}# zt=4UygMi%Q>m4fgzfrsv?S+nT{D! z6%mi-land!P3yWW3h&TCD5uEI0IwFCIzTL;U2oQ#j=h`g&-V@vb4phi=isZdY7ig} z{Q@bah-O0?zIyTOSn}R%<{bu)mWQG1o_v|BXf37ozg+gK06Dte5N4=T9u>i_@3Kw_l$hpSVx~vP$aP-Vv|Q zp1=Q3{;)o|HLNdBZX9`sc}Rff9L{A{Rn=m(xp?t-asF~r=v#N@UwiNxx?*v)UanWB zX|?InFsxUr&mKMnwd147jl;Pkm^8)Bn>U5s#d34MnJqW%W_@L#BQdn=sNi~9g{Y(U z1`tPhiU2?kz{*Jjmh%vcqF{D_q?!ppWazfNl2X}B>dExQ^RsSyUQepM z`SGor_g2g0WYzZlaBwho!yY48cqtA!&-S@5{ObFi8oS*f}*}^scA@z$7!FnyDEP?NqY1(~g*pHxE3s zXAYj3h*8l6HO^^6#MShMuf59fbamQYJ)1X`FUpj;nbd{%i}TZNh&hSI4j{)E5#0;P z%h+`m_X;?F^x@U>uefaL+5BLC*0rm^+;*F;Yb6^Yo!q>clB`#&FCTsu9L*2*C*_1p z&M%iHa`VRi!ND7jpu#9wG!FrirUZru`?I!P646N8B97P$ccC^`J=%>BuBUV6kPwOL z$y6b$f~rXz%Gy$j-W7zVDw0x8IVTw>gl4;7gHb1;W`bbgy;Btc)11(=#g2#y&p^z1 zi7g`G@r@hJ?B?TV=O29h*|egwm(M?ZaXz0-RRwftDo>0>$vM+STEU>+Iq$hDomoGu z+ea^-o;P(>hP`Ryd}Rh@U3GnLs-FGc{@&5?$!59u>Z>nS>o2Q%(lk@{o=leKFOF~C zIJkMQuE7@-XjaMVZEGe>JnH+dM+X05B75i=Y59*u~J(8{V%v1T%7 z?{kW1sy6b!isQloBIvlkU}j>VhJuh8!22L7DfXHosxcC?M->@1-Rdf~!`^Iua^q+| z3E%tn+j+Bi`sl^ws{PRipMUY_<+jg5f}GV%nFKY7MYX8fGXXJFH6HI*WNIMm^=i3X z0O;c491W(keLzb6U>Xk(_P+kkw~z1K>xS+5*^|@fPr7Ya)zi{@0-fz27tIui4V0Ox zqRLsaWFp=bf@|f_$P)qKE3x~iss}{=kN>^Dky2-(#H=ErC=?VF!Sc{=9g~O>bKCY$ zpItn9+LD_)7tFwHr!+RTESA!6IB~OzahzPK`VbH?4XtT5LSjeAk_S!OY3+4bdr-i< zSZv!tw|(yVoJ9!8F(Vr>2G8E3_Xy)uQo&3SO$B@?M6B<+qvPYvdb_whKRi4T#TU=c zLU5t*2M5Q8H*UqD4Wu%3L%Vg54=UK7aap+e(d|KbwQl=>L6hvE`K7wPT$$<)rqL%I!}p&z7?;x5Hu`yCIK? zI1$MzW+pNo3yVobUyUoUEDJ9t#%^a#SkSzqX3F{dUjD&#cVnmH)#lQ92ku#W5-SJmN#~x$p4Ff{|{0e z@{n_i2ExqMq#nkRh)@9|f^i~D(4q~!ZJ8aq^CCdV)kh8_4IjN|L zsjAwJlENWnKyaaW_Ut)3w|98_^AA7Wt`~2A?X9cz^5u({o_TLl-#EDwoHm6W&YJzb zX1+fKGw{{r)|Q)%_inLT7s2mMCqy)gna2UbSUU}1T&}TK0SDk>KM)c*GPANSG=nA~ zL;^y@oD#BUGnKWe7^oQ_5Sooj!?C!iiu10igJZ{KHT3;3#HK29(%8qc3`J3sXOzAu z5WrDRD4KFl&h5_|utP#F9XEdS{EE+4!_~T7w^TS^mc9zij7Z>kRB4VQY!Hb+3Ji&R?Fr)I7ZN&YSOk^IQG$xrbpkshg@wo+K0) zF^OKS7jYQ;UZbX@Nc=C{pWQfl3^9Af9|4Yi1)!Z9V-85BIOOAclNtTq-Y*ybR zo>WCya#dgz-1DohPdWC(W=M|7F^$3=Vq`)_0s>}|EJ;@Tvndl_TwcZ)-@5aZ+-o&DYvVO_4(sFhxPGm_bgonkL)}}&aMC>$&zAXrm8Fv$qY;lnRXiR9nB9& z2s)DByVB~|J5?F_wk%5nVeiHzJ?|WVsnaaNj5(*A6_61KkwmZ6m*Y6X5CI)Q83L9L z&9Y8ZM1jww0EkPsy01VvF+r30p&Qpqe7 zg>xZG&RLvuRS_mlUDw65x|r4Oe3=&8VcTm|v$4@ZGyolGFaTym0|qS}mrPB~kTy5& z?ANy^2aM&GIJFmI1Zi<_d;E`S?!yO4`y_5aOhpGi$EcV{kcIZL$kcvEEd}$kfKXg zbi-!b_EjkNXEQ(`;2kWpR}#tH4AgeNUqN1QLqE)BGw-19`ns6_Az4<9+0+b*qD({Y zTsaJp5D{qHkVG)BY$}M?>ju}@+Ivrc^F39QZ99M}_}#XksjfF|15_4%=)1D20E7s= zcjIQ6XA0q7PA6f0xmvH|y6xINcM*n|R86lX1k6-;u1g;RS7kA&{iF_cSvIq3 zIxPuuC?!yWzt~hpPe6P83Ew4)2v5H%+a8YO6f- zeb*yV@E(Z(scU-`nM|6v8}BbkOKK=B@jlv1>9=BF>u*@wgZ35`Gf^&%r8 zn(l-N_G)r`tpqpPMV;%~KBb`y-b9Byc;`fNipd0s2tXxk&e6=WD$+Pv*WIfbfe9Fy z={Wt|9awY#Flp)`#;wFOC>kXYW_8XPLf=QpQdFTT%aroCM?*BiBqideX@U!rx@o(% z>xQl!V#=zfqABN5d^gfr%!G(O_z((qToh#y0(%$L31gkvaUU;i1^@5G*pfEK6bsC0s|43enPmk zECddbM<{5BW-_YiRn;SiWYu5>nlm#K(cW~HQ%Z3#00l^0G#IKf(73YDS&lIjr2%?o z@0pp^l$>|ONKiL*S(bU4Q;JzEXHl_~qM9&{Tt15GxG8`{&N=4_Uls%?k`N3>rdia; zX||ja74^k(okao%fN@KbcLD-4d=*=UG;U?!^=YLsH4%Zi{iCDUuZJOe7jnwXPLi~% zO(kR~2ApF0~KvAa%v++@KW0NDk~ZoAXmdU;h8 z-iHFzoDb|BJ1*)v_8lWR=Tf`YoGqzj1vEkc6GTHZLRJL;0YU{}=L~TelIMg4IPVRh zsV6d*;pJ&c+B8LsuvoUD?TzCZW)T#P;De7b1|JAfG}l#G)&(=CVer8tkpU1Pl0!gW zcpK%kCObLUPB%B=cu=*Jvzbbkl(QO$nq-OD#OQn#U!Gqb9~}^1V|Fwf7q_ohUq>o! zRD+K<3tu@Ppdo;(s|rWeJECM!)11h(BLpsd&I7R{19GIMXye52TG3^SU}QKh&*YQ< zoG5JDPEB2uq9N~GQ545FjvsyT#pR_;nkp17CpbM{RH1Z?>-8ptqAbG4PahS*-#pn* zLyWPkt2$I(R7S0D2!YrUaR85ut7rmDNKPnMLkSW2T-7Db?sGKglw&0wn5 zG!?T0+bw>L@NDNBu`8lRHr}{jHlVgcZ{%W(jFu&Xf%8sc2Gvj&Mdd+_IOG(WnLX`h zE4y+s?&jLKNeyZS+7CnD5-|#qsujWau}7roWDg6RP3OzSYOBUbQ88yeTW|JeC9qqr zx@XT+*ZJGUyUqOL0+d{LD#B}|E(Hvk8oiNHj2L}o-c?kJ5qL=#i9 zn35TasE8$n7*iJN6281z7iCe`&8Xo4FdP#One7}`^m@Tv$L#>viI8_MhS*A(w5_K2T(JG zA?5A1tAouZH92zZFnD4&wC%;kMO8OdRqgE``cR&qK9^MVQP`t%WtoCbdeLtC zbauII>XMKymupd(RDm3pCH9?&giv5n;V^VQgq@oVpyqLxFpEk~W3ofdDrjb)*)(Mn zG4xT<`LMq?XCkDLmj*-_dqgrIppo_-CoeGivB343#`UVAQ^}H2Rn=-DLq_5<6e)J0 zD4ELj}6llLLt85L4F?BZlB4WkO3SN>TtqpnkLQWz7gjM<*+{ z+-x^7rm`xXb7yB4^S#O2Z%+FtUp_iNzg*uqoSDj|?Fo<_#w?6%wyo>Bn#53)A&dA# zgh*qFV-?G~Bj5lH9YInXMSfs_Btn~Rn9rx7U?k#KzCG8xMw9mg1*bD^vxxJ) z7r35G3UaP*yQ9NB=L?raZHO_AodBRBB9fW00jim(N>+NsSQtn~p^%l@w)bTa?c-H_7)Hzom3Wvf6KWtl(>^z4uj7~gpNZ$J#$7&>MPG6a* zT+eX;fWalB7)48;1TbgR9Agg7`68s0LQ$GvyIqT1?9Jys6jfET^V>GAuNHT19t<&m z^6=@s*KVYo-h6OlI;lVX;;Dl5S-<$?1rxk>Yk%8EyI9m+H{F{C?=@#caNdELY9_~~ zD5`2^3Q6)vUYMydC&6`>)vOE!05~E>RNJ*pbnSFxyEwbH+`v(0@M_?)<9Xe0qxpI@%v{ zS}eDc#W_z?1mGNXT#f_4G$bA+kARAxVkwK5DY7W$3|*JHE=~`4)cC25{lHjA$L#is z#k1?JS0yAh9ethfdPwDpx*Xc|Xx&tlWfEls1I;O#DpJZB2$_ggbVSl4W|JM!F-jyf zc$!RnK*=J8M9c(v==;7)!H0I!7FBJg>(#cJOhQ#;)u&I-ir}NFmrL)-mqm)1fYlNZ z0vfx3gqo5NIOkOrfYi{?2r=spHRJdW3Z>_|a8)Q2P_h)BJo^yJVd!(tNvU71kg%+) ztIHJ=U0z&uU0+Y?O&j|zwOubc9UjalP4(h@ad@~F`?ziU>7>3~^zF7izlyg`>iakM zm~0r*;%Wtev-z~-(galn$;>P#QBz_Ulca1wpn`p}9z;Y{1NfqWYaj(e)igGeegJQtGhp>!LCfX6HSFK~7@_?z+ty!Ko--^C_dOS9eN?ar&-I zPzI{2B8$ct)rDWqg5qJYl1J|#dP zCdfqOsXSNkh4p3Q5Qg;)2E%*+u;QB?pC%8*Arhl+@?bEcBf zLRm{5>01Cq9Hni52t+W#kuf_^QI^gzGZRwqUQD)aR}{r$GTm%DRqflBJvWmIh(Zyn zN}oPEjYGP5I6uE!KYOtXp1*i@X$I3OY@_TSG$Htlm)rRH#W&wPb_nF~=x9EhOwH6e zrv@>mDion8(~zRCm&t z-FCokt=kc?W(!4V+buIwU_w`vEIF!ait3q%VLK-N(Z=n%lSSAK`T!6W(NqzLnS(D3 zA@?%0otY8f&~`azQ;7Z0Z#U;6RaKQu@!*ZSIm+jcURHIrS+_C8qBL?D5s>xAq8WwNA_R`J}0fK$E5k216g!fE+=jI3xv3*@ywXk1=+eE%*vu z4KT2Cqi>s_fgvL*8t%-gV0Sucr|cMePTPTxYjY+5GjK#Mlz!+t=HMNfNY2)8Tj$Y* z-~+2FJ2o?san)d4)EJ$+Mt3$dGe+<(6lIW{Ow-66=A8P=u9;5irXGgw=~s`;w4P2^ zt2Skw@$BgMxNC>%^y*;V?9b|tAHJA0yjriPP34)^>n=sPdC*KsMCa>CdHQk*AVU{J z!MBe0r%O++#>5t^71;dK{voxQH9 z+?^t0$AZAM#Q-6q1F&|xHO=0+uJ4K>AfXH1c_MZU+;>|rBPP*osEE6T(4FXEN6|n^ zdE0j0gL6((M1Ua<;~t-?p{CUL2Zslu7RBbFSuU=o`*Y{Zpi zlCnp-b9;Zb?dvjRqSMRO$S``gcfNLFhRtMBPHN9Cn|Z?=%}AUJsUJ4omP4sSY}?LU zxoL+swh0{oh^m2sD$uy}GggJ&IYmG<85LKABx6YYvbK&2Ds-yCg!OD@s_2ScON*pp zG>RRGd?+P}DiAOl+b=6KyrQCFPB9Lvh0JENP?jmCP*8^63}YX2>e>0ap7h&pwOMLb zN!qtPvv-9HW$S^+Oav=b)%3X4dt6-w#Dmb~yOD-fUtu!9fT)tlEo7Q%{;Eiwu2iyI7aOAt#WS z)BgTcYAK@&rJwE3ickQWB4;&IT3l_KN#%WLx1A9?N8ON#eaZr^K(S>T1#tZFvS=1@ z%nV?!1he|ekP5D8$X(BlwwqwRQn49;1AvrbC<-&pqtgPj59PSy&0MHqFi=n;hroKB zMMYJvk)eqc&gCQ#wJwV7s_WXpM5Ah8?qee7ymLgJO3G0ziDBx8?&XU!5xuy$JUZM@ zIjy$o>|$Ly5(PjEF847XAMGhRF+f+iVs>`EoHi%`j*JU!nyRRaZ5N#=dM8P@T{N?P zNNulNqd@SXUM-i)&BldNL`5~H1fB^Q#BfyO?j%@vEw{SXmzupYk+`lH=K8kt-l-~> zlyxxzuoQbl82zufC~}IDO;ps9K_)7|%poC&j`L_j7hEVDs%RGHvFir{L_k67hSVkN zVoC!vlUe||nC?yHxm~W7D_L*I3~kQYXt^C0FITH=OrtFv(R9y`Vh(jUZn^K^ z?lr^!d^K|4&5f@afZYun1&}Tj9>63^)s#pO+aZ)CfOT!>oC{UCTiQT0Av3^HQ#dvT zKn8+llC!ILT9;^&vJ&}vQts_dRcT1k*4^h{J*TqRn;kyCTErwwbm#8L$^Db*cDvqg z!elnY*hN7fg44|~pxNHxF(9nlwvR(7=A~m_l&fuO>Jn7jZkX-O+AbzB5xiPlDBzGX z0Bwh~+zzYF(Ds87w(S52?6{gt%0^;}S&9H|wA}>eS59%ZGtj12NMkoCfE~BC8)+K3 zI1F`Nfy1GTG4^%S^!)&)WmT~w19RRF{h(lqhQzNX4}#;=%M4AyrnC9&*B@M+y;wef z@$B?vhA^3@v$HEPt()rT?%jifLq*zV`}qA&a_Tdp3xUz?9p5b4{`~x`n!xS*_n$s{ zzFf5I3oeVCQpO1EFW1AIs0d+@9962>wC!SAc4{JWiz@a@`tnCQ6%c7^8-nP@9%F`i;L5jKl$-b{_-#W zygImb|KzP7|K*14QA ztT$b1s-hs+US4gxcF2G50R@mky(bV{wg39NcfR)RU;mf>wg3L3N1umK zymohf{`}edAAI`7lcyn+vuSN+Cfaol0TzpOT~^OtoCDb#w{M)DuO5E!{NCN;*>n<9 zdv>)cOPU`ZZr9t*Fd+FyFU|z8>-zbmu1ojkgIm5TZ|?8y&GvxZ^A|6^di3ISadEY2 zQ_Qp3WIC;bFE1{ydJz#Y1~=je&|l8ocf|Kj*18+E0P;WlcYhZ^ znH)P()0_S-UcDQjg zyIO6Yzql+4Czc;SJAHY+nNO=*w~pqsy|>@Iedp%Uq%3?{T&*`i{Pg+7i?hY$;;L=i z!-Ksy9=vw@)}68_o;`c{=-KndYP;NYbyE`YV%;HeRTouN1n(R<=Fvf6w+Cvk;HO<{ zrfer-gKJZ<-GmB||KY#$d(7m#&pE4PA3Qr^c12O96v-fG>AU{)boKD_i(V@BC7>xN z0`Gu_X&mCu-~Z^p`{O_R;KPsF_2RYH?k<*_KmFk!r!-8Oy~kgDarW|b*~ZIND{6Ha z&aT!e$6H79N6#+KSDWvD`>m7x=EKjQ#5lZl_jtBf63DbHHeLMU>DgkvIo{uU`uv5N z{OY&gx_9U3!RvFa?xqav4tq1oUxy5F4vD}=U zU#giHIOjtMRT)BX&byrz;k8O0%}i}4le~5^zt&(~;}4+Gz@7ht|Jh%!>L%yjR7XEL zRTasmw%a5kGQ-o;%P$`-JE^!RMkl{(%Ofze7`xNcs~6{2n=YN6p8k!${rlhj{%^;W zfBNIUxc}zc2Zx8xo_w`jwl5c}BKSMUvxkqKPp9?0n}=r?%g>)*G$r3TYMj}RK778v z*VH8icGKFGg}+?)FRwO4Ru=xRe)dS>aQkEyhwk0C@2dHaKmFpn-~QTS)or?XcC}nC zmiO=9@h%wAYjWoc#Q9z`pG~%HZ0d0Hc=pE4gKj%~`qlZpJ2xgx@#*99 z6!qe2)pjwZZr1oJgeNZ+by>dg`pG~0(Z_%KqfcY9Pd@$Z``@|uTi^e+pS}O_ciz44 zkj@vw`ww6I(GULY^6E;nEf$NM^K3%j`o}A&NI6Ls$s$1TYR~1Bku@5K zfiGB8*4qtvH<|7K>?c3_-~Dg@lWvH!*?hHHJbQWG4XN->#4fKk-+AZWUQ=DIHplyu zZ@zVNS`!(px0`qFoow2EZ&uG{RTKcArttHoV5XPnS2qufuid}#=~vIcditUY%~zj4 z`i<}0`@O&Zn-4#K^!DpFnP}bSAHDzZXCM3`X)kJ5i}i9fY&Y9F0R#^F@r0|Zt1Kd_ zSwu9cNglTi6-*Tn#*?$NSsU@xcruKorPxDC!)OY0jdS zl$;-RC}`J?4I}y^FjYj1ee9$Bt>63IzU|rZS6@8*{F9F_FV6Q5j~+jI^3g}1K6?D* z#o2PP8Oq?lc>LnQ-GjI8&WCO5nUdt-clP9$&FLtU4Kn3DLS zP?2u4VaH6!K%to|uNHmZi>IN9Lu73{N!@lG<}Ro zAS>3vmxsQpxF`Z?s){+I%W25DE6eH2(`OIv9qjM@`ophYuDAVH&o7>xu7C2uXWx16 zjo^rpRQ2iev*l_#+uKu76&(d_S%ioYM(j3{MWeu2M*ZRFD2%@Z9rDU%$RUDbKU#7W zRc$H&;LBj5#GbuRL*I9;>S$Ry>gz_Ig;7CbV2a3n-+%G&)5&C7Hg#Rr&im3kW_HZ? z-+0}JfQm`-ab;cG=~=FY4wy-?%?%%0K**4?chL@{`YBgb*Iwy;=D1<%`R!b_c}`Xwcf;0Vz>5=jIu_Crc3gun&}4B%24 zOw}>tPE$^ZWaGy`c)ceIYO=UEJ3l`ghJ;sFh{WVZp3bpzo_N$wGCRlK`?9Q>dg{FM z-Vq`)1DHt8DP_$$C&_8(hHbm>8Z=ktT( z<0EE=L;$8D2$UtI97kndimB`L+NgFM*dP%TId;U31AAg(?;MwtS+jR|!#N_v@t|eR zBASMnavJ)Wh9Rfe^G4^e* zYB}Yy$XJ3?~Dr;Yx&45VNJiU?O%=VzzS`|X-t;9Y!q?*cI*lJnjBZ<>OpbLP?I-T;kv(l8Sc6;+X;AG)sZ`?eoq z*LJJbVzXVxzK^jV(qO8ZCFR(4y-H3g=Nv^e#vv4;@CAS|6Cqzar|+bJi0FJM#+~+@ zG7`lhfmvObhETa?=zEboYUcph(6R{tqX7e`sn|}gINzJyy>n+an~`TUCzeGN3`bc{ z%0o;Y8j2>+v6_q+6WM#`JRo{s5F#OYKR)A(kV&$dLdwIasTyLZCLkc!(knCoV0O+q z@4aV2V%pthU+k9+yAvXQ<(wd6dP_sjIi)zHZs>=hABNa>-8QAP*{r*+lbqYOZM!xl zNioKpMY1Unv#K~SHPJq0=a^_*@%P;@AON#70QNonQc2yEv$-h^b`)MrLAW@<_FpuA{dCKp-oAXh?tNOsnrk3nPiO;V-LjM@u+kOMd3U<^6Z^=&N+6WC_{}5-g!VJB+(28h)z|qLV}>=6u+Ls^StNr?!ZCq^SA5s|Dh4x6scs$iJ20V*I8uxdgkLLdZZ zhH=PsU8EeD2#b(X)YzM8@I^`~=d1=f+m3M`-T6lvNS}(jOCUOoH3>grJSVV}( zvCERd4BhxF9>+w0#KfcbqIZ5YFcy)KF~~U%Lmro9aHlR9+iW9XK-+oqp>y6LV{ip~ z=RJ8Bf)5zTksF`4quQwEEQ1KBYRW=r1UcnSV$RvJM$3T60_oL5wg3r{ijq?vfRGG{ z1EA!TvW?n@K;6(20(+NZG=-ul^0;nJz}~BFO~-typaMYG_6lRaD+ts~r?+n3ozC{g zwnJ63D#B>TV?*jSXYakKiRPR$GfP&bnF)yM~vu0Ky--4%+9$`_&{2QKxOHO4acR0anD{=MMXuR zO+(I!5JXazT_qVahZD8fM_+JJ1XVLY7dXYt&MQbLf+UkHDrSPHrep?!JERLRT7aky zeQej;s%Xlp^1%Zrl4qu|Wl1^3m_}*_%(5is92iI*rQ0%=+R<=bRd!6F?q+N`i;W&| zMhL2)%%e9PxS}+~oRi~;nKC(5QIV{cC8=5*hP)j_HRUY3M+1)fD^ycZ00Jar^4 z$b09g;J^sry+=ki=x~yN)lZNV3uOh+xBf?V$h%E%U`98EOkoHc=%Xm*H_vuYL;H335rHIv}W(T1Pd z5s}f(2}U%J@4H&9RWg7{PD9_dZB|uKN|H>+jdewHqB_LhIWEhF7+oj|0J^$d#=fs- z6X$(S$$QVi_idkJ6uBmcudP({nvC4JdYBq00l83ahwb94Mf~&=OW9P7ke#o}n!KCO z4{zPQb8_Rxd_F%qI%%fUP!^MBLhRI(kck5`6QP)af?5Uuv7M!@s3I^iF(UK$`~k?C z!Hkd$KqQVFR?LGVZ)RC#==%W91d}9D8D$)}drF@g7_+G=69-Q@lb9>KXZHQjkF$BT zY=R;wXG|iXLl$*?jA`iDVcAr{`C;gpy=3eAH4>3?fC6TkGXjm45Z4{T^}}z0z+irI zc10xbFvNDXT5UGl&33chY}TvIlb5GI|LhC-^S@|1`suI#45QTl1SdQQU-+1pEckkb=n@Uu& zsENjuV#={g>+O1oon;frh}lHIMAgzD>vq|0H_q!2H|utpQZ&$}oQ85IAS5DUWb(m# z=bb6`!!Vg0ltqI?ij2e|6arRP4Wian9phG2i7*6j7R#z~t_Bb+p!7wGy~UP@hrTCF z?PjBBLmyRQD5}L`5&K>YG$(`6h6sopGY0a2suG*>@ChHlGD zDW;s_tB0Iki<9s=Q=@1Wjhn^AqsN~O!)7vRf-jseoF_&q95>VQl=Ao%3(?)Y* z$L)60Z@U-=15pF-ih4R3y*HU@Xp3!&W!O(Csbn+Al5$Gk1@GMmwqlGiMKE*Dd&eou zs01I!&+cm7PV3-3k6Rj91c+5lB>5r$fLcyjC0`rLn_V--qhFnl&-EhG?Pl>(^92(a zDi{*7u|c+-wYDK4A~|A0M79vhP&8w|R1 zVnyqj-9HhrchKFOeKfH`LJ)INGv%q zI{+}%5JKN|RW%`|IK(W1h$#*tLQYgcOdVnt{r>~7NZc%YLCcu{001R)MObuXVRU6W zV{&C-bY%cCFfuYNF)=MMFjO%&IyEyoG&n0TFgh?W+E#Df0000bbVXQnWMOn=I&E)c wX=Zr Dict[Any, Any]: + imagepath = Path(__file__).absolute().parent / "catimage.png" + with open(imagepath, "rb") as image_file: + encoded_string = base64.b64encode(image_file.read()) + return {"image": encoded_string.decode("UTF-8")} + + +class Number(BaseModel): + prediction: Optional[int] + + @staticmethod + def _get_sample_data() -> Dict[Any, Any]: + return {"prediction": 463} + + class PythonServer(LightningWork, abc.ABC): def __init__( # type: ignore self, @@ -110,6 +137,9 @@ def predict(self, request: Any) -> Any: @staticmethod def _get_sample_dict_from_datatype(datatype: Any) -> dict: + if hasattr(datatype, "_get_sample_data"): + return datatype._get_sample_data() + datatype_props = datatype.schema()["properties"] out: Dict[str, Any] = {} for k, v in datatype_props.items(): @@ -141,7 +171,7 @@ def _attach_frontend(self, fastapi_app: FastAPI) -> None: url = self._future_url if self._future_url else self.url if not url: # if the url is still empty, point it to localhost - url = f"http://127.0.0.1{self.port}" + url = f"http://127.0.0.1:{self.port}" url = f"{url}/predict" datatype_parse_error = False try: diff --git a/tests/tests_app/components/serve/test_python_server.py b/tests/tests_app/components/serve/test_python_server.py index 7a477d98b96aa..313638e9ec42a 100644 --- a/tests/tests_app/components/serve/test_python_server.py +++ b/tests/tests_app/components/serve/test_python_server.py @@ -1,6 +1,6 @@ import multiprocessing as mp -from lightning_app.components import PythonServer +from lightning_app.components import Image, Number, PythonServer from lightning_app.utilities.network import _configure_session, find_free_network_port @@ -29,3 +29,17 @@ def test_python_server_component(): res = session.post(f"http://127.0.0.1:{port}/predict", json={"payload": "test"}) process.terminate() assert res.json()["prediction"] == "test" + + +def test_image_sample_data(): + data = Image()._get_sample_data() + assert isinstance(data, dict) + assert "image" in data + assert len(data["image"]) > 100 + + +def test_number_sample_data(): + data = Number()._get_sample_data() + assert isinstance(data, dict) + assert "prediction" in data + assert data["prediction"] == 463