From a39756bfdada73974befdfb1bd5801a231e4b07f Mon Sep 17 00:00:00 2001 From: Krrish Dholakia Date: Sat, 9 Sep 2023 15:55:36 -0700 Subject: [PATCH] add api manager --- litellm/__init__.py | 5 ++ litellm/__pycache__/__init__.cpython-311.pyc | Bin 7969 -> 8075 bytes litellm/__pycache__/main.cpython-311.pyc | Bin 30886 -> 30921 bytes litellm/__pycache__/utils.cpython-311.pyc | Bin 92039 -> 92489 bytes litellm/apimanager.py | 25 ++++++++ litellm/main.py | 2 +- litellm/tests/test_api_manager.py | 60 +++++++++++++++++++ litellm/tests/test_exceptions.py | 3 - litellm/utils.py | 32 +++++----- pyproject.toml | 2 +- 10 files changed, 110 insertions(+), 19 deletions(-) create mode 100644 litellm/apimanager.py create mode 100644 litellm/tests/test_api_manager.py diff --git a/litellm/__init__.py b/litellm/__init__.py index c2892ad80c..23dff09d5e 100644 --- a/litellm/__init__.py +++ b/litellm/__init__.py @@ -35,6 +35,11 @@ caching = False # deprecated son caching_with_models = False # if you want the caching key to be model + prompt # deprecated soon cache: Optional[Cache] = None # cache object model_alias_map: Dict[str, str] = {} + +####### APIManager ################### +from .apimanager import APIManager +apiManager = APIManager() + def get_model_cost_map(): url = "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json" diff --git a/litellm/__pycache__/__init__.cpython-311.pyc b/litellm/__pycache__/__init__.cpython-311.pyc index 0a9fbfa5bbefa21033b821dee99dec3662126a5e..1d6568e1e56bd228840101147e3acf0da8f1d138 100644 GIT binary patch delta 1044 zcmZ9I&rcIU6vt{Hx>QN7dgD2y`Hw&m?v-A1BeZS`IdzpMZ;eGA(iU^(; zUw%{VsW*VD?>Zj{l%7|+v>*v$Bp?>7Lc&{~R3A|VBlURKLQ7A^>Z z!ve(WX>%OD1T=$a%NC-o4BhH8e+d425$F;*(xsoaLH_}Y$sn8|I8ivma7N&a77=ZK zg-HzbBIp=s2k1EHCD1r%Cujn+3p7cCw7V#f3ED$Lpp)S51%C=OoCG5cMjvPfGy*yW z+7Fs#F*dddW3zFGafbg@?mM3|Q5~?x6ARk{v!I<^lMX>K1h7p6<7E_CJ3vx*=GTmyZjS22v z@b_3b&n#{YfoXdrNhv9YByBb>Y+NqqWi@>088fZAbkh)Iy+L{uMCTQHlELm8y5q;Tm)&6{L!!)(6}3{~6Sg=lZI41Bq7*jt z1UOUXSFs;QEnoe%C!FTDWjLldvK-SKGaU0AvmA3AIrD?B$@=cA;^PIoZhs1;RMcCo zozo}rWm}YQE86}x^kyh<90%*s`DScUD^sSzz!;-m9EH+$hFY^r&9<6oVmL@l z)I?+E>O~J2^`jCiM@P?w~dI84KbC?Z7Z(h7_nhGo`YWssvvr14^a<8 zxBPr$z_}ZMmcV~4K{^5b^AwX1Oc*8t6NQPv#9N4-eT_*1d=8uhPl8k6DR3Hm9-IMB zgR^vo&bAbiqh9I*FF-yAc^>TFg+l=j0dNr<1TTW;!6lYp$@_3^mXb_MW+bzcdC8pQ zf@DFmC|QzR6eLT~8G_E`f1NDNGOUzmMOI>2mSaZ+H2hK}D>Tx=q)ekUrd9L`sbB=> zxK_O?oX}SFHL|9!lXd+9;nytj)X|>EeO$XPoz!mV8)QS@B%6AT)buT~rPoPaZ;%GO zkFOwa%KU60*endCmBBf<=d}62TE*DMKiE7t&cE48?g+$hkr4$MK7rsdVth&U+vGxI z{I=~hf2QVfh<{X_p%6q~+_$s4Y^PVFtXFSq-7bc7LiY5nZ3>(A_B|sDVU9b7!#HY| zhaX#mMF@;Vfs(+Iz_P%Kz^Xu5pdwJ^ho{_wKSZ-R=Gez0&AzR7(_nSl-f0;g^I-HO zo;SqT^;Nw?nO19dx;?`$0t;<7d;LMJ)2wTMJ}fONv!>6vkMSk`Y0P1{3<>`_w$5X& w(VPTD=eb4O#{h{>7bDr~@b5GBE z?|IMJRdQ{WXwGRgYL5Nnx7NE}xTxt%lw{?@=pk)nBC%JZ(To&~=-$peE91EHvPfd` zkzAEQMh~)ldKi2quaiDdnzM-)4CcMW2aV?bqCN~d85k7t#K%zBRH+?Zhp54~=HFR` zn-Aq`H{;O+cdy`a^TDVr#2*dOVayzY%u=t8N7{|xVh~mGez(x&@%O|_3QRLdr~s3t z2lkxAtWya8eu$1kxBYF6fkFDuPT>v9lNp;a8ej>>EcHS!PkA6#J(QOn z-g^`u)gc^X5R@>;&ZY(wMxdoKFEd6M9Yw#20qaYAXJPoUY&ieFo5OrNf&eGWwM2-V zD_48s(7BYN=M-pTe0^4+Yn&MwtxG2H{$iY6`yRETd3K39da6m z6P4=f!x7?Fb2!-bQhSuP#RY`PUVvPCL&WA zk2KbQnLbv;o!Ot}Xe#2a*%~xx=N0-#Ox%1i5gn7d#Vnn-Sz3(J>qa@_*UdT%EbMMn zpuMSerJ!Bh=TxKpuF{!~_Et*c18A2GvThT%9Iv))O6{(bF4sAWG4xZhtIRRR$V#45 ziNdN;Y$V3XsGN(*#0FyWRGJ};Wi%vV##)|iu#j8Ri=nl`)WHhrT7}Duq4gq1F4~P` z$1b#g<~#PGopGc)3q(?1SzjWOrXsbYIY~OxRJPNhZcdQSG$+WJ5YawkBxDvIZY?D; z2)9~@GIF`~qEvAj-!2c{BXi`Nh`G&5$Ow4aTX$SReHvj3;XU}OJ%`QL-S+b-I786{ zHYNk!P>?3WI~_Jv8oR;4Y!-m;?b)!Sb2rI~7&@mFhyLCcn}hc_ZNh>*2)zg%1}tj~ zIc~!Ey6Z<(LdDJEM^&8u5VC>$At>>b9e5R;`y1&pMw?OCN#92vzcI*?5Voq@(fxoy zRORw@@?GL$yo%x!T=8V-#M84$;^>D6vj}qt2@DKL@%`k5dmepa4CPXUU%}W{K=L97 z`-n6n%#^4iI1~)=K7%AGqk@-bo7v-QAcb(jw@9YoC4YJR3ZII6>~AGZ$q772?m$hz zN=jfL(7EdiEQ^PTN?9d(3Ef}dcEFMGDN++gWNsla#Ab^5Q&9ihM`RonR8Qu>MEBT~ nxLC6g@(>CU#H~?+OkByham8JHPg%{b=YW^5rOrs0>J)zgv2M}y delta 1662 zcmah}ZA@Eb6z<#G-j$Y8VIVLWARp}tbfdOFkpXRi!G0*R88b-+6u5NY+$ ze{5_n#uKxRKQ2)*GQY@86kYs4nMza!$+l#j(@{yM1z~}xm`B@DEG&6p7WgZ zp7-;f`4uv`LbR`GwQ3prlr!tyL(^KXhGdCDnxk?};X(Zy>64sHc8(LZNo{$G*EzZe zBBc|g4|L{S;)ham774&(=Dy-SR)9Jg7+7A$Z5qvgIi1#}MKf$QlsF;UTMmgrLs)M7kdZI|CzI zCi3_aV9NTG=3b2UgQo0cRutoUgaZu1at67%)QG|%2-)(}R|%uT=vOgd3y~_0!L70b z1^>Mo%(o+i;AD9Y35jo&Cy)&%pYZn430m#&WCZcqwrjniQVY=s_%H|lE&esoga}S&{kbV&ca0X ze*RU=n}olspCwapxaKesL0S7*hO~|QS6a!kVnkrIZ`5XLzQQrzAS{8xzJ25}(kqxE z?+Vg0=uIGei;^x9>=7cp0&RDB+WUkk{T@T{X)&(u>UBlh{lRX*7gHdoQz$163N#`N z#RK$b9P>8n2|YqUpsq-e(qB;gO(uhB`w4PMta02X$zSeR^bRemN|sd7ORDIiDk|=; zTS^@%lD)D!#nD(Ko3E(XqFqoL9yiGrN{Hl`)Xk;bLWQ-tn7df4Wc*^O9s`T%yLhx$ zvKw@0uWfg#(O$1~rlP%(v?~+s@-~IrBwLPGTQ()TYq;earwKzhOB%`?BaGb2bE;5S zDc&rZS_M_eRyk<_tBPcr#;vB+Ct_$VPcdkat?8xEnjv}6#;w^J%otiPa^#`Ct#zcK zy_4_Qfp*rh*;y!&y2`pzi8L0e9Zec;w$Ym6P&e`1Y!k0!f>{1^2_bXP)oLM1IMr$; z3F6nS(;R;mPty%Y+UCerv8la+kV7!q(fYu9sK1XegYW_T)bTKTJBhAyI(#3oO;iXE z_#$DdgU?+yk_vZRc9J97J7@T2DzJ-h?(j+WvLRf*0 zPz5o==}>3d0t&db7{}^U5#3)w*Y60t6$1 f)Bw!Lr1py4Q|haKsdlozZ@?$i&^qyDs^|X!uTZr_ diff --git a/litellm/__pycache__/utils.cpython-311.pyc b/litellm/__pycache__/utils.cpython-311.pyc index 35670a0f7bdb41118f11bf9f5649dbc511fd2273..c8a4b9f9f99884e5be4b0e1b891a2e43e8ae7065 100644 GIT binary patch delta 9315 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 delta 8965 zcmb7J3w)H-mH+O{e3QrI{U9OaMF^1L5fTXyFhC$0kO0cVU-40fVP+C0CNtsA7YKA9 z15yKM6}hXQT3}Pf2ZdU2)=k&8SS*F5*h-ZmeibUTY9Cgii(Bdg_x$gd%mmln?aojC zoO{l>=bn4+x#!;d<;3f1&uePhv#F`c3jL=1;4|;xCk~~}%o8srWr+GyD*J)nJB;Os zwRveJ*0AETKn=gJ)ysyOBwC8gD%>eK;#gjFiaNj!E3IP3=-foFb(f7a?4mS(g(HCn zNX{Dx#KZZ{0vjJU&^9GOYKCkO8~KZKTZxD$XG5 z;fRe!PRtos$3BQ|8F$TM`A`-6r;il-ChTR+(S=o&Y|IYEJz64l?Ekf<4p3g@9xG_l zSWMwe6V=ZZCwr6q$}_YQ`z>gCy$)}R*^Ko{y+!W*nYh) zgT_+ftCloiO;O@&)tWQFjrGP>@TODniW<@egnQY8j43-T4=5uPZOi~yQOXs5*MUtEg)j#wLqp4NlQJwJddP>iEkF!H&dBmNDYdhMKwO z3Z0h}W$bLrsYSP+UgR?Aeva04TI(LnxvVHf4VEhsiBI&o!pb)bYhN#{6{Bt%m7l2; zO}(rn6%}6rT#}HZ-?g0i~Fz8zx6+_CEOB-T7D_QUAaB_%etPvkEv zHRpaz%vd(0@ervPIU#qm&*kCn&?+kW9YL=711&UTvpE>GC@9`#Wx}wkX>uMf^&bncF)_Ax>)8(!#>ZlWcKJBC9U* zTI$4YJBQjrDO$2PQk+xB%Qblb(=haFjU5G%d@WlX`g*>&#3 zK;reM=!V2_VsExMaz|MOqx;Sh)a#0PSE|<^Zb;I`#yPD+#O1H&WhT?orwoM9n-oqK zLzg$O1dLrAR$KE1I)q6iN45=&EWUH3SbTqZrii?gTcuSEDAJtzRpD;4eL#Ic9(S~x zDcZyVHoAF}ub&gI(Q4vy%7j6!)?ovZ*oqg0le$=IVT|wiYW;63yDjVK&f+PzxMIrT zq|MB$Y)IOew3e+^x~z97Ynd};A@_^7T=VU6)9n*uS4?Or;%3dHQ4DKH<8+tn^m`2z zSYzI&UWF{%`7n}Ne3}c&KE4}FSy+0-$rY6u z5wv3!gi30XyS5-+0AxMc108wX9T6+s70&OX{V#x507n5oB?zSx$ogPHL>zFBvD@h8 z6{;3*yQk-!P0ZSwyyK=*i6b6sBryNGWQpFf@`9y%G<80bF?-6Ka^+|u@Mp^G5%kaT z^5mvM>+#A4XH%Z_WS&Y5K8kdyP+?Gh4sg9UvQVukt*@__h03sd+WfwN#?O=L3yj>s zMf58DBFZJZO}+7wVpGLY-{gv!YR)C)|AzW#d9%}!bCIkVDIIR^ZV$QI-I`|=|2N@Y zHCz1?3Fb$iTXj2Qe-_vLFR6beh9~;t*7w zf|Qn&k}kKO<9Oi(Fe3A87^p%qXU$}_l*pse&1)V=V8ccF#zK}U#%-+3DuW4C3wF5f z;U&<{5N#V@&%Ho)jMV1NfJgHO1C;Y^ZM;V;>AsP@Cm!mqTr>@;Hv&ciMgeL7&2XR= zFdEINfC&I9bqc=$&;w~5Clvjs5UGono<+mr zv&$x)kre1`m#&3)e)Nr=6O8qU-P=~O13S0RaKv@<#Vy-wm*Dg@?9Fa}o6qZ14VAkC zEk6D%Jh%;_jFm_{mxmUz&4)?Ldz3SEkdrd57@6M$$QP%#Ph|5%;{D^)rNr11oqGRO z8!hb(J4UJ=V*Gpb?j3hJio3}C`XT;6NOK1?zZ;i>(okoId!?J+hGB8~+tqB9u6QGH0yMElf1rj{%_*MYs!@D5f40sLAQ-EIq zA_UGvUIe-oa6e!bX&RX!?Cy0gjZ=2HxLfm?L*ebfw~HNRxek69+JJYWukL;})832r zezETRi|rw(T@b(e{uIYGaD8aEi|m8{yis30RFj1q;Kh(z%ssVF%y^-o`x&t1O)kktDdm$Bmr>h}q0W=o$ndOkYp#x9 zNL%0wh1`@n_d_NZ#xCbcU?h0l9U69QJlrzFp2G+`p(d~H4}+4&%7a8L9dwnKE4c~U zn*s6bG%m{gCj`!X^CBq^j}~wr0mP4*UNrZMvC+kjJs@R}o)TN5QUcsXD63S=Yf*&7I8G-Dd0lk3uYWF~Y zE_hgXjt4h?R{ZpMRW}yY3^G=nKL?528S>sQXNkxAm$yf3$@zC7m8&eB`W7_}M_aJP z73%bOCyML~k@V!+dOtv^-HGpsqiD`KRE?uzv>Xa{?+f(tWuRuYvmo zK$;lT+bk_|mjD9Mw_ZQb$`R1@j=8?JwqWVkg1pTu7n=5N+~fuEo6}oIyh4tLETrB4 zqB0z7+--iZd6nZoCuv07_v`&A&1c@dOPbA@>svRjbX9Qe=uoL&D{To55-*+A)YplzD?0J5 z9ahI1MDo*sUyEP9J?gsl7jKVK&yr|wwCdaz8+}iC@j^qcJQG%;gY-Za^e&Nlv4A}* zDlQJMKuitQuld?T=FuUK{7vu-6@=F8C_4XEtiCwa{yUK069+HWs+WoUS@bU#6KxIy z+}{A+-ueERjB}vQ1AYs5M@)PFu9aWu2E@-|qz^&KOn)EL9{_&@{0Sg;k6imrF}G}{ z@sA*vUR@D?d%sNmnA%sO#edk6<@hN?MS$btd!LN6UqIh0;5c+c=ZJ@Lm%g}wjZSt#5%BxIdka{RW$a6)BXad+6pq0Ahvn1& za#iI9nxUU8WaSz3U1jj~^N9XMA)CZL)+ZIQ=V{pA7qQvQqK__SlN_)uujhQC-crnJ z?P?-1Ch1QXvtWT7*urDOQDo#_9j+;QWeKZciG7|DGCb-60;w8yug^ozOCy=?f?NyX zy=iWgB>1ySKU~VXSW4fN;cPjZawGB9CzffxF0E`@*?LRahChBmKQ3)q`3w>pwq`#a zw5YjMqvXi-`m1H^TP$05k7R{?Yeuj|Y!)o>I>2;57iJ_kq%>udrua;Vg%u zz@4rCvVslOhmT}4S#cj3{u(QWO~VntE{8ZV`ZqJp{>&&=lM5H)Ce3=eKrb21=CO*t z*3s-{Rw7-y4SKS>tgwsFTnt!%ftT5(@5&z{y>7}@^yJ=ntLa(+t^Kg zA5UNRf9y~v_)UO25t(7;nIyA*I%yiV0A&)F zncsj;a-%fC%S4w8GM9^^zIB_qu@E{d085~gU>oMx>;2#6E4AfnKc%3@}Cwc*> zQL;Q5sY~dQc?-QL=m8WAP(8zf8ENqZas^km@_I6)Cro9f%%fLKWy9HuzIjvGDeEY? z(X4zW2J#UYS+F-Nv@YO@8Kn(cKb_UGhxK*S*~0DvG=MXcSHp!H022WffEt*Y0+QZ9H_l*xXO(^RGg&2LnR>9E zO{haDGwk$U_pJ5uA?PI!6PqlF5tx$4sJv9zvAqJ#{uWn&6&)>`@t&nFl(#uGs%L9Eo2&^+JiW=%@ zqi1LSfNxxurU)#-HAD5Z1w%e(n)#JMR$RDYB!uWnjA!!&`0zWup^=p*V>u1h%9}0v z>PA+lZl?DBz84zV5^I@sQzkfq>9peOS^()0sI=GdVfzp_)U?LmAn zw&|-p;I@LdjUZ&FEIzt`oZn8ZGkqT{U`y20f5kK{{XO;hOW32`GII9Nx)9yp%!L{W zllXLU-8HliF3B)u8+Q6~;SIJAK5!w$NapUB)dp`;!%o-WPG87$9DiarOR${a52@1} z^Hua7k%rYzPit8$P~GTMmot?2c8qSM2iN#G_j~CN9p*>CC~^6NFuF~DZYgU~A0hfu zU(W4pk?Qy{gz|2D2X|2O1=g5bZ4*Y839^M`TwYIPX^HKD9;%yL%Dm`%UM z#e&_h!d@Y?=`HH^y80d4ilMhb7XM5npR)1+i?=I}Jx$Gr>%-v5ZxUP3Z7V>26hiSa z(p^*%0zpky>kyp`KY_ehNh2%)DewI6={K)n8Hpy&w;`Nj^kCu@si@p(d{fKxivp#Hxemt&L^N<3UM01 z2|!imNFR>k!%Y!x^W5wMYgLnt(H}g&8ZS%!mBG^Gdb5uW&suC@ Q*_V_-sP#SWV+XDO1vJ=pi2wiq diff --git a/litellm/apimanager.py b/litellm/apimanager.py new file mode 100644 index 0000000000..e7d1f1eaf7 --- /dev/null +++ b/litellm/apimanager.py @@ -0,0 +1,25 @@ +import litellm +from litellm.utils import ModelResponse +class APIManager: + def __init__(self): + self.user_dict = {} + + def create_budget(self, total_budget: float, user: str): + self.user_dict[user] = {"total_budget": total_budget} + return self.user_dict[user] + + def projected_cost(self, model: str, messages: list, user: str): + text = "".join(message["content"] for message in messages) + prompt_tokens = litellm.token_counter(model=model, text=text) + prompt_cost, _ = litellm.cost_per_token(model=model, prompt_tokens=prompt_tokens, completion_tokens=0) + current_cost = self.user_dict[user].get("current_cost", 0) + projected_cost = prompt_cost + current_cost + return projected_cost + + def get_total_budget(self, user: str): + return self.user_dict[user]["total_budget"] + + def update_cost(self, completion_obj: ModelResponse, user: str): + cost = litellm.completion_cost(completion_response=completion_obj) + self.user_dict[user]["current_cost"] = cost + self.user_dict[user].get("current_cost", 0) + return self.user_dict[user]["current_cost"] \ No newline at end of file diff --git a/litellm/main.py b/litellm/main.py index ee607d6e40..d376b2f253 100644 --- a/litellm/main.py +++ b/litellm/main.py @@ -168,7 +168,7 @@ def completion( model_alias_map=litellm.model_alias_map, completion_call_id=id ) - logging.update_environment_variables(model=model, optional_params=optional_params, litellm_params=litellm_params) + logging.update_environment_variables(model=model, user=user, optional_params=optional_params, litellm_params=litellm_params) if custom_llm_provider == "azure": # azure configs openai.api_type = "azure" diff --git a/litellm/tests/test_api_manager.py b/litellm/tests/test_api_manager.py new file mode 100644 index 0000000000..d8d0077de9 --- /dev/null +++ b/litellm/tests/test_api_manager.py @@ -0,0 +1,60 @@ +#### What this tests #### +# This tests calling batch_completions by running 100 messages together + +import sys, os +import traceback + +sys.path.insert( + 0, os.path.abspath("../..") +) # Adds the parent directory to the system path +import litellm +from litellm import apiManager, completion + +litellm.success_callback = ["api_manager"] + + +## Scenario 1: User budget enough to make call +def test_user_budget_enough(): + user = "1234" + # create a budget for a user + apiManager.create_budget(total_budget=10, user=user) + + # check if a given call can be made + data = { + "model": "gpt-3.5-turbo", + "messages": [{"role": "user", "content": "Hey, how's it going?"}] + } + model = data["model"] + messages = data["messages"] + if apiManager.projected_cost(**data, user=user) <= apiManager.get_total_budget(user): + response = completion(**data) + else: + response = "Sorry - no budget!" + + print(f"response: {response}") + +## Scenario 2: User budget not enough to make call +def test_user_budget_not_enough(): + user = "12345" + # create a budget for a user + apiManager.create_budget(total_budget=0, user=user) + + # check if a given call can be made + data = { + "model": "gpt-3.5-turbo", + "messages": [{"role": "user", "content": "Hey, how's it going?"}] + } + model = data["model"] + messages = data["messages"] + projectedCost = apiManager.projected_cost(**data, user=user) + print(f"projectedCost: {projectedCost}") + totalBudget = apiManager.get_total_budget(user) + print(f"totalBudget: {totalBudget}") + if projectedCost <= totalBudget: + response = completion(**data) + else: + response = "Sorry - no budget!" + + print(f"response: {response}") + +test_user_budget_not_enough() \ No newline at end of file diff --git a/litellm/tests/test_exceptions.py b/litellm/tests/test_exceptions.py index 8a7af6a580..96aeb98b28 100644 --- a/litellm/tests/test_exceptions.py +++ b/litellm/tests/test_exceptions.py @@ -117,9 +117,6 @@ def invalid_auth(model): # set the model key to an invalid key, depending on th os.environ["TOGETHERAI_API_KEY"] = temporary_key return - -invalid_auth(test_model) - # Test 3: Rate Limit Errors # def test_model_call(model): # try: diff --git a/litellm/utils.py b/litellm/utils.py index 806abb63c1..aae4d7f277 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -144,9 +144,10 @@ class Logging: self.litellm_call_id = litellm_call_id self.function_id = function_id - def update_environment_variables(self, model, optional_params, litellm_params): + def update_environment_variables(self, model, user, optional_params, litellm_params): self.optional_params = optional_params self.model = model + self.user = user self.litellm_params = litellm_params self.logger_fn = litellm_params["logger_fn"] print_verbose(f"self.optional_params: {self.optional_params}") @@ -298,19 +299,22 @@ class Logging: for callback in litellm.success_callback: try: if callback == "lite_debugger": - print_verbose("reaches lite_debugger for logging!") - print_verbose(f"liteDebuggerClient: {liteDebuggerClient}") - print_verbose(f"liteDebuggerClient details function {self.call_type} and stream set to {self.stream}") - liteDebuggerClient.log_event( - end_user=litellm._thread_context.user, - response_obj=result, - start_time=start_time, - end_time=end_time, - litellm_call_id=self.litellm_call_id, - print_verbose=print_verbose, - call_type = self.call_type, - stream = self.stream, - ) + print_verbose("reaches lite_debugger for logging!") + print_verbose(f"liteDebuggerClient: {liteDebuggerClient}") + print_verbose(f"liteDebuggerClient details function {self.call_type} and stream set to {self.stream}") + liteDebuggerClient.log_event( + end_user=litellm._thread_context.user, + response_obj=result, + start_time=start_time, + end_time=end_time, + litellm_call_id=self.litellm_call_id, + print_verbose=print_verbose, + call_type = self.call_type, + stream = self.stream, + ) + if callback == "api_manager": + print_verbose("reaches api manager for updating model cost") + litellm.apiManager.update_cost(completion_obj=result, user=self.user) if callback == "cache": # print("entering logger first time") # print(self.litellm_params["stream_response"]) diff --git a/pyproject.toml b/pyproject.toml index 97841cd08e..43825a9146 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "litellm" -version = "0.1.576" +version = "0.1.577" description = "Library to easily interface with LLM API providers" authors = ["BerriAI"] license = "MIT License"