From 11dbffaa039cfee00c1fc1235abe728cc956bfa9 Mon Sep 17 00:00:00 2001 From: Ghullam Abbas <133848606+GhullamAbbasJoyia@users.noreply.github.com> Date: Wed, 12 Jul 2023 00:26:57 -0700 Subject: [PATCH 1/2] feat: Add get file list end point implement get file list end point in SDK along with example --- Example/Example.xcodeproj/project.pbxproj | 16 ++ .../UserInterfaceState.xcuserstate | Bin 0 -> 53953 bytes .../xcdebugger/Breakpoints_v2.xcbkptlist | 6 + .../Storyboards/Base.lproj/Main.storyboard | 34 +++- .../Example/ViewModles/FilesViewModel.swift | 34 ++++ .../ViewModles/ModelsListViewModel.swift | 2 +- Example/Example/Views/Files/FilesVC.swift | 41 ++++ Example/Example/Views/ViewController.swift | 4 + .../ChatGPTAPIEndpoints.swift | 5 +- .../ChatGPTAPIManager/ChatGPTAPIManager.swift | 184 +++++++++++------- .../DataParser/FilesParser.swift | 49 +++++ .../ChatGPTAPIManager/Models/FilesModel.swift | 22 +++ .../Models/ModelsListModel.swift | 2 +- 13 files changed, 324 insertions(+), 75 deletions(-) create mode 100644 Example/Example.xcodeproj/project.xcworkspace/xcuserdata/ghulamabbas.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 Example/Example.xcodeproj/xcuserdata/ghulamabbas.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist create mode 100644 Example/Example/ViewModles/FilesViewModel.swift create mode 100644 Example/Example/Views/Files/FilesVC.swift create mode 100644 Sources/ChatGPTAPIManager/DataParser/FilesParser.swift create mode 100644 Sources/ChatGPTAPIManager/Models/FilesModel.swift diff --git a/Example/Example.xcodeproj/project.pbxproj b/Example/Example.xcodeproj/project.pbxproj index 79db946..6999ecd 100644 --- a/Example/Example.xcodeproj/project.pbxproj +++ b/Example/Example.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 6A1BB84B2A5E7EC1008664D8 /* FilesVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A1BB84A2A5E7EC1008664D8 /* FilesVC.swift */; }; + 6A1BB84D2A5E7FB3008664D8 /* FilesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A1BB84C2A5E7FB3008664D8 /* FilesViewModel.swift */; }; 777D472B2A53EA9D0050C0E7 /* ChatGPTAPIManager in Frameworks */ = {isa = PBXBuildFile; productRef = 777D472A2A53EA9D0050C0E7 /* ChatGPTAPIManager */; }; 777D472F2A53F7560050C0E7 /* english_song.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 777D472D2A53F7550050C0E7 /* english_song.m4a */; }; 777D47302A53F7560050C0E7 /* translation_file.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 777D472E2A53F7550050C0E7 /* translation_file.m4a */; }; @@ -62,6 +64,8 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 6A1BB84A2A5E7EC1008664D8 /* FilesVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilesVC.swift; sourceTree = ""; }; + 6A1BB84C2A5E7FB3008664D8 /* FilesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilesViewModel.swift; sourceTree = ""; }; 777D47282A53EA8F0050C0E7 /* chatgpt-ios-sdk */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "chatgpt-ios-sdk"; path = ..; sourceTree = ""; }; 777D472D2A53F7550050C0E7 /* english_song.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = english_song.m4a; sourceTree = ""; }; 777D472E2A53F7550050C0E7 /* translation_file.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = translation_file.m4a; sourceTree = ""; }; @@ -129,6 +133,14 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 6A1BB8492A5E7EA7008664D8 /* Files */ = { + isa = PBXGroup; + children = ( + 6A1BB84A2A5E7EC1008664D8 /* FilesVC.swift */, + ); + path = Files; + sourceTree = ""; + }; 777D47292A53EA9D0050C0E7 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -207,6 +219,7 @@ A8B860202A440BB9005FBEDE /* Views */ = { isa = PBXGroup; children = ( + 6A1BB8492A5E7EA7008664D8 /* Files */, A8EA016F2A57EA4F007DFADF /* Moderations */, A8EA016E2A57EA36007DFADF /* Embedding */, A8EA01692A56E3AE007DFADF /* Edit */, @@ -232,6 +245,7 @@ A8EA016C2A56E5A5007DFADF /* EditTextViewModel.swift */, A8EA01722A57EB7B007DFADF /* ModerationsViewModel.swift */, A8EA01742A57EB8F007DFADF /* EmbeddingViewModel.swift */, + 6A1BB84C2A5E7FB3008664D8 /* FilesViewModel.swift */, ); path = ViewModles; sourceTree = ""; @@ -474,6 +488,8 @@ A8EA01732A57EB7B007DFADF /* ModerationsViewModel.swift in Sources */, A8B860342A44431C005FBEDE /* TextGenerationViewModel.swift in Sources */, A8EA016D2A56E5A5007DFADF /* EditTextViewModel.swift in Sources */, + 6A1BB84D2A5E7FB3008664D8 /* FilesViewModel.swift in Sources */, + 6A1BB84B2A5E7EC1008664D8 /* FilesVC.swift in Sources */, A8B8600B2A431AA6005FBEDE /* UserCell.swift in Sources */, A8B860112A431AA6005FBEDE /* ImageWithTextViewController.swift in Sources */, A8B85FD12A431318005FBEDE /* ViewController.swift in Sources */, diff --git a/Example/Example.xcodeproj/project.xcworkspace/xcuserdata/ghulamabbas.xcuserdatad/UserInterfaceState.xcuserstate b/Example/Example.xcodeproj/project.xcworkspace/xcuserdata/ghulamabbas.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..ac7484f8782571c7f7627940b1cf312234149404 GIT binary patch literal 53953 zcmeEv2V4}_+V`9?voo`02C$2O0(OvIj8Umd>;e`nWPw#t1j2$!jAl-nF)@iZy%;0d zqQ)3aqDf5e#%K~Xz4zXG|DH3mL)UQgdcW`e?l1ZSc6Uxc&;P0CJX=y-QSPsei#sMD z0SiQ+f+$FWLr`Z#E%DX(%d0A9MtN&W7nH-hf~eZ6>KRd0B@2C}wfPz9`lF#J2F0RbC=R8dR5S{W zMj2=pnvLe5xu_VOj=ZP@m7+4_L-WugRE4V18K?#=K^LG^=t8s_U4$-1YtYr`8gwnX z4&99ILXV;+&;j%mdKNv0o<}dESI`^i9rO|U6n%z1M_-^X(YNR~OfbbVR*T;2b;-kH?d70WQQdaS@)2i}C5W4Eu07UWhAk753wc@fv&y zz7$`E*W!QS%kdTXN_-W*4sXB>xDnrsx8dD*5567Wf$zk7@%{J#{2+b^Ka3CJBluPP zCVmUQhsyE$_+$JD{sMoAzr{b|pYU(^cY;W75=#1zFcMB8NMF*AM3N{HP5P6;B%UOY zM3PR1lT4CDvPlk^KqitIWF{#hv&d|6I$1!<$wIP-EG5fGJvoysCuflrWFZTs5(Gc2;_NJk<4~?WzbSRCXu{4FI(hQnOvuHLQODEGQbPkr^lADGJwlJt7wC)h75XZDgT6`Mq3_c7=tuNp`Z@iAeo4QgztcbHpQ0cl z5sO5mq9{tDLzKlJv4WJ}N#YJ}y2XJ}Dj$ zpArv>Pm71d=fs!9m&I4ax5T%_kHt^KPsPu~@5JxLKP5pz5|$*%BWY4^DOBnsg-PL3 zgw$6WEX7O1rIFGoDND+h#!7k81Zko)RhlMEmu5+`rPHNlQoVGhv|Kt%S|P2J&Xx>` zN#{rxNS8>LN>@r(NjFOCrJJO!(#_H~X}h#T+9lmC-77sJJtZBMjz}*^uSl;-Z%RK) zzevAIze&GKe@K5i1P5|p2XRn`?9d!t9o-yZj&R2S$3RDdBhiuMNOq(L**DbR!)=C<>B%va)z8K=gN8VBzdx2AkUEJ%EfYtyimSezFNLU zzCm6mZ;%`0&GHs`ySzi*CEq6BA>Sz}!Q29vtSouWx zRQXc*LHSYnUHLJCiQ;x0rf%kA@yPP5%p2^G4*lv3H3?! zY4xajOnqK`Reeo;PkmqgK>bktTKz`-LH$Gh)9G}EIJ-Dwox_}Q&Uj~nGtrskOm?O? zQ=Mtf5zZ`Uw(~USIA^}Iz**>==A7>II!m1MoR!Wh=W^${&hwn>oi{l*I2)Xe&W+AZ z&dts(&aKXyowqn|ci!#1$N8}H5$7T2VdoL&E6!J)A3DEue&teKPM6E&c6nTyOLqmi zf?Xl5F0LM~a94z@ziWVNm@Cc|?@DluaGmPPaOJs9b4_#2brrjox|X@>U1z$MyUud0 zaIJKm?J``k`)$t}9*ZTsOMbyKZuAb=~ZG(Djh(Vb>$BM_rG(9(O(AdeU{k z^_1(d>v`7;t`}XeyWVhp;QG+@k?Skh*KViV<#xM0Zq2Q`gWSRH5O)`MS9ec$guB0c zfP0ub&K>VQ#XZ73+CA2t=Pq>5anE%xbJx4ibT4RITi_MG9V_nhfD$8)ad2G2Urjh^+Mn>-sl4W35NM$abCX3sXyZJxcJeVzwA z4|<;T9PqsBdC&8{=L64&o{u~qdp_}e>iNv`x#w%oPo6(Ke`*d*)`GPVt-BVkMQB5{ zBrRE+q)pbQXj8R(tw1Z(rfJi)8QM&3j#j4mv_)ElR;$%%OSGjL)6UT@&@R<3({9i< zYMZp}+QZr-+N0WI+T+?2+LPJ=?J4b`c1(Lwdr5m$drf;&drNy)dr$jN`$+p#`%L>> z`&#=(`$79r`$_v*Cpy(-UDt#3KKfvNh(1)0(PQ;tdYm4wC+LZKx;|V#MbFm@^g?}_ zK3$)o&(w?bS^8{!jy_i})=$^HdWl}Dm+95|8G4QG*K74UeTlwQU!kwkFVt7-7wH%4 zYxJx2YxL{&?fMS=7Ja9FtG-*`qwm%4)gRO!DU7PDtEf0CxCM`(3Azv>beldgKX#F? z-d_ZN1A5-HsL~3r-`^+%3Bd+7NTbk2=xR`g%Z&lWdQ^5wPFhMzTyjiqLS|x2Qf5k4 zOnPo|YD{8sMoxBIMtWvKW^%FKB`-T?dR5ILf3>&Nmt9p_x7b%%Yxmqs=qC)`D)bgY zg+4-<5H3UreGSo&42K~bilG|LtwN*_B}5DT;qgEr%5WKO!(-_1xEH*Noy%J?_v$H+@jxEy?uOO!xYymHW#}Dtyz+YZv5~SI)2S!INTrV9Rk?O%zYepX&41 zR@Hc+xT(ixduzSL`pA|=p>kGLWo=DWMTM`XI5jINAv-rMGbS@J3DzJhCnF{!H6b@9 zDJL;AEj2qOJv}kESPzE=GD>SflWtmx*3IZWn}=OhRZ-%t$+L%DtoLYsW=^T)qvgxv z(^G~RKBleFpWt;Vy_Zg7DN@YtdE0tcm$qoOUMyQNZi`+WHFL1h0P)5QyFN1hW>W#>w2=@z=tu zyfXMzKChfNtv3yFytlrpuGU|y_iXwIhERT{Z;Y?fSL3Y(Q>j=FvDh$Mnj2q%yT{y#o7Js~1KEQ!udM-iL)Wbz<-F1AK0YCC z#gW`GWAlnEMpy~NG{bu7^TR&296;mP(|}SZnFjK)@e@)fP8u+I3LxL!ZEKhyf_<;#I3#F^Z|niTB!3O=jCX-$-9jjgfpH28SN z%-Iw3v&(^5RaJUx>KkXAHaBirN*w%4P4^|nrNn`eA0+ewo;(Q5_*5YeNMj|K=GP0G zg`Hr8-zPjPd?NgSFdBkJq9QPim!tF073eB3g|9=`qZ`nTXg%718qp@S6>UR1&`z`q z?M8Q)rtyzp@`iyKyAq#`ufgl_7BExq!uQ~N!9;x!%+mw-J^VBN75|R^1cNh?q=A_^ z9!$%*WIm||)A4rl40#UB!{^CYU{MYSFev`6Y1?g~Hd;7M7`zQ&lPP2YY;uHLVT>?V$TNbB zU?arnVstgS8QqN@M$c^^(#8uDgo(l=VX`m<7BwHlT5n^fQDmHMc#TpZ`FTbx@FKuX z{(`Ed6TM5y=X*gySsyjM&8YE#oC<*+67jzyh?vH_-(3cnu|5n zG>griR_#%SSs|{aSVP5NY?D3o{oF{bKu)!E$5$Y=8!qz|)RtY05 zU7=N%`Bgv;0A#zFi-k*sZVkd3V{n6TsWF5ra$LXYu+9lV1F~-nILDJ6F%Eh_oT|BeA*0o4Uh z)Z{8ZP-|7?9DiW{@}Q1?m)=j(yL1l?j~p;0CO$DW{nU({vEwJ@Pb->zdf9?SRcF*K zJL~KtAT_muYH#g=nVDSHY~T~^R5eFI9XG56jOg@Y zeYo~hs5ug9s-s31a<1hs1mO7mM>4arJKf69TRwzVa-8iz_?dn*21hR^1!ueAE%J06JeW2V8pc5&)*Uw20FSOofw6{h7-<-^R=o zXk!K7Q(c*#QC)q+VCQtc^68l-i&*vizWB!TFKoPERiv$YM2=?5%-4;pFNz$!)cQDb z^y-1;tA;hu=_Q=fS6&M12mNLPiv;2Ci}f!ppI2+@VZA{OKUEk9I#?ZurSl*>a=EYt z!Xght@Z%Zb7z93kfKUfTGEyPX(GSI=;b;VeGIG!uG#&yOm1rqC3mFiqxD<4>E$B{k zKY9c`jt)X_;&b!^`W5|-G42W>h!~uJQz7^;3BnEYaRojDFU2eHIS^FXgm*$H;ZFPn zei{M?UqGPXH_*;pBnZL+iDU%HfIvV#1OXO-yZ>BrA-MS0f@^;d*$?jg$H^<;!vBE$ z437IC+6`Rw!)Ov6L#Kf|zKkxQi@^zh8MxhVqz&{Ix|==<&h^*m+w^_<8}hf#573E}kmpij%}C;3yC1cTM`6=hJzToEwCp^o{i zwYCaG7U-Hgip&C&YkW(}tLpr1*7S(!uR90M;Tfb3wL3l|R z30ArJ)?VmWgtvrle4$@67y2$(=xlSL(>Dum!!i#P-V@$8a$uQz8DosGT)~XCXO&R_ zc1l@2-}%bis+x(urIWpNpb(nNV~y!!;b5cil<+CcF4q_}Cm;_aqNBkaw@Q3zj=I%! zbODs`W=l6QC2eR#Dz|g(L4Pm&EDYWV%=2(&0yanlm?uCD(M`5N zD;vbLA!5O`P*+-8R|DkU??mPD{Qf$wTlPIsA#;NRBLh3x0cHjwz@$Ya8Iz4E##AF8 z%nYO;)ig5-jKcp5X2uE30DGt*s4JKbsEaYJ0d+H`|CQ;0dI?vc(7!SrW=sk~=d?B* zdh`tc`=-Mt$sODUB&XtPV;X>3WTOQ*Q%=$NDsLGe)O5?1*VbD?71Vz2(d?w|KK+G7 zSDLzehzm4e@PUGdslB1&Yi}=1Kg4b|wSuCg%d#4Kg*Nu?-J}&X_6cjD3|#nJP2y%hk?}7SSa<54q zMp*Cd->6^Y=<3ntJA1Pu5P0SrP+wzK1Bx_ebA{p zb8(QD?Kc661_;MCqJd}-8f?rl<{HHYxa(2_fZ!Z_9s~k1>wq!(YBf?RhMZPji@PVsv#?+=K z0r8ewQ?@L;^XZq$<)%dth;H@e5S5=zQy%5MGurgLvOXh0d6tPO55bBKKBkD~c#fuNys;Tyy)9f()h zD>U9$Ip1``wfM}`nsj6USis?kD$rtxPc+qNM3utGmLC*Ns`gdpRYL5*&!t>&U^T}3 z=G7KdO)a0lpw(^rcEbH(Mr(vfI{lgnc##y3#|aUs5j0umK$doE4HAs zLGNeq`&=N+mB!f&YsN~3M_5D}WUVHT$#^Zt7A&Fl*;w!Z0q$Y>L0_9=ea3eI39lS5d}^dNM>Cr~1wS*;ot2!ecIeo!A4t1pNzyGgu&(p|yr#Fyow! z=yG(0u+=!1VGn4cK#akB0W$o7z608lZc`{cG*=L;`Rsb|(wCRopID1?J=%H;c%Ijp zzUQ03``iHj=Z)Zj-i)>w=NZ=+HyK-vml*27&;W*t7`mFFjSTH!=mTTbOW>v64u0xe zV2^jATftj>8~CgDpxeP`eJ9$B_CZ{zED+bUNIam=@z@h^P4M@bUSqD_$NJ3}MQb91 zQTzF!xn{3B@R&-|(;H~1ZTX;9Pt6#YJ%YliO|7b`<(?Sp zbEvr(LUzr?VU5fknl#UDv-z2^+PJ`2V_XKKy3pFM$I#Xd#wtrOeF;6;$o0^Wv;VaI z9YqIWuur2y=rGzd%bqFBduDC#Y?AdMG%hrgFal^5r zN8n;bFQ6CEOGVs~X+^M%ON~p4_1u4J&;dPpSm1B$GVV~XuBlpR4eeF*+AJ8Dy+MuW zb>K2BKCnu?iQcl};;qQI*%EF|hK=ZLJ}Vwa?^OAt=v|oXdq7$rphG;?2iw47v#~Y4 z3ZSkfKG^?%85dbY`51iyW(#a;Bl_4}yXv}q%k;kYY~Is0I|%eS-)9oAe?0KFfu$hQDtuf889vAw(O2ke>o7wrF334i zBl?C9ksowu_pCkh_|9Y=KLYdk8U2Fx88@16ycXcN-dNWbj=$S*#MrpL2_@IH#R3*N z7K|G#s`ve;s6OCAw>F{0c4E=ox*I^RZeHM4g+aRk4Z-h&=q5z&{l0-^;AtP;a*^9D z6xR7d;Sh8O_@BDLLTxq|Y6C3P7GqPJg~C0X7AnkWY+9&>b_>x`2}rG=Y;p1CFkF)vY_e&5D%!dQkHn+!Xqe zxYfAL*kjyj>@!v!#kqKlpy9E?R(x7fGrKP|1%Yu32=<+zE^(gZZ@E?`-0%cE5rTdI zsb=_(06yX2=drZrUn}ugX zBexrO7(4AK5-2f&S$fSj_F8SUjVaiL=9z`=;)QHmG$76JB9k!hu?TbFe~d8Ot#(To zFET0fo`7D4Yw_8_;O)2$F9BcgGF*?(#LMwn;PqW;+-KZxJYYO%JY+mfCT{l}G@dh#z~7^m3Dv8aD_blx){6fDzl9xb{}5Ej z3FVbw4pf6e)!}2#;IpdWssfw@0vvT%Ca-ddbrg(yXxf#iFi-h3X-rTivRxS~XbGw> zc;Tz&&GY-fL)pHimZi8q`FK;xsHwIq51L9vSo4O ztI^g5e2wuW*O}lz9|nDQ6TShj<3Gj$<0H>_2foEPY&_G5Z$%Fn&jPm{FxOVYEQ@CrpS1~8pFhaa zC319}AH$CW zvwRXCK>HZ#2Hf%!<7ET%{qDxcZQ141_)rtO{LpyCW|!6)ALY#N7=9kVfM3Kf;g^k9 zjn|F0jCYLpjQ5+F-)o%t8LwHqt}8c_Doh2#d=-!l0S@vueg}%aVZ3SV3Nxg^hISY)hmj3ICzJU~W4)j!(tKD)vs zk`G=DGMP*vQyC%*QHI2gq<|EXX$(mWIT-574=`s2)-1o&%a5$+O&>r2tQ;bOJZxl_ zF;5g#RmR7~fyb&8+$cp=Rf{7>1;%PJCNhVw=3Itk;6l~`Z{j6oeBvdflp%#7wUPM9 zJcgVMxq#!A@`JK-N~_>x()>F6IBUby0|z z2RdlcVC;DAGHZ_F1e%@HJc8KCRW-FW-tyYWQO{Z=0ItUl*%j?HcCAQFED3YOGt;7zwf@9-KauvCnT*FXr zhQb(%VBn{>^=*i;-+)hpei-V*_1T`yV-K8v@KsoXN2dW66raj3w?Era-93)ROG?<~G48<}uta;P!vet7*K*qN_?P0I`F)rg7 zis3?@pG7&r7QJpY8Q0Mky<=@rg0)36PsSF(V1~6HcC$n$?^t`1VDpbp$&Xy5e?~qh zUyv`!SLAE*4f&RQN4_UNFqF(t3PY(3r7@Jw&~S!MVQ2(Hr!q8>p;0@?PXX!v8%Xy* zxOAsT7|0Nh@AG?0D2L1U(=7Qu{vY`s`)?a1Cr!Rn9V8M3Nsti`@U#oyfp&%SK3yre z+%p-X*`$k<4#b?u8~GZfQYB*bT|d#oWRgTh9-fCrz7boQ^ZeZ zXvRqq@up;_IeZ;+8Jf~0*=Zgf-&(TM2^2;F8b>}~tG|@ubSj;GJSk3R(3!M|&SI#5 zp+bhHF$6*Xx&JFAbd0weVv|;sVqo#`vhuQA@E77n%#=&(^|B3Gp(ab z=u*0j)-yDRp<;%-41p3>*2MYgSr(g~YjOT={H7B`iR_cS5d$;9OFk&T<|(rZpKcY_ z+7z}+U0`VdC8h?@@>uZkr3JmrYT4I;w4hg7(qjJqz#wcZ&|92U9>!-FTfu`B!`e=$ zS$xndE%5>Fkipc#&4qA z;4%l@00$5o=|;MVZl+u4R(dl-6$~wAsFI;7hCuy2gP|IR{0!A@quc2YIIg&p-b#1T z+vsi~iXqU2&t>R5hR$aQIMIa+t!C&V5LFP|)IhNY1(@qI)u4R(i?~*w>*Y5#;L4J9 zvLG+Jpo(k%<0|3oRF=1LiPvwRou9zHVu1?~;6R&PQ?;bryd2llj*r594!CO8?1BZG zqC0OagI`;y1ZP%rhqJO^Byh}wN4NMn8Mxo!D=Vm~9`9S?s|d7{4fS~NC#I&x$Hu25r=}(+rt^R108)};(^3)x|C5u_dH>1j z$+2;1$;m14N$IKa$tnD5X1o4V;8IPsVY2N=Zy=-&0C*hjU6l@toeWdOD|R`BGBS zW7AUO5`jjNQ<74X5_wNaX|bv4N%8Ti@JU=!d|aTbwA5I8rxKInQeaT9Q%SK&>GA2Q zX(@0^EDOrMcKQwdlzvCQr$5ji=}+`$`V0M)p^KpxhSo522}74MbQwcy83J1f zESM{x_xhBQn5D@v-sE{j6UXPq6wQyRTd=ffetmsRRZ+~srPGSW%&U(nm>!ccV`9;` z2@7K87sO0SuPK_A?29SPjfpSFEUKT97n5EUQ#~fJXiUknm~3CnqU404>ZR2&iH!`%oN&Je6*q0kr*E4hjx0bt@0g^VBr7i~q zXDdVb_`+0-wS?(S9SBn~(GsQ&mM|?n8KzfYxZFDKX!tD*V=>W^q7Cg=euTO5qtG2< zhM37$eyg?eo4Ee7o1xp(J$7*9xM@;@;%tg9S;vObUWXK_Zj#rTc6hv z&lHz8Z^C^H-O+jzV0AZ(=ZNQu=ZWWwpmyBJc&m3abPq%On|I<2Yq`wm<($CiS_LP> zORW-S=+e4z)zQA3U`KAS8o0Nk9ob;*$oK=dWfNi8G3{vP--4y=y8UgVCYGP4lwi-LkD+= zdo7QIc#pVWyqDY{M2Qb@kHpiqN8(wAo@eL8oxw#WH{_zSou#2>|<#Ge^@ znW0x0dKFv~;&0;brfULb@ZQODO-KZmQ=$yL4ot-gI!F#lZS9(noRW(nShP1g<(iOm z3GN$o9AJ>TN!_I$Qcs57V(4v#-eKt7|DCRhBKug`!1i7TsUO-cMM=@<4rzci5I8e- zaen_JLmvXa$G{|hXv6QNA=1!he*YaqAGPB5QUaJ?QlgY3B}*w%ssz5%j~N2J^K*v2 zWaw*#zG-6m(kYfe{e%ltu;)x(X~qg#aeisERqV6&acL>X;^|*-o_>OZGtz06)B3B< zMW&^EtJ!Zm5Ear4OH_PsiHeha(#?vLSn{IfN;G>Rq#2gT_}(URuT%kNWTX!SW z@?OJH~242R0 z1NV=#_xdvFU%>mNwG2xQ(&Y?0I>-B^tEKBq-Y;DXydTTJy`>v~_hY3!??>zH&NfIJ zO_nb;0?WtF6IAK|yE8eMO$yc}(_WNrf$IU%PKI^3?lqGW_>^`EDvyjwd!>D?BV)K1!@*oZo!LGzCfz69-^8$RPliKUGpt8p-KEE*$E7Ev zCmHU-a94)AG2Fe0O_7$7v4DO_T1LT+uX9Q-nv4YZ=zx)smJu*}&EJwf1N~2WTY5)& zS9(u+U;04$Q2I#vSo%czl;PeChceuU;V_278IEAMFT?#9j$}BB;piRG=K(~2O}a?m znwb89W4gbM>46ZD!b2@s$Nu-h`Y$kf5>S8AB2o?!@b8cq9uUC4LoxB+QA8?091h(P z4Cr?NE(SF?LKq(0IrKZaJ9?Sucl6}w9|Ax=UM$M)DZ&wHLf_GkLqDbyH3m6iK-+T+ zb_{V0Wq26FaSX?Uw&xh;h~wHGPGETW$bc|v+ ziQ(iz1`j+u_4059Fj@EC?i26$SZTgYxI_I!YX+jxvYO zF^^%`fYA(t9Lr)jo8g>hu6m!PW6k8OF~C6`i!FAU!9SbTB9w1)-M`O?9V@M-b6axa zSI|MnxsLN3=Q}PCG{-9RwBtg@YVwXa-ElFb>HfyC#&HSSZe!^$dJrcpSrki3yt=>l`=YcN{k{Jdxpi<4uMO zjo2CdiXeBX%`|Tb@>fOHv0kniSR~kVhq38Oq}|&V#}3}xR>#ebZI0~>Phxm7!&4ZZ zx(UvBZ$seOfY?f-TeQ;i(yc!~4P`_KNB4+FSGMzovy^g!!imn69r-BB!*pSD4^FiQ<^H){) zKoJ5;;4`*M-{*LMm%g9jX$_7C8J=zyhdpar4D)uO1*u1cV~vi-9FH?RgW)+%cPkwS z9EXH%8y!zM4mzG@cqYR|4A0u=xJDT0cow$C0F7w2F<=g~+8lJ7&EGX=_0-`lpX~(i ze8?bCSLTZxz49&7?6*hyqT|($I=L1)c>^||cQV%)5INd-uvN8p9Pe5Y3SF>U`q1%l z^PE3nxWtIH=Jz?D-xrQA87^gbUi19Eas1Fx*FQqnKQmm$yY?9aW;SuL$kFF)Xf=pG zWZXdmG7$#KBE$1}0}HrZ(4YzXMlHXR8#&rlgUomCA(#htjW3@BnQhO zau*p?#f1znVz`3g#SB+6T*YuT!)GvD!?2&>+8uItxrf|S?gib3%6;T8VVfKwgW6Wd z@Og}0&*+UX61t1gCmB6pe>;;A}->+u`5=CbBh&Z~lx@>8qeszR-|^?=O4 zEzcGR*X1=kRNT~H4{P4mWbN+wTmwWU50evNi{&^uUIz7I3ByYnUbazAl9Oc+)AbCm zV3_ee=2=hLEvGd(p69h#PwuDyUlh2uS=M^Yne|phvmVz6+cn&}Jnz6B@CbP%pg@L; z?q@d0AR3n&vGy&TBXX9Y$=Pxazn93bkw!vVxAeI`c&9RamdV@YG4fa|;iIon9@CUl zM?Os+&l?3+ys|-_!0_2E8igjO$W!I~nLMy6vkmsWl@5k_M-x z#bo9tCdDMBSM$@Y{_@3eXO$lWSeBMjoRVaXrBI#*Th^4W#kv@^ zQ7)9H3nL*NrS;yP_Dp#eA7K&0=QPN(89tZO_y1@N=3<>L=a`FB+~>iwVUg_KN@d9Y z*ogMgMaC6yVy01^FE3#Dd8{vM($(eMMl17RA)4j(G*4@S!Ii0ntYY%48p65^+oee>PwhbfXrzt62Zf-CgBp+K)Hq z+pRfYQLGpLM<~9UGV%_=Q=ZiTB z&X&J$=lqq6RelM41oF!an~5CY$cp?LxLD-ZI2WMg~_9SLseYO&_U? zwtV>@<$ABX^=r(-P$=o)+m48G$ z&qR=%7&$uLQakl7_8@*&1k(#6|H-{Dx1Ol6Kovz&f*Y~b7{KedQvXgcG`P*LdrJ@M}Zq^4a!i4?+y45m0^G7 zKU7kbG$3jvmErpvlyrt4=p0cirz)dOqE<$6qJ9wQkPhZV-N9jYn+|goNIry#w!y{ci>|TKi+{m@GtI}fgh#mA{rP6{BBy)2{vn43iz@VGWSDC zCZ$|is4P;zBz%_P=NLZ1@X`P8uAbQ&xl}pRQsZ2A=#1!>=;@8pE$M46X!l7`?S!SrcGCYn6YQ%;!ojFWgXn>#q=Ys>KA=2o5#&Rh zAU^?uR6u-zg#EBxb-T)w$}uh!4=7J52bHIlL&{<08Rc2!IS`6R8UBpn&l&!L;V&8f zis7#rhT(wF{>~JN-|tYK4^ZXH$}7S^ofm_@R|IF|o+?(_#h(#hWBK;#4 zA+5gYoQmaH7&=NW(RsqP*!pLjHes9W3);$8K%2_f!Z!ZH@K4}4lcP%pI)M@qBcQp416Mkpg9pUYp~tWqOYxP26|IRVaL zq)UMPs}RgPKKobatK|SMbpa#rdm$s;I|nbdQiVJF9A4D`FVcgPmY>6m^lS$&eU?pJ z%haUs{Tz9*WuJ?qWtZVss}>Q?n;b(^|f-J#y1?o@9DNZrOrBqLFbL^IN#kpYYh zWMmK{gBclOLTcy^bx#0Nd)0mLYO4^X?pN<+kk7(8;6>sYNrBfXTx_K>a_T>rI_a1? zz$x%4Mq+JD9Rf_Lht+5J4?F2cS0OPv z$JU!1TS=V8-Z8NS2O!$yGYTTtM2@z;=D`khsUN9u_^1P;P5nZJqnm)TG)B_fq3l~e z$L|;!-i)#zRS>g)?B zb9QrfclL1hboO%gc7{6pIKvd(8NtYCMlu-5WCVm*HX}KVQ+F>ud;~CD`9fHg`*9kX10c3@YOlu1=XDOdy86(r1K<1q9T-X|9 z&PC1&MrJTFvvVM;cGmqpke%f`+XC524zgJ%S_6C5=Q|<6@($+(&Q;C}ovWP}IWKmu zabDuQ6hO9?5zsp3GE&UQ>5O<8DPfQ$h`?-pCdlUPa9$n&+10jo=)A$Xju8mrTOccM z)(#gl;{OL?CmmwjI00^FWPuH_odB`+8M5sCzQehf!|P5)7B)EdF|w$W@Y?UZA4to2 zFE|HCg_$5r{>JzN0M-s&c2AEwpX?YVbbIb0Bb zHf%VZYifp!T*zhCYDO;m2T&&)P_C{(fv#?hKsEx?#o^)?h2=L~z4;H1Op$Y}-=G>6 z1c=?$*9GTt8(eTu;JgMGX#eMT4py##t|35Su0b4D7XYkWL&4`p;0R%RTm`9%^gecf ziLTTR!R1PK4L8Ac5hEA31($0ipBkKGSknY9SEehcHMm^4F3_SbVdTmr|VYNF4t|Y-L5^Z+Znl;5$F^o^A1J;-8&h%m62VHfQMlBcGsN&g1j3P zCkW@d?&Acx$0o?Vpf>SfF5v;*f5@?_=A;HxTn9NhKF!GOHaUXUu}Lg&JqJHWA>{xg zaHku7-w7<R%zBabrj7$b0k`EEv@*x~xqqDeP_D4%)Az%9EKMxL~(5(2Xy!E2K+VIt4} zw^8PQ`jo+6A0BY?V1v6mBL@PM>Fx!TdE8K+yRVz89d1xN4mP+!?RdI#6zLx5=4uDN z#XXo)2AxN$GHB zxU-@A7V#5zjvEaAqm00v_fEu5+^4z0*#8^x6ZbUtOcPY@85~qEoM__qtc%^CbnI}S z?)JJ%+@R`R(cPeSfFT0>;1x!IAH2rM>x{g?$eWD7F(v@j+dJF=&BI;o zK0_Gj_6t$&Iycw>@7SRFfRRtR8|pL8?muVb+ka4XvQ>IFk2ko_W8_^MRs2e?`$G3> z{=>+7jJ$9C27W(9x3iGC*Sas~=mOp2!v;4fmmhT!UDvp;x6pMRN7u)k$l&B5Co(f>6g z-*gUW``r)zJ)k||e#!#c0S>h9PP7L0te1NVoF3IU)|0$(!$ zhXJ^jPi00u|KRMTPV!*hsuWH6nn1g5jc38pi30MOc_Olq`y3-WaB5L%w@9!NJU zF{&`CwuP1_6ei~B!>F?fTAm0GzlqyIhIyhq(Tutnb$1F{oDYUnZsXo?Mw=milKKaK^Imvd42Lk;K z9xtPz0X%ui08j0|yv5$-MV`eRNfnHSHFzo+H6!PpKvInd;tik;dTK#l(Fh&p0xoAywb9iJ#fd7QJy1#r}Cz80ZW-C{X>B#|LCCyP8v3N zwlWIo=uKy+XZwll5zlVV?VJMlFdEH=NZqlp65JAJVzDX^E{)ejHWS~&ggIkDZA+i zMo(pQB!hI_pkUC^J3KE22=P^Mzc7$M4mZzRp0^pzut_lsa=3wpVWx1SV;G(A-^LOD z-`mHYFE~AZ$!MlckKX`2cAT2cCX}B&zjB)Vh0*K=&u@(8bdDx9K_ezjYM9exE)bZ= z&%$<;mo3nhrfBXCl?zSNbW^ziaSK<_TOTmgy1<+?ki4fgDHmD~tvB@DLb=dFHBdjs zF*?3e%7xZf>;Jcu3oS;AGhw9-} zI=4Y9XSBGJz*?+TTfnN~z&agBOsg^VS8qFgBgpZ99%}cuOzZfpp|(;p&l=J)Mt$wj z#ch8LF7(f9M%OB>%~?b3Vr>nhFcCBFz+WEU)z)f%@2sJ=PP5J$YW%Drg&WYvpSnHk z%^LUu8t6j!mVpNCW=1QT?n-Mrw7sBHX}4%QwOh4a+HKlyZI5<4!0t{)7c&YPU=^d) zjGn=04WoWWYfa46ZP)ez%I?|91+vEWYj1&m(E=xRnU zVstHsT-!|aaOJ0Mp7;O#$>~icMtd5v;b@1n!`d_2v)Xgo5k{9XTF>ZmMprO;Hlxj% z=(Xp~MB;RrnMmBqIiDPx9-owym&)Zyl>mvpkK0##NBQkf(AVo$UuU)G>!jz>4=M@ITL*-!{R#_J#K4zn@@UsykW4-$Aq_}0At^aMJ;9`D_$Im7#DtUtD`$RkT3Y-Hn<@RGL7=IF1F5>8BU912 zn9((DS+UMDtLflkxul5|>kyf0t?1}(-NPstg_m_o(b0qT?*E>mV{!mJ407b_;o5h4 zU%j6msYmJ2dVhU@4wmJ=V4)bjoY5;7y^_(Z7`>X&YZ$$j(d+)NGSmkI_OuoF}j=4J&fMINnfN_=!5p(Y2U->{*C&%`g!^yM(<_xKA0q*8^5F7dTy=yo?KH7-xbO86%9FY!AwZCm+z~F zL~!PJ=nOh>X{!%2TUq32D^4R!iLfDei4Lb{+YO!+=vU}hntbp9Mjtd{ONEGNEJPd; zk_An_R!E%`M4ct@omBqXxVU2o6Dmp$bw(6?Lp9%$nNi-F(go%4t{|$ms(MCLRmnmi za(}RZF4$n^_JPDjkoPH2=s8&_sHv)|HP9}-r_&YECA80=!EwV+84-DEM&4=T#!twf zK4W%qVN_*ZMa5CKN7I9XoALlni!#69bN0mij9N%SR8m*#^BdUcVUU^mb)}^~UzxA$ zXxDC@?mc_+>_>}y^?v?MJb?i<^e|{cFGDm!Ap21+WW;(QEIgubKTl*-bpHVZ;j{em zGkwt4yxa=!d_Q#3oVg8J8SC{=FE6WI0OdGOiyYnGTHc@wb;BVWlF=RLITmsaR`~Mk z{k6Wug?YS>O!yAyqn;r{V`7Ivx;(4j=60J%w^!RIEhgA4*g(*}%x4y#+YU*M$6{9_1kh?V!6(sF8FJE1%+D&|1IhJyIpfKP<;zR?_nQG=8z)bNEtzDJ6x1jvoZFNuiYExG z-&inhD(toS8i>uBD_?YTDo|r)5wPmEtJ^qhY6qV}={a))w9zC*lP$!%voG+{qt`lw$ZWL~U6B4%xcL|RO zj|oo*2ZV#dA>o+tw(ybgweSa0kdAtyP!xv3QC}2^MxZP-2c3z|0#)T)bP>7~twook zE77&+dbAF$M;p*y^fLMm{fvG^zoS2~gca<>Zmi>A+y!^TNq8cjjHlx1xCAf4%ixRe z&%>+nweXedoA6$|A0Nig;rH;z_$&M^{)xDWZqYSH0rpWE_#5~`q7BXFCpYMg!r(2y z3~$ue>rCIEgSZBk_%Nf709R!2omup;EzSY>9euOD1(L77!|$-X$>`&ZJ^@MC-{gF< z--#I-r<=bl1R0i~(0~)S#0%xu)^qXl7bOcIYnoZo%%!I9veJX)PCsxS-0?mOGBOra zm3iwUytVK>OT!bAA~Ggeg5!2j7=<8UNcPQJeV=|eSi}6Y1|0;&Q-NfK`hAeY+ANuA z)qF@ewgJ*v^Y25_9|c{H+>aB`FOW{GMy{4C<$AIjAAsCp#(rZRPad|0=MTddLbfo- z5@vjCtOCO8DfAPD3h}~lVH6PEG-0+dSNToFs-|{V`>BJ}ST#;fP*dSz?FhJ1>r>BC zSF6{m*Q@K)_38$-QQZXh1MgJ#sdvNezWdY%)Q8kZ)W_6g>hI2h&T_bBvDNvo^L6JN z&JUem2DyW@pdLYyK|_Ov2W13}4Vn@(H|UHYe^6b}(xCdF z;t+qxnvks_cZA#-vNzDLcH1zS%qoHqvz7_gT=zF0bgnktIZRq!*KZgDs`fKR#p?~)2-sjXlXY{$e z&mDd4>+@irhx%!KDZ3t@&+Z47ZY=79jVfTj}3_BF|Uf9=RKZX4g z_FLE=;bOQWTnTrEyTg;ii^5liUmSjA_|@UphF>4PE_`$N*6?lNJHmH{?+SlB{FU%; zBRmmR!7!E)hY-0qH%O|bW-%#=)&mo=(D0%MjO$qqpym-K6*>^?&#a2pNxJk z`dIV}(Jw{6AN@`AchNsY{}la8^l#CB^mq1m|DUSP`zsB@jn|1WJ57^jebdaQiF*Qy z2!c2fQ9uF+4p1Q~2r7brASeg{5flP~C;P0ZRgw1}qDR3`h+i1keKH0gVBM084;1pd+9&peLX&z#A|a zFdQ%za5dmb!0W*2finYV2Ywg$ec=4Sg@H=~e+*m^xH|CX!2jNXz>GjLa&D*!Z2akVYslIu!=B4*htv6upMDL!*+-5 z4ci}fFzj&Hjj&r`cf#(4JqUXg_BiZS*vGKXVPC^1g;#`&!zJPM;qq`(_-OdG@ay3> z!*7S*4Zk1$F#PxMC*fZsCPnx~_(x2Om=Q560v3@PkrS~#f)tS(L5;|dD2$*-a3Vwz zvWSKVMMP7CEy5i!7I7ltal~H{;}P#7{*CmD{62DiyZI;1@DS(+oC=%{oC%x_{0=w|_yceu zFdP{9U%L?qi~)jy5MUAz3&aBnKq8O~qyY1P1wa}kc0X0Ai&H5-1<0j95t>aZbMvoTt!@ETy>lAR+4^0*DAw z2a!VLkVZ%oWFtfi>4Ee^1|UO_&5*4SA7n4&DC7j>G~^uQ0^}0pF605^cgU0Y$?;R- z=fy9GUlhM2eocI2d~`f8J|;dXJ~ci)J|i95GV`^hmxUGXaST4ErOOnnNTiN2(5$GLmQw#&=!+pxQ^2e3!5C$Oim=dhQs*RZz<-z9`4;1YNV?Fk1G zZYO+$uY{+=8E_7~3SI*jz-91_@MgFk-Ui3x5Z4g55O)y|5RVXF6K5wbOk9%qW8#X$)rrB0VTqB6 zfW(+YaAI0wb)qBjXyUoVPsruSRme5Sb;uxO2r?WQg#;ooNGvi3xgJSE<|3)c5+oN{ zjpQSR$U0;_QjTmvwjzzlO~}p2y~qQ|L&!1Y736*7Bjgk0Q{;Hkq$Iy2|DYUX1sVh@|N?n^ON!6t4QVpqpq>iUfq<%=lr4^*n(@N6z zrJYJUoAyiky7Y*2XgVxCAsvyvA-yu4mo7*brYq8Q>ATa%(yyi8NWYzaFa2TqNDzV#_Wu_8S^t1WQ1gdWk51u8Ssq6jI0c720nw3 zLC+}3U}ltNRAxvs4d{Nf7d?vJjoypik3NFFfWCyjg8mi#5d9ea z2l^TME&5C5q)fj||4e2kFO#2Hn<>t0%NX2(tvU4gH~oRyZ9 zk%h^^W^KqS&thkBvMRH9S%NH4mL#h_t07B~)s*GV8q0c|JuN#V8<$;~y(xQp_U-KV z*vVLb>~!o*><`#w*p=9yuxqh_*kEiZHXIv|O~58%ld)-76qbqQVTD*RR*G%JDzR#; z25ZIIvAtLyb|-c>b|3aI_6YVk_9XTi_7V0u_9gZW_HXP5>}TvZoFC2~w*VJ_OUL1G z1RM#Mi(}$gI1a7~C%}nt5?np51Lwhw;I`v-;`ZS7ecoW`&x8m)12fiEMgYU=h4__O%)_zU>!_{aFC_!szB__z3R`~?1e z&eWV4IkR%+xpurg4jgdL~JMa5(kJw#4W__#8KjI z;$Gru;%(v+;#1;V;y7`F_?|SGw4Ahxw1$*SN+Y32nWStIjzl1lNV%kH5}za_iAfSt zJxNZ|kc=cV$x5=59Heg2X3_|08)*k=jC722f^>@XE9p1V4bm;rQ_>64OVVr71bGU1 z8hHkJ7I_Idf*ef-k-_A6asoM#oJ>w5XOJ;uEO`UDoXjS3$dzOsnNJpy#bgOtMs6T0 z$lc^a6X`m=5Mv9ZtOX;T!P_|G;DBCHclw*`jlZ0~iJ=8(!cIr;* z9_oJTA?g_QBK2clKwf6v`n-ZXL0(;+DX%Z@VBT2XvAh#`r}EC^oy+?*?_u8Kyr+3D z@?Pb=%^S~qm+zN9HGg{k%>2dqOY@iIugDM1kIjeVL-P~z(fL{V*nE6`VLm;-IG>SU zozKs&%@^f2jV z!m>hD;XvV$!V86$3x6%VUU;+ccHx`C&xPM;ezd8y8MIlnm9#)w7%h?ppn+&e8j6-l z%ckLJxwJf50gX;8rd84EX>GI)nuoT9=A-SP?V=r|jnR(MPS8%#F46AN?$Pek9@2iN zy`_!QCTJgMpJ`v|)9G{Q-_w7fFQorO52A&&A(L{7U>w=9DZdSy2*D5?lf(ft0{YGE1^c@FnX@$R(7L zq7qgKzeHHFv*b|8rIPC<4@zE@ye%0onJD>C@`(XqBr!4>*^E2}ol*QB!(}lzj4B3? zA!m3PgN)6L5ym#gC}THcAL9VyFyjd0IO7!K4C6fG0^>5{SH^Y5SLS4B7V|si zJmv!CV&+oja^@=L8s<7?5Hpk+!Hi~tn6b=cW-2qCiDvF$o?xD0o?)Kf0NIeX0kr|W zA#1~q4PzUQZaBW-R4J$wS(;p$T8b(iDBW4QyL4~qfwG{om@;q~qzqQ(EE_HxD?3(p zvg}OR`Lc^;SIVxH-6*?VcCT!_Y@+Oa*~hZaW#7vE%BPl3FP~LDr+jXCXgRu^Ti#Ya zT7IkiD{BP{#-gzPHGlCtD11xv-!u$oydECZ{JWny)+dRYCe0oE{U3+pWF zI_nPW9_u0N57u+mOV(@F7xpyvboNa49QGpi682hlFguhT!3MHp*$_6Ajb@YCTy`~^ z&la-l*!AoNwvw%8YuPRAR@d=8CM%wcj$Ied~Mg`34CaVgwV^j zYq=7xjN8ana6mD?+KSMIAkSb4beLgnqsx0U0S6O|t-KUaRM@~fI!HKS^F)!eF|s{*Qm zszR#5sv@fZRiLWaDo7QyDxr#6C9ZN*9j^MldS-QaHKv+ft*JIvo2#wW9o0S6!_`}= zN2<3~@2K8ceYE;S_37$!)fcKSRllnKSpALX$MfgS#mW%F=68n1$<8&Wcw@YyyyLu6ytBOXyoHF-7in*N%jHGlA@^4IeJ>#p;G{1`r*pUy|~F?=i^&nNJS{9-^fc6mSLA0=_^fs1qm!YJpbJB4`yD1x`V) zpkFW`*dp)=b_jL~jtedeo(cXGycYZ=_($-s;G^J6?WEc%wbN>6)~>GoxprM`U~O=1 zSZzdYR4t$uR12<+uZ7i8YDKkOwTEgS31j3`b76~RTRB9tgo zlr6%ED57E!Q&c8miG(7lNG?){Hj0`>dQq!rShPoUM08wqN_1BAi|9AeP0=0EebFP) zW6@ut3DJAeC-Efl6!A3i4Dk~2S}{}%7bC?f;&d@uoF&GI31X6%BF-1rh-<|nah+Hy zmWvhQCb3$q5$nVTahrIH_`LXS-4AuKb@_GTI!E1sy4!V+>z>xVsC!xWuI{U3vcz99 zT{25DM>1D3PqIR?TJp0bKoTqom7pX<300CWp-C8$QVB~^A(2RAl8q9xq*LOQxFvm( zVaZm>Hp!@Dm*lYIwB(%Rg5;9quH=#AiR78&mE^5tT=GsjU%FBnC=HQ@OQWPfDNKrx zCP`DJC@ES>mgY+frA5*W(sF5qlq;>5HcQ>oKB-qaB;6wQNq0zhN%u+*NDoVoN^eT< zNbgA>NFPa`NS{exNMA|cNdK0;lm1)3upU@Xt{2xk>W|ewkon7gmL5EiH2F;VJoy6oV);_}GWlA0xI9V@l*h=EJWHMRC%pjDQ}Ut%1v^M z+$ML+`{Z8vkbH}LM1DYiM1D+uQhrW;L4H|&RsKl+=08<7^FJ&0{eOOH(SK@iS;NYP zpBmOS1UA4MkPXQVsSW83=mtzfb_1>B!Z!(<%uRcmt~X6I zeN*|VrmCi^=BbvdmaA5&)~MF00#(7PSQSJCQz2AIsuWd`imR$o)v83QdR2o;sZy!T zDyynP`BXbpyHp2NW2$4Sld99I%c@(dyQ&AON2)ife^mdfKB~T{{nS&{)73w# zqtp;JOpQ<{sZ-V2YP@>AnyjX(^VQ{QuDVKHqZX+pYMHu0-Ky?VZ&Qz|cdPfQ530x1 z$J8g)XVmA_7uAo|Pu0)Wf2v=p->S#e6YBTsPwFq~ZyT3ygl?p5Y~0wt@!ZBYnz@>A z4O&CckTeuco`#{}XsR?kjX)#Rh&57;R@0(s)tEFEja4(MIifkKIjuRTxum(O`Au^} z^HlRf^Gfqk^G!Qh>#v=uoumC;J72q68?H^#rfN~zOl`InuU)StYpL1-EnO?ninMiF zsaB?K)GDbZl&%g-CA9sE?AeQBj|E! zsdMUFx)I$0-BsOhx|_N?y8F6Ex+l74x<7TVb${vpX_?(Jw`E?-4=oE@mbCoXvb<$w z%j%Y&TLM~wT2fmWEt;00mJ2Qa=;!NW^y~FCdZ}KnSLmDcdVRazrnl?6^iI7?zeVrU z@6hkk@73?u-_SqNztF$bztR7r|5yJ}|Jg9xFxRlmu*R^?5M&5701PpPI0Mv>U`R7y z4LJs)foxzH$_*8UN(0{@G}IZS2AiSZu+^~5FlyLs*k?FqIB7UzIB&RUxNNv*_}%ct z@XYYa@YXPHc-QLRI=?ljHMBLNHM$kl3T};WO=wMQO>RwV&1j{!mb5ZkOIyoZD_SdC zt6TZ4wXNb-X{)TYvvptVy|zhhYunImrER*lp|&$^SK6+%-Dtbj_IumQwl{5mx4mn7 z-}bTXbK6(rY~x(xeB(mn65~>1tTEY$GNO%H#vCKjm}{gO%Z(LAfl+8|GU|*5qtR$K zb{d^Vx3SOYF^(Ab821|w8OMyj7_S(w8E+Wx8Xp*cH$E{5S>T z>4NE!>5A!^>ALBr>5l21>7nVd>5olQHm%u|wyA7W%ckv{E^Zn(|6q6WByHiA`o}v^Ci_+L~?MwjNub&0`y|4coTZMr_+`qqbeP zJ+^DMe>(ox5#LeR(bO@}ajN4F`xN^e`}g)A>;d*5dx$;E9$}BNC)gA1$@VmR zhCS0>W*6A&>{7ej-elisZ??DCJM9DZE%p)ncKdGoKKnuYVfzL9ZTsK$clP)8Pxh~! zlRN!8r+3ck{H}9e=Yr0V&hXC2&gf2HXKW{=6WR&yOzceVOzT8-GCP|(2RhGozV2Gs z72QSb;&*N8>gww5>gnq1+S0YFYj4+quESkNyN-8V?)tUsde^P4yIuFYK09VQ<~rs% z7C8RrSms#iSnY^(z#PerG)IO5;~+Rl4vHh+QRpajR5@xKwGNR(Pa!{+F8 zI2?N&Cmk0ZR~*+IHypPej~!1PFC4ENZykR-zB&D!)0{J%bDi^@3!RId>zn{*h7;q& zI&+*vXRb5PS?DZsGMuGOmb1~>Q3!u zcWb&gcc1Hi(LLTh(fy(Olgr=rook+JforjAscV^Qg)77r?uv2&U9qk>7tvMhDs`2+ zDqPhrzDwv5yEHDHOYgF~+^#;C*EQtY<{EYFcI|T=aGh{na9wu&>iW&~yX%?jPuFYL zxNE}o!S%_##J$!X?v8Q;-LY0S>z+LQSxJ%s??n*b$&37x^ZSGC( zc6W!n%k6XzyT{ze+$Y^<+~?gF-B;Y#+&A2}-S^z%?g{sM_b2z)p2|Be3N`(Jwg=UL|o^F(?8o){0zgYYDIQa$M&oQLAc_s~2=9H){V_JIQfmj|8? zd>Z_2Fnf?V$R6Yk)(=^7C>>eB#93I>{xNUHBaM$3)!52eQhvJ6dLuo^( zA^cG8P~K4CP|;AyP}PudsBWl!s9|X1Q1g&}sBOqJw14RN@S@?B!>fnGhe5;O;rQW% z;gsR@Vf1j;Fm{+UOdH{jRE^Y+G>_;<+D0~ww2yR*bd3y-Y#!Mp(ee`|tefxit8o&R0=Uw{$CpFt9{~xe)H>dyr literal 0 HcmV?d00001 diff --git a/Example/Example.xcodeproj/xcuserdata/ghulamabbas.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Example/Example.xcodeproj/xcuserdata/ghulamabbas.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..662ccd2 --- /dev/null +++ b/Example/Example.xcodeproj/xcuserdata/ghulamabbas.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,6 @@ + + + diff --git a/Example/Example/Storyboards/Base.lproj/Main.storyboard b/Example/Example/Storyboards/Base.lproj/Main.storyboard index 6971817..47935a2 100644 --- a/Example/Example/Storyboards/Base.lproj/Main.storyboard +++ b/Example/Example/Storyboards/Base.lproj/Main.storyboard @@ -3,7 +3,7 @@ - + @@ -129,12 +129,27 @@ + + @@ -145,6 +160,7 @@ + @@ -153,6 +169,7 @@ + @@ -652,6 +669,21 @@ + + + + + + + + + + + + + + + diff --git a/Example/Example/ViewModles/FilesViewModel.swift b/Example/Example/ViewModles/FilesViewModel.swift new file mode 100644 index 0000000..498cdc3 --- /dev/null +++ b/Example/Example/ViewModles/FilesViewModel.swift @@ -0,0 +1,34 @@ +// +// FilesViewModel.swift +// Example +// +// Created by Ghulam Abbas on 11/07/2023. +// + +import Foundation +import ChatGPTAPIManager + + +class FilesViewModel { + + var model: FielsModel? + + func getFilesList(completion: @escaping (Result)-> Void) { + EZLoadingActivity.show("Loading...", disableUI: true) + ChatGPTAPIManager.shared.getFilesList() { [weak self] result in + + switch result { + case .success(let model): + // Handle the models list + EZLoadingActivity.hide(true, animated: true) + self?.model = model + completion(.success(true)) + case .failure(let error): + // Handle the error + print("Error: \(error)") + EZLoadingActivity.hide(false, animated: true) + completion(.failure(error)) + } + } + } +} diff --git a/Example/Example/ViewModles/ModelsListViewModel.swift b/Example/Example/ViewModles/ModelsListViewModel.swift index 6e6d1d7..a3733ea 100644 --- a/Example/Example/ViewModles/ModelsListViewModel.swift +++ b/Example/Example/ViewModles/ModelsListViewModel.swift @@ -45,7 +45,7 @@ class ModelsListViewModel: ModelsListProtocol { case .success(let models): // Handle the models list EZLoadingActivity.hide(true, animated: true) - self?.modelsArray = models.data + self?.modelsArray = models.data ?? [] completion(.success(true)) case .failure(let error): // Handle the error diff --git a/Example/Example/Views/Files/FilesVC.swift b/Example/Example/Views/Files/FilesVC.swift new file mode 100644 index 0000000..e617601 --- /dev/null +++ b/Example/Example/Views/Files/FilesVC.swift @@ -0,0 +1,41 @@ +// +// filesVC.swift +// Example +// +// Created by Ghulam Abbas on 11/07/2023. +// + +import UIKit + +class FilesVC: UIViewController { + let vm = FilesViewModel() + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + self.getFiles() + } + + func getFiles() { + vm.getFilesList(completion: { [weak self] result in + + switch result { + case.success: + print(self?.vm.model?.data.count ?? 0) + case.failure(let error): + print(error.localizedDescription) + } + + }) + } + /* + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + // Get the new view controller using segue.destination. + // Pass the selected object to the new view controller. + } + */ + +} diff --git a/Example/Example/Views/ViewController.swift b/Example/Example/Views/ViewController.swift index 505a5dc..da98fe6 100644 --- a/Example/Example/Views/ViewController.swift +++ b/Example/Example/Views/ViewController.swift @@ -53,5 +53,9 @@ class ViewController: UIViewController { let vc = self.storyboard?.instantiateViewController(withIdentifier: "ModerationVC") as! ModerationVC self.navigationController?.pushViewController(vc, animated: true) } + @IBAction func filesDidTab(_ sender: UIButton) { + let vc = self.storyboard?.instantiateViewController(withIdentifier: "FilesVC") as! FilesVC + self.navigationController?.pushViewController(vc, animated: true) + } } diff --git a/Sources/ChatGPTAPIManager/ChatGPTAPIEndpoints.swift b/Sources/ChatGPTAPIManager/ChatGPTAPIEndpoints.swift index 44288f5..1568411 100644 --- a/Sources/ChatGPTAPIManager/ChatGPTAPIEndpoints.swift +++ b/Sources/ChatGPTAPIManager/ChatGPTAPIEndpoints.swift @@ -37,6 +37,7 @@ enum ChatGPTAPIEndpoint { case retrievedModel(String) case moderations case embeddings + case files } extension ChatGPTAPIEndpoint { @@ -46,7 +47,7 @@ extension ChatGPTAPIEndpoint { case .completion, .chat, .generateImage, .imageEdits, .imageVariations, .translations, .transcriptions, .moderations, .textEdit, .embeddings: return "POST" - case .modelsList, .retrievedModel: + case .modelsList, .retrievedModel, .files: return "GET" } } @@ -77,6 +78,8 @@ extension ChatGPTAPIEndpoint { return URL(string: ChatGPTAPIEndpoint.baseURL + "/moderations")! case .embeddings: return URL(string: ChatGPTAPIEndpoint.baseURL + "/embeddings")! + case.files: + return URL(string: ChatGPTAPIEndpoint.baseURL + "/files")! } } } diff --git a/Sources/ChatGPTAPIManager/ChatGPTAPIManager.swift b/Sources/ChatGPTAPIManager/ChatGPTAPIManager.swift index 68806d6..3a642f3 100644 --- a/Sources/ChatGPTAPIManager/ChatGPTAPIManager.swift +++ b/Sources/ChatGPTAPIManager/ChatGPTAPIManager.swift @@ -140,7 +140,7 @@ final public class ChatGPTAPIManager { public func audioTranslationRequest(fileUrl: URL, prompt: String? = nil, temperature: Double? = nil, model: AudioGPTModels = .whisper1, completion: @escaping (Result) -> Void) { self.audioTranslation(fileUrl: fileUrl,prompt: prompt, temperature: temperature, model: model, endPoint: .translations, completion: completion) } - + /// Endpoint for generating edits. /// /// - Parameters: @@ -154,7 +154,7 @@ final public class ChatGPTAPIManager { public func createEditsRequest(model: EditGPTModels = .textDavinciEdit001, input: String? = nil, instruction: String, n: Int = 1, temperature: Double = 1.0, topP: Double = 1.0, completion: @escaping (Result<[String],Error>) -> Void) { self.textEditsRequest(endPoint: .textEdit, model: model, input: input, instruction: instruction, n: n, temperature: temperature, topP: topP, completion: completion) } - + /// Requests text moderations based on the provided parameters. /// /// - Parameters: @@ -174,47 +174,89 @@ final public class ChatGPTAPIManager { public func createEmbeddingsRequest(input: String, user: String? = nil, model: EmbeddingGPTModels = .textEmbeddingAda002, completion: @escaping (Result) -> Void) { self.embeddingsRequest(input: input, model: model, endPoint: .embeddings, completion: completion) } - + + + /// Retrieves a list of files from the OpenAI API. + /// + /// - Parameter completion: A closure to be called when the API call is complete. It provides a `Result` object that represents either the retrieved data or an error. + public func getFilesList(completion: @escaping (Result) -> Void) { + self.getFiles(endPoint: .files, completion: completion) + } + + // MARK: - Private Functions - + private func getFiles(endPoint: ChatGPTAPIEndpoint, completion: @escaping (Result) -> Void) { + + let requestBuilder = GetRequestBuilder() + guard let request = requestBuilder.buildRequest(params: nil, endPoint: endPoint, apiKey: apiKey) else { + completion(.failure(NetworkError.invalidURL)) + return + } + self.performDataTask(with: request) { result in + + switch result { + case.success(let data): + + let parser = FilesParser() + parser.parseResponse(data: data, completion: { result in + + switch result { + case.success(let files): + + completion(.success(files)) + + case.failure(let error): + completion(.failure(error)) + } + }) + + + case.failure(let error): + completion(.failure(error)) + } + + } + } + private func textEditsRequest(endPoint: ChatGPTAPIEndpoint, model: EditGPTModels, input: String?, instruction: String, n: Int, temperature: Double, topP: Double, completion: @escaping (Result<[String],Error>) -> Void) { - var parameters: [String: Any] = [ - "instruction":instruction, - "model": model.rawValue, - "n":n, - "temperature":temperature, - "top_p":topP - ] + var parameters: [String: Any] = [ + "instruction":instruction, + "model": model.rawValue, + "n":n, + "temperature":temperature, + "top_p":topP + ] if let input = input { parameters["input"] = input } - let requestBuilder = DefaultRequestBuilder() - guard let request = requestBuilder.buildRequest(params: parameters, endPoint: endPoint, apiKey: apiKey) else { - completion(.failure(NetworkError.invalidURL)) - return - } - - self.performDataTask(with: request) { result in - - switch result { - case.success(let data): - let parser = TextCompletionResponseParser() - parser.parseResponse(data: data, completion: { result in - - switch result { - case.success(let succesString): - - completion(.success(succesString)) - - case.failure(let error): - completion(.failure(error)) - } - }) - case.failure(let error): - completion(.failure(error)) - } - } + let requestBuilder = DefaultRequestBuilder() + guard let request = requestBuilder.buildRequest(params: parameters, endPoint: endPoint, apiKey: apiKey) else { + completion(.failure(NetworkError.invalidURL)) + return + } + + self.performDataTask(with: request) { result in + + switch result { + case.success(let data): + let parser = TextCompletionResponseParser() + parser.parseResponse(data: data, completion: { result in + + switch result { + case.success(let succesString): + + completion(.success(succesString)) + + case.failure(let error): + completion(.failure(error)) + } + }) + case.failure(let error): + completion(.failure(error)) + } + } } private func retrieveSingleModel(endPoint: ChatGPTAPIEndpoint, completion: @escaping (Result) -> Void) { let requestBuilder = GetRequestBuilder() @@ -617,43 +659,43 @@ final public class ChatGPTAPIManager { } } - private func embeddingsRequest(input: String, user: String? = nil, model: EmbeddingGPTModels, endPoint: ChatGPTAPIEndpoint, completion: @escaping (Result) -> Void) { - - var parameters: [String: Any] = [ - "input": input, - "model": model.rawValue - ] - if let user = user { - parameters["user"] = user - } - let requestBuilder = DefaultRequestBuilder() - guard let request = requestBuilder.buildRequest(params: parameters, endPoint: endPoint, apiKey: apiKey) else { - completion(.failure(NetworkError.invalidURL)) - return - } - - self.performDataTask(with: request) { result in - - switch result { - case.success(let data): - - do { - // Parse the JSON response into an array of type T - let models = try JSONDecoder().decode(EmbeddingModel.self, from: data) - completion(.success(models)) - } catch { - // Error occurred during decoding, return failure in completion handler - completion(.failure(error)) - } - - case.failure(let error): - completion(.failure(error)) - } - - } + private func embeddingsRequest(input: String, user: String? = nil, model: EmbeddingGPTModels, endPoint: ChatGPTAPIEndpoint, completion: @escaping (Result) -> Void) { + + var parameters: [String: Any] = [ + "input": input, + "model": model.rawValue + ] + if let user = user { + parameters["user"] = user + } + let requestBuilder = DefaultRequestBuilder() + guard let request = requestBuilder.buildRequest(params: parameters, endPoint: endPoint, apiKey: apiKey) else { + completion(.failure(NetworkError.invalidURL)) + return + } + + self.performDataTask(with: request) { result in + + switch result { + case.success(let data): + + do { + // Parse the JSON response into an array of type T + let models = try JSONDecoder().decode(EmbeddingModel.self, from: data) + completion(.success(models)) + } catch { + // Error occurred during decoding, return failure in completion handler + completion(.failure(error)) + } + + case.failure(let error): + completion(.failure(error)) + } + + } } private func moderations(input: String, model: ModerationGPTModels, endPoint: ChatGPTAPIEndpoint, completion: @escaping (Result) -> Void) { - + let parameters: [String: Any] = [ "input": input, "model": model.rawValue diff --git a/Sources/ChatGPTAPIManager/DataParser/FilesParser.swift b/Sources/ChatGPTAPIManager/DataParser/FilesParser.swift new file mode 100644 index 0000000..06eb92c --- /dev/null +++ b/Sources/ChatGPTAPIManager/DataParser/FilesParser.swift @@ -0,0 +1,49 @@ +// +// File.swift +// +// +// Created by Ghulam Abbas on 12/07/2023. +// + +import Foundation + +class FilesParser { + + /// Parse the response data for generating an image. + /// - Parameter data: The response data from the API. + /// - Returns: The parsed image URL. + /// - Throws: An error if the response cannot be parsed. + func parseResponse(data: Data,completion: @escaping(Result)->Void) { + do { + + let responseJSON = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] + debugPrint(responseJSON ?? []) + if let transcription = responseJSON?["data"] as? [[String:Any]] { + //debugPrint(transcription) + //completion(.success(transcription)) + do { + // Parse the JSON response into an array of type T + let models = try JSONDecoder().decode(FielsModel.self, from: data) + completion(.success(models)) + } catch { + // Error occurred during decoding, return failure in completion handler + completion(.failure(error)) + } + + } else { + if let error = responseJSON?["error"] as? [String:Any],let message = error["message"] as? String { + let error = NSError(domain: message, code: 401, userInfo: [ NSLocalizedDescriptionKey: message]) + + completion(.failure(error)) + return + } else { + completion(.failure(NetworkError.invalidResponse)) + return + } + } + + } catch (let error) { + completion(.failure(error)) + } + } +} diff --git a/Sources/ChatGPTAPIManager/Models/FilesModel.swift b/Sources/ChatGPTAPIManager/Models/FilesModel.swift new file mode 100644 index 0000000..d0b50ba --- /dev/null +++ b/Sources/ChatGPTAPIManager/Models/FilesModel.swift @@ -0,0 +1,22 @@ +// +// File.swift +// +// +// Created by Ghulam Abbas on 11/07/2023. +// + +import Foundation + +public struct FielsModel: Codable { + public struct FileModel: Codable { + public let id: String + public let object: String + public let bytes: String + public let created_at: String + public let filename: String + public let purpose: String + } + + public let data: [FileModel] + public let object: String +} diff --git a/Sources/ChatGPTAPIManager/Models/ModelsListModel.swift b/Sources/ChatGPTAPIManager/Models/ModelsListModel.swift index cb78dae..1b1979c 100644 --- a/Sources/ChatGPTAPIManager/Models/ModelsListModel.swift +++ b/Sources/ChatGPTAPIManager/Models/ModelsListModel.swift @@ -14,6 +14,6 @@ public struct ChatGPTModel: Codable, Equatable { } public struct ChatGPTModelList: Codable, Equatable { - public let data: [ChatGPTModel] + public let data: [ChatGPTModel]? public let object: String } From 0c735dcbdcd791b8b3ab176b8923dd920e2ae8a3 Mon Sep 17 00:00:00 2001 From: Ghullam Abbas <133848606+GhullamAbbasJoyia@users.noreply.github.com> Date: Wed, 12 Jul 2023 05:11:58 -0700 Subject: [PATCH 2/2] Feat: Add upload,delete, retrieved, retrieved content and file list endpoints Implementupload,delete, retrieved, retrieved content and file list endpoints in SDK along with example --- Example/Example.xcodeproj/project.pbxproj | 8 + .../UserInterfaceState.xcuserstate | Bin 53953 -> 59690 bytes .../xcdebugger/Breakpoints_v2.xcbkptlist | 256 ++++++++++++++++++ .../Storyboards/Base.lproj/Main.storyboard | 79 +++++- .../Supporting/mj_test_dataset_2.jsonl | 228 ++++++++++++++++ Example/Example/Supporting/samplefile.rtf | 8 + .../Example/ViewModles/FilesViewModel.swift | 78 +++++- Example/Example/Views/Files/FilesVC.swift | 65 ++++- .../ChatGPTAPIEndpoints.swift | 13 +- .../ChatGPTAPIManager/ChatGPTAPIManager.swift | 177 +++++++++++- .../DataParser/FilesParser.swift | 45 ++- .../ChatGPTAPIManager/Models/FilesModel.swift | 21 +- .../Utils/RequestBuilder.swift | 15 +- 13 files changed, 963 insertions(+), 30 deletions(-) create mode 100644 Example/Example/Supporting/mj_test_dataset_2.jsonl create mode 100644 Example/Example/Supporting/samplefile.rtf diff --git a/Example/Example.xcodeproj/project.pbxproj b/Example/Example.xcodeproj/project.pbxproj index 6999ecd..ca91dc8 100644 --- a/Example/Example.xcodeproj/project.pbxproj +++ b/Example/Example.xcodeproj/project.pbxproj @@ -9,6 +9,8 @@ /* Begin PBXBuildFile section */ 6A1BB84B2A5E7EC1008664D8 /* FilesVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A1BB84A2A5E7EC1008664D8 /* FilesVC.swift */; }; 6A1BB84D2A5E7FB3008664D8 /* FilesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A1BB84C2A5E7FB3008664D8 /* FilesViewModel.swift */; }; + 6A1BB84F2A5EBFFD008664D8 /* samplefile.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 6A1BB84E2A5EBFFD008664D8 /* samplefile.rtf */; }; + 6A1BB8512A5EC5B4008664D8 /* mj_test_dataset_2.jsonl in Resources */ = {isa = PBXBuildFile; fileRef = 6A1BB8502A5EC5B4008664D8 /* mj_test_dataset_2.jsonl */; }; 777D472B2A53EA9D0050C0E7 /* ChatGPTAPIManager in Frameworks */ = {isa = PBXBuildFile; productRef = 777D472A2A53EA9D0050C0E7 /* ChatGPTAPIManager */; }; 777D472F2A53F7560050C0E7 /* english_song.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 777D472D2A53F7550050C0E7 /* english_song.m4a */; }; 777D47302A53F7560050C0E7 /* translation_file.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 777D472E2A53F7550050C0E7 /* translation_file.m4a */; }; @@ -66,6 +68,8 @@ /* Begin PBXFileReference section */ 6A1BB84A2A5E7EC1008664D8 /* FilesVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilesVC.swift; sourceTree = ""; }; 6A1BB84C2A5E7FB3008664D8 /* FilesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilesViewModel.swift; sourceTree = ""; }; + 6A1BB84E2A5EBFFD008664D8 /* samplefile.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; path = samplefile.rtf; sourceTree = ""; }; + 6A1BB8502A5EC5B4008664D8 /* mj_test_dataset_2.jsonl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mj_test_dataset_2.jsonl; sourceTree = ""; }; 777D47282A53EA8F0050C0E7 /* chatgpt-ios-sdk */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "chatgpt-ios-sdk"; path = ..; sourceTree = ""; }; 777D472D2A53F7550050C0E7 /* english_song.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = english_song.m4a; sourceTree = ""; }; 777D472E2A53F7550050C0E7 /* translation_file.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = translation_file.m4a; sourceTree = ""; }; @@ -290,6 +294,8 @@ A8B860292A440CC0005FBEDE /* Supporting */ = { isa = PBXGroup; children = ( + 6A1BB8502A5EC5B4008664D8 /* mj_test_dataset_2.jsonl */, + 6A1BB84E2A5EBFFD008664D8 /* samplefile.rtf */, 777D472D2A53F7550050C0E7 /* english_song.m4a */, 777D472E2A53F7550050C0E7 /* translation_file.m4a */, A8B85FD52A43131A005FBEDE /* Assets.xcassets */, @@ -449,12 +455,14 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 6A1BB84F2A5EBFFD008664D8 /* samplefile.rtf in Resources */, 777D472F2A53F7560050C0E7 /* english_song.m4a in Resources */, A8B8600A2A431AA6005FBEDE /* UserCell.xib in Resources */, A8EA01682A56AB5D007DFADF /* pngwing.com.png in Resources */, 777D47302A53F7560050C0E7 /* translation_file.m4a in Resources */, A8B85FD92A43131A005FBEDE /* LaunchScreen.storyboard in Resources */, A8B860132A432135005FBEDE /* openai.svg in Resources */, + 6A1BB8512A5EC5B4008664D8 /* mj_test_dataset_2.jsonl in Resources */, A8B85FD62A43131A005FBEDE /* Assets.xcassets in Resources */, A8B8600F2A431AA6005FBEDE /* AssistantCell.xib in Resources */, A8B85FD42A431318005FBEDE /* Main.storyboard in Resources */, diff --git a/Example/Example.xcodeproj/project.xcworkspace/xcuserdata/ghulamabbas.xcuserdatad/UserInterfaceState.xcuserstate b/Example/Example.xcodeproj/project.xcworkspace/xcuserdata/ghulamabbas.xcuserdatad/UserInterfaceState.xcuserstate index ac7484f8782571c7f7627940b1cf312234149404..38e0d60c2ca32eedffb889a7d6099e0c89ea40df 100644 GIT binary patch literal 59690 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%0AIJU3CkYa2!5ZJs-AqP&9-(>_nw2EA3Q&LexiJT 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 diff --git a/Example/Example.xcodeproj/xcuserdata/ghulamabbas.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Example/Example.xcodeproj/xcuserdata/ghulamabbas.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index 662ccd2..48b8fd7 100644 --- a/Example/Example.xcodeproj/xcuserdata/ghulamabbas.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/Example/Example.xcodeproj/xcuserdata/ghulamabbas.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -3,4 +3,260 @@ uuid = "673E1103-B942-496C-B2AE-DE116532E5B4" type = "1" version = "2.0"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Example/Example/Storyboards/Base.lproj/Main.storyboard b/Example/Example/Storyboards/Base.lproj/Main.storyboard index 47935a2..8ce5a90 100644 --- a/Example/Example/Storyboards/Base.lproj/Main.storyboard +++ b/Example/Example/Storyboards/Base.lproj/Main.storyboard @@ -676,19 +676,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + - + + + + diff --git a/Example/Example/Supporting/mj_test_dataset_2.jsonl b/Example/Example/Supporting/mj_test_dataset_2.jsonl new file mode 100644 index 0000000..17f95ea --- /dev/null +++ b/Example/Example/Supporting/mj_test_dataset_2.jsonl @@ -0,0 +1,228 @@ +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} +{"prompt": "Whats is your name? \n\n###\n\n", "completion": " I am Minhaj ###"} +{"prompt": "Whats is your company name? \n\n###\n\n", "completion": " Devcrew.io ###"} \ No newline at end of file diff --git a/Example/Example/Supporting/samplefile.rtf b/Example/Example/Supporting/samplefile.rtf new file mode 100644 index 0000000..5de5b84 --- /dev/null +++ b/Example/Example/Supporting/samplefile.rtf @@ -0,0 +1,8 @@ +{\rtf1\ansi\ansicpg1252\cocoartf2709 +\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +{\*\expandedcolortbl;;} +\paperw11900\paperh16840\margl1440\margr1440\vieww11520\viewh8400\viewkind0 +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 + +\f0\fs24 \cf0 Hello this is text file to upload on chatgpt.} \ No newline at end of file diff --git a/Example/Example/ViewModles/FilesViewModel.swift b/Example/Example/ViewModles/FilesViewModel.swift index 498cdc3..6075cf9 100644 --- a/Example/Example/ViewModles/FilesViewModel.swift +++ b/Example/Example/ViewModles/FilesViewModel.swift @@ -11,12 +11,52 @@ import ChatGPTAPIManager class FilesViewModel { - var model: FielsModel? + var model: FileModel? + var models: FilesModel? + var fileID: String? func getFilesList(completion: @escaping (Result)-> Void) { EZLoadingActivity.show("Loading...", disableUI: true) ChatGPTAPIManager.shared.getFilesList() { [weak self] result in + switch result { + case .success(let model): + // Handle the models list + EZLoadingActivity.hide(true, animated: true) + self?.models = model + completion(.success(true)) + case .failure(let error): + // Handle the error + print("Error: \(error)") + EZLoadingActivity.hide(false, animated: true) + completion(.failure(error)) + } + } + } + + func uploadFile(fileURL: URL, purpose: String, completion: @escaping (Result)-> Void) { + EZLoadingActivity.show("Loading...", disableUI: true) + ChatGPTAPIManager.shared.fileRequest(fileUrl: fileURL, purpose: purpose) { [weak self] result in + + switch result { + case .success(let model): + // Handle the models list + EZLoadingActivity.hide(true, animated: true) + self?.model = model + self?.fileID = model.id + completion(.success(true)) + case .failure(let error): + // Handle the error + print("Error: \(error)") + EZLoadingActivity.hide(false, animated: true) + completion(.failure(error)) + } + } + } + func retrievedFile(fileID: String, completion: @escaping (Result)-> Void) { + EZLoadingActivity.show("Loading...", disableUI: true) + ChatGPTAPIManager.shared.retrieveFile(fileID: fileID) { [weak self] result in + switch result { case .success(let model): // Handle the models list @@ -31,4 +71,40 @@ class FilesViewModel { } } } + func retrievedFileContent(fileID: String, completion: @escaping (Result)-> Void) { + EZLoadingActivity.show("Loading...", disableUI: true) + ChatGPTAPIManager.shared.retrieveFileContent(fileID: fileID) { [weak self] result in + + switch result { + case .success(let data): + print(String(data: data, encoding: .utf8)) + EZLoadingActivity.hide(true, animated: true) + // self?.model = model + completion(.success(true)) + case .failure(let error): + // Handle the error + print("Error: \(error)") + EZLoadingActivity.hide(false, animated: true) + completion(.failure(error)) + } + } + } + func deleteFile(fileID: String, completion: @escaping (Result)-> Void) { + EZLoadingActivity.show("Loading...", disableUI: true) + ChatGPTAPIManager.shared.deleteFile(fileID: fileID) { [weak self] result in + + switch result { + case .success(let model): + // Handle the models list + EZLoadingActivity.hide(true, animated: true) + // self?.model = model + completion(.success(true)) + case .failure(let error): + // Handle the error + print("Error: \(error)") + EZLoadingActivity.hide(false, animated: true) + completion(.failure(error)) + } + } + } } diff --git a/Example/Example/Views/Files/FilesVC.swift b/Example/Example/Views/Files/FilesVC.swift index e617601..d368405 100644 --- a/Example/Example/Views/Files/FilesVC.swift +++ b/Example/Example/Views/Files/FilesVC.swift @@ -8,34 +8,77 @@ import UIKit class FilesVC: UIViewController { - let vm = FilesViewModel() + let vm = FilesViewModel() override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. + //self.getFiles() + // self.uploadFile() + + } + @IBAction func uploadFileButtonDidTab(sender: UIButton) { + self.uploadFile() + } + @IBAction func retrievedFileButtonDidTab(sender: UIButton) { + vm.retrievedFile(fileID: vm.fileID ?? "", completion: { [weak self] result in + switch result { + case.success: + print(self?.vm.models?.data.count ?? 0) + case.failure(let error): + print(error.localizedDescription) + } + }) + } + @IBAction func retrievedFileContentButtonDidTab(sender: UIButton) { + vm.retrievedFileContent(fileID: vm.fileID ?? "", completion: { [weak self] result in + switch result { + case.success: + print(self?.vm.models?.data.count ?? 0) + case.failure(let error): + print(error.localizedDescription) + } + }) + } + @IBAction func listFileButtonDidTab(sender: UIButton) { self.getFiles() } - + @IBAction func deleteFileButtonDidTab(sender: UIButton) { + vm.deleteFile(fileID: vm.fileID ?? "", completion: { [weak self] result in + switch result { + case.success: + print(self?.vm.models?.data.count ?? 0) + case.failure(let error): + print(error.localizedDescription) + } + }) + } func getFiles() { vm.getFilesList(completion: { [weak self] result in switch result { case.success: - print(self?.vm.model?.data.count ?? 0) + print(self?.vm.models?.data.count ?? 0) case.failure(let error): print(error.localizedDescription) } }) } - /* - // MARK: - Navigation - - // In a storyboard-based application, you will often want to do a little preparation before navigation - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { - // Get the new view controller using segue.destination. - // Pass the selected object to the new view controller. + func uploadFile() { + if let fileURL = Bundle.main.url(forResource: "mj_test_dataset_2", withExtension: "jsonl") { + vm.uploadFile(fileURL: fileURL, purpose: "fine-tune", completion: { [weak self] result in + switch result { + case.success(_): + print("fileName:\(String(describing: self?.vm.model?.filename))fileID:\(self?.vm.model?.id)") + print(self?.vm.fileID ?? "") + case.failure(let error): + print(error.localizedDescription) + } + }) + } + } - */ + } diff --git a/Sources/ChatGPTAPIManager/ChatGPTAPIEndpoints.swift b/Sources/ChatGPTAPIManager/ChatGPTAPIEndpoints.swift index 1568411..1839aa3 100644 --- a/Sources/ChatGPTAPIManager/ChatGPTAPIEndpoints.swift +++ b/Sources/ChatGPTAPIManager/ChatGPTAPIEndpoints.swift @@ -38,6 +38,9 @@ enum ChatGPTAPIEndpoint { case moderations case embeddings case files + case deleteFile(String) + case retrieveFile(String) + case retrieveFileContent(String) } extension ChatGPTAPIEndpoint { @@ -47,8 +50,10 @@ extension ChatGPTAPIEndpoint { case .completion, .chat, .generateImage, .imageEdits, .imageVariations, .translations, .transcriptions, .moderations, .textEdit, .embeddings: return "POST" - case .modelsList, .retrievedModel, .files: + case .modelsList, .retrievedModel, .files, .retrieveFile, .retrieveFileContent: return "GET" + case.deleteFile: + return "DELETE" } } @@ -80,6 +85,12 @@ extension ChatGPTAPIEndpoint { return URL(string: ChatGPTAPIEndpoint.baseURL + "/embeddings")! case.files: return URL(string: ChatGPTAPIEndpoint.baseURL + "/files")! + case.deleteFile(let fileID): + return URL(string: ChatGPTAPIEndpoint.baseURL + "/files/\(fileID)")! + case.retrieveFile(let fileID): + return URL(string: ChatGPTAPIEndpoint.baseURL + "/files/\(fileID)")! + case.retrieveFileContent(let fileID): + return URL(string: ChatGPTAPIEndpoint.baseURL + "/files/\(fileID)/content")! } } } diff --git a/Sources/ChatGPTAPIManager/ChatGPTAPIManager.swift b/Sources/ChatGPTAPIManager/ChatGPTAPIManager.swift index 3a642f3..03fb3ff 100644 --- a/Sources/ChatGPTAPIManager/ChatGPTAPIManager.swift +++ b/Sources/ChatGPTAPIManager/ChatGPTAPIManager.swift @@ -179,14 +179,142 @@ final public class ChatGPTAPIManager { /// Retrieves a list of files from the OpenAI API. /// /// - Parameter completion: A closure to be called when the API call is complete. It provides a `Result` object that represents either the retrieved data or an error. - public func getFilesList(completion: @escaping (Result) -> Void) { + public func getFilesList(completion: @escaping (Result) -> Void) { self.getFiles(endPoint: .files, completion: completion) } + /// This function is used to make a file request using the provided parameters. + /// - Parameters: + /// - fileUrl: The URL of the file to be requested. + /// - purpose: The purpose or description of the file request. + /// - endPoint: The endpoint or URL where the file request should be sent. + /// - completion: A closure that takes a Result type as input, indicating the success or failure of the file request operation. + + public func fileRequest(fileUrl: URL, purpose: String, completion: @escaping (Result) -> Void) { + self.sendFileRequest(fileUrl: fileUrl, purpose: purpose, endPoint: .files, completion: completion) + } + + + /// Deletes a file with the specified file ID from the OpenAI API. + + /// - Parameters: + /// - fileID: The ID of the file to delete. + /// - completion: A completion handler called when the deletion is complete. The handler takes a `Result` object as its parameter. If the deletion is successful, the `Result` object will contain `Void`. If an error occurs, the `Result` object will contain the corresponding `Error`. + + + public func deleteFile(fileID: String, completion: @escaping (Result) -> Void) { + + let url = ChatGPTAPIEndpoint.deleteFile(fileID) + self.deleteFileRequest(endPoint: url, completion: completion) + } + + /// Retrieves file from the API. + /// + /// - Parameters: + /// - fileID: file id to retrieve + /// - completion: A completion handler that receives the result of the API request. + /// The result will either contain model of type `FilesModel` on success, + /// or an error on failure. + /// + + public func retrieveFile(fileID: String, completion: @escaping (Result) -> Void) { + self.retrieveFileRequest(endPoint: .retrieveFile(fileID), completion: completion) + } + + /// Retrieves file content from the API. + /// + /// - Parameters: + /// - fileID: file id to retrieve content + /// - completion: A completion handler that receives the result of the API request. + /// + /// + + public func retrieveFileContent(fileID: String, completion: @escaping (Result) -> Void) { + self.retrieveFileContentRequest(endPoint: .retrieveFileContent(fileID), completion: completion) + } // MARK: - Private Functions - - private func getFiles(endPoint: ChatGPTAPIEndpoint, completion: @escaping (Result) -> Void) { + private func deleteFileRequest(endPoint: ChatGPTAPIEndpoint, completion: @escaping (Result) -> Void) { + let requestBuilder = GetRequestBuilder() + guard let request = requestBuilder.buildRequest(params: nil, endPoint: endPoint, apiKey: apiKey) else { + completion(.failure(NetworkError.invalidURL)) + return + } + self.performDataTask(with: request) { result in + + switch result { + case.success(let data): + + let parser = FileParser() + parser.parseResponse(data: data, completion: { result in + + switch result { + case.success(let fileID): + print(fileID) + completion(.success(true)) + + case.failure(let error): + completion(.failure(error)) + } + }) + + + case.failure(let error): + completion(.failure(error)) + } + + } + } + private func retrieveFileContentRequest(endPoint: ChatGPTAPIEndpoint, completion: @escaping (Result) -> Void) { + let requestBuilder = GetRequestBuilder() + guard let request = requestBuilder.buildRequest(params: nil, endPoint: endPoint, apiKey: apiKey) else { + completion(.failure(NetworkError.invalidURL)) + return + } + self.performDataTask(with: request) { result in + + switch result { + case.success(let data): + completion(.success(data)) + case.failure(let error): + completion(.failure(error)) + } + + } + } + private func retrieveFileRequest(endPoint: ChatGPTAPIEndpoint, completion: @escaping (Result) -> Void) { + let requestBuilder = GetRequestBuilder() + guard let request = requestBuilder.buildRequest(params: nil, endPoint: endPoint, apiKey: apiKey) else { + completion(.failure(NetworkError.invalidURL)) + return + } + self.performDataTask(with: request) { result in + + switch result { + case.success(let data): + + let parser = FileParser() + parser.parseResponse(data: data, completion: { result in + + switch result { + case.success(let files): + + completion(.success(files)) + + case.failure(let error): + completion(.failure(error)) + } + }) + + + case.failure(let error): + completion(.failure(error)) + } + + } + } + private func getFiles(endPoint: ChatGPTAPIEndpoint, completion: @escaping (Result) -> Void) { let requestBuilder = GetRequestBuilder() guard let request = requestBuilder.buildRequest(params: nil, endPoint: endPoint, apiKey: apiKey) else { @@ -218,7 +346,50 @@ final public class ChatGPTAPIManager { } } - + private func sendFileRequest(fileUrl: URL, purpose: String, endPoint: ChatGPTAPIEndpoint, completion: @escaping (Result) -> Void) { + + // Define the key-value pairs + let parameters: [String: Any] = [ + "purpose": purpose + ] + + let filenName = fileUrl.lastPathComponent + let fileData: Data + do { + fileData = try Data(contentsOf: fileUrl) + } catch { + completion(.failure(NetworkError.invalidURL)) + return + } + + guard let request = self.createMultiPartRequest(data: [fileData], fileNames: [filenName], params: parameters, name: "file", contentType: "application/octet-stream", endPoint: endPoint) else { + completion(.failure(NetworkError.invalidURL)) + return + } + + self.performDataTask(with: request) { result in + + switch result { + case.success(let data): + let parser = FileParser() + parser.parseResponse(data: data, completion: { result in + + switch result { + case.success(let fileObject): + + completion(.success(fileObject)) + + case.failure(let error): + completion(.failure(error)) + } + + }) + case.failure(let error): + completion(.failure(error)) + } + } + + } private func textEditsRequest(endPoint: ChatGPTAPIEndpoint, model: EditGPTModels, input: String?, instruction: String, n: Int, temperature: Double, topP: Double, completion: @escaping (Result<[String],Error>) -> Void) { var parameters: [String: Any] = [ diff --git a/Sources/ChatGPTAPIManager/DataParser/FilesParser.swift b/Sources/ChatGPTAPIManager/DataParser/FilesParser.swift index 06eb92c..40b8b21 100644 --- a/Sources/ChatGPTAPIManager/DataParser/FilesParser.swift +++ b/Sources/ChatGPTAPIManager/DataParser/FilesParser.swift @@ -13,7 +13,7 @@ class FilesParser { /// - Parameter data: The response data from the API. /// - Returns: The parsed image URL. /// - Throws: An error if the response cannot be parsed. - func parseResponse(data: Data,completion: @escaping(Result)->Void) { + func parseResponse(data: Data,completion: @escaping(Result)->Void) { do { let responseJSON = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] @@ -23,7 +23,48 @@ class FilesParser { //completion(.success(transcription)) do { // Parse the JSON response into an array of type T - let models = try JSONDecoder().decode(FielsModel.self, from: data) + let models = try JSONDecoder().decode(FilesModel.self, from: data) + completion(.success(models)) + } catch { + // Error occurred during decoding, return failure in completion handler + completion(.failure(error)) + } + + } else { + if let error = responseJSON?["error"] as? [String:Any],let message = error["message"] as? String { + let error = NSError(domain: message, code: 401, userInfo: [ NSLocalizedDescriptionKey: message]) + + completion(.failure(error)) + return + } else { + completion(.failure(NetworkError.invalidResponse)) + return + } + } + + } catch (let error) { + completion(.failure(error)) + } + } +} + +class FileParser { + + /// Parse the response data for generating an image. + /// - Parameter data: The response data from the API. + /// - Returns: The parsed image URL. + /// - Throws: An error if the response cannot be parsed. + func parseResponse(data: Data,completion: @escaping(Result)->Void) { + do { + + let responseJSON = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] + debugPrint(responseJSON ?? []) + if let status = responseJSON?["status"] as? String, status == "uploaded" || status == "processed" { + //debugPrint(transcription) + //completion(.success(transcription)) + do { + // Parse the JSON response into an array of type T + let models = try JSONDecoder().decode(FileModel.self, from: data) completion(.success(models)) } catch { // Error occurred during decoding, return failure in completion handler diff --git a/Sources/ChatGPTAPIManager/Models/FilesModel.swift b/Sources/ChatGPTAPIManager/Models/FilesModel.swift index d0b50ba..9ecef2b 100644 --- a/Sources/ChatGPTAPIManager/Models/FilesModel.swift +++ b/Sources/ChatGPTAPIManager/Models/FilesModel.swift @@ -7,16 +7,17 @@ import Foundation -public struct FielsModel: Codable { - public struct FileModel: Codable { - public let id: String - public let object: String - public let bytes: String - public let created_at: String - public let filename: String - public let purpose: String - } - +public struct FilesModel: Codable { + public let data: [FileModel] public let object: String } + +public struct FileModel: Codable { + public let id: String + public let object: String + public let bytes: Int + public let created_at: Int + public let filename: String + public let purpose: String +} diff --git a/Sources/ChatGPTAPIManager/Utils/RequestBuilder.swift b/Sources/ChatGPTAPIManager/Utils/RequestBuilder.swift index 265ada5..68efbca 100644 --- a/Sources/ChatGPTAPIManager/Utils/RequestBuilder.swift +++ b/Sources/ChatGPTAPIManager/Utils/RequestBuilder.swift @@ -48,7 +48,20 @@ struct GetRequestBuilder: RequestBuilder { return request } } - +struct DeleteRequestBuilder: RequestBuilder { + func buildRequest(params: [String: Any]?, endPoint: ChatGPTAPIEndpoint?, apiKey: String) -> URLRequest? { + guard let endPoint = endPoint else { + return nil + } + + var request = URLRequest(url: endPoint.url) + request.httpMethod = "DELETE" + request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization") + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + + return request + } +} func createUrlRequest(requestBuilder: RequestBuilder, params: [String: Any]?, endPoint: ChatGPTAPIEndpoint?, apiKey: String) -> URLRequest? { return requestBuilder.buildRequest(params: params, endPoint: endPoint, apiKey: apiKey) }