diff --git a/litellm/proxy/_experimental/out/404.html b/litellm/proxy/_experimental/out/404.html
index 554dcf93ae5..687a52941c0 100644
--- a/litellm/proxy/_experimental/out/404.html
+++ b/litellm/proxy/_experimental/out/404.html
@@ -1 +1 @@
-
404: This page could not be found.🚅 LiteLLM404
This page could not be found.
\ No newline at end of file
+404: This page could not be found.🚅 LiteLLM404
This page could not be found.
\ No newline at end of file
diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/app/page-cc9d300e3b13fc1b.js b/litellm/proxy/_experimental/out/_next/static/chunks/app/page-cc9d300e3b13fc1b.js
new file mode 100644
index 00000000000..7f6ada01e1a
--- /dev/null
+++ b/litellm/proxy/_experimental/out/_next/static/chunks/app/page-cc9d300e3b13fc1b.js
@@ -0,0 +1 @@
+(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[931],{79615:function(e,t,s){Promise.resolve().then(s.bind(s,24143))},24143:function(e,t,s){"use strict";s.r(t),s.d(t,{default:function(){return eS}});var l=s(3827),n=s(64090),r=s(47907),a=s(8792),o=s(2179),i=e=>{let{userID:t,userRole:s,userEmail:n,showSSOBanner:r}=e;return console.log("User ID:",t),console.log("userEmail:",n),(0,l.jsxs)("nav",{className:"left-0 right-0 top-0 flex justify-between items-center h-12 mb-4",children:[(0,l.jsx)("div",{className:"text-left my-2 absolute top-0 left-0",children:(0,l.jsx)("div",{className:"flex flex-col items-center",children:(0,l.jsx)(a.default,{href:"/",children:(0,l.jsx)("button",{className:"text-gray-800 text-2xl py-1 rounded text-center",children:(0,l.jsx)("img",{src:"/get_image",width:200,height:200,alt:"LiteLLM Brand",className:"mr-2"})})})})}),(0,l.jsxs)("div",{className:"text-right mx-4 my-2 absolute top-0 right-0 flex items-center justify-end space-x-2",children:[r?(0,l.jsx)("a",{href:"https://docs.litellm.ai/docs/proxy/ui#setup-ssoauth-for-ui",target:"_blank",className:"mr-2",children:(0,l.jsx)(o.Z,{variant:"primary",size:"lg",children:"Enable SSO"})}):null,(0,l.jsxs)(o.Z,{variant:"secondary",size:"lg",children:[n,(0,l.jsxs)("p",{children:["Role: ",s]}),(0,l.jsxs)("p",{children:["ID: ",t]})]})]})]})},c=s(80588);let d=async(e,t,s)=>{try{if(console.log("Form Values in keyCreateCall:",s),s.description&&(s.metadata||(s.metadata={}),s.metadata.description=s.description,delete s.description,s.metadata=JSON.stringify(s.metadata)),s.metadata){console.log("formValues.metadata:",s.metadata);try{s.metadata=JSON.parse(s.metadata)}catch(e){throw c.ZP.error("Failed to parse metadata: "+e),Error("Failed to parse metadata: "+e)}}console.log("Form Values after check:",s);let l=await fetch("/key/generate",{method:"POST",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({user_id:t,...s})});if(!l.ok){let e=await l.text();throw c.ZP.error("Failed to create key: "+e),console.error("Error response from the server:",e),Error("Network response was not ok")}let n=await l.json();return console.log("API Response:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},h=async(e,t,s)=>{try{if(console.log("Form Values in keyCreateCall:",s),s.description&&(s.metadata||(s.metadata={}),s.metadata.description=s.description,delete s.description,s.metadata=JSON.stringify(s.metadata)),s.metadata){console.log("formValues.metadata:",s.metadata);try{s.metadata=JSON.parse(s.metadata)}catch(e){throw c.ZP.error("Failed to parse metadata: "+e),Error("Failed to parse metadata: "+e)}}console.log("Form Values after check:",s);let l=await fetch("/user/new",{method:"POST",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({user_id:t,...s})});if(!l.ok){let e=await l.text();throw c.ZP.error("Failed to create key: "+e),console.error("Error response from the server:",e),Error("Network response was not ok")}let n=await l.json();return console.log("API Response:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},m=async(e,t)=>{try{console.log("in keyDeleteCall:",t),c.ZP.info("Making key delete request");let s=await fetch("/key/delete",{method:"POST",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({keys:[t]})});if(!s.ok){let e=await s.text();throw c.ZP.error("Failed to delete key: "+e),Error("Network response was not ok")}let l=await s.json();return console.log(l),c.ZP.success("API Key Deleted"),l}catch(e){throw console.error("Failed to create key:",e),e}},u=async function(e,t,s){let l=arguments.length>3&&void 0!==arguments[3]&&arguments[3];try{let n="/user/info";"App Owner"==s&&t&&(n="".concat(n,"/?user_id=").concat(t)),console.log("in userInfoCall viewAll=",l),l&&(n="".concat(n,"/?view_all=true")),c.ZP.info("Requesting user data");let r=await fetch(n,{method:"GET",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw c.ZP.error(e),Error("Network response was not ok")}let a=await r.json();return console.log("API Response:",a),c.ZP.info("Received user data"),a}catch(e){throw console.error("Failed to create key:",e),e}},x=async(e,t,s)=>{try{c.ZP.info("Requesting model data");let t=await fetch("/v2/model/info",{method:"GET",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!t.ok){let e=await t.text();throw c.ZP.error(e),Error("Network response was not ok")}let s=await t.json();return c.ZP.info("Received model data"),s}catch(e){throw console.error("Failed to create key:",e),e}},p=async(e,t,s)=>{try{c.ZP.info("Requesting model data");let t=await fetch("/models",{method:"GET",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!t.ok){let e=await t.text();throw c.ZP.error(e),Error("Network response was not ok")}let s=await t.json();return c.ZP.info("Received model data"),s}catch(e){throw console.error("Failed to create key:",e),e}},j=async(e,t)=>{try{let s="/spend/logs";console.log("in keySpendLogsCall:",s);let l=await fetch("".concat(s,"/?api_key=").concat(t),{method:"GET",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!l.ok){let e=await l.text();throw c.ZP.error(e),Error("Network response was not ok")}let n=await l.json();return console.log(n),n}catch(e){throw console.error("Failed to create key:",e),e}},g=async(e,t,s,l,n,r)=>{try{if(console.log("user role in spend logs call: ".concat(s)),"Admin"==s)return await Z(e);let t="/spend/logs";t="App Owner"==s?"".concat(t,"/?user_id=").concat(l,"&start_date=").concat(n,"&end_date=").concat(r):"".concat(t,"/?start_date=").concat(n,"&end_date=").concat(r),c.ZP.info("Making spend logs request");let a=await fetch(t,{method:"GET",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!a.ok){let e=await a.text();throw c.ZP.error(e),Error("Network response was not ok")}let o=await a.json();return console.log(o),c.ZP.success("Spend Logs received"),o}catch(e){throw console.error("Failed to create key:",e),e}},Z=async e=>{try{c.ZP.info("Making spend logs request");let t=await fetch("/global/spend/logs",{method:"GET",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!t.ok){let e=await t.text();throw c.ZP.error(e),Error("Network response was not ok")}let s=await t.json();return console.log(s),c.ZP.success("Spend Logs received"),s}catch(e){throw console.error("Failed to create key:",e),e}},y=async(e,t)=>{try{let s="/spend/users";console.log("in spendUsersCall:",s);let l=await fetch("".concat(s,"/?user_id=").concat(t),{method:"GET",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!l.ok){let e=await l.text();throw c.ZP.error(e),Error("Network response was not ok")}let n=await l.json();return console.log(n),n}catch(e){throw console.error("Failed to get spend for user",e),e}},f=async(e,t,s,l)=>{try{let n=await fetch("/user/request_model",{method:"POST",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({models:[t],user_id:s,justification:l})});if(!n.ok){let e=await n.text();throw c.ZP.error("Failed to delete key: "+e),Error("Network response was not ok")}let r=await n.json();return console.log(r),c.ZP.success(""),r}catch(e){throw console.error("Failed to create key:",e),e}},w=async e=>{try{let t="/user/get_requests";console.log("in userGetRequesedtModelsCall:",t);let s=await fetch(t,{method:"GET",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!s.ok){let e=await s.text();throw c.ZP.error("Failed to delete key: "+e),Error("Network response was not ok")}let l=await s.json();return console.log(l),c.ZP.success(""),l}catch(e){throw console.error("Failed to get requested models:",e),e}},k=async(e,t)=>{try{console.log("Form Values in teamCreateCall:",t);let s=await fetch("/team/new",{method:"POST",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!s.ok){let e=await s.text();throw c.ZP.error("Failed to create key: "+e),console.error("Error response from the server:",e),Error("Network response was not ok")}let l=await s.json();return console.log("API Response:",l),l}catch(e){throw console.error("Failed to create key:",e),e}},_=async(e,t,s)=>{try{console.log("Form Values in teamMemberAddCall:",s);let l=await fetch("/team/member_add",{method:"POST",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({team_id:t,member:s})});if(!l.ok){let e=await l.text();throw c.ZP.error("Failed to create key: "+e),console.error("Error response from the server:",e),Error("Network response was not ok")}let n=await l.json();return console.log("API Response:",n),n}catch(e){throw console.error("Failed to create key:",e),e}};var b=s(10384),v=s(46453),S=s(71801),N=s(17189),I=s(12143),C=s(77171),A=s(42539),T=s(88707),P=s(1861);let{Option:E}=N.default;var D=e=>{let{userID:t,teamID:s,userRole:r,accessToken:a,data:i,userModels:h,setData:m}=e,[u]=I.Z.useForm(),[x,p]=(0,n.useState)(!1),[j,g]=(0,n.useState)(null),Z=()=>{p(!1),u.resetFields()},y=()=>{p(!1),g(null),u.resetFields()},f=async e=>{try{c.ZP.info("Making API Call"),p(!0);let s=await d(a,t,e);m(e=>e?[...e,s]:[s]),g(s.key),c.ZP.success("API Key Created"),u.resetFields(),localStorage.removeItem("userData"+t)}catch(e){console.error("Error creating the key:",e)}};return(0,l.jsxs)("div",{children:[(0,l.jsx)(o.Z,{className:"mx-auto",onClick:()=>p(!0),children:"+ Create New Key"}),(0,l.jsx)(C.Z,{title:"Create Key",visible:x,width:800,footer:null,onOk:Z,onCancel:y,children:(0,l.jsxs)(I.Z,{form:u,onFinish:f,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",children:["App Owner"===r||"Admin"===r?(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(I.Z.Item,{label:"Key Name",name:"key_alias",children:(0,l.jsx)(A.Z,{})}),(0,l.jsx)(I.Z.Item,{label:"Team ID",name:"team_id",children:(0,l.jsx)(A.Z,{placeholder:"ai_team",defaultValue:s||""})}),(0,l.jsx)(I.Z.Item,{label:"Models",name:"models",children:(0,l.jsx)(N.default,{mode:"multiple",placeholder:"Select models",style:{width:"100%"},children:h.map(e=>(0,l.jsx)(E,{value:e,children:e},e))})}),(0,l.jsx)(I.Z.Item,{label:"Max Budget (USD)",name:"max_budget",children:(0,l.jsx)(T.Z,{step:.01,precision:2,width:200})}),(0,l.jsx)(I.Z.Item,{label:"Reset Budget",name:"budget_duration",children:(0,l.jsxs)(N.default,{defaultValue:null,placeholder:"n/a",children:[(0,l.jsx)(N.default.Option,{value:"24h",children:"daily"}),(0,l.jsx)(N.default.Option,{value:"30d",children:"monthly"})]})}),(0,l.jsx)(I.Z.Item,{label:"Tokens per minute Limit (TPM)",name:"tpm_limit",children:(0,l.jsx)(T.Z,{step:1,width:400})}),(0,l.jsx)(I.Z.Item,{label:"Requests per minute Limit (RPM)",name:"rpm_limit",children:(0,l.jsx)(T.Z,{step:1,width:400})}),(0,l.jsx)(I.Z.Item,{label:"Expire Key (eg: 30s, 30h, 30d)",name:"duration",children:(0,l.jsx)(A.Z,{})}),(0,l.jsx)(I.Z.Item,{label:"Metadata",name:"metadata",children:(0,l.jsx)(A.Z.TextArea,{rows:4,placeholder:"Enter metadata as JSON"})})]}):(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(I.Z.Item,{label:"Key Name",name:"key_alias",children:(0,l.jsx)(A.Z,{})}),(0,l.jsx)(I.Z.Item,{label:"Team ID (Contact Group)",name:"team_id",children:(0,l.jsx)(A.Z,{placeholder:"ai_team"})}),(0,l.jsx)(I.Z.Item,{label:"Description",name:"description",children:(0,l.jsx)(A.Z.TextArea,{placeholder:"Enter description",rows:4})})]}),(0,l.jsx)("div",{style:{textAlign:"right",marginTop:"10px"},children:(0,l.jsx)(P.ZP,{htmlType:"submit",children:"Create Key"})})]})}),j&&(0,l.jsx)(C.Z,{title:"Save your key",visible:x,onOk:Z,onCancel:y,footer:null,children:(0,l.jsxs)(v.Z,{numItems:1,className:"gap-2 w-full",children:[(0,l.jsx)(b.Z,{numColSpan:1,children:(0,l.jsxs)("p",{children:["Please save this secret key somewhere safe and accessible. For security reasons, ",(0,l.jsx)("b",{children:"you will not be able to view it again"})," ","through your LiteLLM account. If you lose this secret key, you will need to generate a new one."]})}),(0,l.jsx)(b.Z,{numColSpan:1,children:null!=j?(0,l.jsxs)(S.Z,{children:["API Key: ",j]}):(0,l.jsx)(S.Z,{children:"Key being created, this might take 30s"})})]})})]})},F=s(33393),M=s(13810),R=s(61244),O=s(10827),U=s(3851),L=s(2044),z=s(64167),q=s(74480),B=s(7178),K=s(9853),J=s(67989),V=s(56863),G=s(42440),$=e=>{let{token:t,accessToken:s,keySpend:r,keyBudget:a,keyName:i}=e,[c,d]=(0,n.useState)(!1),[h,m]=(0,n.useState)(null),[u,x]=(0,n.useState)(null),p=async()=>{try{if(null==s||null==t)return;console.log("accessToken: ".concat(s,"; token: ").concat(t));let e=await j(s,t);console.log("Response:",e);let l=Object.values(e).reduce((e,t)=>{let s=new Date(t.startTime),l=new Intl.DateTimeFormat("en-US",{day:"2-digit",month:"short"}).format(s);return e[l]=(e[l]||0)+t.spend,e},{}),n=Object.entries(l);n.sort((e,t)=>{let[s]=e,[l]=t,n=new Date(s),r=new Date(l);return n.getTime()-r.getTime()});let r=Object.fromEntries(n);console.log(r);let a=Object.values(e).reduce((e,t)=>{let s=t.user;return e[s]=(e[s]||0)+t.spend,e},{});console.log(l),console.log(a);let o=[];for(let[e,t]of Object.entries(r))o.push({day:e,spend:t});let i=Object.entries(a).sort((e,t)=>t[1]-e[1]).slice(0,5).map(e=>{let[t,s]=e;return{name:t,value:s}});m(o),x(i),console.log("arrayBarChart:",o)}catch(e){console.error("There was an error fetching the data",e)}};return t?(0,l.jsxs)("div",{children:[(0,l.jsx)(o.Z,{className:"mx-auto",onClick:()=>{console.log("Show Modal triggered"),d(!0),p()},children:"View Spend Report"}),(0,l.jsxs)(C.Z,{visible:c,width:1e3,onOk:()=>{d(!1)},onCancel:()=>{d(!1)},footer:null,children:[(0,l.jsxs)(G.Z,{style:{textAlign:"left"},children:["Key Name: ",i]}),(0,l.jsxs)(V.Z,{children:["Monthly Spend $",r]}),(0,l.jsx)(M.Z,{className:"mt-6 mb-6",children:h&&(0,l.jsx)(K.Z,{className:"mt-6",data:h,colors:["green"],index:"day",categories:["spend"],yAxisWidth:48})}),(0,l.jsx)(G.Z,{className:"mt-6",children:"Top 5 Users Spend (USD)"}),(0,l.jsx)(M.Z,{className:"mb-6",children:u&&(0,l.jsx)(J.Z,{className:"mt-6",data:u,color:"teal"})})]})]}):null},Y=e=>{let{userID:t,accessToken:s,data:r,setData:a}=e,[i,c]=(0,n.useState)(!1),[d,h]=(0,n.useState)(!1),[u,x]=(0,n.useState)(null),p=async e=>{null!=r&&(x(e),localStorage.removeItem("userData"+t),h(!0))},j=async()=>{if(null!=u&&null!=r){try{await m(s,u);let e=r.filter(e=>e.token!==u);a(e)}catch(e){console.error("Error deleting the key:",e)}h(!1),x(null)}};if(null!=r)return console.log("RERENDER TRIGGERED"),(0,l.jsxs)(M.Z,{className:"w-full mx-auto flex-auto overflow-y-auto max-h-[50vh] mb-4",children:[(0,l.jsxs)(O.Z,{className:"mt-5",children:[(0,l.jsx)(z.Z,{children:(0,l.jsxs)(B.Z,{children:[(0,l.jsx)(q.Z,{children:"Key Alias"}),(0,l.jsx)(q.Z,{children:"Secret Key"}),(0,l.jsx)(q.Z,{children:"Spend (USD)"}),(0,l.jsx)(q.Z,{children:"Key Budget (USD)"}),(0,l.jsx)(q.Z,{children:"Team ID"}),(0,l.jsx)(q.Z,{children:"Metadata"}),(0,l.jsx)(q.Z,{children:"Models"}),(0,l.jsx)(q.Z,{children:"TPM / RPM Limits"}),(0,l.jsx)(q.Z,{children:"Expires"})]})}),(0,l.jsx)(U.Z,{children:r.map(e=>(console.log(e),"litellm-dashboard"===e.team_id)?null:(0,l.jsxs)(B.Z,{children:[(0,l.jsx)(L.Z,{children:null!=e.key_alias?(0,l.jsx)(S.Z,{children:e.key_alias}):(0,l.jsx)(S.Z,{children:"Not Set"})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(S.Z,{children:e.key_name})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(S.Z,{children:e.spend})}),(0,l.jsx)(L.Z,{children:null!=e.max_budget?(0,l.jsx)(S.Z,{children:e.max_budget}):(0,l.jsx)(S.Z,{children:"Unlimited Budget"})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(S.Z,{children:e.team_id})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(S.Z,{children:JSON.stringify(e.metadata)})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(S.Z,{children:JSON.stringify(e.models)})}),(0,l.jsx)(L.Z,{children:(0,l.jsxs)(S.Z,{children:["TPM Limit: ",e.tpm_limit?e.tpm_limit:"Unlimited"," ",(0,l.jsx)("br",{})," RPM Limit:"," ",e.rpm_limit?e.rpm_limit:"Unlimited"]})}),(0,l.jsx)(L.Z,{children:null!=e.expires?(0,l.jsx)(S.Z,{children:e.expires}):(0,l.jsx)(S.Z,{children:"Never expires"})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(R.Z,{onClick:()=>p(e.token),icon:F.Z,size:"sm"})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)($,{token:e.token,accessToken:s,keySpend:e.spend,keyBudget:e.max_budget,keyName:e.key_name})})]},e.token))})]}),d&&(0,l.jsx)("div",{className:"fixed z-10 inset-0 overflow-y-auto",children:(0,l.jsxs)("div",{className:"flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0",children:[(0,l.jsx)("div",{className:"fixed inset-0 transition-opacity","aria-hidden":"true",children:(0,l.jsx)("div",{className:"absolute inset-0 bg-gray-500 opacity-75"})}),(0,l.jsx)("span",{className:"hidden sm:inline-block sm:align-middle sm:h-screen","aria-hidden":"true",children:"​"}),(0,l.jsxs)("div",{className:"inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full",children:[(0,l.jsx)("div",{className:"bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4",children:(0,l.jsx)("div",{className:"sm:flex sm:items-start",children:(0,l.jsxs)("div",{className:"mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left",children:[(0,l.jsx)("h3",{className:"text-lg leading-6 font-medium text-gray-900",children:"Delete Key"}),(0,l.jsx)("div",{className:"mt-2",children:(0,l.jsx)("p",{className:"text-sm text-gray-500",children:"Are you sure you want to delete this key ?"})})]})})}),(0,l.jsxs)("div",{className:"bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse",children:[(0,l.jsx)(o.Z,{onClick:j,color:"red",className:"ml-2",children:"Delete"}),(0,l.jsx)(o.Z,{onClick:()=>{h(!1),x(null)},children:"Cancel"})]})]})]})})]})},W=e=>{let{userID:t,userSpendData:s,userRole:r,accessToken:a}=e;console.log("User SpendData:",s);let[o,i]=(0,n.useState)(null==s?void 0:s.spend),[c,d]=(0,n.useState)((null==s?void 0:s.max_budget)||null);return(0,n.useEffect)(()=>{(async()=>{if("Admin"===r)try{let e=await y(a,"litellm-proxy-budget");console.log("Result from callSpendUsers:",e);let t=e[0];i(null==t?void 0:t.spend),d((null==t?void 0:t.max_budget)||null)}catch(e){console.error("Failed to get spend for user",e)}})()},[r,a,t]),(0,l.jsx)(l.Fragment,{children:(0,l.jsxs)(M.Z,{className:"mx-auto mb-4",children:[(0,l.jsxs)(V.Z,{children:["$",o]}),(0,l.jsxs)(G.Z,{children:["/ ",null!==c?"$".concat(c," limit"):"No limit"]})]})})},H=s(36083),X=s(68967),Q=s(27166),ee=e=>{let{teams:t,setSelectedTeam:s}=e,{Title:r,Paragraph:a}=H.default,[o,i]=(0,n.useState)("");return(0,l.jsxs)("div",{className:"mt-10",children:[(0,l.jsx)(r,{level:4,children:"Default Team"}),(0,l.jsx)(a,{children:"If you belong to multiple teams, this setting controls which team is used by default when creating new API Keys."}),t&&t.length>0?(0,l.jsx)(X.Z,{defaultValue:"0",children:t.map((e,t)=>(0,l.jsx)(Q.Z,{value:String(t),onClick:()=>s(e),children:e.team_alias},t))}):(0,l.jsxs)(a,{children:["No team created. ",(0,l.jsx)("b",{children:"Defaulting to personal account."})]})]})},et=s(37963);console.log("isLocal:",!1);var es=e=>{let{userID:t,userRole:s,teams:a,setUserRole:o,userEmail:i,setUserEmail:c,setTeams:d}=e,[h,m]=(0,n.useState)(null),[x,j]=(0,n.useState)(null),g=(0,r.useSearchParams)();g.get("viewSpend"),(0,r.useRouter)();let Z=g.get("token"),[y,f]=(0,n.useState)(null),[w,k]=(0,n.useState)([]),[_,S]=(0,n.useState)(a?a[0]:null);if(window.addEventListener("beforeunload",function(){sessionStorage.clear()}),(0,n.useEffect)(()=>{if(Z){let e=(0,et.o)(Z);if(e){if(console.log("Decoded token:",e),console.log("Decoded key:",e.key),f(e.key),e.user_role){let t=function(e){if(!e)return"Undefined Role";switch(console.log("Received user role: ".concat(e)),e.toLowerCase()){case"app_owner":case"demo_app_owner":return"App Owner";case"app_admin":return"Admin";case"app_user":return"App User";default:return"Unknown Role"}}(e.user_role);console.log("Decoded user_role:",t),o(t)}else console.log("User role not defined");e.user_email?c(e.user_email):console.log("User Email is not set ".concat(e))}}if(t&&y&&s&&!h){let e=sessionStorage.getItem("userModels"+t);e?k(JSON.parse(e)):(async()=>{try{let e=await u(y,t,s);console.log("received teams in user dashboard: ".concat(Object.keys(e),"; team values: ").concat(Object.entries(e.teams))),j(e.user_info),m(e.keys),d(e.teams),S(e.teams?e.teams[0]:null),sessionStorage.setItem("userData"+t,JSON.stringify(e.keys)),sessionStorage.setItem("userSpendData"+t,JSON.stringify(e.user_info));let l=(await p(y,t,s)).data.map(e=>e.id);console.log("available_model_names:",l),k(l),console.log("userModels:",w),sessionStorage.setItem("userModels"+t,JSON.stringify(l))}catch(e){console.error("There was an error fetching the data",e)}})()}},[t,Z,y,h,s]),null==t||null==Z){let e="/sso/key/generate";return console.log("Full URL:",e),window.location.href=e,null}return null==y?null:(null==s&&o("App Owner"),(0,l.jsx)("div",{children:(0,l.jsx)(v.Z,{numItems:1,className:"gap-0 p-10 h-[75vh] w-full",children:(0,l.jsxs)(b.Z,{numColSpan:1,children:[(0,l.jsx)(W,{userID:t,userSpendData:x,userRole:s,accessToken:y}),(0,l.jsx)(Y,{userID:t,accessToken:y,data:h,setData:m}),(0,l.jsx)(D,{userID:t,teamID:_?_.team_id:null,userRole:s,userModels:w,accessToken:y,data:h,setData:m}),(0,l.jsx)(ee,{teams:a,setSelectedTeam:S})]})})}))},el=s(5);let{Option:en}=N.default;var er=e=>{let{userModels:t,accessToken:s,userID:r}=e,[a]=I.Z.useForm(),[i,d]=(0,n.useState)(!1),h=async e=>{try{c.ZP.info("Requesting access");let{selectedModel:t,accessReason:l}=e;await f(s,t,r,l),d(!0)}catch(e){console.error("Error requesting access:",e)}};return(0,l.jsxs)("div",{children:[(0,l.jsx)(o.Z,{size:"xs",onClick:()=>d(!0),children:"Request Access"}),(0,l.jsx)(C.Z,{title:"Request Access",visible:i,width:800,footer:null,onOk:()=>{d(!1),a.resetFields()},onCancel:()=>{d(!1),a.resetFields()},children:(0,l.jsxs)(I.Z,{form:a,onFinish:h,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",children:[(0,l.jsx)(I.Z.Item,{label:"Select Model",name:"selectedModel",children:(0,l.jsx)(N.default,{placeholder:"Select model",style:{width:"100%"},children:t.map(e=>(0,l.jsx)(en,{value:e,children:e},e))})}),(0,l.jsx)(I.Z.Item,{label:"Reason for Access",name:"accessReason",children:(0,l.jsx)(A.Z.TextArea,{rows:4,placeholder:"Enter reason for access"})}),(0,l.jsx)("div",{style:{textAlign:"right",marginTop:"10px"},children:(0,l.jsx)(o.Z,{children:"Request Access"})})]})})]})},ea=e=>{let{accessToken:t,token:s,userRole:r,userID:a}=e,[i,c]=(0,n.useState)({data:[]}),[d,h]=(0,n.useState)([]);if((0,n.useEffect)(()=>{if(!t||!s||!r||!a)return;let e=async()=>{try{let e=await x(t,a,r);if(console.log("Model data response:",e.data),c(e),"Admin"===r&&t){let e=await w(t);console.log("Pending Requests:",d),h(e.requests||[])}}catch(e){console.error("There was an error fetching the model data",e)}};t&&s&&r&&a&&e()},[t,s,r,a]),!i||!t||!s||!r||!a)return(0,l.jsx)("div",{children:"Loading..."});let m=[];for(let e=0;e(0,l.jsxs)(B.Z,{children:[(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:e.model_name})}),(0,l.jsx)(L.Z,{children:e.provider}),(0,l.jsx)(L.Z,{children:e.user_access?(0,l.jsx)(el.Z,{color:"green",children:"Yes"}):(0,l.jsx)(er,{userModels:m,accessToken:t,userID:a})}),(0,l.jsx)(L.Z,{children:e.input_cost}),(0,l.jsx)(L.Z,{children:e.output_cost}),(0,l.jsx)(L.Z,{children:e.max_tokens})]},e.model_name))})]})}),"Admin"===r&&d&&d.length>0?(0,l.jsx)(M.Z,{children:(0,l.jsxs)(O.Z,{children:[(0,l.jsxs)(z.Z,{children:[(0,l.jsx)(G.Z,{children:"Pending Requests"}),(0,l.jsxs)(B.Z,{children:[(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:"User ID"})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:"Requested Models"})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:"Justification"})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:"Justification"})})]})]}),(0,l.jsx)(U.Z,{children:d.map(e=>(0,l.jsxs)(B.Z,{children:[(0,l.jsx)(L.Z,{children:(0,l.jsx)("p",{children:e.user_id})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)("p",{children:e.models[0]})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)("p",{children:e.justification})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)("p",{children:e.user_id})}),(0,l.jsx)(o.Z,{children:"Approve"}),(0,l.jsx)(o.Z,{variant:"secondary",className:"ml-2",children:"Deny"})]},e.request_id))})]})}):null]})})};let{Option:eo}=N.default;var ei=e=>{let{userID:t,accessToken:s}=e,[r]=I.Z.useForm(),[a,i]=(0,n.useState)(!1),[d,m]=(0,n.useState)(null),[u,x]=(0,n.useState)([]);(0,n.useEffect)(()=>{(async()=>{try{let e=await p(s,t,"any"),l=[];for(let t=0;t{i(!1),r.resetFields()},g=()=>{i(!1),m(null),r.resetFields()},Z=async e=>{try{c.ZP.info("Making API Call"),i(!0),console.log("formValues in create user:",e);let l=await h(s,t,e);console.log("user create Response:",l),m(l.key),c.ZP.success("API user Created"),r.resetFields(),localStorage.removeItem("userData"+t)}catch(e){console.error("Error creating the user:",e)}};return(0,l.jsxs)("div",{children:[(0,l.jsx)(o.Z,{className:"mx-auto",onClick:()=>i(!0),children:"+ Create New User"}),(0,l.jsx)(C.Z,{title:"Create User",visible:a,width:800,footer:null,onOk:j,onCancel:g,children:(0,l.jsxs)(I.Z,{form:r,onFinish:Z,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",children:[(0,l.jsx)(I.Z.Item,{label:"User ID",name:"user_id",children:(0,l.jsx)(A.Z,{placeholder:"Enter User ID"})}),(0,l.jsx)(I.Z.Item,{label:"Team ID",name:"team_id",children:(0,l.jsx)(A.Z,{placeholder:"ai_team"})}),(0,l.jsx)(I.Z.Item,{label:"Models",name:"models",children:(0,l.jsx)(N.default,{mode:"multiple",placeholder:"Select models",style:{width:"100%"},children:u.map(e=>(0,l.jsx)(eo,{value:e,children:e},e))})}),(0,l.jsx)(I.Z.Item,{label:"Max Budget (USD)",name:"max_budget",children:(0,l.jsx)(T.Z,{step:.01,precision:2,width:200})}),(0,l.jsx)(I.Z.Item,{label:"Tokens per minute Limit (TPM)",name:"tpm_limit",children:(0,l.jsx)(T.Z,{step:1,width:400})}),(0,l.jsx)(I.Z.Item,{label:"Requests per minute Limit (RPM)",name:"rpm_limit",children:(0,l.jsx)(T.Z,{step:1,width:400})}),(0,l.jsx)(I.Z.Item,{label:"Duration (eg: 30s, 30h, 30d)",name:"duration",children:(0,l.jsx)(A.Z,{})}),(0,l.jsx)(I.Z.Item,{label:"Metadata",name:"metadata",children:(0,l.jsx)(A.Z.TextArea,{rows:4,placeholder:"Enter metadata as JSON"})}),(0,l.jsx)("div",{style:{textAlign:"right",marginTop:"10px"},children:(0,l.jsx)(P.ZP,{htmlType:"submit",children:"Create User"})})]})}),d&&(0,l.jsxs)(C.Z,{title:"Save Your User",visible:a,onOk:j,onCancel:g,footer:null,children:[(0,l.jsxs)("p",{children:["Please save this secret user somewhere safe and accessible. For security reasons, ",(0,l.jsx)("b",{children:"you will not be able to view it again"})," ","through your LiteLLM account. If you lose this secret user, you will need to generate a new one."]}),(0,l.jsx)("p",{children:null!=d?"API user: ".concat(d):"User being created, this might take 30s"})]})]})},ec=e=>{let{accessToken:t,token:s,userRole:r,userID:a}=e,[o,i]=(0,n.useState)(null),[c,d]=(0,n.useState)([]);return((0,n.useEffect)(()=>{if(!t||!s||!r||!a)return;let e=async()=>{try{let e=await u(t,null,r,!0);console.log("user data response:",e),i(e)}catch(e){console.error("There was an error fetching the model data",e)}};t&&s&&r&&a&&e()},[t,s,r,a]),o&&t&&s&&r&&a)?(0,l.jsx)("div",{style:{width:"100%"},children:(0,l.jsxs)(v.Z,{className:"gap-2 p-10 h-[75vh] w-full",children:[(0,l.jsx)(ei,{userID:a,accessToken:t}),(0,l.jsx)(M.Z,{children:(0,l.jsxs)(O.Z,{className:"mt-5",children:[(0,l.jsx)(z.Z,{children:(0,l.jsxs)(B.Z,{children:[(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:"User ID "})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:"User Role"})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:"User Models"})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:"User Spend ($ USD)"})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:"User Max Budget ($ USD)"})})]})}),(0,l.jsx)(U.Z,{children:o.map(e=>(0,l.jsxs)(B.Z,{children:[(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:e.user_id})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:e.user_role?e.user_role:"app_user"})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:e.models&&e.models.length>0?e.models:"All Models"})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:e.spend?e.spend:0})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:e.max_budget?e.max_budget:"Unlimited"})})]},e.user_id))})]})})]})}):(0,l.jsx)("div",{children:"Loading..."})},ed=s(8510),eh=e=>{let{teams:t,searchParams:s,accessToken:r,setTeams:a}=e,[i]=I.Z.useForm(),[d]=I.Z.useForm(),{Title:h,Paragraph:m}=H.default,[u,x]=(0,n.useState)(""),[p,j]=(0,n.useState)(t?t[0]:null),[g,Z]=(0,n.useState)(!1),[y,f]=(0,n.useState)(!1),w=async e=>{try{if(null!=r){c.ZP.info("Making API Call");let s=await k(r,e);null!==t?a([...t,s]):a([s]),console.log("response for team create call: ".concat(s)),Z(!1)}}catch(e){console.error("Error creating the key:",e)}},E=async e=>{try{if(null!=r&&null!=t){c.ZP.info("Making API Call");let s={role:"user",user_email:e.user_email,user_id:e.user_id},l=await _(r,p.team_id,s);console.log("response for team create call: ".concat(l.data));let n=t.findIndex(e=>(console.log("team.team_id=".concat(e.team_id,"; response.data.team_id=").concat(l.data.team_id)),e.team_id===l.data.team_id));if(console.log("foundIndex: ".concat(n)),-1!==n){let e=[...t];e[n]=l.data,a(e),j(l.data)}f(!1)}}catch(e){console.error("Error creating the key:",e)}};return console.log("received teams ".concat(t)),(0,l.jsx)("div",{className:"w-full",children:(0,l.jsxs)(v.Z,{numItems:1,className:"gap-2 p-2 h-[75vh] w-full",children:[(0,l.jsxs)(b.Z,{numColSpan:1,children:[(0,l.jsx)(h,{level:4,children:"All Teams"}),(0,l.jsx)(M.Z,{className:"w-full mx-auto flex-auto overflow-y-auto max-h-[50vh]",children:(0,l.jsxs)(O.Z,{children:[(0,l.jsx)(z.Z,{children:(0,l.jsxs)(B.Z,{children:[(0,l.jsx)(q.Z,{children:"Team Name"}),(0,l.jsx)(q.Z,{children:"Spend (USD)"}),(0,l.jsx)(q.Z,{children:"Budget (USD)"}),(0,l.jsx)(q.Z,{children:"TPM / RPM Limits"})]})}),(0,l.jsx)(U.Z,{children:t&&t.length>0?t.map(e=>(0,l.jsxs)(B.Z,{children:[(0,l.jsx)(L.Z,{children:e.team_alias}),(0,l.jsx)(L.Z,{children:e.spend}),(0,l.jsx)(L.Z,{children:e.max_budget?e.max_budget:"No limit"}),(0,l.jsx)(L.Z,{children:(0,l.jsxs)(S.Z,{children:["TPM Limit:"," ",e.tpm_limit?e.tpm_limit:"Unlimited"," ",(0,l.jsx)("br",{})," RPM Limit:"," ",e.rpm_limit?e.rpm_limit:"Unlimited"]})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(R.Z,{icon:ed.Z,size:"sm"})})]},e.team_id)):null})]})})]}),(0,l.jsxs)(b.Z,{numColSpan:1,children:[(0,l.jsx)(o.Z,{className:"mx-auto",onClick:()=>Z(!0),children:"+ Create New Team"}),(0,l.jsx)(C.Z,{title:"Create Team",visible:g,width:800,footer:null,onOk:()=>{Z(!1),i.resetFields()},onCancel:()=>{Z(!1),i.resetFields()},children:(0,l.jsxs)(I.Z,{form:i,onFinish:w,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",children:[(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(I.Z.Item,{label:"Team Name",name:"team_alias",children:(0,l.jsx)(A.Z,{})}),(0,l.jsx)(I.Z.Item,{label:"Models",name:"models",children:(0,l.jsx)(N.default,{mode:"multiple",placeholder:"Select models",style:{width:"100%"}})}),(0,l.jsx)(I.Z.Item,{label:"Max Budget (USD)",name:"max_budget",children:(0,l.jsx)(T.Z,{step:.01,precision:2,width:200})}),(0,l.jsx)(I.Z.Item,{label:"Tokens per minute Limit (TPM)",name:"tpm_limit",children:(0,l.jsx)(T.Z,{step:1,width:400})}),(0,l.jsx)(I.Z.Item,{label:"Requests per minute Limit (RPM)",name:"rpm_limit",children:(0,l.jsx)(T.Z,{step:1,width:400})})]}),(0,l.jsx)("div",{style:{textAlign:"right",marginTop:"10px"},children:(0,l.jsx)(P.ZP,{htmlType:"submit",children:"Create Team"})})]})})]}),(0,l.jsxs)(b.Z,{numColSpan:1,children:[(0,l.jsx)(h,{level:4,children:"Team Members"}),(0,l.jsx)(m,{children:"If you belong to multiple teams, this setting controls which teams members you see."}),t&&t.length>0?(0,l.jsx)(X.Z,{defaultValue:"0",children:t.map((e,t)=>(0,l.jsx)(Q.Z,{value:String(t),onClick:()=>{j(e)},children:e.team_alias},t))}):(0,l.jsxs)(m,{children:["No team created. ",(0,l.jsx)("b",{children:"Defaulting to personal account."})]})]}),(0,l.jsx)(b.Z,{numColSpan:1,children:(0,l.jsx)(M.Z,{className:"w-full mx-auto flex-auto overflow-y-auto max-h-[50vh]",children:(0,l.jsxs)(O.Z,{children:[(0,l.jsx)(z.Z,{children:(0,l.jsxs)(B.Z,{children:[(0,l.jsx)(q.Z,{children:"Member Name"}),(0,l.jsx)(q.Z,{children:"Role"}),(0,l.jsx)(q.Z,{children:"Action"})]})}),(0,l.jsx)(U.Z,{children:p?p.members_with_roles.map((e,t)=>(0,l.jsxs)(B.Z,{children:[(0,l.jsx)(L.Z,{children:e.user_email?e.user_email:e.user_id?e.user_id:null}),(0,l.jsx)(L.Z,{children:e.role}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(R.Z,{icon:ed.Z,size:"sm"})})]},t)):null})]})})}),(0,l.jsxs)(b.Z,{numColSpan:1,children:[(0,l.jsx)(o.Z,{className:"mx-auto mb-5",onClick:()=>f(!0),children:"+ Add member"}),(0,l.jsx)(C.Z,{title:"Add member",visible:y,width:800,footer:null,onOk:()=>{f(!1),d.resetFields()},onCancel:()=>{f(!1),d.resetFields()},children:(0,l.jsxs)(I.Z,{form:i,onFinish:E,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",children:[(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(I.Z.Item,{label:"Email",name:"user_email",className:"mb-4",children:(0,l.jsx)(A.Z,{name:"user_email",className:"px-3 py-2 border rounded-md w-full"})}),(0,l.jsx)("div",{className:"text-center mb-4",children:"OR"}),(0,l.jsx)(I.Z.Item,{label:"User ID",name:"user_id",className:"mb-4",children:(0,l.jsx)(A.Z,{name:"user_id",className:"px-3 py-2 border rounded-md w-full"})})]}),(0,l.jsx)("div",{style:{textAlign:"right",marginTop:"10px"},children:(0,l.jsx)(P.ZP,{htmlType:"submit",children:"Add member"})})]})})]})]})})},em=s(92836),eu=s(26734),ex=s(41608),ep=s(32126),ej=s(23682),eg=s(12968),eZ=s(67951);async function ey(e,t,s,l){console.log("isLocal:",!1);let n=window.location.origin,r=new eg.ZP.OpenAI({apiKey:l,baseURL:n,dangerouslyAllowBrowser:!0});for await(let l of(await r.chat.completions.create({model:s,stream:!0,messages:[{role:"user",content:e}]})))console.log(l),l.choices[0].delta.content&&t(l.choices[0].delta.content)}var ef=e=>{let{accessToken:t,token:s,userRole:r,userID:a}=e,[o,i]=(0,n.useState)(""),[c,d]=(0,n.useState)([]),[h,m]=(0,n.useState)(void 0),[u,x]=(0,n.useState)(null);(0,n.useEffect)(()=>{t&&s&&r&&a&&(async()=>{let e=await p(t,a,r);console.log("model_info:",e),(null==e?void 0:e.data.length)>0&&(x(e.data),m(e.data[0].id))})()},[t,a,r]);let j=(e,t)=>{d(s=>{let l=s[s.length-1];return l&&l.role===e?[...s.slice(0,s.length-1),{role:e,content:l.content+t}]:[...s,{role:e,content:t}]})},g=async()=>{if(""!==o.trim()&&t&&s&&r&&a){d(e=>[...e,{role:"user",content:o}]);try{h&&await ey(o,e=>j("assistant",e),h,t)}catch(e){console.error("Error fetching model response",e),j("assistant","Error fetching model response")}i("")}};return(0,l.jsx)("div",{style:{width:"100%",position:"relative"},children:(0,l.jsx)(v.Z,{className:"gap-2 p-10 h-[75vh] w-full",children:(0,l.jsx)(M.Z,{children:(0,l.jsxs)(eu.Z,{children:[(0,l.jsxs)(ex.Z,{className:"mt-4",children:[(0,l.jsx)(em.Z,{children:"Chat"}),(0,l.jsx)(em.Z,{children:"API Reference"})]}),(0,l.jsxs)(ej.Z,{children:[(0,l.jsxs)(ep.Z,{children:[(0,l.jsxs)("div",{children:[(0,l.jsx)("label",{children:"Select Model:"}),(0,l.jsx)("select",{value:h||"",onChange:e=>m(e.target.value),children:null==u?void 0:u.map(e=>(0,l.jsx)("option",{value:e.id,children:e.id},e.id))})]}),(0,l.jsxs)(O.Z,{className:"mt-5",style:{display:"block",maxHeight:"60vh",overflowY:"auto"},children:[(0,l.jsx)(z.Z,{children:(0,l.jsx)(B.Z,{children:(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:"Chat"})})})}),(0,l.jsx)(U.Z,{children:c.map((e,t)=>(0,l.jsx)(B.Z,{children:(0,l.jsx)(L.Z,{children:"".concat(e.role,": ").concat(e.content)})},t))})]}),(0,l.jsx)("div",{className:"mt-3",style:{position:"absolute",bottom:5,width:"95%"},children:(0,l.jsxs)("div",{className:"flex",children:[(0,l.jsx)("input",{type:"text",value:o,onChange:e=>i(e.target.value),className:"flex-1 p-2 border rounded-md mr-2",placeholder:"Type your message..."}),(0,l.jsx)("button",{onClick:g,className:"p-2 bg-blue-500 text-white rounded-md",children:"Send"})]})})]}),(0,l.jsx)(ep.Z,{children:(0,l.jsxs)(eu.Z,{children:[(0,l.jsxs)(ex.Z,{children:[(0,l.jsx)(em.Z,{children:"OpenAI Python SDK"}),(0,l.jsx)(em.Z,{children:"LlamaIndex"}),(0,l.jsx)(em.Z,{children:"Langchain Py"})]}),(0,l.jsxs)(ej.Z,{children:[(0,l.jsx)(ep.Z,{children:(0,l.jsx)(eZ.Z,{language:"python",children:'\nimport openai\nclient = openai.OpenAI(\n api_key="your_api_key",\n base_url="http://0.0.0.0:4000" # proxy base url\n)\n\nresponse = client.chat.completions.create(\n model="gpt-3.5-turbo", # model to use from Models Tab\n messages = [\n {\n "role": "user",\n "content": "this is a test request, write a short poem"\n }\n ],\n extra_body={\n "metadata": {\n "generation_name": "ishaan-generation-openai-client",\n "generation_id": "openai-client-gen-id22",\n "trace_id": "openai-client-trace-id22",\n "trace_user_id": "openai-client-user-id2"\n }\n }\n)\n\nprint(response)\n '})}),(0,l.jsx)(ep.Z,{children:(0,l.jsx)(eZ.Z,{language:"python",children:'\nimport os, dotenv\n\nfrom llama_index.llms import AzureOpenAI\nfrom llama_index.embeddings import AzureOpenAIEmbedding\nfrom llama_index import VectorStoreIndex, SimpleDirectoryReader, ServiceContext\n\nllm = AzureOpenAI(\n engine="azure-gpt-3.5", # model_name on litellm proxy\n temperature=0.0,\n azure_endpoint="http://0.0.0.0:4000", # litellm proxy endpoint\n api_key="sk-1234", # litellm proxy API Key\n api_version="2023-07-01-preview",\n)\n\nembed_model = AzureOpenAIEmbedding(\n deployment_name="azure-embedding-model",\n azure_endpoint="http://0.0.0.0:4000",\n api_key="sk-1234",\n api_version="2023-07-01-preview",\n)\n\n\ndocuments = SimpleDirectoryReader("llama_index_data").load_data()\nservice_context = ServiceContext.from_defaults(llm=llm, embed_model=embed_model)\nindex = VectorStoreIndex.from_documents(documents, service_context=service_context)\n\nquery_engine = index.as_query_engine()\nresponse = query_engine.query("What did the author do growing up?")\nprint(response)\n\n '})}),(0,l.jsx)(ep.Z,{children:(0,l.jsx)(eZ.Z,{language:"python",children:'\nfrom langchain.chat_models import ChatOpenAI\nfrom langchain.prompts.chat import (\n ChatPromptTemplate,\n HumanMessagePromptTemplate,\n SystemMessagePromptTemplate,\n)\nfrom langchain.schema import HumanMessage, SystemMessage\n\nchat = ChatOpenAI(\n openai_api_base="http://0.0.0.0:8000",\n model = "gpt-3.5-turbo",\n temperature=0.1,\n extra_body={\n "metadata": {\n "generation_name": "ishaan-generation-langchain-client",\n "generation_id": "langchain-client-gen-id22",\n "trace_id": "langchain-client-trace-id22",\n "trace_user_id": "langchain-client-user-id2"\n }\n }\n)\n\nmessages = [\n SystemMessage(\n content="You are a helpful assistant that im using to make a test request to."\n ),\n HumanMessage(\n content="test from litellm. tell me why it\'s amazing in 1 sentence"\n ),\n]\nresponse = chat(messages)\n\nprint(response)\n\n '})})]})]})})]})]})})})})},ew=s(33509),ek=s(30569);let{Sider:e_}=ew.default;var eb=e=>{let{setPage:t,userRole:s,defaultSelectedKey:n}=e;return(0,l.jsx)(ew.default,{style:{minHeight:"100vh",maxWidth:"120px"},children:(0,l.jsx)(e_,{width:120,children:(0,l.jsxs)(ek.Z,{mode:"inline",defaultSelectedKeys:n||["1"],style:{height:"100%",borderRight:0},children:[(0,l.jsx)(ek.Z.Item,{onClick:()=>t("api-keys"),children:"API Keys"},"1"),(0,l.jsx)(ek.Z.Item,{onClick:()=>t("models"),children:"Models"},"2"),(0,l.jsx)(ek.Z.Item,{onClick:()=>t("llm-playground"),children:"Chat UI"},"3"),(0,l.jsx)(ek.Z.Item,{onClick:()=>t("usage"),children:"Usage"},"4"),"Admin"==s?(0,l.jsx)(ek.Z.Item,{onClick:()=>t("users"),children:"Users"},"5"):null,"Admin"==s?(0,l.jsx)(ek.Z.Item,{onClick:()=>t("teams"),children:"Teams"},"6"):null]})})})},ev=e=>{let{accessToken:t,token:s,userRole:r,userID:a}=e,o=new Date,[i,c]=(0,n.useState)([]),[d,h]=(0,n.useState)([]),[m,u]=(0,n.useState)([]),x=new Date(o.getFullYear(),o.getMonth(),1),p=new Date(o.getFullYear(),o.getMonth()+1,0),j=y(x),Z=y(p);function y(e){let t=e.getFullYear(),s=e.getMonth()+1,l=e.getDate();return"".concat(t,"-").concat(s<10?"0"+s:s,"-").concat(l<10?"0"+l:l)}return console.log("Start date is ".concat(j)),console.log("End date is ".concat(Z)),(0,n.useEffect)(()=>{t&&s&&r&&a&&(async()=>{try{await g(t,s,r,a,j,Z).then(async e=>{if(console.log("result from spend logs call",e),"daily_spend"in e){let t=e.daily_spend;console.log("daily spend",t),c(t);let s=e.top_api_keys;h(s)}else c(e)})}catch(e){console.error("There was an error fetching the data",e)}})()},[t,s,r,a,j,Z]),(0,l.jsx)("div",{style:{width:"100%"},children:(0,l.jsxs)(v.Z,{numItems:2,className:"gap-2 p-10 h-[75vh] w-full",children:[(0,l.jsx)(b.Z,{numColSpan:2,children:(0,l.jsxs)(M.Z,{children:[(0,l.jsx)(G.Z,{children:"Monthly Spend"}),(0,l.jsx)(K.Z,{data:i,index:"startTime",categories:["spend"],colors:["blue"],valueFormatter:e=>"$ ".concat(new Intl.NumberFormat("us").format(e).toString()),yAxisWidth:100,tickGap:5})]})}),(0,l.jsx)(b.Z,{numColSpan:1,children:(0,l.jsxs)(M.Z,{children:[(0,l.jsx)(G.Z,{children:"Top API Keys"}),(0,l.jsx)(K.Z,{className:"mt-4 h-40",data:d,index:"key",categories:["spend"],colors:["blue"],yAxisWidth:80,tickGap:5,layout:"vertical",showXAxis:!1,showLegend:!1})]})}),(0,l.jsx)(b.Z,{numColSpan:1,children:(0,l.jsxs)(M.Z,{children:[(0,l.jsx)(G.Z,{children:"Top Users"}),(0,l.jsx)(K.Z,{className:"mt-4 h-40",data:m,index:"user_id",categories:["spend"],colors:["blue"],yAxisWidth:200,layout:"vertical",showXAxis:!1,showLegend:!1})]})})]})})},eS=()=>{let[e,t]=(0,n.useState)(""),[s,a]=(0,n.useState)(null),[o,c]=(0,n.useState)(null),[d,h]=(0,n.useState)(!0),m=(0,r.useSearchParams)(),u=m.get("userID"),x=m.get("token"),[p,j]=(0,n.useState)("api-keys"),[g,Z]=(0,n.useState)(null);return(0,n.useEffect)(()=>{if(x){let e=(0,et.o)(x);if(e){if(console.log("Decoded token:",e),console.log("Decoded key:",e.key),Z(e.key),e.user_role){let s=function(e){if(!e)return"Undefined Role";switch(console.log("Received user role: ".concat(e)),e.toLowerCase()){case"app_owner":case"demo_app_owner":return"App Owner";case"app_admin":return"Admin";case"app_user":return"App User";default:return"Unknown Role"}}(e.user_role);console.log("Decoded user_role:",s),t(s)}else console.log("User role not defined");e.user_email?a(e.user_email):console.log("User Email is not set ".concat(e)),e.login_method?h("username_password"==e.login_method):console.log("User Email is not set ".concat(e))}}},[x]),(0,l.jsx)(n.Suspense,{fallback:(0,l.jsx)("div",{children:"Loading..."}),children:(0,l.jsxs)("div",{className:"flex flex-col min-h-screen",children:[(0,l.jsx)(i,{userID:u,userRole:e,userEmail:s,showSSOBanner:d}),(0,l.jsxs)("div",{className:"flex flex-1 overflow-auto",children:[(0,l.jsx)(eb,{setPage:j,userRole:e,defaultSelectedKey:null}),"api-keys"==p?(0,l.jsx)(es,{userID:u,userRole:e,teams:o,setUserRole:t,userEmail:s,setUserEmail:a,setTeams:c}):"models"==p?(0,l.jsx)(ea,{userID:u,userRole:e,token:x,accessToken:g}):"llm-playground"==p?(0,l.jsx)(ef,{userID:u,userRole:e,token:x,accessToken:g}):"users"==p?(0,l.jsx)(ec,{userID:u,userRole:e,token:x,accessToken:g}):"teams"==p?(0,l.jsx)(eh,{teams:o,setTeams:c,searchParams:m,accessToken:g}):(0,l.jsx)(ev,{userID:u,userRole:e,token:x,accessToken:g})]})]})})}}},function(e){e.O(0,[303,971,69,744],function(){return e(e.s=79615)}),_N_E=e.O()}]);
\ No newline at end of file
diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/app/page-d4fe4a48cbd3572c.js b/litellm/proxy/_experimental/out/_next/static/chunks/app/page-d4fe4a48cbd3572c.js
deleted file mode 100644
index d1b147c028b..00000000000
--- a/litellm/proxy/_experimental/out/_next/static/chunks/app/page-d4fe4a48cbd3572c.js
+++ /dev/null
@@ -1 +0,0 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[931],{79615:function(e,t,s){Promise.resolve().then(s.bind(s,24143))},24143:function(e,t,s){"use strict";s.r(t),s.d(t,{default:function(){return eN}});var l=s(3827),n=s(64090),r=s(47907),a=s(8792),o=s(2179),i=e=>{let{userID:t,userRole:s,userEmail:n,showSSOBanner:r}=e;return console.log("User ID:",t),console.log("userEmail:",n),(0,l.jsxs)("nav",{className:"left-0 right-0 top-0 flex justify-between items-center h-12 mb-4",children:[(0,l.jsx)("div",{className:"text-left my-2 absolute top-0 left-0",children:(0,l.jsx)("div",{className:"flex flex-col items-center",children:(0,l.jsx)(a.default,{href:"/",children:(0,l.jsx)("button",{className:"text-gray-800 text-2xl py-1 rounded text-center",children:(0,l.jsx)("img",{src:"/get_image",width:200,height:200,alt:"LiteLLM Brand",className:"mr-2"})})})})}),(0,l.jsxs)("div",{className:"text-right mx-4 my-2 absolute top-0 right-0 flex items-center justify-end space-x-2",children:[r?(0,l.jsx)("a",{href:"https://docs.litellm.ai/docs/proxy/ui#setup-ssoauth-for-ui",target:"_blank",className:"mr-2",children:(0,l.jsx)(o.Z,{variant:"primary",size:"lg",children:"Enable SSO"})}):null,(0,l.jsxs)(o.Z,{variant:"secondary",size:"lg",children:[n,(0,l.jsxs)("p",{children:["Role: ",s]}),(0,l.jsxs)("p",{children:["ID: ",t]})]})]})]})},c=s(80588);let d=async(e,t,s)=>{try{if(console.log("Form Values in keyCreateCall:",s),s.description&&(s.metadata||(s.metadata={}),s.metadata.description=s.description,delete s.description,s.metadata=JSON.stringify(s.metadata)),s.metadata){console.log("formValues.metadata:",s.metadata);try{s.metadata=JSON.parse(s.metadata)}catch(e){throw c.ZP.error("Failed to parse metadata: "+e),Error("Failed to parse metadata: "+e)}}console.log("Form Values after check:",s);let l=await fetch("/key/generate",{method:"POST",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({user_id:t,...s})});if(!l.ok){let e=await l.text();throw c.ZP.error("Failed to create key: "+e),console.error("Error response from the server:",e),Error("Network response was not ok")}let n=await l.json();return console.log("API Response:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},m=async(e,t,s)=>{try{if(console.log("Form Values in keyCreateCall:",s),s.description&&(s.metadata||(s.metadata={}),s.metadata.description=s.description,delete s.description,s.metadata=JSON.stringify(s.metadata)),s.metadata){console.log("formValues.metadata:",s.metadata);try{s.metadata=JSON.parse(s.metadata)}catch(e){throw c.ZP.error("Failed to parse metadata: "+e),Error("Failed to parse metadata: "+e)}}console.log("Form Values after check:",s);let l=await fetch("/user/new",{method:"POST",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({user_id:t,...s})});if(!l.ok){let e=await l.text();throw c.ZP.error("Failed to create key: "+e),console.error("Error response from the server:",e),Error("Network response was not ok")}let n=await l.json();return console.log("API Response:",n),n}catch(e){throw console.error("Failed to create key:",e),e}},h=async(e,t)=>{try{console.log("in keyDeleteCall:",t),c.ZP.info("Making key delete request");let s=await fetch("/key/delete",{method:"POST",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({keys:[t]})});if(!s.ok){let e=await s.text();throw c.ZP.error("Failed to delete key: "+e),Error("Network response was not ok")}let l=await s.json();return console.log(l),c.ZP.success("API Key Deleted"),l}catch(e){throw console.error("Failed to create key:",e),e}},u=async function(e,t,s){let l=arguments.length>3&&void 0!==arguments[3]&&arguments[3];try{let n="/user/info";"App Owner"==s&&t&&(n="".concat(n,"/?user_id=").concat(t)),console.log("in userInfoCall viewAll=",l),l&&(n="".concat(n,"/?view_all=true")),c.ZP.info("Requesting user data");let r=await fetch(n,{method:"GET",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw c.ZP.error(e),Error("Network response was not ok")}let a=await r.json();return console.log("API Response:",a),c.ZP.info("Received user data"),a}catch(e){throw console.error("Failed to create key:",e),e}},x=async(e,t,s)=>{try{c.ZP.info("Requesting model data");let t=await fetch("/v2/model/info",{method:"GET",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!t.ok){let e=await t.text();throw c.ZP.error(e),Error("Network response was not ok")}let s=await t.json();return c.ZP.info("Received model data"),s}catch(e){throw console.error("Failed to create key:",e),e}},p=async(e,t,s)=>{try{c.ZP.info("Requesting model data");let t=await fetch("/models",{method:"GET",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!t.ok){let e=await t.text();throw c.ZP.error(e),Error("Network response was not ok")}let s=await t.json();return c.ZP.info("Received model data"),s}catch(e){throw console.error("Failed to create key:",e),e}},j=async(e,t)=>{try{let s="/spend/logs";console.log("in keySpendLogsCall:",s);let l=await fetch("".concat(s,"/?api_key=").concat(t),{method:"GET",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!l.ok){let e=await l.text();throw c.ZP.error(e),Error("Network response was not ok")}let n=await l.json();return console.log(n),n}catch(e){throw console.error("Failed to create key:",e),e}},g=async(e,t,s,l,n,r)=>{try{let t="/spend/logs";t="App Owner"==s?"".concat(t,"/?user_id=").concat(l,"&start_date=").concat(n,"&end_date=").concat(r):"".concat(t,"/?start_date=").concat(n,"&end_date=").concat(r),c.ZP.info("Making spend logs request");let a=await fetch(t,{method:"GET",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!a.ok){let e=await a.text();throw c.ZP.error(e),Error("Network response was not ok")}let o=await a.json();return console.log(o),c.ZP.success("Spend Logs received"),o}catch(e){throw console.error("Failed to create key:",e),e}},Z=async(e,t)=>{try{let s=await fetch("/v2/key/info",{method:"POST",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({keys:t})});if(!s.ok){let e=await s.text();throw c.ZP.error(e),Error("Network response was not ok")}let l=await s.json();return console.log(l),l}catch(e){throw console.error("Failed to create key:",e),e}},y=async(e,t)=>{try{let s="/spend/users";console.log("in spendUsersCall:",s);let l=await fetch("".concat(s,"/?user_id=").concat(t),{method:"GET",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!l.ok){let e=await l.text();throw c.ZP.error(e),Error("Network response was not ok")}let n=await l.json();return console.log(n),n}catch(e){throw console.error("Failed to get spend for user",e),e}},f=async(e,t,s,l)=>{try{let n=await fetch("/user/request_model",{method:"POST",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({models:[t],user_id:s,justification:l})});if(!n.ok){let e=await n.text();throw c.ZP.error("Failed to delete key: "+e),Error("Network response was not ok")}let r=await n.json();return console.log(r),c.ZP.success(""),r}catch(e){throw console.error("Failed to create key:",e),e}},w=async e=>{try{let t="/user/get_requests";console.log("in userGetRequesedtModelsCall:",t);let s=await fetch(t,{method:"GET",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!s.ok){let e=await s.text();throw c.ZP.error("Failed to delete key: "+e),Error("Network response was not ok")}let l=await s.json();return console.log(l),c.ZP.success(""),l}catch(e){throw console.error("Failed to get requested models:",e),e}},k=async(e,t)=>{try{console.log("Form Values in teamCreateCall:",t);let s=await fetch("/team/new",{method:"POST",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({...t})});if(!s.ok){let e=await s.text();throw c.ZP.error("Failed to create key: "+e),console.error("Error response from the server:",e),Error("Network response was not ok")}let l=await s.json();return console.log("API Response:",l),l}catch(e){throw console.error("Failed to create key:",e),e}},_=async(e,t,s)=>{try{console.log("Form Values in teamMemberAddCall:",s);let l=await fetch("/team/member_add",{method:"POST",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({team_id:t,member:s})});if(!l.ok){let e=await l.text();throw c.ZP.error("Failed to create key: "+e),console.error("Error response from the server:",e),Error("Network response was not ok")}let n=await l.json();return console.log("API Response:",n),n}catch(e){throw console.error("Failed to create key:",e),e}};var b=s(10384),v=s(46453),S=s(71801),N=s(17189),I=s(12143),C=s(77171),T=s(42539),A=s(88707),P=s(1861);let{Option:E}=N.default;var O=e=>{let{userID:t,teamID:s,userRole:r,accessToken:a,data:i,userModels:m,setData:h}=e,[u]=I.Z.useForm(),[x,p]=(0,n.useState)(!1),[j,g]=(0,n.useState)(null),Z=()=>{p(!1),u.resetFields()},y=()=>{p(!1),g(null),u.resetFields()},f=async e=>{try{c.ZP.info("Making API Call"),p(!0);let s=await d(a,t,e);h(e=>e?[...e,s]:[s]),g(s.key),c.ZP.success("API Key Created"),u.resetFields(),localStorage.removeItem("userData"+t)}catch(e){console.error("Error creating the key:",e)}};return(0,l.jsxs)("div",{children:[(0,l.jsx)(o.Z,{className:"mx-auto",onClick:()=>p(!0),children:"+ Create New Key"}),(0,l.jsx)(C.Z,{title:"Create Key",visible:x,width:800,footer:null,onOk:Z,onCancel:y,children:(0,l.jsxs)(I.Z,{form:u,onFinish:f,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",children:["App Owner"===r||"Admin"===r?(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(I.Z.Item,{label:"Key Name",name:"key_alias",children:(0,l.jsx)(T.Z,{})}),(0,l.jsx)(I.Z.Item,{label:"Team ID",name:"team_id",children:(0,l.jsx)(T.Z,{placeholder:"ai_team",defaultValue:s||""})}),(0,l.jsx)(I.Z.Item,{label:"Models",name:"models",children:(0,l.jsx)(N.default,{mode:"multiple",placeholder:"Select models",style:{width:"100%"},children:m.map(e=>(0,l.jsx)(E,{value:e,children:e},e))})}),(0,l.jsx)(I.Z.Item,{label:"Max Budget (USD)",name:"max_budget",children:(0,l.jsx)(A.Z,{step:.01,precision:2,width:200})}),(0,l.jsx)(I.Z.Item,{label:"Reset Budget",name:"budget_duration",children:(0,l.jsxs)(N.default,{defaultValue:null,placeholder:"n/a",children:[(0,l.jsx)(N.default.Option,{value:"24h",children:"daily"}),(0,l.jsx)(N.default.Option,{value:"30d",children:"monthly"})]})}),(0,l.jsx)(I.Z.Item,{label:"Tokens per minute Limit (TPM)",name:"tpm_limit",children:(0,l.jsx)(A.Z,{step:1,width:400})}),(0,l.jsx)(I.Z.Item,{label:"Requests per minute Limit (RPM)",name:"rpm_limit",children:(0,l.jsx)(A.Z,{step:1,width:400})}),(0,l.jsx)(I.Z.Item,{label:"Expire Key (eg: 30s, 30h, 30d)",name:"duration",children:(0,l.jsx)(T.Z,{})}),(0,l.jsx)(I.Z.Item,{label:"Metadata",name:"metadata",children:(0,l.jsx)(T.Z.TextArea,{rows:4,placeholder:"Enter metadata as JSON"})})]}):(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(I.Z.Item,{label:"Key Name",name:"key_alias",children:(0,l.jsx)(T.Z,{})}),(0,l.jsx)(I.Z.Item,{label:"Team ID (Contact Group)",name:"team_id",children:(0,l.jsx)(T.Z,{placeholder:"ai_team"})}),(0,l.jsx)(I.Z.Item,{label:"Description",name:"description",children:(0,l.jsx)(T.Z.TextArea,{placeholder:"Enter description",rows:4})})]}),(0,l.jsx)("div",{style:{textAlign:"right",marginTop:"10px"},children:(0,l.jsx)(P.ZP,{htmlType:"submit",children:"Create Key"})})]})}),j&&(0,l.jsx)(C.Z,{title:"Save your key",visible:x,onOk:Z,onCancel:y,footer:null,children:(0,l.jsxs)(v.Z,{numItems:1,className:"gap-2 w-full",children:[(0,l.jsx)(b.Z,{numColSpan:1,children:(0,l.jsxs)("p",{children:["Please save this secret key somewhere safe and accessible. For security reasons, ",(0,l.jsx)("b",{children:"you will not be able to view it again"})," ","through your LiteLLM account. If you lose this secret key, you will need to generate a new one."]})}),(0,l.jsx)(b.Z,{numColSpan:1,children:null!=j?(0,l.jsxs)(S.Z,{children:["API Key: ",j]}):(0,l.jsx)(S.Z,{children:"Key being created, this might take 30s"})})]})})]})},D=s(33393),F=s(13810),R=s(61244),M=s(10827),U=s(3851),L=s(2044),z=s(64167),q=s(74480),B=s(7178),K=s(9853),J=s(67989),V=s(56863),G=s(42440),$=e=>{let{token:t,accessToken:s,keySpend:r,keyBudget:a,keyName:i}=e,[c,d]=(0,n.useState)(!1),[m,h]=(0,n.useState)(null),[u,x]=(0,n.useState)(null),p=async()=>{try{if(null==s||null==t)return;console.log("accessToken: ".concat(s,"; token: ").concat(t));let e=await j(s,t);console.log("Response:",e);let l=Object.values(e).reduce((e,t)=>{let s=new Date(t.startTime),l=new Intl.DateTimeFormat("en-US",{day:"2-digit",month:"short"}).format(s);return e[l]=(e[l]||0)+t.spend,e},{}),n=Object.entries(l);n.sort((e,t)=>{let[s]=e,[l]=t,n=new Date(s),r=new Date(l);return n.getTime()-r.getTime()});let r=Object.fromEntries(n);console.log(r);let a=Object.values(e).reduce((e,t)=>{let s=t.user;return e[s]=(e[s]||0)+t.spend,e},{});console.log(l),console.log(a);let o=[];for(let[e,t]of Object.entries(r))o.push({day:e,spend:t});let i=Object.entries(a).sort((e,t)=>t[1]-e[1]).slice(0,5).map(e=>{let[t,s]=e;return{name:t,value:s}});h(o),x(i),console.log("arrayBarChart:",o)}catch(e){console.error("There was an error fetching the data",e)}};return t?(0,l.jsxs)("div",{children:[(0,l.jsx)(o.Z,{className:"mx-auto",onClick:()=>{console.log("Show Modal triggered"),d(!0),p()},children:"View Spend Report"}),(0,l.jsxs)(C.Z,{visible:c,width:1e3,onOk:()=>{d(!1)},onCancel:()=>{d(!1)},footer:null,children:[(0,l.jsxs)(G.Z,{style:{textAlign:"left"},children:["Key Name: ",i]}),(0,l.jsxs)(V.Z,{children:["Monthly Spend $",r]}),(0,l.jsx)(F.Z,{className:"mt-6 mb-6",children:m&&(0,l.jsx)(K.Z,{className:"mt-6",data:m,colors:["green"],index:"day",categories:["spend"],yAxisWidth:48})}),(0,l.jsx)(G.Z,{className:"mt-6",children:"Top 5 Users Spend (USD)"}),(0,l.jsx)(F.Z,{className:"mb-6",children:u&&(0,l.jsx)(J.Z,{className:"mt-6",data:u,color:"teal"})})]})]}):null},Y=e=>{let{userID:t,accessToken:s,data:r,setData:a}=e,[i,c]=(0,n.useState)(!1),[d,m]=(0,n.useState)(!1),[u,x]=(0,n.useState)(null),p=async e=>{null!=r&&(x(e),localStorage.removeItem("userData"+t),m(!0))},j=async()=>{if(null!=u&&null!=r){try{await h(s,u);let e=r.filter(e=>e.token!==u);a(e)}catch(e){console.error("Error deleting the key:",e)}m(!1),x(null)}};if(null!=r)return console.log("RERENDER TRIGGERED"),(0,l.jsxs)(F.Z,{className:"w-full mx-auto flex-auto overflow-y-auto max-h-[50vh] mb-4",children:[(0,l.jsxs)(M.Z,{className:"mt-5",children:[(0,l.jsx)(z.Z,{children:(0,l.jsxs)(B.Z,{children:[(0,l.jsx)(q.Z,{children:"Key Alias"}),(0,l.jsx)(q.Z,{children:"Secret Key"}),(0,l.jsx)(q.Z,{children:"Spend (USD)"}),(0,l.jsx)(q.Z,{children:"Key Budget (USD)"}),(0,l.jsx)(q.Z,{children:"Team ID"}),(0,l.jsx)(q.Z,{children:"Metadata"}),(0,l.jsx)(q.Z,{children:"Models"}),(0,l.jsx)(q.Z,{children:"TPM / RPM Limits"}),(0,l.jsx)(q.Z,{children:"Expires"})]})}),(0,l.jsx)(U.Z,{children:r.map(e=>(console.log(e),"litellm-dashboard"===e.team_id)?null:(0,l.jsxs)(B.Z,{children:[(0,l.jsx)(L.Z,{children:null!=e.key_alias?(0,l.jsx)(S.Z,{children:e.key_alias}):(0,l.jsx)(S.Z,{children:"Not Set"})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(S.Z,{children:e.key_name})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(S.Z,{children:e.spend})}),(0,l.jsx)(L.Z,{children:null!=e.max_budget?(0,l.jsx)(S.Z,{children:e.max_budget}):(0,l.jsx)(S.Z,{children:"Unlimited Budget"})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(S.Z,{children:e.team_id})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(S.Z,{children:JSON.stringify(e.metadata)})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(S.Z,{children:JSON.stringify(e.models)})}),(0,l.jsx)(L.Z,{children:(0,l.jsxs)(S.Z,{children:["TPM Limit: ",e.tpm_limit?e.tpm_limit:"Unlimited"," ",(0,l.jsx)("br",{})," RPM Limit:"," ",e.rpm_limit?e.rpm_limit:"Unlimited"]})}),(0,l.jsx)(L.Z,{children:null!=e.expires?(0,l.jsx)(S.Z,{children:e.expires}):(0,l.jsx)(S.Z,{children:"Never expires"})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(R.Z,{onClick:()=>p(e.token),icon:D.Z,size:"sm"})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)($,{token:e.token,accessToken:s,keySpend:e.spend,keyBudget:e.max_budget,keyName:e.key_name})})]},e.token))})]}),d&&(0,l.jsx)("div",{className:"fixed z-10 inset-0 overflow-y-auto",children:(0,l.jsxs)("div",{className:"flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0",children:[(0,l.jsx)("div",{className:"fixed inset-0 transition-opacity","aria-hidden":"true",children:(0,l.jsx)("div",{className:"absolute inset-0 bg-gray-500 opacity-75"})}),(0,l.jsx)("span",{className:"hidden sm:inline-block sm:align-middle sm:h-screen","aria-hidden":"true",children:"​"}),(0,l.jsxs)("div",{className:"inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full",children:[(0,l.jsx)("div",{className:"bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4",children:(0,l.jsx)("div",{className:"sm:flex sm:items-start",children:(0,l.jsxs)("div",{className:"mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left",children:[(0,l.jsx)("h3",{className:"text-lg leading-6 font-medium text-gray-900",children:"Delete Key"}),(0,l.jsx)("div",{className:"mt-2",children:(0,l.jsx)("p",{className:"text-sm text-gray-500",children:"Are you sure you want to delete this key ?"})})]})})}),(0,l.jsxs)("div",{className:"bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse",children:[(0,l.jsx)(o.Z,{onClick:j,color:"red",className:"ml-2",children:"Delete"}),(0,l.jsx)(o.Z,{onClick:()=>{m(!1),x(null)},children:"Cancel"})]})]})]})})]})},W=e=>{let{userID:t,userSpendData:s,userRole:r,accessToken:a}=e;console.log("User SpendData:",s);let[o,i]=(0,n.useState)(null==s?void 0:s.spend),[c,d]=(0,n.useState)((null==s?void 0:s.max_budget)||null);return(0,n.useEffect)(()=>{(async()=>{if("Admin"===r)try{let e=await y(a,"litellm-proxy-budget");console.log("Result from callSpendUsers:",e);let t=e[0];i(null==t?void 0:t.spend),d((null==t?void 0:t.max_budget)||null)}catch(e){console.error("Failed to get spend for user",e)}})()},[r,a,t]),(0,l.jsx)(l.Fragment,{children:(0,l.jsxs)(F.Z,{className:"mx-auto mb-4",children:[(0,l.jsxs)(V.Z,{children:["$",o]}),(0,l.jsxs)(G.Z,{children:["/ ",null!==c?"$".concat(c," limit"):"No limit"]})]})})},H=s(36083),X=s(68967),Q=s(27166),ee=e=>{let{teams:t,setSelectedTeam:s}=e,{Title:r,Paragraph:a}=H.default,[o,i]=(0,n.useState)("");return(0,l.jsxs)("div",{className:"mt-10",children:[(0,l.jsx)(r,{level:4,children:"Default Team"}),(0,l.jsx)(a,{children:"If you belong to multiple teams, this setting controls which team is used by default when creating new API Keys."}),t&&t.length>0?(0,l.jsx)(X.Z,{defaultValue:"0",children:t.map((e,t)=>(0,l.jsx)(Q.Z,{value:String(t),onClick:()=>s(e),children:e.team_alias},t))}):(0,l.jsxs)(a,{children:["No team created. ",(0,l.jsx)("b",{children:"Defaulting to personal account."})]})]})},et=s(37963);console.log("isLocal:",!1);var es=e=>{let{userID:t,userRole:s,teams:a,setUserRole:o,userEmail:i,setUserEmail:c,setTeams:d}=e,[m,h]=(0,n.useState)(null),[x,j]=(0,n.useState)(null),g=(0,r.useSearchParams)();g.get("viewSpend"),(0,r.useRouter)();let Z=g.get("token"),[y,f]=(0,n.useState)(null),[w,k]=(0,n.useState)([]),[_,S]=(0,n.useState)(a?a[0]:null);if(window.addEventListener("beforeunload",function(){sessionStorage.clear()}),(0,n.useEffect)(()=>{if(Z){let e=(0,et.o)(Z);if(e){if(console.log("Decoded token:",e),console.log("Decoded key:",e.key),f(e.key),e.user_role){let t=function(e){if(!e)return"Undefined Role";switch(console.log("Received user role: ".concat(e)),e.toLowerCase()){case"app_owner":case"demo_app_owner":return"App Owner";case"app_admin":return"Admin";case"app_user":return"App User";default:return"Unknown Role"}}(e.user_role);console.log("Decoded user_role:",t),o(t)}else console.log("User role not defined");e.user_email?c(e.user_email):console.log("User Email is not set ".concat(e))}}if(t&&y&&s&&!m){let e=sessionStorage.getItem("userModels"+t);e?k(JSON.parse(e)):(async()=>{try{let e=await u(y,t,s);console.log("received teams in user dashboard: ".concat(Object.keys(e),"; team values: ").concat(Object.entries(e.teams))),j(e.user_info),h(e.keys),d(e.teams),S(e.teams?e.teams[0]:null),sessionStorage.setItem("userData"+t,JSON.stringify(e.keys)),sessionStorage.setItem("userSpendData"+t,JSON.stringify(e.user_info));let l=(await p(y,t,s)).data.map(e=>e.id);console.log("available_model_names:",l),k(l),console.log("userModels:",w),sessionStorage.setItem("userModels"+t,JSON.stringify(l))}catch(e){console.error("There was an error fetching the data",e)}})()}},[t,Z,y,m,s]),null==t||null==Z){let e="/sso/key/generate";return console.log("Full URL:",e),window.location.href=e,null}return null==y?null:(null==s&&o("App Owner"),(0,l.jsx)("div",{children:(0,l.jsx)(v.Z,{numItems:1,className:"gap-0 p-10 h-[75vh] w-full",children:(0,l.jsxs)(b.Z,{numColSpan:1,children:[(0,l.jsx)(W,{userID:t,userSpendData:x,userRole:s,accessToken:y}),(0,l.jsx)(Y,{userID:t,accessToken:y,data:m,setData:h}),(0,l.jsx)(O,{userID:t,teamID:_?_.team_id:null,userRole:s,userModels:w,accessToken:y,data:m,setData:h}),(0,l.jsx)(ee,{teams:a,setSelectedTeam:S})]})})}))},el=s(5);let{Option:en}=N.default;var er=e=>{let{userModels:t,accessToken:s,userID:r}=e,[a]=I.Z.useForm(),[i,d]=(0,n.useState)(!1),m=async e=>{try{c.ZP.info("Requesting access");let{selectedModel:t,accessReason:l}=e;await f(s,t,r,l),d(!0)}catch(e){console.error("Error requesting access:",e)}};return(0,l.jsxs)("div",{children:[(0,l.jsx)(o.Z,{size:"xs",onClick:()=>d(!0),children:"Request Access"}),(0,l.jsx)(C.Z,{title:"Request Access",visible:i,width:800,footer:null,onOk:()=>{d(!1),a.resetFields()},onCancel:()=>{d(!1),a.resetFields()},children:(0,l.jsxs)(I.Z,{form:a,onFinish:m,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",children:[(0,l.jsx)(I.Z.Item,{label:"Select Model",name:"selectedModel",children:(0,l.jsx)(N.default,{placeholder:"Select model",style:{width:"100%"},children:t.map(e=>(0,l.jsx)(en,{value:e,children:e},e))})}),(0,l.jsx)(I.Z.Item,{label:"Reason for Access",name:"accessReason",children:(0,l.jsx)(T.Z.TextArea,{rows:4,placeholder:"Enter reason for access"})}),(0,l.jsx)("div",{style:{textAlign:"right",marginTop:"10px"},children:(0,l.jsx)(o.Z,{children:"Request Access"})})]})})]})},ea=e=>{let{accessToken:t,token:s,userRole:r,userID:a}=e,[i,c]=(0,n.useState)({data:[]}),[d,m]=(0,n.useState)([]);if((0,n.useEffect)(()=>{if(!t||!s||!r||!a)return;let e=async()=>{try{let e=await x(t,a,r);if(console.log("Model data response:",e.data),c(e),"Admin"===r&&t){let e=await w(t);console.log("Pending Requests:",d),m(e.requests||[])}}catch(e){console.error("There was an error fetching the model data",e)}};t&&s&&r&&a&&e()},[t,s,r,a]),!i||!t||!s||!r||!a)return(0,l.jsx)("div",{children:"Loading..."});let h=[];for(let e=0;e(0,l.jsxs)(B.Z,{children:[(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:e.model_name})}),(0,l.jsx)(L.Z,{children:e.provider}),(0,l.jsx)(L.Z,{children:e.user_access?(0,l.jsx)(el.Z,{color:"green",children:"Yes"}):(0,l.jsx)(er,{userModels:h,accessToken:t,userID:a})}),(0,l.jsx)(L.Z,{children:e.input_cost}),(0,l.jsx)(L.Z,{children:e.output_cost}),(0,l.jsx)(L.Z,{children:e.max_tokens})]},e.model_name))})]})}),"Admin"===r&&d&&d.length>0?(0,l.jsx)(F.Z,{children:(0,l.jsxs)(M.Z,{children:[(0,l.jsxs)(z.Z,{children:[(0,l.jsx)(G.Z,{children:"Pending Requests"}),(0,l.jsxs)(B.Z,{children:[(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:"User ID"})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:"Requested Models"})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:"Justification"})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:"Justification"})})]})]}),(0,l.jsx)(U.Z,{children:d.map(e=>(0,l.jsxs)(B.Z,{children:[(0,l.jsx)(L.Z,{children:(0,l.jsx)("p",{children:e.user_id})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)("p",{children:e.models[0]})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)("p",{children:e.justification})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)("p",{children:e.user_id})}),(0,l.jsx)(o.Z,{children:"Approve"}),(0,l.jsx)(o.Z,{variant:"secondary",className:"ml-2",children:"Deny"})]},e.request_id))})]})}):null]})})};let{Option:eo}=N.default;var ei=e=>{let{userID:t,accessToken:s}=e,[r]=I.Z.useForm(),[a,i]=(0,n.useState)(!1),[d,h]=(0,n.useState)(null),[u,x]=(0,n.useState)([]);(0,n.useEffect)(()=>{(async()=>{try{let e=await p(s,t,"any"),l=[];for(let t=0;t{i(!1),r.resetFields()},g=()=>{i(!1),h(null),r.resetFields()},Z=async e=>{try{c.ZP.info("Making API Call"),i(!0),console.log("formValues in create user:",e);let l=await m(s,t,e);console.log("user create Response:",l),h(l.key),c.ZP.success("API user Created"),r.resetFields(),localStorage.removeItem("userData"+t)}catch(e){console.error("Error creating the user:",e)}};return(0,l.jsxs)("div",{children:[(0,l.jsx)(o.Z,{className:"mx-auto",onClick:()=>i(!0),children:"+ Create New User"}),(0,l.jsx)(C.Z,{title:"Create User",visible:a,width:800,footer:null,onOk:j,onCancel:g,children:(0,l.jsxs)(I.Z,{form:r,onFinish:Z,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",children:[(0,l.jsx)(I.Z.Item,{label:"User ID",name:"user_id",children:(0,l.jsx)(T.Z,{placeholder:"Enter User ID"})}),(0,l.jsx)(I.Z.Item,{label:"Team ID",name:"team_id",children:(0,l.jsx)(T.Z,{placeholder:"ai_team"})}),(0,l.jsx)(I.Z.Item,{label:"Models",name:"models",children:(0,l.jsx)(N.default,{mode:"multiple",placeholder:"Select models",style:{width:"100%"},children:u.map(e=>(0,l.jsx)(eo,{value:e,children:e},e))})}),(0,l.jsx)(I.Z.Item,{label:"Max Budget (USD)",name:"max_budget",children:(0,l.jsx)(A.Z,{step:.01,precision:2,width:200})}),(0,l.jsx)(I.Z.Item,{label:"Tokens per minute Limit (TPM)",name:"tpm_limit",children:(0,l.jsx)(A.Z,{step:1,width:400})}),(0,l.jsx)(I.Z.Item,{label:"Requests per minute Limit (RPM)",name:"rpm_limit",children:(0,l.jsx)(A.Z,{step:1,width:400})}),(0,l.jsx)(I.Z.Item,{label:"Duration (eg: 30s, 30h, 30d)",name:"duration",children:(0,l.jsx)(T.Z,{})}),(0,l.jsx)(I.Z.Item,{label:"Metadata",name:"metadata",children:(0,l.jsx)(T.Z.TextArea,{rows:4,placeholder:"Enter metadata as JSON"})}),(0,l.jsx)("div",{style:{textAlign:"right",marginTop:"10px"},children:(0,l.jsx)(P.ZP,{htmlType:"submit",children:"Create User"})})]})}),d&&(0,l.jsxs)(C.Z,{title:"Save Your User",visible:a,onOk:j,onCancel:g,footer:null,children:[(0,l.jsxs)("p",{children:["Please save this secret user somewhere safe and accessible. For security reasons, ",(0,l.jsx)("b",{children:"you will not be able to view it again"})," ","through your LiteLLM account. If you lose this secret user, you will need to generate a new one."]}),(0,l.jsx)("p",{children:null!=d?"API user: ".concat(d):"User being created, this might take 30s"})]})]})},ec=e=>{let{accessToken:t,token:s,userRole:r,userID:a}=e,[o,i]=(0,n.useState)(null),[c,d]=(0,n.useState)([]);return((0,n.useEffect)(()=>{if(!t||!s||!r||!a)return;let e=async()=>{try{let e=await u(t,null,r,!0);console.log("user data response:",e),i(e)}catch(e){console.error("There was an error fetching the model data",e)}};t&&s&&r&&a&&e()},[t,s,r,a]),o&&t&&s&&r&&a)?(0,l.jsx)("div",{style:{width:"100%"},children:(0,l.jsxs)(v.Z,{className:"gap-2 p-10 h-[75vh] w-full",children:[(0,l.jsx)(ei,{userID:a,accessToken:t}),(0,l.jsx)(F.Z,{children:(0,l.jsxs)(M.Z,{className:"mt-5",children:[(0,l.jsx)(z.Z,{children:(0,l.jsxs)(B.Z,{children:[(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:"User ID "})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:"User Role"})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:"User Models"})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:"User Spend ($ USD)"})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:"User Max Budget ($ USD)"})})]})}),(0,l.jsx)(U.Z,{children:o.map(e=>(0,l.jsxs)(B.Z,{children:[(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:e.user_id})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:e.user_role?e.user_role:"app_user"})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:e.models&&e.models.length>0?e.models:"All Models"})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:e.spend?e.spend:0})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:e.max_budget?e.max_budget:"Unlimited"})})]},e.user_id))})]})})]})}):(0,l.jsx)("div",{children:"Loading..."})},ed=s(8510),em=e=>{let{teams:t,searchParams:s,accessToken:r,setTeams:a}=e,[i]=I.Z.useForm(),[d]=I.Z.useForm(),{Title:m,Paragraph:h}=H.default,[u,x]=(0,n.useState)(""),[p,j]=(0,n.useState)(t?t[0]:null),[g,Z]=(0,n.useState)(!1),[y,f]=(0,n.useState)(!1),w=async e=>{try{if(null!=r){c.ZP.info("Making API Call");let s=await k(r,e);null!==t?a([...t,s]):a([s]),console.log("response for team create call: ".concat(s)),Z(!1)}}catch(e){console.error("Error creating the key:",e)}},E=async e=>{try{if(null!=r&&null!=t){c.ZP.info("Making API Call");let s={role:"user",user_email:e.user_email,user_id:e.user_id},l=await _(r,p.team_id,s);console.log("response for team create call: ".concat(l.data));let n=t.findIndex(e=>(console.log("team.team_id=".concat(e.team_id,"; response.data.team_id=").concat(l.data.team_id)),e.team_id===l.data.team_id));if(console.log("foundIndex: ".concat(n)),-1!==n){let e=[...t];e[n]=l.data,a(e),j(l.data)}f(!1)}}catch(e){console.error("Error creating the key:",e)}};return console.log("received teams ".concat(t)),(0,l.jsx)("div",{className:"w-full",children:(0,l.jsxs)(v.Z,{numItems:1,className:"gap-2 p-2 h-[75vh] w-full",children:[(0,l.jsxs)(b.Z,{numColSpan:1,children:[(0,l.jsx)(m,{level:4,children:"All Teams"}),(0,l.jsx)(F.Z,{className:"w-full mx-auto flex-auto overflow-y-auto max-h-[50vh]",children:(0,l.jsxs)(M.Z,{children:[(0,l.jsx)(z.Z,{children:(0,l.jsxs)(B.Z,{children:[(0,l.jsx)(q.Z,{children:"Team Name"}),(0,l.jsx)(q.Z,{children:"Spend (USD)"}),(0,l.jsx)(q.Z,{children:"Budget (USD)"}),(0,l.jsx)(q.Z,{children:"TPM / RPM Limits"})]})}),(0,l.jsx)(U.Z,{children:t&&t.length>0?t.map(e=>(0,l.jsxs)(B.Z,{children:[(0,l.jsx)(L.Z,{children:e.team_alias}),(0,l.jsx)(L.Z,{children:e.spend}),(0,l.jsx)(L.Z,{children:e.max_budget?e.max_budget:"No limit"}),(0,l.jsx)(L.Z,{children:(0,l.jsxs)(S.Z,{children:["TPM Limit:"," ",e.tpm_limit?e.tpm_limit:"Unlimited"," ",(0,l.jsx)("br",{})," RPM Limit:"," ",e.rpm_limit?e.rpm_limit:"Unlimited"]})}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(R.Z,{icon:ed.Z,size:"sm"})})]},e.team_id)):null})]})})]}),(0,l.jsxs)(b.Z,{numColSpan:1,children:[(0,l.jsx)(o.Z,{className:"mx-auto",onClick:()=>Z(!0),children:"+ Create New Team"}),(0,l.jsx)(C.Z,{title:"Create Team",visible:g,width:800,footer:null,onOk:()=>{Z(!1),i.resetFields()},onCancel:()=>{Z(!1),i.resetFields()},children:(0,l.jsxs)(I.Z,{form:i,onFinish:w,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",children:[(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(I.Z.Item,{label:"Team Name",name:"team_alias",children:(0,l.jsx)(T.Z,{})}),(0,l.jsx)(I.Z.Item,{label:"Models",name:"models",children:(0,l.jsx)(N.default,{mode:"multiple",placeholder:"Select models",style:{width:"100%"}})}),(0,l.jsx)(I.Z.Item,{label:"Max Budget (USD)",name:"max_budget",children:(0,l.jsx)(A.Z,{step:.01,precision:2,width:200})}),(0,l.jsx)(I.Z.Item,{label:"Tokens per minute Limit (TPM)",name:"tpm_limit",children:(0,l.jsx)(A.Z,{step:1,width:400})}),(0,l.jsx)(I.Z.Item,{label:"Requests per minute Limit (RPM)",name:"rpm_limit",children:(0,l.jsx)(A.Z,{step:1,width:400})})]}),(0,l.jsx)("div",{style:{textAlign:"right",marginTop:"10px"},children:(0,l.jsx)(P.ZP,{htmlType:"submit",children:"Create Team"})})]})})]}),(0,l.jsxs)(b.Z,{numColSpan:1,children:[(0,l.jsx)(m,{level:4,children:"Team Members"}),(0,l.jsx)(h,{children:"If you belong to multiple teams, this setting controls which teams members you see."}),t&&t.length>0?(0,l.jsx)(X.Z,{defaultValue:"0",children:t.map((e,t)=>(0,l.jsx)(Q.Z,{value:String(t),onClick:()=>{j(e)},children:e.team_alias},t))}):(0,l.jsxs)(h,{children:["No team created. ",(0,l.jsx)("b",{children:"Defaulting to personal account."})]})]}),(0,l.jsx)(b.Z,{numColSpan:1,children:(0,l.jsx)(F.Z,{className:"w-full mx-auto flex-auto overflow-y-auto max-h-[50vh]",children:(0,l.jsxs)(M.Z,{children:[(0,l.jsx)(z.Z,{children:(0,l.jsxs)(B.Z,{children:[(0,l.jsx)(q.Z,{children:"Member Name"}),(0,l.jsx)(q.Z,{children:"Role"}),(0,l.jsx)(q.Z,{children:"Action"})]})}),(0,l.jsx)(U.Z,{children:p?p.members_with_roles.map((e,t)=>(0,l.jsxs)(B.Z,{children:[(0,l.jsx)(L.Z,{children:e.user_email?e.user_email:e.user_id?e.user_id:null}),(0,l.jsx)(L.Z,{children:e.role}),(0,l.jsx)(L.Z,{children:(0,l.jsx)(R.Z,{icon:ed.Z,size:"sm"})})]},t)):null})]})})}),(0,l.jsxs)(b.Z,{numColSpan:1,children:[(0,l.jsx)(o.Z,{className:"mx-auto mb-5",onClick:()=>f(!0),children:"+ Add member"}),(0,l.jsx)(C.Z,{title:"Add member",visible:y,width:800,footer:null,onOk:()=>{f(!1),d.resetFields()},onCancel:()=>{f(!1),d.resetFields()},children:(0,l.jsxs)(I.Z,{form:i,onFinish:E,labelCol:{span:8},wrapperCol:{span:16},labelAlign:"left",children:[(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(I.Z.Item,{label:"Email",name:"user_email",className:"mb-4",children:(0,l.jsx)(T.Z,{name:"user_email",className:"px-3 py-2 border rounded-md w-full"})}),(0,l.jsx)("div",{className:"text-center mb-4",children:"OR"}),(0,l.jsx)(I.Z.Item,{label:"User ID",name:"user_id",className:"mb-4",children:(0,l.jsx)(T.Z,{name:"user_id",className:"px-3 py-2 border rounded-md w-full"})})]}),(0,l.jsx)("div",{style:{textAlign:"right",marginTop:"10px"},children:(0,l.jsx)(P.ZP,{htmlType:"submit",children:"Add member"})})]})})]})]})})},eh=s(92836),eu=s(26734),ex=s(41608),ep=s(32126),ej=s(23682),eg=s(12968),eZ=s(67951);async function ey(e,t,s,l){console.log("isLocal:",!1);let n=window.location.origin,r=new eg.ZP.OpenAI({apiKey:l,baseURL:n,dangerouslyAllowBrowser:!0});for await(let l of(await r.chat.completions.create({model:s,stream:!0,messages:[{role:"user",content:e}]})))console.log(l),l.choices[0].delta.content&&t(l.choices[0].delta.content)}var ef=e=>{let{accessToken:t,token:s,userRole:r,userID:a}=e,[o,i]=(0,n.useState)(""),[c,d]=(0,n.useState)([]),[m,h]=(0,n.useState)(void 0),[u,x]=(0,n.useState)(null);(0,n.useEffect)(()=>{t&&s&&r&&a&&(async()=>{let e=await p(t,a,r);console.log("model_info:",e),(null==e?void 0:e.data.length)>0&&(x(e.data),h(e.data[0].id))})()},[t,a,r]);let j=(e,t)=>{d(s=>{let l=s[s.length-1];return l&&l.role===e?[...s.slice(0,s.length-1),{role:e,content:l.content+t}]:[...s,{role:e,content:t}]})},g=async()=>{if(""!==o.trim()&&t&&s&&r&&a){d(e=>[...e,{role:"user",content:o}]);try{m&&await ey(o,e=>j("assistant",e),m,t)}catch(e){console.error("Error fetching model response",e),j("assistant","Error fetching model response")}i("")}};return(0,l.jsx)("div",{style:{width:"100%",position:"relative"},children:(0,l.jsx)(v.Z,{className:"gap-2 p-10 h-[75vh] w-full",children:(0,l.jsx)(F.Z,{children:(0,l.jsxs)(eu.Z,{children:[(0,l.jsxs)(ex.Z,{className:"mt-4",children:[(0,l.jsx)(eh.Z,{children:"Chat"}),(0,l.jsx)(eh.Z,{children:"API Reference"})]}),(0,l.jsxs)(ej.Z,{children:[(0,l.jsxs)(ep.Z,{children:[(0,l.jsxs)("div",{children:[(0,l.jsx)("label",{children:"Select Model:"}),(0,l.jsx)("select",{value:m||"",onChange:e=>h(e.target.value),children:null==u?void 0:u.map(e=>(0,l.jsx)("option",{value:e.id,children:e.id},e.id))})]}),(0,l.jsxs)(M.Z,{className:"mt-5",style:{display:"block",maxHeight:"60vh",overflowY:"auto"},children:[(0,l.jsx)(z.Z,{children:(0,l.jsx)(B.Z,{children:(0,l.jsx)(L.Z,{children:(0,l.jsx)(G.Z,{children:"Chat"})})})}),(0,l.jsx)(U.Z,{children:c.map((e,t)=>(0,l.jsx)(B.Z,{children:(0,l.jsx)(L.Z,{children:"".concat(e.role,": ").concat(e.content)})},t))})]}),(0,l.jsx)("div",{className:"mt-3",style:{position:"absolute",bottom:5,width:"95%"},children:(0,l.jsxs)("div",{className:"flex",children:[(0,l.jsx)("input",{type:"text",value:o,onChange:e=>i(e.target.value),className:"flex-1 p-2 border rounded-md mr-2",placeholder:"Type your message..."}),(0,l.jsx)("button",{onClick:g,className:"p-2 bg-blue-500 text-white rounded-md",children:"Send"})]})})]}),(0,l.jsx)(ep.Z,{children:(0,l.jsxs)(eu.Z,{children:[(0,l.jsxs)(ex.Z,{children:[(0,l.jsx)(eh.Z,{children:"OpenAI Python SDK"}),(0,l.jsx)(eh.Z,{children:"LlamaIndex"}),(0,l.jsx)(eh.Z,{children:"Langchain Py"})]}),(0,l.jsxs)(ej.Z,{children:[(0,l.jsx)(ep.Z,{children:(0,l.jsx)(eZ.Z,{language:"python",children:'\nimport openai\nclient = openai.OpenAI(\n api_key="your_api_key",\n base_url="http://0.0.0.0:4000" # proxy base url\n)\n\nresponse = client.chat.completions.create(\n model="gpt-3.5-turbo", # model to use from Models Tab\n messages = [\n {\n "role": "user",\n "content": "this is a test request, write a short poem"\n }\n ],\n extra_body={\n "metadata": {\n "generation_name": "ishaan-generation-openai-client",\n "generation_id": "openai-client-gen-id22",\n "trace_id": "openai-client-trace-id22",\n "trace_user_id": "openai-client-user-id2"\n }\n }\n)\n\nprint(response)\n '})}),(0,l.jsx)(ep.Z,{children:(0,l.jsx)(eZ.Z,{language:"python",children:'\nimport os, dotenv\n\nfrom llama_index.llms import AzureOpenAI\nfrom llama_index.embeddings import AzureOpenAIEmbedding\nfrom llama_index import VectorStoreIndex, SimpleDirectoryReader, ServiceContext\n\nllm = AzureOpenAI(\n engine="azure-gpt-3.5", # model_name on litellm proxy\n temperature=0.0,\n azure_endpoint="http://0.0.0.0:4000", # litellm proxy endpoint\n api_key="sk-1234", # litellm proxy API Key\n api_version="2023-07-01-preview",\n)\n\nembed_model = AzureOpenAIEmbedding(\n deployment_name="azure-embedding-model",\n azure_endpoint="http://0.0.0.0:4000",\n api_key="sk-1234",\n api_version="2023-07-01-preview",\n)\n\n\ndocuments = SimpleDirectoryReader("llama_index_data").load_data()\nservice_context = ServiceContext.from_defaults(llm=llm, embed_model=embed_model)\nindex = VectorStoreIndex.from_documents(documents, service_context=service_context)\n\nquery_engine = index.as_query_engine()\nresponse = query_engine.query("What did the author do growing up?")\nprint(response)\n\n '})}),(0,l.jsx)(ep.Z,{children:(0,l.jsx)(eZ.Z,{language:"python",children:'\nfrom langchain.chat_models import ChatOpenAI\nfrom langchain.prompts.chat import (\n ChatPromptTemplate,\n HumanMessagePromptTemplate,\n SystemMessagePromptTemplate,\n)\nfrom langchain.schema import HumanMessage, SystemMessage\n\nchat = ChatOpenAI(\n openai_api_base="http://0.0.0.0:8000",\n model = "gpt-3.5-turbo",\n temperature=0.1,\n extra_body={\n "metadata": {\n "generation_name": "ishaan-generation-langchain-client",\n "generation_id": "langchain-client-gen-id22",\n "trace_id": "langchain-client-trace-id22",\n "trace_user_id": "langchain-client-user-id2"\n }\n }\n)\n\nmessages = [\n SystemMessage(\n content="You are a helpful assistant that im using to make a test request to."\n ),\n HumanMessage(\n content="test from litellm. tell me why it\'s amazing in 1 sentence"\n ),\n]\nresponse = chat(messages)\n\nprint(response)\n\n '})})]})]})})]})]})})})})},ew=s(33509),ek=s(30569);let{Sider:e_}=ew.default;var eb=e=>{let{setPage:t,userRole:s,defaultSelectedKey:n}=e;return(0,l.jsx)(ew.default,{style:{minHeight:"100vh",maxWidth:"120px"},children:(0,l.jsx)(e_,{width:120,children:(0,l.jsxs)(ek.Z,{mode:"inline",defaultSelectedKeys:n||["1"],style:{height:"100%",borderRight:0},children:[(0,l.jsx)(ek.Z.Item,{onClick:()=>t("api-keys"),children:"API Keys"},"1"),(0,l.jsx)(ek.Z.Item,{onClick:()=>t("models"),children:"Models"},"2"),(0,l.jsx)(ek.Z.Item,{onClick:()=>t("llm-playground"),children:"Chat UI"},"3"),(0,l.jsx)(ek.Z.Item,{onClick:()=>t("usage"),children:"Usage"},"4"),"Admin"==s?(0,l.jsx)(ek.Z.Item,{onClick:()=>t("users"),children:"Users"},"5"):null,"Admin"==s?(0,l.jsx)(ek.Z.Item,{onClick:()=>t("teams"),children:"Teams"},"6"):null]})})})};let ev=e=>{let{payload:t,active:s}=e;if(!s||!t)return null;let n=t[0].payload,r=n.startTime,a=Object.entries(n.models).map(e=>{let[t,s]=e;return[t,s]});a.sort((e,t)=>t[1]-e[1]);let o=a.slice(0,5);return(0,l.jsxs)("div",{className:"w-56 rounded-tremor-default border border-tremor-border bg-tremor-background p-2 text-tremor-default shadow-tremor-dropdown",children:[r,o.map(e=>{let[t,s]=e;return(0,l.jsx)("div",{className:"flex flex-1 space-x-10",children:(0,l.jsx)("div",{className:"p-2",children:(0,l.jsxs)("p",{className:"text-tremor-content text-xs",children:[t,":",(0,l.jsxs)("span",{className:"text-xs text-tremor-content-emphasis",children:[" ",s?s<.01?"<$0.01":s.toFixed(2):""]})]})})},t)})]})};var eS=e=>{let{accessToken:t,token:s,userRole:r,userID:a}=e,o=new Date,[i,c]=(0,n.useState)([]),[d,m]=(0,n.useState)([]),[h,u]=(0,n.useState)([]),x=new Date(o.getFullYear(),o.getMonth(),1),p=new Date(o.getFullYear(),o.getMonth()+1,0),j=f(x),y=f(p);function f(e){let t=e.getFullYear(),s=e.getMonth()+1,l=e.getDate();return"".concat(t,"-").concat(s<10?"0"+s:s,"-").concat(l<10?"0"+l:l)}return console.log("Start date is ".concat(j)),console.log("End date is ".concat(y)),(0,n.useEffect)(()=>{t&&s&&r&&a&&(async()=>{try{await g(t,s,r,a,j,y).then(async e=>{let s=(await Z(t,function(e){let t=[];e.forEach(e=>{Object.entries(e).forEach(e=>{let[s,l]=e;"spend"!==s&&"startTime"!==s&&"models"!==s&&"users"!==s&&t.push({key:s,spend:l})})}),t.sort((e,t)=>Number(t.spend)-Number(e.spend));let s=t.slice(0,5).map(e=>e.key);return console.log("topKeys: ".concat(Object.keys(s[0]))),s}(e))).info.map(e=>({key:(e.key_name||e.key_alias||e.token).substring(0,7),spend:e.spend}));m(s),u(function(e){let t={};e.forEach(e=>{Object.entries(e.users).forEach(e=>{let[s,l]=e;""!==s&&null!=s&&"None"!=s&&(t[s]||(t[s]=0),t[s]+=l)})});let s=Object.entries(t).map(e=>{let[t,s]=e;return{user_id:t,spend:s}});s.sort((e,t)=>t.spend-e.spend);let l=s.slice(0,5);return console.log("topKeys: ".concat(Object.values(l[0]))),l}(e)),c(e)})}catch(e){console.error("There was an error fetching the data",e)}})()},[t,s,r,a,j,y]),(0,l.jsx)("div",{style:{width:"100%"},children:(0,l.jsxs)(v.Z,{numItems:2,className:"gap-2 p-10 h-[75vh] w-full",children:[(0,l.jsx)(b.Z,{numColSpan:2,children:(0,l.jsxs)(F.Z,{children:[(0,l.jsx)(G.Z,{children:"Monthly Spend"}),(0,l.jsx)(K.Z,{data:i,index:"startTime",categories:["spend"],colors:["blue"],valueFormatter:e=>"$ ".concat(new Intl.NumberFormat("us").format(e).toString()),yAxisWidth:100,tickGap:5,customTooltip:ev})]})}),(0,l.jsx)(b.Z,{numColSpan:1,children:(0,l.jsxs)(F.Z,{children:[(0,l.jsx)(G.Z,{children:"Top API Keys"}),(0,l.jsx)(K.Z,{className:"mt-4 h-40",data:d,index:"key",categories:["spend"],colors:["blue"],yAxisWidth:80,tickGap:5,layout:"vertical",showXAxis:!1,showLegend:!1})]})}),(0,l.jsx)(b.Z,{numColSpan:1,children:(0,l.jsxs)(F.Z,{children:[(0,l.jsx)(G.Z,{children:"Top Users"}),(0,l.jsx)(K.Z,{className:"mt-4 h-40",data:h,index:"user_id",categories:["spend"],colors:["blue"],yAxisWidth:200,layout:"vertical",showXAxis:!1,showLegend:!1})]})})]})})},eN=()=>{let[e,t]=(0,n.useState)(""),[s,a]=(0,n.useState)(null),[o,c]=(0,n.useState)(null),[d,m]=(0,n.useState)(!0),h=(0,r.useSearchParams)(),u=h.get("userID"),x=h.get("token"),[p,j]=(0,n.useState)("api-keys"),[g,Z]=(0,n.useState)(null);return(0,n.useEffect)(()=>{if(x){let e=(0,et.o)(x);if(e){if(console.log("Decoded token:",e),console.log("Decoded key:",e.key),Z(e.key),e.user_role){let s=function(e){if(!e)return"Undefined Role";switch(console.log("Received user role: ".concat(e)),e.toLowerCase()){case"app_owner":case"demo_app_owner":return"App Owner";case"app_admin":return"Admin";case"app_user":return"App User";default:return"Unknown Role"}}(e.user_role);console.log("Decoded user_role:",s),t(s)}else console.log("User role not defined");e.user_email?a(e.user_email):console.log("User Email is not set ".concat(e)),e.login_method?m("username_password"==e.login_method):console.log("User Email is not set ".concat(e))}}},[x]),(0,l.jsx)(n.Suspense,{fallback:(0,l.jsx)("div",{children:"Loading..."}),children:(0,l.jsxs)("div",{className:"flex flex-col min-h-screen",children:[(0,l.jsx)(i,{userID:u,userRole:e,userEmail:s,showSSOBanner:d}),(0,l.jsxs)("div",{className:"flex flex-1 overflow-auto",children:[(0,l.jsx)(eb,{setPage:j,userRole:e,defaultSelectedKey:null}),"api-keys"==p?(0,l.jsx)(es,{userID:u,userRole:e,teams:o,setUserRole:t,userEmail:s,setUserEmail:a,setTeams:c}):"models"==p?(0,l.jsx)(ea,{userID:u,userRole:e,token:x,accessToken:g}):"llm-playground"==p?(0,l.jsx)(ef,{userID:u,userRole:e,token:x,accessToken:g}):"users"==p?(0,l.jsx)(ec,{userID:u,userRole:e,token:x,accessToken:g}):"teams"==p?(0,l.jsx)(em,{teams:o,setTeams:c,searchParams:h,accessToken:g}):(0,l.jsx)(eS,{userID:u,userRole:e,token:x,accessToken:g})]})]})})}}},function(e){e.O(0,[303,971,69,744],function(){return e(e.s=79615)}),_N_E=e.O()}]);
\ No newline at end of file
diff --git a/litellm/proxy/_experimental/out/_next/static/eSwVwl_InIrhYtCAqDMKF/_buildManifest.js b/litellm/proxy/_experimental/out/_next/static/h6IXdBMiZG7ES547qg1M-/_buildManifest.js
similarity index 100%
rename from litellm/proxy/_experimental/out/_next/static/eSwVwl_InIrhYtCAqDMKF/_buildManifest.js
rename to litellm/proxy/_experimental/out/_next/static/h6IXdBMiZG7ES547qg1M-/_buildManifest.js
diff --git a/litellm/proxy/_experimental/out/_next/static/eSwVwl_InIrhYtCAqDMKF/_ssgManifest.js b/litellm/proxy/_experimental/out/_next/static/h6IXdBMiZG7ES547qg1M-/_ssgManifest.js
similarity index 100%
rename from litellm/proxy/_experimental/out/_next/static/eSwVwl_InIrhYtCAqDMKF/_ssgManifest.js
rename to litellm/proxy/_experimental/out/_next/static/h6IXdBMiZG7ES547qg1M-/_ssgManifest.js
diff --git a/litellm/proxy/_experimental/out/index.html b/litellm/proxy/_experimental/out/index.html
index 935323194c4..a1e9ec23f07 100644
--- a/litellm/proxy/_experimental/out/index.html
+++ b/litellm/proxy/_experimental/out/index.html
@@ -1 +1 @@
-🚅 LiteLLM
\ No newline at end of file
+🚅 LiteLLM
\ No newline at end of file
diff --git a/litellm/proxy/_experimental/out/index.txt b/litellm/proxy/_experimental/out/index.txt
index b732f427065..6f20aff67e7 100644
--- a/litellm/proxy/_experimental/out/index.txt
+++ b/litellm/proxy/_experimental/out/index.txt
@@ -1,7 +1,7 @@
2:I[77831,[],""]
-3:I[24143,["303","static/chunks/303-d80f23087a9e6aec.js","931","static/chunks/app/page-d4fe4a48cbd3572c.js"],""]
+3:I[24143,["303","static/chunks/303-d80f23087a9e6aec.js","931","static/chunks/app/page-cc9d300e3b13fc1b.js"],""]
4:I[5613,[],""]
5:I[31778,[],""]
-0:["eSwVwl_InIrhYtCAqDMKF",[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",{"children":["__PAGE__",{},["$L1",["$","$L2",null,{"propsForComponent":{"params":{}},"Component":"$3","isStaticGeneration":true}],null]]},[null,["$","html",null,{"lang":"en","children":["$","body",null,{"className":"__className_c23dc8","children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"loading":"$undefined","loadingStyles":"$undefined","loadingScripts":"$undefined","hasLoading":false,"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[],"styles":null}]}]}],null]],[[["$","link","0",{"rel":"stylesheet","href":"/ui/_next/static/css/6920a121699cde9c.css","precedence":"next","crossOrigin":""}]],"$L6"]]]]
+0:["h6IXdBMiZG7ES547qg1M-",[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",{"children":["__PAGE__",{},["$L1",["$","$L2",null,{"propsForComponent":{"params":{}},"Component":"$3","isStaticGeneration":true}],null]]},[null,["$","html",null,{"lang":"en","children":["$","body",null,{"className":"__className_c23dc8","children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"loading":"$undefined","loadingStyles":"$undefined","loadingScripts":"$undefined","hasLoading":false,"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[],"styles":null}]}]}],null]],[[["$","link","0",{"rel":"stylesheet","href":"/ui/_next/static/css/6920a121699cde9c.css","precedence":"next","crossOrigin":""}]],"$L6"]]]]
6:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"🚅 LiteLLM"}],["$","meta","3",{"name":"description","content":"LiteLLM Proxy Admin UI"}],["$","link","4",{"rel":"icon","href":"/ui/favicon.ico","type":"image/x-icon","sizes":"16x16"}],["$","meta","5",{"name":"next-size-adjust"}]]
1:null
diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py
index 2e9a48460cd..069d40487be 100644
--- a/litellm/proxy/proxy_server.py
+++ b/litellm/proxy/proxy_server.py
@@ -2315,7 +2315,6 @@ async def startup_event():
### CHECK IF VIEW EXISTS ###
if prisma_client is not None:
create_view_response = await prisma_client.check_view_exists()
- print(f"create_view_response: {create_view_response}") # noqa
### START BUDGET SCHEDULER ###
if prisma_client is not None:
@@ -3788,7 +3787,7 @@ async def view_spend_tags(
@router.get(
"/spend/logs",
- tags=["budget & spend Tracking"],
+ tags=["Budget & Spend Tracking"],
dependencies=[Depends(user_api_key_auth)],
responses={
200: {"model": List[LiteLLM_SpendLogs]},
@@ -4048,6 +4047,83 @@ async def view_spend_logs(
)
+@router.get(
+ "/global/spend/logs",
+ tags=["Budget & Spend Tracking"],
+ dependencies=[Depends(user_api_key_auth)],
+)
+async def global_spend_logs():
+ """
+ [BETA] This is a beta endpoint. It will change.
+
+ Use this to get global spend (spend per day for last 30d). Admin-only endpoint
+
+ More efficient implementation of /spend/logs, by creating a view over the spend logs table.
+ """
+ global prisma_client
+
+ sql_query = """SELECT * FROM "MonthlyGlobalSpend";"""
+
+ response = await prisma_client.db.query_raw(query=sql_query)
+
+ return response
+
+
+@router.get(
+ "/global/spend/keys",
+ tags=["Budget & Spend Tracking"],
+ dependencies=[Depends(user_api_key_auth)],
+)
+async def global_spend_keys(
+ limit: int = fastapi.Query(
+ default=None,
+ description="Number of keys to get. Will return Top 'n' keys.",
+ )
+):
+ """
+ [BETA] This is a beta endpoint. It will change.
+
+ Use this to get the top 'n' keys with the highest spend, ordered by spend.
+ """
+ global prisma_client
+
+ if prisma_client is None:
+ raise HTTPException(status_code=500, detail={"error": "No db connected"})
+ sql_query = f"""SELECT * FROM "Last30dKeysBySpend" LIMIT {limit};"""
+
+ response = await prisma_client.db.query_raw(query=sql_query)
+
+ return response
+
+
+@router.get(
+ "/global/spend/models",
+ tags=["Budget & Spend Tracking"],
+ dependencies=[Depends(user_api_key_auth)],
+)
+async def global_spend_models(
+ limit: int = fastapi.Query(
+ default=None,
+ description="Number of models to get. Will return Top 'n' models.",
+ )
+):
+ """
+ [BETA] This is a beta endpoint. It will change.
+
+ Use this to get the top 'n' keys with the highest spend, ordered by spend.
+ """
+ global prisma_client
+
+ if prisma_client is None:
+ raise HTTPException(status_code=500, detail={"error": "No db connected"})
+
+ sql_query = f"""SELECT * FROM "Last30dModelsBySpend" LIMIT {limit};"""
+
+ response = await prisma_client.db.query_raw(query=sql_query)
+
+ return response
+
+
@router.get(
"/daily_metrics",
summary="Get daily spend metrics",
@@ -4064,7 +4140,11 @@ async def view_daily_metrics(
description="Time till which to view key spend",
),
):
- """ """
+ """
+ [BETA] This is a beta endpoint. It might change without notice.
+
+ Please give feedback - https://github.com/BerriAI/litellm/issues
+ """
try:
if os.getenv("CLICKHOUSE_HOST") is not None:
# gettting spend logs from clickhouse
diff --git a/litellm/proxy/utils.py b/litellm/proxy/utils.py
index f814d609887..ec563bbf339 100644
--- a/litellm/proxy/utils.py
+++ b/litellm/proxy/utils.py
@@ -489,18 +489,20 @@ class PrismaClient:
)
async def check_view_exists(self):
"""
- Checks if the LiteLLM_VerificationTokenView exists in the user's db.
+ Checks if the LiteLLM_VerificationTokenView and MonthlyGlobalSpend exists in the user's db.
- This is used for getting the token + team data in user_api_key_auth
+ LiteLLM_VerificationTokenView: This view is used for getting the token + team data in user_api_key_auth
+
+ MonthlyGlobalSpend: This view is used for the admin view to see global spend for this month
If the view doesn't exist, one will be created.
"""
try:
# Try to select one row from the view
- await self.db.execute_raw(
+ await self.db.query_raw(
"""SELECT 1 FROM "LiteLLM_VerificationTokenView" LIMIT 1"""
)
- return "LiteLLM_VerificationTokenView Exists!"
+ print("LiteLLM_VerificationTokenView Exists!") # noqa
except Exception as e:
# If an error occurs, the view does not exist, so create it
value = await self.health_check()
@@ -518,7 +520,29 @@ class PrismaClient:
"""
)
- return "LiteLLM_VerificationTokenView Created!"
+ print("LiteLLM_VerificationTokenView Created!") # noqa
+
+ try:
+ await self.db.query_raw("""SELECT 1 FROM "MonthlyGlobalSpend" LIMIT 1""")
+ print("MonthlyGlobalSpend Exists!") # noqa
+ except Exception as e:
+ sql_query = """
+ CREATE OR REPLACE VIEW "MonthlyGlobalSpend" AS
+ SELECT
+ DATE("startTime") AS date,
+ SUM("spend") AS spend
+ FROM
+ "LiteLLM_SpendLogs"
+ WHERE
+ "startTime" >= (CURRENT_DATE - INTERVAL '30 days')
+ GROUP BY
+ DATE("startTime");
+ """
+ await self.db.execute_raw(query=sql_query)
+
+ print("MonthlyGlobalSpend Created!") # noqa
+
+ return
@backoff.on_exception(
backoff.expo,
diff --git a/litellm/tests/test_amazing_s3_logs.py b/litellm/tests/test_amazing_s3_logs.py
index 7b8eb4a47d7..74d6eb5b945 100644
--- a/litellm/tests/test_amazing_s3_logs.py
+++ b/litellm/tests/test_amazing_s3_logs.py
@@ -1,253 +1,254 @@
-import sys
-import os
-import io, asyncio
+## @pytest.mark.skip(reason="AWS Suspended Account")
+# import sys
+# import os
+# import io, asyncio
-# import logging
-# logging.basicConfig(level=logging.DEBUG)
-sys.path.insert(0, os.path.abspath("../.."))
+# # import logging
+# # logging.basicConfig(level=logging.DEBUG)
+# sys.path.insert(0, os.path.abspath("../.."))
-from litellm import completion
-import litellm
+# from litellm import completion
+# import litellm
-litellm.num_retries = 3
+# litellm.num_retries = 3
-import time, random
-import pytest
+# import time, random
+# import pytest
-def test_s3_logging():
- # all s3 requests need to be in one test function
- # since we are modifying stdout, and pytests runs tests in parallel
- # on circle ci - we only test litellm.acompletion()
- try:
- # redirect stdout to log_file
- litellm.cache = litellm.Cache(
- type="s3", s3_bucket_name="cache-bucket-litellm", s3_region_name="us-west-2"
- )
+# def test_s3_logging():
+# # all s3 requests need to be in one test function
+# # since we are modifying stdout, and pytests runs tests in parallel
+# # on circle ci - we only test litellm.acompletion()
+# try:
+# # redirect stdout to log_file
+# litellm.cache = litellm.Cache(
+# type="s3", s3_bucket_name="cache-bucket-litellm", s3_region_name="us-west-2"
+# )
- litellm.success_callback = ["s3"]
- litellm.s3_callback_params = {
- "s3_bucket_name": "litellm-logs",
- "s3_aws_secret_access_key": "os.environ/AWS_SECRET_ACCESS_KEY",
- "s3_aws_access_key_id": "os.environ/AWS_ACCESS_KEY_ID",
- }
- litellm.set_verbose = True
+# litellm.success_callback = ["s3"]
+# litellm.s3_callback_params = {
+# "s3_bucket_name": "litellm-logs",
+# "s3_aws_secret_access_key": "os.environ/AWS_SECRET_ACCESS_KEY",
+# "s3_aws_access_key_id": "os.environ/AWS_ACCESS_KEY_ID",
+# }
+# litellm.set_verbose = True
- print("Testing async s3 logging")
+# print("Testing async s3 logging")
- expected_keys = []
+# expected_keys = []
- import time
+# import time
- curr_time = str(time.time())
+# curr_time = str(time.time())
- async def _test():
- return await litellm.acompletion(
- model="gpt-3.5-turbo",
- messages=[{"role": "user", "content": f"This is a test {curr_time}"}],
- max_tokens=10,
- temperature=0.7,
- user="ishaan-2",
- )
+# async def _test():
+# return await litellm.acompletion(
+# model="gpt-3.5-turbo",
+# messages=[{"role": "user", "content": f"This is a test {curr_time}"}],
+# max_tokens=10,
+# temperature=0.7,
+# user="ishaan-2",
+# )
- response = asyncio.run(_test())
- print(f"response: {response}")
- expected_keys.append(response.id)
+# response = asyncio.run(_test())
+# print(f"response: {response}")
+# expected_keys.append(response.id)
- async def _test():
- return await litellm.acompletion(
- model="gpt-3.5-turbo",
- messages=[{"role": "user", "content": f"This is a test {curr_time}"}],
- max_tokens=10,
- temperature=0.7,
- user="ishaan-2",
- )
+# async def _test():
+# return await litellm.acompletion(
+# model="gpt-3.5-turbo",
+# messages=[{"role": "user", "content": f"This is a test {curr_time}"}],
+# max_tokens=10,
+# temperature=0.7,
+# user="ishaan-2",
+# )
- response = asyncio.run(_test())
- expected_keys.append(response.id)
- print(f"response: {response}")
- time.sleep(5) # wait 5s for logs to land
+# response = asyncio.run(_test())
+# expected_keys.append(response.id)
+# print(f"response: {response}")
+# time.sleep(5) # wait 5s for logs to land
- import boto3
+# import boto3
- s3 = boto3.client("s3")
- bucket_name = "litellm-logs"
- # List objects in the bucket
- response = s3.list_objects(Bucket=bucket_name)
+# s3 = boto3.client("s3")
+# bucket_name = "litellm-logs"
+# # List objects in the bucket
+# response = s3.list_objects(Bucket=bucket_name)
- # Sort the objects based on the LastModified timestamp
- objects = sorted(
- response["Contents"], key=lambda x: x["LastModified"], reverse=True
- )
- # Get the keys of the most recent objects
- most_recent_keys = [obj["Key"] for obj in objects]
- print(most_recent_keys)
- # for each key, get the part before "-" as the key. Do it safely
- cleaned_keys = []
- for key in most_recent_keys:
- split_key = key.split("_")
- if len(split_key) < 2:
- continue
- cleaned_keys.append(split_key[1])
- print("\n most recent keys", most_recent_keys)
- print("\n cleaned keys", cleaned_keys)
- print("\n Expected keys: ", expected_keys)
- matches = 0
- for key in expected_keys:
- key += ".json"
- assert key in cleaned_keys
+# # Sort the objects based on the LastModified timestamp
+# objects = sorted(
+# response["Contents"], key=lambda x: x["LastModified"], reverse=True
+# )
+# # Get the keys of the most recent objects
+# most_recent_keys = [obj["Key"] for obj in objects]
+# print(most_recent_keys)
+# # for each key, get the part before "-" as the key. Do it safely
+# cleaned_keys = []
+# for key in most_recent_keys:
+# split_key = key.split("_")
+# if len(split_key) < 2:
+# continue
+# cleaned_keys.append(split_key[1])
+# print("\n most recent keys", most_recent_keys)
+# print("\n cleaned keys", cleaned_keys)
+# print("\n Expected keys: ", expected_keys)
+# matches = 0
+# for key in expected_keys:
+# key += ".json"
+# assert key in cleaned_keys
- if key in cleaned_keys:
- matches += 1
- # remove the match key
- cleaned_keys.remove(key)
- # this asserts we log, the first request + the 2nd cached request
- print("we had two matches ! passed ", matches)
- assert matches == 2
- try:
- # cleanup s3 bucket in test
- for key in most_recent_keys:
- s3.delete_object(Bucket=bucket_name, Key=key)
- except:
- # don't let cleanup fail a test
- pass
- except Exception as e:
- pytest.fail(f"An exception occurred - {e}")
- finally:
- # post, close log file and verify
- # Reset stdout to the original value
- print("Passed! Testing async s3 logging")
+# if key in cleaned_keys:
+# matches += 1
+# # remove the match key
+# cleaned_keys.remove(key)
+# # this asserts we log, the first request + the 2nd cached request
+# print("we had two matches ! passed ", matches)
+# assert matches == 2
+# try:
+# # cleanup s3 bucket in test
+# for key in most_recent_keys:
+# s3.delete_object(Bucket=bucket_name, Key=key)
+# except:
+# # don't let cleanup fail a test
+# pass
+# except Exception as e:
+# pytest.fail(f"An exception occurred - {e}")
+# finally:
+# # post, close log file and verify
+# # Reset stdout to the original value
+# print("Passed! Testing async s3 logging")
-# test_s3_logging()
+# # test_s3_logging()
-def test_s3_logging_async():
- # this tests time added to make s3 logging calls, vs just acompletion calls
- try:
- litellm.set_verbose = True
- # Make 5 calls with an empty success_callback
- litellm.success_callback = []
- start_time_empty_callback = asyncio.run(make_async_calls())
- print("done with no callback test")
+# def test_s3_logging_async():
+# # this tests time added to make s3 logging calls, vs just acompletion calls
+# try:
+# litellm.set_verbose = True
+# # Make 5 calls with an empty success_callback
+# litellm.success_callback = []
+# start_time_empty_callback = asyncio.run(make_async_calls())
+# print("done with no callback test")
- print("starting s3 logging load test")
- # Make 5 calls with success_callback set to "langfuse"
- litellm.success_callback = ["s3"]
- litellm.s3_callback_params = {
- "s3_bucket_name": "litellm-logs",
- "s3_aws_secret_access_key": "os.environ/AWS_SECRET_ACCESS_KEY",
- "s3_aws_access_key_id": "os.environ/AWS_ACCESS_KEY_ID",
- }
- start_time_s3 = asyncio.run(make_async_calls())
- print("done with s3 test")
+# print("starting s3 logging load test")
+# # Make 5 calls with success_callback set to "langfuse"
+# litellm.success_callback = ["s3"]
+# litellm.s3_callback_params = {
+# "s3_bucket_name": "litellm-logs",
+# "s3_aws_secret_access_key": "os.environ/AWS_SECRET_ACCESS_KEY",
+# "s3_aws_access_key_id": "os.environ/AWS_ACCESS_KEY_ID",
+# }
+# start_time_s3 = asyncio.run(make_async_calls())
+# print("done with s3 test")
- # Compare the time for both scenarios
- print(f"Time taken with success_callback='s3': {start_time_s3}")
- print(f"Time taken with empty success_callback: {start_time_empty_callback}")
+# # Compare the time for both scenarios
+# print(f"Time taken with success_callback='s3': {start_time_s3}")
+# print(f"Time taken with empty success_callback: {start_time_empty_callback}")
- # assert the diff is not more than 1 second
- assert abs(start_time_s3 - start_time_empty_callback) < 1
+# # assert the diff is not more than 1 second
+# assert abs(start_time_s3 - start_time_empty_callback) < 1
- except litellm.Timeout as e:
- pass
- except Exception as e:
- pytest.fail(f"An exception occurred - {e}")
+# except litellm.Timeout as e:
+# pass
+# except Exception as e:
+# pytest.fail(f"An exception occurred - {e}")
-async def make_async_calls():
- tasks = []
- for _ in range(5):
- task = asyncio.create_task(
- litellm.acompletion(
- model="azure/chatgpt-v-2",
- messages=[{"role": "user", "content": "This is a test"}],
- max_tokens=5,
- temperature=0.7,
- timeout=5,
- user="langfuse_latency_test_user",
- mock_response="It's simple to use and easy to get started",
- )
- )
- tasks.append(task)
+# async def make_async_calls():
+# tasks = []
+# for _ in range(5):
+# task = asyncio.create_task(
+# litellm.acompletion(
+# model="azure/chatgpt-v-2",
+# messages=[{"role": "user", "content": "This is a test"}],
+# max_tokens=5,
+# temperature=0.7,
+# timeout=5,
+# user="langfuse_latency_test_user",
+# mock_response="It's simple to use and easy to get started",
+# )
+# )
+# tasks.append(task)
- # Measure the start time before running the tasks
- start_time = asyncio.get_event_loop().time()
+# # Measure the start time before running the tasks
+# start_time = asyncio.get_event_loop().time()
- # Wait for all tasks to complete
- responses = await asyncio.gather(*tasks)
+# # Wait for all tasks to complete
+# responses = await asyncio.gather(*tasks)
- # Print the responses when tasks return
- for idx, response in enumerate(responses):
- print(f"Response from Task {idx + 1}: {response}")
+# # Print the responses when tasks return
+# for idx, response in enumerate(responses):
+# print(f"Response from Task {idx + 1}: {response}")
- # Calculate the total time taken
- total_time = asyncio.get_event_loop().time() - start_time
+# # Calculate the total time taken
+# total_time = asyncio.get_event_loop().time() - start_time
- return total_time
+# return total_time
-def test_s3_logging_r2():
- # all s3 requests need to be in one test function
- # since we are modifying stdout, and pytests runs tests in parallel
- # on circle ci - we only test litellm.acompletion()
- try:
- # redirect stdout to log_file
- # litellm.cache = litellm.Cache(
- # type="s3", s3_bucket_name="litellm-r2-bucket", s3_region_name="us-west-2"
- # )
- litellm.set_verbose = True
- from litellm._logging import verbose_logger
- import logging
+# def test_s3_logging_r2():
+# # all s3 requests need to be in one test function
+# # since we are modifying stdout, and pytests runs tests in parallel
+# # on circle ci - we only test litellm.acompletion()
+# try:
+# # redirect stdout to log_file
+# # litellm.cache = litellm.Cache(
+# # type="s3", s3_bucket_name="litellm-r2-bucket", s3_region_name="us-west-2"
+# # )
+# litellm.set_verbose = True
+# from litellm._logging import verbose_logger
+# import logging
- verbose_logger.setLevel(level=logging.DEBUG)
+# verbose_logger.setLevel(level=logging.DEBUG)
- litellm.success_callback = ["s3"]
- litellm.s3_callback_params = {
- "s3_bucket_name": "litellm-r2-bucket",
- "s3_aws_secret_access_key": "os.environ/R2_S3_ACCESS_KEY",
- "s3_aws_access_key_id": "os.environ/R2_S3_ACCESS_ID",
- "s3_endpoint_url": "os.environ/R2_S3_URL",
- "s3_region_name": "os.environ/R2_S3_REGION_NAME",
- }
- print("Testing async s3 logging")
+# litellm.success_callback = ["s3"]
+# litellm.s3_callback_params = {
+# "s3_bucket_name": "litellm-r2-bucket",
+# "s3_aws_secret_access_key": "os.environ/R2_S3_ACCESS_KEY",
+# "s3_aws_access_key_id": "os.environ/R2_S3_ACCESS_ID",
+# "s3_endpoint_url": "os.environ/R2_S3_URL",
+# "s3_region_name": "os.environ/R2_S3_REGION_NAME",
+# }
+# print("Testing async s3 logging")
- expected_keys = []
+# expected_keys = []
- import time
+# import time
- curr_time = str(time.time())
+# curr_time = str(time.time())
- async def _test():
- return await litellm.acompletion(
- model="gpt-3.5-turbo",
- messages=[{"role": "user", "content": f"This is a test {curr_time}"}],
- max_tokens=10,
- temperature=0.7,
- user="ishaan-2",
- )
+# async def _test():
+# return await litellm.acompletion(
+# model="gpt-3.5-turbo",
+# messages=[{"role": "user", "content": f"This is a test {curr_time}"}],
+# max_tokens=10,
+# temperature=0.7,
+# user="ishaan-2",
+# )
- response = asyncio.run(_test())
- print(f"response: {response}")
- expected_keys.append(response.id)
+# response = asyncio.run(_test())
+# print(f"response: {response}")
+# expected_keys.append(response.id)
- import boto3
+# import boto3
- s3 = boto3.client(
- "s3",
- endpoint_url=os.getenv("R2_S3_URL"),
- region_name=os.getenv("R2_S3_REGION_NAME"),
- aws_access_key_id=os.getenv("R2_S3_ACCESS_ID"),
- aws_secret_access_key=os.getenv("R2_S3_ACCESS_KEY"),
- )
+# s3 = boto3.client(
+# "s3",
+# endpoint_url=os.getenv("R2_S3_URL"),
+# region_name=os.getenv("R2_S3_REGION_NAME"),
+# aws_access_key_id=os.getenv("R2_S3_ACCESS_ID"),
+# aws_secret_access_key=os.getenv("R2_S3_ACCESS_KEY"),
+# )
- bucket_name = "litellm-r2-bucket"
- # List objects in the bucket
- response = s3.list_objects(Bucket=bucket_name)
+# bucket_name = "litellm-r2-bucket"
+# # List objects in the bucket
+# response = s3.list_objects(Bucket=bucket_name)
- except Exception as e:
- pytest.fail(f"An exception occurred - {e}")
- finally:
- # post, close log file and verify
- # Reset stdout to the original value
- print("Passed! Testing async s3 logging")
+# except Exception as e:
+# pytest.fail(f"An exception occurred - {e}")
+# finally:
+# # post, close log file and verify
+# # Reset stdout to the original value
+# print("Passed! Testing async s3 logging")
diff --git a/litellm/tests/test_async_fn.py b/litellm/tests/test_async_fn.py
index 68adf997aaa..f3246d6d371 100644
--- a/litellm/tests/test_async_fn.py
+++ b/litellm/tests/test_async_fn.py
@@ -212,6 +212,7 @@ async def test_hf_completion_tgi():
# test_get_cloudflare_response_streaming()
+@pytest.mark.skip(reason="AWS Suspended Account")
@pytest.mark.asyncio
async def test_completion_sagemaker():
# litellm.set_verbose=True
diff --git a/litellm/tests/test_bedrock_completion.py b/litellm/tests/test_bedrock_completion.py
index d672ca78011..a448fc3a57f 100644
--- a/litellm/tests/test_bedrock_completion.py
+++ b/litellm/tests/test_bedrock_completion.py
@@ -1,257 +1,259 @@
-import sys, os
-import traceback
-from dotenv import load_dotenv
+# @pytest.mark.skip(reason="AWS Suspended Account")
+# import sys, os
+# import traceback
+# from dotenv import load_dotenv
-load_dotenv()
-import os, io
+# load_dotenv()
+# import os, io
-sys.path.insert(
- 0, os.path.abspath("../..")
-) # Adds the parent directory to the system path
-import pytest
-import litellm
-from litellm import embedding, completion, completion_cost, Timeout
-from litellm import RateLimitError
+# sys.path.insert(
+# 0, os.path.abspath("../..")
+# ) # Adds the parent directory to the system path
+# import pytest
+# import litellm
+# from litellm import embedding, completion, completion_cost, Timeout
+# from litellm import RateLimitError
-# litellm.num_retries = 3
-litellm.cache = None
-litellm.success_callback = []
-user_message = "Write a short poem about the sky"
-messages = [{"content": user_message, "role": "user"}]
+# # litellm.num_retries = 3
+# litellm.cache = None
+# litellm.success_callback = []
+# user_message = "Write a short poem about the sky"
+# messages = [{"content": user_message, "role": "user"}]
-@pytest.fixture(autouse=True)
-def reset_callbacks():
- print("\npytest fixture - resetting callbacks")
- litellm.success_callback = []
- litellm._async_success_callback = []
- litellm.failure_callback = []
- litellm.callbacks = []
+# @pytest.fixture(autouse=True)
+# def reset_callbacks():
+# print("\npytest fixture - resetting callbacks")
+# litellm.success_callback = []
+# litellm._async_success_callback = []
+# litellm.failure_callback = []
+# litellm.callbacks = []
-def test_completion_bedrock_claude_completion_auth():
- print("calling bedrock claude completion params auth")
- import os
+# def test_completion_bedrock_claude_completion_auth():
+# print("calling bedrock claude completion params auth")
+# import os
- aws_access_key_id = os.environ["AWS_ACCESS_KEY_ID"]
- aws_secret_access_key = os.environ["AWS_SECRET_ACCESS_KEY"]
- aws_region_name = os.environ["AWS_REGION_NAME"]
+# aws_access_key_id = os.environ["AWS_ACCESS_KEY_ID"]
+# aws_secret_access_key = os.environ["AWS_SECRET_ACCESS_KEY"]
+# aws_region_name = os.environ["AWS_REGION_NAME"]
- os.environ.pop("AWS_ACCESS_KEY_ID", None)
- os.environ.pop("AWS_SECRET_ACCESS_KEY", None)
- os.environ.pop("AWS_REGION_NAME", None)
+# os.environ.pop("AWS_ACCESS_KEY_ID", None)
+# os.environ.pop("AWS_SECRET_ACCESS_KEY", None)
+# os.environ.pop("AWS_REGION_NAME", None)
- try:
- response = completion(
- model="bedrock/anthropic.claude-instant-v1",
- messages=messages,
- max_tokens=10,
- temperature=0.1,
- aws_access_key_id=aws_access_key_id,
- aws_secret_access_key=aws_secret_access_key,
- aws_region_name=aws_region_name,
- )
- # Add any assertions here to check the response
- print(response)
+# try:
+# response = completion(
+# model="bedrock/anthropic.claude-instant-v1",
+# messages=messages,
+# max_tokens=10,
+# temperature=0.1,
+# aws_access_key_id=aws_access_key_id,
+# aws_secret_access_key=aws_secret_access_key,
+# aws_region_name=aws_region_name,
+# )
+# # Add any assertions here to check the response
+# print(response)
- os.environ["AWS_ACCESS_KEY_ID"] = aws_access_key_id
- os.environ["AWS_SECRET_ACCESS_KEY"] = aws_secret_access_key
- os.environ["AWS_REGION_NAME"] = aws_region_name
- except RateLimitError:
- pass
- except Exception as e:
- pytest.fail(f"Error occurred: {e}")
+# os.environ["AWS_ACCESS_KEY_ID"] = aws_access_key_id
+# os.environ["AWS_SECRET_ACCESS_KEY"] = aws_secret_access_key
+# os.environ["AWS_REGION_NAME"] = aws_region_name
+# except RateLimitError:
+# pass
+# except Exception as e:
+# pytest.fail(f"Error occurred: {e}")
-# test_completion_bedrock_claude_completion_auth()
+# # test_completion_bedrock_claude_completion_auth()
-def test_completion_bedrock_claude_2_1_completion_auth():
- print("calling bedrock claude 2.1 completion params auth")
- import os
+# def test_completion_bedrock_claude_2_1_completion_auth():
+# print("calling bedrock claude 2.1 completion params auth")
+# import os
- aws_access_key_id = os.environ["AWS_ACCESS_KEY_ID"]
- aws_secret_access_key = os.environ["AWS_SECRET_ACCESS_KEY"]
- aws_region_name = os.environ["AWS_REGION_NAME"]
+# aws_access_key_id = os.environ["AWS_ACCESS_KEY_ID"]
+# aws_secret_access_key = os.environ["AWS_SECRET_ACCESS_KEY"]
+# aws_region_name = os.environ["AWS_REGION_NAME"]
- os.environ.pop("AWS_ACCESS_KEY_ID", None)
- os.environ.pop("AWS_SECRET_ACCESS_KEY", None)
- os.environ.pop("AWS_REGION_NAME", None)
- try:
- response = completion(
- model="bedrock/anthropic.claude-v2:1",
- messages=messages,
- max_tokens=10,
- temperature=0.1,
- aws_access_key_id=aws_access_key_id,
- aws_secret_access_key=aws_secret_access_key,
- aws_region_name=aws_region_name,
- )
- # Add any assertions here to check the response
- print(response)
+# os.environ.pop("AWS_ACCESS_KEY_ID", None)
+# os.environ.pop("AWS_SECRET_ACCESS_KEY", None)
+# os.environ.pop("AWS_REGION_NAME", None)
+# try:
+# response = completion(
+# model="bedrock/anthropic.claude-v2:1",
+# messages=messages,
+# max_tokens=10,
+# temperature=0.1,
+# aws_access_key_id=aws_access_key_id,
+# aws_secret_access_key=aws_secret_access_key,
+# aws_region_name=aws_region_name,
+# )
+# # Add any assertions here to check the response
+# print(response)
- os.environ["AWS_ACCESS_KEY_ID"] = aws_access_key_id
- os.environ["AWS_SECRET_ACCESS_KEY"] = aws_secret_access_key
- os.environ["AWS_REGION_NAME"] = aws_region_name
- except RateLimitError:
- pass
- except Exception as e:
- pytest.fail(f"Error occurred: {e}")
+# os.environ["AWS_ACCESS_KEY_ID"] = aws_access_key_id
+# os.environ["AWS_SECRET_ACCESS_KEY"] = aws_secret_access_key
+# os.environ["AWS_REGION_NAME"] = aws_region_name
+# except RateLimitError:
+# pass
+# except Exception as e:
+# pytest.fail(f"Error occurred: {e}")
-# test_completion_bedrock_claude_2_1_completion_auth()
+# # test_completion_bedrock_claude_2_1_completion_auth()
-def test_completion_bedrock_claude_external_client_auth():
- print("\ncalling bedrock claude external client auth")
- import os
+# def test_completion_bedrock_claude_external_client_auth():
+# print("\ncalling bedrock claude external client auth")
+# import os
- aws_access_key_id = os.environ["AWS_ACCESS_KEY_ID"]
- aws_secret_access_key = os.environ["AWS_SECRET_ACCESS_KEY"]
- aws_region_name = os.environ["AWS_REGION_NAME"]
+# aws_access_key_id = os.environ["AWS_ACCESS_KEY_ID"]
+# aws_secret_access_key = os.environ["AWS_SECRET_ACCESS_KEY"]
+# aws_region_name = os.environ["AWS_REGION_NAME"]
- os.environ.pop("AWS_ACCESS_KEY_ID", None)
- os.environ.pop("AWS_SECRET_ACCESS_KEY", None)
- os.environ.pop("AWS_REGION_NAME", None)
+# os.environ.pop("AWS_ACCESS_KEY_ID", None)
+# os.environ.pop("AWS_SECRET_ACCESS_KEY", None)
+# os.environ.pop("AWS_REGION_NAME", None)
- try:
- import boto3
+# try:
+# import boto3
- litellm.set_verbose = True
+# litellm.set_verbose = True
- bedrock = boto3.client(
- service_name="bedrock-runtime",
- region_name=aws_region_name,
- aws_access_key_id=aws_access_key_id,
- aws_secret_access_key=aws_secret_access_key,
- endpoint_url=f"https://bedrock-runtime.{aws_region_name}.amazonaws.com",
- )
+# bedrock = boto3.client(
+# service_name="bedrock-runtime",
+# region_name=aws_region_name,
+# aws_access_key_id=aws_access_key_id,
+# aws_secret_access_key=aws_secret_access_key,
+# endpoint_url=f"https://bedrock-runtime.{aws_region_name}.amazonaws.com",
+# )
- response = completion(
- model="bedrock/anthropic.claude-instant-v1",
- messages=messages,
- max_tokens=10,
- temperature=0.1,
- aws_bedrock_client=bedrock,
- )
- # Add any assertions here to check the response
- print(response)
+# response = completion(
+# model="bedrock/anthropic.claude-instant-v1",
+# messages=messages,
+# max_tokens=10,
+# temperature=0.1,
+# aws_bedrock_client=bedrock,
+# )
+# # Add any assertions here to check the response
+# print(response)
- os.environ["AWS_ACCESS_KEY_ID"] = aws_access_key_id
- os.environ["AWS_SECRET_ACCESS_KEY"] = aws_secret_access_key
- os.environ["AWS_REGION_NAME"] = aws_region_name
- except RateLimitError:
- pass
- except Exception as e:
- pytest.fail(f"Error occurred: {e}")
+# os.environ["AWS_ACCESS_KEY_ID"] = aws_access_key_id
+# os.environ["AWS_SECRET_ACCESS_KEY"] = aws_secret_access_key
+# os.environ["AWS_REGION_NAME"] = aws_region_name
+# except RateLimitError:
+# pass
+# except Exception as e:
+# pytest.fail(f"Error occurred: {e}")
-# test_completion_bedrock_claude_external_client_auth()
+# # test_completion_bedrock_claude_external_client_auth()
-def test_completion_bedrock_claude_sts_client_auth():
- print("\ncalling bedrock claude external client auth")
- import os
+# @pytest.mark.skip(reason="Expired token, need to renew")
+# def test_completion_bedrock_claude_sts_client_auth():
+# print("\ncalling bedrock claude external client auth")
+# import os
- aws_access_key_id = os.environ["AWS_TEMP_ACCESS_KEY_ID"]
- aws_secret_access_key = os.environ["AWS_TEMP_SECRET_ACCESS_KEY"]
- aws_region_name = os.environ["AWS_REGION_NAME"]
- aws_role_name = os.environ["AWS_TEMP_ROLE_NAME"]
+# aws_access_key_id = os.environ["AWS_TEMP_ACCESS_KEY_ID"]
+# aws_secret_access_key = os.environ["AWS_TEMP_SECRET_ACCESS_KEY"]
+# aws_region_name = os.environ["AWS_REGION_NAME"]
+# aws_role_name = os.environ["AWS_TEMP_ROLE_NAME"]
- try:
- import boto3
+# try:
+# import boto3
- litellm.set_verbose = True
+# litellm.set_verbose = True
- response = completion(
- model="bedrock/anthropic.claude-instant-v1",
- messages=messages,
- max_tokens=10,
- temperature=0.1,
- aws_region_name=aws_region_name,
- aws_access_key_id=aws_access_key_id,
- aws_secret_access_key=aws_secret_access_key,
- aws_role_name=aws_role_name,
- aws_session_name="my-test-session",
- )
+# response = completion(
+# model="bedrock/anthropic.claude-instant-v1",
+# messages=messages,
+# max_tokens=10,
+# temperature=0.1,
+# aws_region_name=aws_region_name,
+# aws_access_key_id=aws_access_key_id,
+# aws_secret_access_key=aws_secret_access_key,
+# aws_role_name=aws_role_name,
+# aws_session_name="my-test-session",
+# )
- response = embedding(
- model="cohere.embed-multilingual-v3",
- input=["hello world"],
- aws_region_name="us-east-1",
- aws_access_key_id=aws_access_key_id,
- aws_secret_access_key=aws_secret_access_key,
- aws_role_name=aws_role_name,
- aws_session_name="my-test-session",
- )
+# response = embedding(
+# model="cohere.embed-multilingual-v3",
+# input=["hello world"],
+# aws_region_name="us-east-1",
+# aws_access_key_id=aws_access_key_id,
+# aws_secret_access_key=aws_secret_access_key,
+# aws_role_name=aws_role_name,
+# aws_session_name="my-test-session",
+# )
- response = completion(
- model="gpt-3.5-turbo",
- messages=messages,
- aws_region_name="us-east-1",
- aws_access_key_id=aws_access_key_id,
- aws_secret_access_key=aws_secret_access_key,
- aws_role_name=aws_role_name,
- aws_session_name="my-test-session",
- )
- # Add any assertions here to check the response
- print(response)
- except RateLimitError:
- pass
- except Exception as e:
- pytest.fail(f"Error occurred: {e}")
+# response = completion(
+# model="gpt-3.5-turbo",
+# messages=messages,
+# aws_region_name="us-east-1",
+# aws_access_key_id=aws_access_key_id,
+# aws_secret_access_key=aws_secret_access_key,
+# aws_role_name=aws_role_name,
+# aws_session_name="my-test-session",
+# )
+# # Add any assertions here to check the response
+# print(response)
+# except RateLimitError:
+# pass
+# except Exception as e:
+# pytest.fail(f"Error occurred: {e}")
-test_completion_bedrock_claude_sts_client_auth()
+# # test_completion_bedrock_claude_sts_client_auth()
-def test_provisioned_throughput():
- try:
- litellm.set_verbose = True
- import botocore, json, io
- import botocore.session
- from botocore.stub import Stubber
+# def test_provisioned_throughput():
+# try:
+# litellm.set_verbose = True
+# import botocore, json, io
+# import botocore.session
+# from botocore.stub import Stubber
- bedrock_client = botocore.session.get_session().create_client(
- "bedrock-runtime", region_name="us-east-1"
- )
+# bedrock_client = botocore.session.get_session().create_client(
+# "bedrock-runtime", region_name="us-east-1"
+# )
- expected_params = {
- "accept": "application/json",
- "body": '{"prompt": "\\n\\nHuman: Hello, how are you?\\n\\nAssistant: ", '
- '"max_tokens_to_sample": 256}',
- "contentType": "application/json",
- "modelId": "provisioned-model-arn",
- }
- response_from_bedrock = {
- "body": io.StringIO(
- json.dumps(
- {
- "completion": " Here is a short poem about the sky:",
- "stop_reason": "max_tokens",
- "stop": None,
- }
- )
- ),
- "contentType": "contentType",
- "ResponseMetadata": {"HTTPStatusCode": 200},
- }
+# expected_params = {
+# "accept": "application/json",
+# "body": '{"prompt": "\\n\\nHuman: Hello, how are you?\\n\\nAssistant: ", '
+# '"max_tokens_to_sample": 256}',
+# "contentType": "application/json",
+# "modelId": "provisioned-model-arn",
+# }
+# response_from_bedrock = {
+# "body": io.StringIO(
+# json.dumps(
+# {
+# "completion": " Here is a short poem about the sky:",
+# "stop_reason": "max_tokens",
+# "stop": None,
+# }
+# )
+# ),
+# "contentType": "contentType",
+# "ResponseMetadata": {"HTTPStatusCode": 200},
+# }
- with Stubber(bedrock_client) as stubber:
- stubber.add_response(
- "invoke_model",
- service_response=response_from_bedrock,
- expected_params=expected_params,
- )
- response = litellm.completion(
- model="bedrock/anthropic.claude-instant-v1",
- model_id="provisioned-model-arn",
- messages=[{"content": "Hello, how are you?", "role": "user"}],
- aws_bedrock_client=bedrock_client,
- )
- print("response stubbed", response)
- except Exception as e:
- pytest.fail(f"Error occurred: {e}")
+# with Stubber(bedrock_client) as stubber:
+# stubber.add_response(
+# "invoke_model",
+# service_response=response_from_bedrock,
+# expected_params=expected_params,
+# )
+# response = litellm.completion(
+# model="bedrock/anthropic.claude-instant-v1",
+# model_id="provisioned-model-arn",
+# messages=[{"content": "Hello, how are you?", "role": "user"}],
+# aws_bedrock_client=bedrock_client,
+# )
+# print("response stubbed", response)
+# except Exception as e:
+# pytest.fail(f"Error occurred: {e}")
-# test_provisioned_throughput()
+# # test_provisioned_throughput()
diff --git a/litellm/tests/test_caching.py b/litellm/tests/test_caching.py
index de9740ebdfa..1764b65c046 100644
--- a/litellm/tests/test_caching.py
+++ b/litellm/tests/test_caching.py
@@ -546,6 +546,7 @@ def test_redis_cache_acompletion_stream():
# test_redis_cache_acompletion_stream()
+@pytest.mark.skip(reason="AWS Suspended Account")
def test_redis_cache_acompletion_stream_bedrock():
import asyncio
diff --git a/litellm/tests/test_completion.py b/litellm/tests/test_completion.py
index ebcd958e1c3..db83152af84 100644
--- a/litellm/tests/test_completion.py
+++ b/litellm/tests/test_completion.py
@@ -1404,6 +1404,7 @@ def test_customprompt_together_ai():
# test_customprompt_together_ai()
+@pytest.mark.skip(reason="AWS Suspended Account")
def test_completion_sagemaker():
try:
litellm.set_verbose = True
@@ -1429,6 +1430,7 @@ def test_completion_sagemaker():
# test_completion_sagemaker()
+@pytest.mark.skip(reason="AWS Suspended Account")
def test_completion_sagemaker_stream():
try:
litellm.set_verbose = False
@@ -1459,6 +1461,7 @@ def test_completion_sagemaker_stream():
pytest.fail(f"Error occurred: {e}")
+@pytest.mark.skip(reason="AWS Suspended Account")
def test_completion_chat_sagemaker():
try:
messages = [{"role": "user", "content": "Hey, how's it going?"}]
@@ -1483,6 +1486,7 @@ def test_completion_chat_sagemaker():
# test_completion_chat_sagemaker()
+@pytest.mark.skip(reason="AWS Suspended Account")
def test_completion_chat_sagemaker_mistral():
try:
messages = [{"role": "user", "content": "Hey, how's it going?"}]
@@ -1501,6 +1505,7 @@ def test_completion_chat_sagemaker_mistral():
# test_completion_chat_sagemaker_mistral()
+@pytest.mark.skip(reason="AWS Suspended Account")
def test_completion_bedrock_titan_null_response():
try:
response = completion(
@@ -1526,6 +1531,7 @@ def test_completion_bedrock_titan_null_response():
pytest.fail(f"An error occurred - {str(e)}")
+@pytest.mark.skip(reason="AWS Suspended Account")
def test_completion_bedrock_titan():
try:
response = completion(
@@ -1547,6 +1553,7 @@ def test_completion_bedrock_titan():
# test_completion_bedrock_titan()
+@pytest.mark.skip(reason="AWS Suspended Account")
def test_completion_bedrock_claude():
print("calling claude")
try:
@@ -1568,6 +1575,7 @@ def test_completion_bedrock_claude():
# test_completion_bedrock_claude()
+@pytest.mark.skip(reason="AWS Suspended Account")
def test_completion_bedrock_cohere():
print("calling bedrock cohere")
litellm.set_verbose = True
diff --git a/litellm/tests/test_completion_cost.py b/litellm/tests/test_completion_cost.py
index bb460b76bd9..b82cfd0a623 100644
--- a/litellm/tests/test_completion_cost.py
+++ b/litellm/tests/test_completion_cost.py
@@ -171,6 +171,7 @@ def test_cost_openai_image_gen():
assert cost == 0.019922944
+@pytest.mark.skip(reason="AWS Suspended Account")
def test_cost_bedrock_pricing():
"""
- get pricing specific to region for a model
diff --git a/litellm/tests/test_custom_callback_input.py b/litellm/tests/test_custom_callback_input.py
index 6e55cc5a1e5..683173b21e7 100644
--- a/litellm/tests/test_custom_callback_input.py
+++ b/litellm/tests/test_custom_callback_input.py
@@ -478,6 +478,7 @@ async def test_async_chat_azure_stream():
## Test Bedrock + sync
+@pytest.mark.skip(reason="AWS Suspended Account")
def test_chat_bedrock_stream():
try:
customHandler = CompletionCustomHandler()
@@ -518,6 +519,7 @@ def test_chat_bedrock_stream():
## Test Bedrock + Async
+@pytest.mark.skip(reason="AWS Suspended Account")
@pytest.mark.asyncio
async def test_async_chat_bedrock_stream():
try:
@@ -561,6 +563,7 @@ async def test_async_chat_bedrock_stream():
## Test Sagemaker + Async
+@pytest.mark.skip(reason="AWS Suspended Account")
@pytest.mark.asyncio
async def test_async_chat_sagemaker_stream():
try:
@@ -793,6 +796,7 @@ async def test_async_embedding_azure():
## Test Bedrock + Async
+@pytest.mark.skip(reason="AWS Suspended Account")
@pytest.mark.asyncio
async def test_async_embedding_bedrock():
try:
diff --git a/litellm/tests/test_custom_logger.py b/litellm/tests/test_custom_logger.py
index a7b0c937f0a..fe130768906 100644
--- a/litellm/tests/test_custom_logger.py
+++ b/litellm/tests/test_custom_logger.py
@@ -388,6 +388,7 @@ async def test_async_custom_handler_embedding_optional_param():
# asyncio.run(test_async_custom_handler_embedding_optional_param())
+@pytest.mark.skip(reason="AWS Account suspended. Pending their approval")
@pytest.mark.asyncio
async def test_async_custom_handler_embedding_optional_param_bedrock():
"""
diff --git a/litellm/tests/test_embedding.py b/litellm/tests/test_embedding.py
index 4637a79e044..2c9de496c47 100644
--- a/litellm/tests/test_embedding.py
+++ b/litellm/tests/test_embedding.py
@@ -256,6 +256,7 @@ async def test_vertexai_aembedding():
pytest.fail(f"Error occurred: {e}")
+@pytest.mark.skip(reason="AWS Suspended Account")
def test_bedrock_embedding_titan():
try:
# this tests if we support str input for bedrock embedding
@@ -301,6 +302,7 @@ def test_bedrock_embedding_titan():
# test_bedrock_embedding_titan()
+@pytest.mark.skip(reason="AWS Suspended Account")
def test_bedrock_embedding_cohere():
try:
litellm.set_verbose = False
@@ -422,6 +424,7 @@ def test_aembedding_azure():
# test_aembedding_azure()
+@pytest.mark.skip(reason="AWS Suspended Account")
def test_sagemaker_embeddings():
try:
response = litellm.embedding(
@@ -438,6 +441,7 @@ def test_sagemaker_embeddings():
pytest.fail(f"Error occurred: {e}")
+@pytest.mark.skip(reason="AWS Suspended Account")
@pytest.mark.asyncio
async def test_sagemaker_aembeddings():
try:
diff --git a/litellm/tests/test_exceptions.py b/litellm/tests/test_exceptions.py
index 4729cabb235..9c90014c0d6 100644
--- a/litellm/tests/test_exceptions.py
+++ b/litellm/tests/test_exceptions.py
@@ -42,6 +42,7 @@ exception_models = [
# Test 1: Context Window Errors
+@pytest.mark.skip(reason="AWS Suspended Account")
@pytest.mark.parametrize("model", exception_models)
def test_context_window(model):
print("Testing context window error")
@@ -120,9 +121,9 @@ def invalid_auth(model): # set the model key to an invalid key, depending on th
os.environ["AI21_API_KEY"] = "bad-key"
elif "togethercomputer" in model:
temporary_key = os.environ["TOGETHERAI_API_KEY"]
- os.environ[
- "TOGETHERAI_API_KEY"
- ] = "84060c79880fc49df126d3e87b53f8a463ff6e1c6d27fe64207cde25cdfcd1f24a"
+ os.environ["TOGETHERAI_API_KEY"] = (
+ "84060c79880fc49df126d3e87b53f8a463ff6e1c6d27fe64207cde25cdfcd1f24a"
+ )
elif model in litellm.openrouter_models:
temporary_key = os.environ["OPENROUTER_API_KEY"]
os.environ["OPENROUTER_API_KEY"] = "bad-key"
diff --git a/litellm/tests/test_health_check.py b/litellm/tests/test_health_check.py
index 21b72d2ac39..f632e769216 100644
--- a/litellm/tests/test_health_check.py
+++ b/litellm/tests/test_health_check.py
@@ -87,6 +87,7 @@ async def test_azure_img_gen_health_check():
# asyncio.run(test_azure_img_gen_health_check())
+@pytest.mark.skip(reason="AWS Suspended Account")
@pytest.mark.asyncio
async def test_sagemaker_embedding_health_check():
response = await litellm.ahealth_check(
diff --git a/litellm/tests/test_image_generation.py b/litellm/tests/test_image_generation.py
index 59ccaacd8d8..0672319a21a 100644
--- a/litellm/tests/test_image_generation.py
+++ b/litellm/tests/test_image_generation.py
@@ -121,6 +121,7 @@ async def test_async_image_generation_azure():
pytest.fail(f"An exception occurred - {str(e)}")
+@pytest.mark.skip(reason="AWS Suspended Account")
def test_image_generation_bedrock():
try:
litellm.set_verbose = True
@@ -141,6 +142,7 @@ def test_image_generation_bedrock():
pytest.fail(f"An exception occurred - {str(e)}")
+@pytest.mark.skip(reason="AWS Suspended Account")
@pytest.mark.asyncio
async def test_aimage_generation_bedrock_with_optional_params():
try:
diff --git a/litellm/tests/test_key_generate_dynamodb.py b/litellm/tests/test_key_generate_dynamodb.py
index 573bd944db6..e28b9f047fa 100644
--- a/litellm/tests/test_key_generate_dynamodb.py
+++ b/litellm/tests/test_key_generate_dynamodb.py
@@ -1,516 +1,517 @@
-# Test the following scenarios:
-# 1. Generate a Key, and use it to make a call
-# 2. Make a call with invalid key, expect it to fail
-# 3. Make a call to a key with invalid model - expect to fail
-# 4. Make a call to a key with valid model - expect to pass
-# 5. Make a call with key over budget, expect to fail
-# 6. Make a streaming chat/completions call with key over budget, expect to fail
-
-
-# function to call to generate key - async def new_user(data: NewUserRequest):
-# function to validate a request - async def user_auth(request: Request):
-
-import sys, os
-import traceback
-from dotenv import load_dotenv
-from fastapi import Request
-
-load_dotenv()
-import os, io
-
-# this file is to test litellm/proxy
-
-sys.path.insert(
- 0, os.path.abspath("../..")
-) # Adds the parent directory to the system path
-import pytest, logging, asyncio
-import litellm, asyncio
-from litellm.proxy.proxy_server import (
- new_user,
- user_api_key_auth,
- user_update,
- generate_key_fn,
-)
-
-from litellm.proxy._types import NewUserRequest, DynamoDBArgs, GenerateKeyRequest
-from litellm.proxy.utils import DBClient, hash_token
-from starlette.datastructures import URL
-
-
-request_data = {
- "model": "azure-gpt-3.5",
- "messages": [
- {"role": "user", "content": "this is my new test. respond in 50 lines"}
- ],
-}
-
-
-@pytest.fixture
-def custom_db_client():
- # Assuming DBClient is a class that needs to be instantiated
- db_args = {
- "ssl_verify": False,
- "billing_mode": "PAY_PER_REQUEST",
- "region_name": "us-west-2",
- }
- custom_db_client = DBClient(
- custom_db_type="dynamo_db",
- custom_db_args=db_args,
- )
- # Reset litellm.proxy.proxy_server.prisma_client to None
- litellm.proxy.proxy_server.prisma_client = None
-
- return custom_db_client
-
-
-def test_generate_and_call_with_valid_key(custom_db_client):
- # 1. Generate a Key, and use it to make a call
- setattr(litellm.proxy.proxy_server, "custom_db_client", custom_db_client)
- setattr(litellm.proxy.proxy_server, "master_key", "sk-1234")
- try:
-
- async def test():
- request = NewUserRequest()
- key = await new_user(request)
- print(key)
-
- generated_key = key.key
- bearer_token = "Bearer " + generated_key
-
- request = Request(scope={"type": "http"})
- request._url = URL(url="/chat/completions")
-
- # use generated key to auth in
- result = await user_api_key_auth(request=request, api_key=bearer_token)
- print("result from user auth with new key", result)
+# @pytest.mark.skip(reason="AWS Suspended Account")
+# # Test the following scenarios:
+# # 1. Generate a Key, and use it to make a call
+# # 2. Make a call with invalid key, expect it to fail
+# # 3. Make a call to a key with invalid model - expect to fail
+# # 4. Make a call to a key with valid model - expect to pass
+# # 5. Make a call with key over budget, expect to fail
+# # 6. Make a streaming chat/completions call with key over budget, expect to fail
+
+
+# # function to call to generate key - async def new_user(data: NewUserRequest):
+# # function to validate a request - async def user_auth(request: Request):
+
+# import sys, os
+# import traceback
+# from dotenv import load_dotenv
+# from fastapi import Request
+
+# load_dotenv()
+# import os, io
+
+# # this file is to test litellm/proxy
+
+# sys.path.insert(
+# 0, os.path.abspath("../..")
+# ) # Adds the parent directory to the system path
+# import pytest, logging, asyncio
+# import litellm, asyncio
+# from litellm.proxy.proxy_server import (
+# new_user,
+# user_api_key_auth,
+# user_update,
+# generate_key_fn,
+# )
+
+# from litellm.proxy._types import NewUserRequest, DynamoDBArgs, GenerateKeyRequest
+# from litellm.proxy.utils import DBClient, hash_token
+# from starlette.datastructures import URL
+
+
+# request_data = {
+# "model": "azure-gpt-3.5",
+# "messages": [
+# {"role": "user", "content": "this is my new test. respond in 50 lines"}
+# ],
+# }
+
+
+# @pytest.fixture
+# def custom_db_client():
+# # Assuming DBClient is a class that needs to be instantiated
+# db_args = {
+# "ssl_verify": False,
+# "billing_mode": "PAY_PER_REQUEST",
+# "region_name": "us-west-2",
+# }
+# custom_db_client = DBClient(
+# custom_db_type="dynamo_db",
+# custom_db_args=db_args,
+# )
+# # Reset litellm.proxy.proxy_server.prisma_client to None
+# litellm.proxy.proxy_server.prisma_client = None
+
+# return custom_db_client
+
+
+# def test_generate_and_call_with_valid_key(custom_db_client):
+# # 1. Generate a Key, and use it to make a call
+# setattr(litellm.proxy.proxy_server, "custom_db_client", custom_db_client)
+# setattr(litellm.proxy.proxy_server, "master_key", "sk-1234")
+# try:
+
+# async def test():
+# request = NewUserRequest()
+# key = await new_user(request)
+# print(key)
+
+# generated_key = key.key
+# bearer_token = "Bearer " + generated_key
+
+# request = Request(scope={"type": "http"})
+# request._url = URL(url="/chat/completions")
+
+# # use generated key to auth in
+# result = await user_api_key_auth(request=request, api_key=bearer_token)
+# print("result from user auth with new key", result)
- asyncio.run(test())
- except Exception as e:
- pytest.fail(f"An exception occurred - {str(e)}")
-
-
-def test_call_with_invalid_key(custom_db_client):
- # 2. Make a call with invalid key, expect it to fail
- setattr(litellm.proxy.proxy_server, "custom_db_client", custom_db_client)
- setattr(litellm.proxy.proxy_server, "master_key", "sk-1234")
- try:
-
- async def test():
- generated_key = "bad-key"
- bearer_token = "Bearer " + generated_key
-
- request = Request(scope={"type": "http"}, receive=None)
- request._url = URL(url="/chat/completions")
-
- # use generated key to auth in
- result = await user_api_key_auth(request=request, api_key=bearer_token)
- pytest.fail(f"This should have failed!. IT's an invalid key")
+# asyncio.run(test())
+# except Exception as e:
+# pytest.fail(f"An exception occurred - {str(e)}")
+
+
+# def test_call_with_invalid_key(custom_db_client):
+# # 2. Make a call with invalid key, expect it to fail
+# setattr(litellm.proxy.proxy_server, "custom_db_client", custom_db_client)
+# setattr(litellm.proxy.proxy_server, "master_key", "sk-1234")
+# try:
+
+# async def test():
+# generated_key = "bad-key"
+# bearer_token = "Bearer " + generated_key
+
+# request = Request(scope={"type": "http"}, receive=None)
+# request._url = URL(url="/chat/completions")
+
+# # use generated key to auth in
+# result = await user_api_key_auth(request=request, api_key=bearer_token)
+# pytest.fail(f"This should have failed!. IT's an invalid key")
- asyncio.run(test())
- except Exception as e:
- print("Got Exception", e)
- print(e.message)
- assert "Authentication Error" in e.message
- pass
-
-
-def test_call_with_invalid_model(custom_db_client):
- # 3. Make a call to a key with an invalid model - expect to fail
- from litellm._logging import verbose_proxy_logger
- import logging
-
- verbose_proxy_logger.setLevel(logging.DEBUG)
- setattr(litellm.proxy.proxy_server, "custom_db_client", custom_db_client)
- setattr(litellm.proxy.proxy_server, "master_key", "sk-1234")
- try:
-
- async def test():
- request = NewUserRequest(models=["mistral"])
- key = await new_user(request)
- print(key)
-
- generated_key = key.key
- bearer_token = "Bearer " + generated_key
-
- request = Request(scope={"type": "http"})
- request._url = URL(url="/chat/completions")
-
- async def return_body():
- return b'{"model": "gemini-pro-vision"}'
-
- request.body = return_body
-
- # use generated key to auth in
- result = await user_api_key_auth(request=request, api_key=bearer_token)
- pytest.fail(f"This should have failed!. IT's an invalid model")
-
- asyncio.run(test())
- except Exception as e:
- assert (
- e.message
- == "Authentication Error, API Key not allowed to access model. This token can only access models=['mistral']. Tried to access gemini-pro-vision"
- )
- pass
-
-
-def test_call_with_valid_model(custom_db_client):
- # 4. Make a call to a key with a valid model - expect to pass
- setattr(litellm.proxy.proxy_server, "custom_db_client", custom_db_client)
- setattr(litellm.proxy.proxy_server, "master_key", "sk-1234")
- try:
-
- async def test():
- request = NewUserRequest(models=["mistral"])
- key = await new_user(request)
- print(key)
-
- generated_key = key.key
- bearer_token = "Bearer " + generated_key
-
- request = Request(scope={"type": "http"})
- request._url = URL(url="/chat/completions")
-
- async def return_body():
- return b'{"model": "mistral"}'
-
- request.body = return_body
-
- # use generated key to auth in
- result = await user_api_key_auth(request=request, api_key=bearer_token)
- print("result from user auth with new key", result)
-
- asyncio.run(test())
- except Exception as e:
- pytest.fail(f"An exception occurred - {str(e)}")
-
-
-def test_call_with_user_over_budget(custom_db_client):
- # 5. Make a call with a key over budget, expect to fail
- setattr(litellm.proxy.proxy_server, "custom_db_client", custom_db_client)
- setattr(litellm.proxy.proxy_server, "master_key", "sk-1234")
- from litellm._logging import verbose_proxy_logger, verbose_logger
- import logging
-
- litellm.set_verbose = True
- verbose_logger.setLevel(logging.DEBUG)
- verbose_proxy_logger.setLevel(logging.DEBUG)
- try:
-
- async def test():
- request = NewUserRequest(max_budget=0.00001)
- key = await new_user(request)
- print(key)
-
- generated_key = key.key
- user_id = key.user_id
- bearer_token = "Bearer " + generated_key
-
- request = Request(scope={"type": "http"})
- request._url = URL(url="/chat/completions")
-
- # use generated key to auth in
- result = await user_api_key_auth(request=request, api_key=bearer_token)
- print("result from user auth with new key", result)
-
- # update spend using track_cost callback, make 2nd request, it should fail
- from litellm.proxy.proxy_server import (
- _PROXY_track_cost_callback as track_cost_callback,
- )
- from litellm import ModelResponse, Choices, Message, Usage
-
- resp = ModelResponse(
- id="chatcmpl-e41836bb-bb8b-4df2-8e70-8f3e160155ac",
- choices=[
- Choices(
- finish_reason=None,
- index=0,
- message=Message(
- content=" Sure! Here is a short poem about the sky:\n\nA canvas of blue, a",
- role="assistant",
- ),
- )
- ],
- model="gpt-35-turbo", # azure always has model written like this
- usage=Usage(prompt_tokens=210, completion_tokens=200, total_tokens=410),
- )
- await track_cost_callback(
- kwargs={
- "stream": False,
- "litellm_params": {
- "metadata": {
- "user_api_key": hash_token(generated_key),
- "user_api_key_user_id": user_id,
- }
- },
- "response_cost": 0.00002,
- },
- completion_response=resp,
- )
- await asyncio.sleep(5)
- # use generated key to auth in
- result = await user_api_key_auth(request=request, api_key=bearer_token)
- print("result from user auth with new key", result)
- pytest.fail(f"This should have failed!. They key crossed it's budget")
-
- asyncio.run(test())
- except Exception as e:
- error_detail = e.message
- assert "Authentication Error, ExceededBudget:" in error_detail
- print(vars(e))
-
-
-def test_call_with_user_over_budget_stream(custom_db_client):
- # 6. Make a call with a key over budget, expect to fail
- setattr(litellm.proxy.proxy_server, "custom_db_client", custom_db_client)
- setattr(litellm.proxy.proxy_server, "master_key", "sk-1234")
- from litellm._logging import verbose_proxy_logger
- import logging
-
- litellm.set_verbose = True
- verbose_proxy_logger.setLevel(logging.DEBUG)
- try:
-
- async def test():
- request = NewUserRequest(max_budget=0.00001)
- key = await new_user(request)
- print(key)
-
- generated_key = key.key
- user_id = key.user_id
- bearer_token = "Bearer " + generated_key
-
- request = Request(scope={"type": "http"})
- request._url = URL(url="/chat/completions")
-
- # use generated key to auth in
- result = await user_api_key_auth(request=request, api_key=bearer_token)
- print("result from user auth with new key", result)
-
- # update spend using track_cost callback, make 2nd request, it should fail
- from litellm.proxy.proxy_server import (
- _PROXY_track_cost_callback as track_cost_callback,
- )
- from litellm import ModelResponse, Choices, Message, Usage
-
- resp = ModelResponse(
- id="chatcmpl-e41836bb-bb8b-4df2-8e70-8f3e160155ac",
- choices=[
- Choices(
- finish_reason=None,
- index=0,
- message=Message(
- content=" Sure! Here is a short poem about the sky:\n\nA canvas of blue, a",
- role="assistant",
- ),
- )
- ],
- model="gpt-35-turbo", # azure always has model written like this
- usage=Usage(prompt_tokens=210, completion_tokens=200, total_tokens=410),
- )
- await track_cost_callback(
- kwargs={
- "stream": True,
- "complete_streaming_response": resp,
- "litellm_params": {
- "metadata": {
- "user_api_key": hash_token(generated_key),
- "user_api_key_user_id": user_id,
- }
- },
- "response_cost": 0.00002,
- },
- completion_response=ModelResponse(),
- )
- await asyncio.sleep(5)
- # use generated key to auth in
- result = await user_api_key_auth(request=request, api_key=bearer_token)
- print("result from user auth with new key", result)
- pytest.fail(f"This should have failed!. They key crossed it's budget")
-
- asyncio.run(test())
- except Exception as e:
- error_detail = e.message
- assert "Authentication Error, ExceededBudget:" in error_detail
- print(vars(e))
-
-
-def test_call_with_user_key_budget(custom_db_client):
- # 7. Make a call with a key over budget, expect to fail
- setattr(litellm.proxy.proxy_server, "custom_db_client", custom_db_client)
- setattr(litellm.proxy.proxy_server, "master_key", "sk-1234")
- from litellm._logging import verbose_proxy_logger
- import logging
-
- verbose_proxy_logger.setLevel(logging.DEBUG)
- try:
-
- async def test():
- request = GenerateKeyRequest(max_budget=0.00001)
- key = await generate_key_fn(request)
- print(key)
-
- generated_key = key.key
- user_id = key.user_id
- bearer_token = "Bearer " + generated_key
-
- request = Request(scope={"type": "http"})
- request._url = URL(url="/chat/completions")
-
- # use generated key to auth in
- result = await user_api_key_auth(request=request, api_key=bearer_token)
- print("result from user auth with new key", result)
-
- # update spend using track_cost callback, make 2nd request, it should fail
- from litellm.proxy.proxy_server import (
- _PROXY_track_cost_callback as track_cost_callback,
- )
- from litellm import ModelResponse, Choices, Message, Usage
-
- resp = ModelResponse(
- id="chatcmpl-e41836bb-bb8b-4df2-8e70-8f3e160155ac",
- choices=[
- Choices(
- finish_reason=None,
- index=0,
- message=Message(
- content=" Sure! Here is a short poem about the sky:\n\nA canvas of blue, a",
- role="assistant",
- ),
- )
- ],
- model="gpt-35-turbo", # azure always has model written like this
- usage=Usage(prompt_tokens=210, completion_tokens=200, total_tokens=410),
- )
- await track_cost_callback(
- kwargs={
- "stream": False,
- "litellm_params": {
- "metadata": {
- "user_api_key": hash_token(generated_key),
- "user_api_key_user_id": user_id,
- }
- },
- "response_cost": 0.00002,
- },
- completion_response=resp,
- )
- await asyncio.sleep(5)
- # use generated key to auth in
- result = await user_api_key_auth(request=request, api_key=bearer_token)
- print("result from user auth with new key", result)
- pytest.fail(f"This should have failed!. They key crossed it's budget")
-
- asyncio.run(test())
- except Exception as e:
- error_detail = e.message
- assert "Authentication Error, ExceededTokenBudget:" in error_detail
- print(vars(e))
-
-
-def test_call_with_key_over_budget_stream(custom_db_client):
- # 8. Make a call with a key over budget, expect to fail
- setattr(litellm.proxy.proxy_server, "custom_db_client", custom_db_client)
- setattr(litellm.proxy.proxy_server, "master_key", "sk-1234")
- from litellm._logging import verbose_proxy_logger
- import logging
-
- litellm.set_verbose = True
- verbose_proxy_logger.setLevel(logging.DEBUG)
- try:
-
- async def test():
- request = GenerateKeyRequest(max_budget=0.00001)
- key = await generate_key_fn(request)
- print(key)
-
- generated_key = key.key
- user_id = key.user_id
- bearer_token = "Bearer " + generated_key
-
- request = Request(scope={"type": "http"})
- request._url = URL(url="/chat/completions")
-
- # use generated key to auth in
- result = await user_api_key_auth(request=request, api_key=bearer_token)
- print("result from user auth with new key", result)
-
- # update spend using track_cost callback, make 2nd request, it should fail
- from litellm.proxy.proxy_server import (
- _PROXY_track_cost_callback as track_cost_callback,
- )
- from litellm import ModelResponse, Choices, Message, Usage
-
- resp = ModelResponse(
- id="chatcmpl-e41836bb-bb8b-4df2-8e70-8f3e160155ac",
- choices=[
- Choices(
- finish_reason=None,
- index=0,
- message=Message(
- content=" Sure! Here is a short poem about the sky:\n\nA canvas of blue, a",
- role="assistant",
- ),
- )
- ],
- model="gpt-35-turbo", # azure always has model written like this
- usage=Usage(prompt_tokens=210, completion_tokens=200, total_tokens=410),
- )
- await track_cost_callback(
- kwargs={
- "stream": True,
- "complete_streaming_response": resp,
- "litellm_params": {
- "metadata": {
- "user_api_key": hash_token(generated_key),
- "user_api_key_user_id": user_id,
- }
- },
- "response_cost": 0.00002,
- },
- completion_response=ModelResponse(),
- )
- await asyncio.sleep(5)
- # use generated key to auth in
- result = await user_api_key_auth(request=request, api_key=bearer_token)
- print("result from user auth with new key", result)
- pytest.fail(f"This should have failed!. They key crossed it's budget")
-
- asyncio.run(test())
- except Exception as e:
- error_detail = e.message
- assert "Authentication Error, ExceededTokenBudget:" in error_detail
- print(vars(e))
-
-
-def test_dynamo_db_migration(custom_db_client):
- # Tests the temporary patch we have in place
- setattr(litellm.proxy.proxy_server, "custom_db_client", custom_db_client)
- setattr(litellm.proxy.proxy_server, "master_key", "sk-1234")
- setattr(litellm.proxy.proxy_server, "user_custom_auth", None)
- try:
-
- async def test():
- request = GenerateKeyRequest(max_budget=1)
- key = await generate_key_fn(request)
- print(key)
-
- generated_key = key.key
- bearer_token = (
- "Bearer " + generated_key
- ) # this works with ishaan's db, it's a never expiring key
-
- request = Request(scope={"type": "http"})
- request._url = URL(url="/chat/completions")
-
- async def return_body():
- return b'{"model": "azure-models"}'
-
- request.body = return_body
-
- # use generated key to auth in
- result = await user_api_key_auth(request=request, api_key=bearer_token)
- print("result from user auth with new key", result)
-
- asyncio.run(test())
- except Exception as e:
- pytest.fail(f"An exception occurred - {traceback.format_exc()}")
+# asyncio.run(test())
+# except Exception as e:
+# print("Got Exception", e)
+# print(e.message)
+# assert "Authentication Error" in e.message
+# pass
+
+
+# def test_call_with_invalid_model(custom_db_client):
+# # 3. Make a call to a key with an invalid model - expect to fail
+# from litellm._logging import verbose_proxy_logger
+# import logging
+
+# verbose_proxy_logger.setLevel(logging.DEBUG)
+# setattr(litellm.proxy.proxy_server, "custom_db_client", custom_db_client)
+# setattr(litellm.proxy.proxy_server, "master_key", "sk-1234")
+# try:
+
+# async def test():
+# request = NewUserRequest(models=["mistral"])
+# key = await new_user(request)
+# print(key)
+
+# generated_key = key.key
+# bearer_token = "Bearer " + generated_key
+
+# request = Request(scope={"type": "http"})
+# request._url = URL(url="/chat/completions")
+
+# async def return_body():
+# return b'{"model": "gemini-pro-vision"}'
+
+# request.body = return_body
+
+# # use generated key to auth in
+# result = await user_api_key_auth(request=request, api_key=bearer_token)
+# pytest.fail(f"This should have failed!. IT's an invalid model")
+
+# asyncio.run(test())
+# except Exception as e:
+# assert (
+# e.message
+# == "Authentication Error, API Key not allowed to access model. This token can only access models=['mistral']. Tried to access gemini-pro-vision"
+# )
+# pass
+
+
+# def test_call_with_valid_model(custom_db_client):
+# # 4. Make a call to a key with a valid model - expect to pass
+# setattr(litellm.proxy.proxy_server, "custom_db_client", custom_db_client)
+# setattr(litellm.proxy.proxy_server, "master_key", "sk-1234")
+# try:
+
+# async def test():
+# request = NewUserRequest(models=["mistral"])
+# key = await new_user(request)
+# print(key)
+
+# generated_key = key.key
+# bearer_token = "Bearer " + generated_key
+
+# request = Request(scope={"type": "http"})
+# request._url = URL(url="/chat/completions")
+
+# async def return_body():
+# return b'{"model": "mistral"}'
+
+# request.body = return_body
+
+# # use generated key to auth in
+# result = await user_api_key_auth(request=request, api_key=bearer_token)
+# print("result from user auth with new key", result)
+
+# asyncio.run(test())
+# except Exception as e:
+# pytest.fail(f"An exception occurred - {str(e)}")
+
+
+# def test_call_with_user_over_budget(custom_db_client):
+# # 5. Make a call with a key over budget, expect to fail
+# setattr(litellm.proxy.proxy_server, "custom_db_client", custom_db_client)
+# setattr(litellm.proxy.proxy_server, "master_key", "sk-1234")
+# from litellm._logging import verbose_proxy_logger, verbose_logger
+# import logging
+
+# litellm.set_verbose = True
+# verbose_logger.setLevel(logging.DEBUG)
+# verbose_proxy_logger.setLevel(logging.DEBUG)
+# try:
+
+# async def test():
+# request = NewUserRequest(max_budget=0.00001)
+# key = await new_user(request)
+# print(key)
+
+# generated_key = key.key
+# user_id = key.user_id
+# bearer_token = "Bearer " + generated_key
+
+# request = Request(scope={"type": "http"})
+# request._url = URL(url="/chat/completions")
+
+# # use generated key to auth in
+# result = await user_api_key_auth(request=request, api_key=bearer_token)
+# print("result from user auth with new key", result)
+
+# # update spend using track_cost callback, make 2nd request, it should fail
+# from litellm.proxy.proxy_server import (
+# _PROXY_track_cost_callback as track_cost_callback,
+# )
+# from litellm import ModelResponse, Choices, Message, Usage
+
+# resp = ModelResponse(
+# id="chatcmpl-e41836bb-bb8b-4df2-8e70-8f3e160155ac",
+# choices=[
+# Choices(
+# finish_reason=None,
+# index=0,
+# message=Message(
+# content=" Sure! Here is a short poem about the sky:\n\nA canvas of blue, a",
+# role="assistant",
+# ),
+# )
+# ],
+# model="gpt-35-turbo", # azure always has model written like this
+# usage=Usage(prompt_tokens=210, completion_tokens=200, total_tokens=410),
+# )
+# await track_cost_callback(
+# kwargs={
+# "stream": False,
+# "litellm_params": {
+# "metadata": {
+# "user_api_key": hash_token(generated_key),
+# "user_api_key_user_id": user_id,
+# }
+# },
+# "response_cost": 0.00002,
+# },
+# completion_response=resp,
+# )
+# await asyncio.sleep(5)
+# # use generated key to auth in
+# result = await user_api_key_auth(request=request, api_key=bearer_token)
+# print("result from user auth with new key", result)
+# pytest.fail(f"This should have failed!. They key crossed it's budget")
+
+# asyncio.run(test())
+# except Exception as e:
+# error_detail = e.message
+# assert "Authentication Error, ExceededBudget:" in error_detail
+# print(vars(e))
+
+
+# def test_call_with_user_over_budget_stream(custom_db_client):
+# # 6. Make a call with a key over budget, expect to fail
+# setattr(litellm.proxy.proxy_server, "custom_db_client", custom_db_client)
+# setattr(litellm.proxy.proxy_server, "master_key", "sk-1234")
+# from litellm._logging import verbose_proxy_logger
+# import logging
+
+# litellm.set_verbose = True
+# verbose_proxy_logger.setLevel(logging.DEBUG)
+# try:
+
+# async def test():
+# request = NewUserRequest(max_budget=0.00001)
+# key = await new_user(request)
+# print(key)
+
+# generated_key = key.key
+# user_id = key.user_id
+# bearer_token = "Bearer " + generated_key
+
+# request = Request(scope={"type": "http"})
+# request._url = URL(url="/chat/completions")
+
+# # use generated key to auth in
+# result = await user_api_key_auth(request=request, api_key=bearer_token)
+# print("result from user auth with new key", result)
+
+# # update spend using track_cost callback, make 2nd request, it should fail
+# from litellm.proxy.proxy_server import (
+# _PROXY_track_cost_callback as track_cost_callback,
+# )
+# from litellm import ModelResponse, Choices, Message, Usage
+
+# resp = ModelResponse(
+# id="chatcmpl-e41836bb-bb8b-4df2-8e70-8f3e160155ac",
+# choices=[
+# Choices(
+# finish_reason=None,
+# index=0,
+# message=Message(
+# content=" Sure! Here is a short poem about the sky:\n\nA canvas of blue, a",
+# role="assistant",
+# ),
+# )
+# ],
+# model="gpt-35-turbo", # azure always has model written like this
+# usage=Usage(prompt_tokens=210, completion_tokens=200, total_tokens=410),
+# )
+# await track_cost_callback(
+# kwargs={
+# "stream": True,
+# "complete_streaming_response": resp,
+# "litellm_params": {
+# "metadata": {
+# "user_api_key": hash_token(generated_key),
+# "user_api_key_user_id": user_id,
+# }
+# },
+# "response_cost": 0.00002,
+# },
+# completion_response=ModelResponse(),
+# )
+# await asyncio.sleep(5)
+# # use generated key to auth in
+# result = await user_api_key_auth(request=request, api_key=bearer_token)
+# print("result from user auth with new key", result)
+# pytest.fail(f"This should have failed!. They key crossed it's budget")
+
+# asyncio.run(test())
+# except Exception as e:
+# error_detail = e.message
+# assert "Authentication Error, ExceededBudget:" in error_detail
+# print(vars(e))
+
+
+# def test_call_with_user_key_budget(custom_db_client):
+# # 7. Make a call with a key over budget, expect to fail
+# setattr(litellm.proxy.proxy_server, "custom_db_client", custom_db_client)
+# setattr(litellm.proxy.proxy_server, "master_key", "sk-1234")
+# from litellm._logging import verbose_proxy_logger
+# import logging
+
+# verbose_proxy_logger.setLevel(logging.DEBUG)
+# try:
+
+# async def test():
+# request = GenerateKeyRequest(max_budget=0.00001)
+# key = await generate_key_fn(request)
+# print(key)
+
+# generated_key = key.key
+# user_id = key.user_id
+# bearer_token = "Bearer " + generated_key
+
+# request = Request(scope={"type": "http"})
+# request._url = URL(url="/chat/completions")
+
+# # use generated key to auth in
+# result = await user_api_key_auth(request=request, api_key=bearer_token)
+# print("result from user auth with new key", result)
+
+# # update spend using track_cost callback, make 2nd request, it should fail
+# from litellm.proxy.proxy_server import (
+# _PROXY_track_cost_callback as track_cost_callback,
+# )
+# from litellm import ModelResponse, Choices, Message, Usage
+
+# resp = ModelResponse(
+# id="chatcmpl-e41836bb-bb8b-4df2-8e70-8f3e160155ac",
+# choices=[
+# Choices(
+# finish_reason=None,
+# index=0,
+# message=Message(
+# content=" Sure! Here is a short poem about the sky:\n\nA canvas of blue, a",
+# role="assistant",
+# ),
+# )
+# ],
+# model="gpt-35-turbo", # azure always has model written like this
+# usage=Usage(prompt_tokens=210, completion_tokens=200, total_tokens=410),
+# )
+# await track_cost_callback(
+# kwargs={
+# "stream": False,
+# "litellm_params": {
+# "metadata": {
+# "user_api_key": hash_token(generated_key),
+# "user_api_key_user_id": user_id,
+# }
+# },
+# "response_cost": 0.00002,
+# },
+# completion_response=resp,
+# )
+# await asyncio.sleep(5)
+# # use generated key to auth in
+# result = await user_api_key_auth(request=request, api_key=bearer_token)
+# print("result from user auth with new key", result)
+# pytest.fail(f"This should have failed!. They key crossed it's budget")
+
+# asyncio.run(test())
+# except Exception as e:
+# error_detail = e.message
+# assert "Authentication Error, ExceededTokenBudget:" in error_detail
+# print(vars(e))
+
+
+# def test_call_with_key_over_budget_stream(custom_db_client):
+# # 8. Make a call with a key over budget, expect to fail
+# setattr(litellm.proxy.proxy_server, "custom_db_client", custom_db_client)
+# setattr(litellm.proxy.proxy_server, "master_key", "sk-1234")
+# from litellm._logging import verbose_proxy_logger
+# import logging
+
+# litellm.set_verbose = True
+# verbose_proxy_logger.setLevel(logging.DEBUG)
+# try:
+
+# async def test():
+# request = GenerateKeyRequest(max_budget=0.00001)
+# key = await generate_key_fn(request)
+# print(key)
+
+# generated_key = key.key
+# user_id = key.user_id
+# bearer_token = "Bearer " + generated_key
+
+# request = Request(scope={"type": "http"})
+# request._url = URL(url="/chat/completions")
+
+# # use generated key to auth in
+# result = await user_api_key_auth(request=request, api_key=bearer_token)
+# print("result from user auth with new key", result)
+
+# # update spend using track_cost callback, make 2nd request, it should fail
+# from litellm.proxy.proxy_server import (
+# _PROXY_track_cost_callback as track_cost_callback,
+# )
+# from litellm import ModelResponse, Choices, Message, Usage
+
+# resp = ModelResponse(
+# id="chatcmpl-e41836bb-bb8b-4df2-8e70-8f3e160155ac",
+# choices=[
+# Choices(
+# finish_reason=None,
+# index=0,
+# message=Message(
+# content=" Sure! Here is a short poem about the sky:\n\nA canvas of blue, a",
+# role="assistant",
+# ),
+# )
+# ],
+# model="gpt-35-turbo", # azure always has model written like this
+# usage=Usage(prompt_tokens=210, completion_tokens=200, total_tokens=410),
+# )
+# await track_cost_callback(
+# kwargs={
+# "stream": True,
+# "complete_streaming_response": resp,
+# "litellm_params": {
+# "metadata": {
+# "user_api_key": hash_token(generated_key),
+# "user_api_key_user_id": user_id,
+# }
+# },
+# "response_cost": 0.00002,
+# },
+# completion_response=ModelResponse(),
+# )
+# await asyncio.sleep(5)
+# # use generated key to auth in
+# result = await user_api_key_auth(request=request, api_key=bearer_token)
+# print("result from user auth with new key", result)
+# pytest.fail(f"This should have failed!. They key crossed it's budget")
+
+# asyncio.run(test())
+# except Exception as e:
+# error_detail = e.message
+# assert "Authentication Error, ExceededTokenBudget:" in error_detail
+# print(vars(e))
+
+
+# def test_dynamo_db_migration(custom_db_client):
+# # Tests the temporary patch we have in place
+# setattr(litellm.proxy.proxy_server, "custom_db_client", custom_db_client)
+# setattr(litellm.proxy.proxy_server, "master_key", "sk-1234")
+# setattr(litellm.proxy.proxy_server, "user_custom_auth", None)
+# try:
+
+# async def test():
+# request = GenerateKeyRequest(max_budget=1)
+# key = await generate_key_fn(request)
+# print(key)
+
+# generated_key = key.key
+# bearer_token = (
+# "Bearer " + generated_key
+# ) # this works with ishaan's db, it's a never expiring key
+
+# request = Request(scope={"type": "http"})
+# request._url = URL(url="/chat/completions")
+
+# async def return_body():
+# return b'{"model": "azure-models"}'
+
+# request.body = return_body
+
+# # use generated key to auth in
+# result = await user_api_key_auth(request=request, api_key=bearer_token)
+# print("result from user auth with new key", result)
+
+# asyncio.run(test())
+# except Exception as e:
+# pytest.fail(f"An exception occurred - {traceback.format_exc()}")
diff --git a/litellm/tests/test_key_generate_prisma.py b/litellm/tests/test_key_generate_prisma.py
index 3660d6371c8..91f34e79100 100644
--- a/litellm/tests/test_key_generate_prisma.py
+++ b/litellm/tests/test_key_generate_prisma.py
@@ -80,6 +80,14 @@ request_data = {
@pytest.fixture
def prisma_client():
+ from litellm.proxy.proxy_cli import append_query_params
+
+ ### add connection pool + pool timeout args
+ params = {"connection_limit": 100, "pool_timeout": 60}
+ database_url = os.getenv("DATABASE_URL")
+ modified_url = append_query_params(database_url, params)
+ os.environ["DATABASE_URL"] = modified_url
+
# Assuming DBClient is a class that needs to be instantiated
prisma_client = PrismaClient(
database_url=os.environ["DATABASE_URL"], proxy_logging_obj=proxy_logging_obj
@@ -1633,3 +1641,99 @@ async def test_key_with_no_permissions(prisma_client):
except Exception as e:
print("Got Exception", e)
print(e.message)
+
+
+async def track_cost_callback_helper_fn(generated_key: str, user_id: str):
+ from litellm import ModelResponse, Choices, Message, Usage
+ from litellm.proxy.proxy_server import (
+ _PROXY_track_cost_callback as track_cost_callback,
+ )
+
+ import uuid
+
+ request_id = f"chatcmpl-e41836bb-bb8b-4df2-8e70-8f3e160155ac{uuid.uuid4()}"
+ resp = ModelResponse(
+ id=request_id,
+ choices=[
+ Choices(
+ finish_reason=None,
+ index=0,
+ message=Message(
+ content=" Sure! Here is a short poem about the sky:\n\nA canvas of blue, a",
+ role="assistant",
+ ),
+ )
+ ],
+ model="gpt-35-turbo", # azure always has model written like this
+ usage=Usage(prompt_tokens=210, completion_tokens=200, total_tokens=410),
+ )
+ await track_cost_callback(
+ kwargs={
+ "call_type": "acompletion",
+ "model": "sagemaker-chatgpt-v-2",
+ "stream": True,
+ "complete_streaming_response": resp,
+ "litellm_params": {
+ "metadata": {
+ "user_api_key": hash_token(generated_key),
+ "user_api_key_user_id": user_id,
+ }
+ },
+ "response_cost": 0.00005,
+ },
+ completion_response=resp,
+ start_time=datetime.now(),
+ end_time=datetime.now(),
+ )
+
+
+# @pytest.mark.skip(reason="High traffic load test for spend tracking")
+@pytest.mark.asyncio
+async def test_proxy_load_test_db(prisma_client):
+ """
+ Run 1500 req./s against track_cost_callback function
+ """
+ setattr(litellm.proxy.proxy_server, "prisma_client", prisma_client)
+ setattr(litellm.proxy.proxy_server, "master_key", "sk-1234")
+ from litellm._logging import verbose_proxy_logger
+ import logging, time
+
+ litellm.set_verbose = True
+ verbose_proxy_logger.setLevel(logging.DEBUG)
+ try:
+ start_time = time.time()
+ await litellm.proxy.proxy_server.prisma_client.connect()
+ request = GenerateKeyRequest(max_budget=0.00001)
+ key = await generate_key_fn(request)
+ print(key)
+
+ generated_key = key.key
+ user_id = key.user_id
+ bearer_token = "Bearer " + generated_key
+
+ request = Request(scope={"type": "http"})
+ request._url = URL(url="/chat/completions")
+
+ # use generated key to auth in
+ result = await user_api_key_auth(request=request, api_key=bearer_token)
+ print("result from user auth with new key", result)
+ # update spend using track_cost callback, make 2nd request, it should fail
+ n = 5000
+ tasks = [
+ track_cost_callback_helper_fn(generated_key=generated_key, user_id=user_id)
+ for _ in range(n)
+ ]
+ completions = await asyncio.gather(*tasks)
+ await asyncio.sleep(120)
+ try:
+ # call spend logs
+ spend_logs = await view_spend_logs(api_key=generated_key)
+
+ print(f"len responses: {len(spend_logs)}")
+ assert len(spend_logs) == n
+ print(n, time.time() - start_time, len(spend_logs))
+ except:
+ print(n, time.time() - start_time, 0)
+ raise Exception(f"it worked! key={key.key}")
+ except Exception as e:
+ pytest.fail(f"An exception occurred - {str(e)}")
diff --git a/litellm/tests/test_model_max_token_adjust.py b/litellm/tests/test_model_max_token_adjust.py
index b4d48b5e28e..e6b31245f03 100644
--- a/litellm/tests/test_model_max_token_adjust.py
+++ b/litellm/tests/test_model_max_token_adjust.py
@@ -12,6 +12,7 @@ import litellm
from litellm import completion
+@pytest.mark.skip(reason="AWS Suspended Account")
def test_completion_sagemaker():
litellm.set_verbose = True
litellm.drop_params = True
diff --git a/litellm/tests/test_provider_specific_config.py b/litellm/tests/test_provider_specific_config.py
index 6c0edf02bd1..5e5d19c7862 100644
--- a/litellm/tests/test_provider_specific_config.py
+++ b/litellm/tests/test_provider_specific_config.py
@@ -473,6 +473,7 @@ def aleph_alpha_test_completion():
# Sagemaker
+@pytest.mark.skip(reason="AWS Suspended Account")
def sagemaker_test_completion():
litellm.SagemakerConfig(max_new_tokens=10)
# litellm.set_verbose=True
@@ -514,6 +515,7 @@ def sagemaker_test_completion():
# Bedrock
+@pytest.mark.skip(reason="AWS Suspended Account")
def bedrock_test_completion():
litellm.AmazonCohereConfig(max_tokens=10)
# litellm.set_verbose=True
diff --git a/litellm/tests/test_proxy_server.py b/litellm/tests/test_proxy_server.py
index 70fef0e064e..caf32299f21 100644
--- a/litellm/tests/test_proxy_server.py
+++ b/litellm/tests/test_proxy_server.py
@@ -125,6 +125,7 @@ def test_embedding(client_no_auth):
pytest.fail(f"LiteLLM Proxy test failed. Exception - {str(e)}")
+@pytest.mark.skip(reason="AWS Suspended Account")
def test_bedrock_embedding(client_no_auth):
global headers
from litellm.proxy.proxy_server import user_custom_auth
diff --git a/litellm/tests/test_proxy_server_caching.py b/litellm/tests/test_proxy_server_caching.py
index a9cf3504e43..d6f98d27b46 100644
--- a/litellm/tests/test_proxy_server_caching.py
+++ b/litellm/tests/test_proxy_server_caching.py
@@ -61,6 +61,7 @@ def generate_random_word(length=4):
return "".join(random.choice(letters) for _ in range(length))
+@pytest.mark.skip(reason="AWS Suspended Account")
def test_chat_completion(client_no_auth):
global headers
try:
diff --git a/litellm/tests/test_router.py b/litellm/tests/test_router.py
index ab329e14ae7..127caf223ba 100644
--- a/litellm/tests/test_router.py
+++ b/litellm/tests/test_router.py
@@ -166,14 +166,6 @@ def test_call_one_endpoint():
"tpm": 240000,
"rpm": 1800,
},
- {
- "model_name": "claude-v1",
- "litellm_params": {
- "model": "bedrock/anthropic.claude-instant-v1",
- },
- "tpm": 100000,
- "rpm": 10000,
- },
{
"model_name": "text-embedding-ada-002",
"litellm_params": {
@@ -202,15 +194,6 @@ def test_call_one_endpoint():
)
print("\n response", response)
- async def call_bedrock_claude():
- response = await router.acompletion(
- model="bedrock/anthropic.claude-instant-v1",
- messages=[{"role": "user", "content": "hello this request will pass"}],
- specific_deployment=True,
- )
-
- print("\n response", response)
-
async def call_azure_embedding():
response = await router.aembedding(
model="azure/azure-embedding-model",
@@ -221,7 +204,6 @@ def test_call_one_endpoint():
print("\n response", response)
asyncio.run(call_azure_completion())
- asyncio.run(call_bedrock_claude())
asyncio.run(call_azure_embedding())
os.environ["AZURE_API_BASE"] = old_api_base
@@ -593,6 +575,7 @@ def test_azure_embedding_on_router():
# test_azure_embedding_on_router()
+@pytest.mark.skip(reason="AWS Suspended Account")
def test_bedrock_on_router():
litellm.set_verbose = True
print("\n Testing bedrock on router\n")
diff --git a/litellm/tests/test_router_timeout.py b/litellm/tests/test_router_timeout.py
index b22683c41e1..139914f6dff 100644
--- a/litellm/tests/test_router_timeout.py
+++ b/litellm/tests/test_router_timeout.py
@@ -87,6 +87,7 @@ def test_router_timeouts():
print("********** TOKENS USED SO FAR = ", total_tokens_used)
+@pytest.mark.skip(reason="AWS Suspended Account")
@pytest.mark.asyncio
async def test_router_timeouts_bedrock():
import openai
diff --git a/litellm/tests/test_streaming.py b/litellm/tests/test_streaming.py
index 0343b97ae2a..083953f5748 100644
--- a/litellm/tests/test_streaming.py
+++ b/litellm/tests/test_streaming.py
@@ -764,6 +764,7 @@ def test_completion_replicate_stream_bad_key():
# test_completion_replicate_stream_bad_key()
+@pytest.mark.skip(reason="AWS Suspended Account")
def test_completion_bedrock_claude_stream():
try:
litellm.set_verbose = False
@@ -810,6 +811,7 @@ def test_completion_bedrock_claude_stream():
# test_completion_bedrock_claude_stream()
+@pytest.mark.skip(reason="AWS Suspended Account")
def test_completion_bedrock_ai21_stream():
try:
litellm.set_verbose = False
@@ -911,6 +913,7 @@ def test_sagemaker_weird_response():
# test_sagemaker_weird_response()
+@pytest.mark.skip(reason="AWS Suspended Account")
@pytest.mark.asyncio
async def test_sagemaker_streaming_async():
try:
@@ -949,6 +952,7 @@ async def test_sagemaker_streaming_async():
# asyncio.run(test_sagemaker_streaming_async())
+@pytest.mark.skip(reason="AWS Suspended Account")
def test_completion_sagemaker_stream():
try:
response = completion(
diff --git a/litellm/utils.py b/litellm/utils.py
index 18307eebc85..0157c305a2e 100644
--- a/litellm/utils.py
+++ b/litellm/utils.py
@@ -6963,7 +6963,7 @@ def exception_type(
if "500 An internal error has occurred." in error_str:
exception_mapping_worked = True
raise APIError(
- status_code=original_exception.status_code,
+ status_code=getattr(original_exception, "status_code", 500),
message=f"PalmException - {original_exception.message}",
llm_provider="palm",
model=model,
diff --git a/tests/test_keys.py b/tests/test_keys.py
index c2b9571805e..a6e85d6d9c0 100644
--- a/tests/test_keys.py
+++ b/tests/test_keys.py
@@ -490,6 +490,7 @@ async def test_key_crossing_budget():
assert "ExceededTokenBudget: Current spend for token:" in str(e)
+@pytest.mark.skip(reason="AWS Suspended Account")
@pytest.mark.asyncio
async def test_key_info_spend_values_sagemaker():
"""
diff --git a/ui/litellm-dashboard/out/404.html b/ui/litellm-dashboard/out/404.html
index 554dcf93ae5..687a52941c0 100644
--- a/ui/litellm-dashboard/out/404.html
+++ b/ui/litellm-dashboard/out/404.html
@@ -1 +1 @@
-404: This page could not be found.🚅 LiteLLM404
This page could not be found.
\ No newline at end of file
+404: This page could not be found.🚅 LiteLLM404
This page could not be found.
\ No newline at end of file
diff --git a/ui/litellm-dashboard/out/index.html b/ui/litellm-dashboard/out/index.html
index 935323194c4..a1e9ec23f07 100644
--- a/ui/litellm-dashboard/out/index.html
+++ b/ui/litellm-dashboard/out/index.html
@@ -1 +1 @@
-🚅 LiteLLM
\ No newline at end of file
+🚅 LiteLLM
\ No newline at end of file
diff --git a/ui/litellm-dashboard/out/index.txt b/ui/litellm-dashboard/out/index.txt
index b732f427065..6f20aff67e7 100644
--- a/ui/litellm-dashboard/out/index.txt
+++ b/ui/litellm-dashboard/out/index.txt
@@ -1,7 +1,7 @@
2:I[77831,[],""]
-3:I[24143,["303","static/chunks/303-d80f23087a9e6aec.js","931","static/chunks/app/page-d4fe4a48cbd3572c.js"],""]
+3:I[24143,["303","static/chunks/303-d80f23087a9e6aec.js","931","static/chunks/app/page-cc9d300e3b13fc1b.js"],""]
4:I[5613,[],""]
5:I[31778,[],""]
-0:["eSwVwl_InIrhYtCAqDMKF",[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",{"children":["__PAGE__",{},["$L1",["$","$L2",null,{"propsForComponent":{"params":{}},"Component":"$3","isStaticGeneration":true}],null]]},[null,["$","html",null,{"lang":"en","children":["$","body",null,{"className":"__className_c23dc8","children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"loading":"$undefined","loadingStyles":"$undefined","loadingScripts":"$undefined","hasLoading":false,"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[],"styles":null}]}]}],null]],[[["$","link","0",{"rel":"stylesheet","href":"/ui/_next/static/css/6920a121699cde9c.css","precedence":"next","crossOrigin":""}]],"$L6"]]]]
+0:["h6IXdBMiZG7ES547qg1M-",[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",{"children":["__PAGE__",{},["$L1",["$","$L2",null,{"propsForComponent":{"params":{}},"Component":"$3","isStaticGeneration":true}],null]]},[null,["$","html",null,{"lang":"en","children":["$","body",null,{"className":"__className_c23dc8","children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"loading":"$undefined","loadingStyles":"$undefined","loadingScripts":"$undefined","hasLoading":false,"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[],"styles":null}]}]}],null]],[[["$","link","0",{"rel":"stylesheet","href":"/ui/_next/static/css/6920a121699cde9c.css","precedence":"next","crossOrigin":""}]],"$L6"]]]]
6:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"🚅 LiteLLM"}],["$","meta","3",{"name":"description","content":"LiteLLM Proxy Admin UI"}],["$","link","4",{"rel":"icon","href":"/ui/favicon.ico","type":"image/x-icon","sizes":"16x16"}],["$","meta","5",{"name":"next-size-adjust"}]]
1:null
diff --git a/ui/litellm-dashboard/src/components/networking.tsx b/ui/litellm-dashboard/src/components/networking.tsx
index 33e9c4fa31f..749fbb35e56 100644
--- a/ui/litellm-dashboard/src/components/networking.tsx
+++ b/ui/litellm-dashboard/src/components/networking.tsx
@@ -313,6 +313,7 @@ export const userSpendLogsCall = async (
endTime: String
) => {
try {
+ console.log(`user role in spend logs call: ${userRole}`);
let url = proxyBaseUrl ? `${proxyBaseUrl}/spend/logs` : `/spend/logs`;
if (userRole == "App Owner") {
url = `${url}/?user_id=${userID}&start_date=${startTime}&end_date=${endTime}`;
@@ -343,6 +344,96 @@ export const userSpendLogsCall = async (
}
};
+export const adminSpendLogsCall = async (accessToken: String) => {
+ try {
+ let url = proxyBaseUrl
+ ? `${proxyBaseUrl}/global/spend/logs`
+ : `/global/spend/logs`;
+
+ message.info("Making spend logs request");
+ const response = await fetch(url, {
+ method: "GET",
+ headers: {
+ Authorization: `Bearer ${accessToken}`,
+ "Content-Type": "application/json",
+ },
+ });
+ if (!response.ok) {
+ const errorData = await response.text();
+ message.error(errorData);
+ throw new Error("Network response was not ok");
+ }
+
+ const data = await response.json();
+ console.log(data);
+ message.success("Spend Logs received");
+ return data;
+ } catch (error) {
+ console.error("Failed to create key:", error);
+ throw error;
+ }
+};
+
+export const adminTopKeysCall = async (accessToken: String) => {
+ try {
+ let url = proxyBaseUrl
+ ? `${proxyBaseUrl}/global/spend/keys?limit=5`
+ : `/global/spend/keys?limit=5`;
+
+ message.info("Making spend keys request");
+ const response = await fetch(url, {
+ method: "GET",
+ headers: {
+ Authorization: `Bearer ${accessToken}`,
+ "Content-Type": "application/json",
+ },
+ });
+ if (!response.ok) {
+ const errorData = await response.text();
+ message.error(errorData);
+ throw new Error("Network response was not ok");
+ }
+
+ const data = await response.json();
+ console.log(data);
+ message.success("Spend Logs received");
+ return data;
+ } catch (error) {
+ console.error("Failed to create key:", error);
+ throw error;
+ }
+};
+
+export const adminTopModelsCall = async (accessToken: String) => {
+ try {
+ let url = proxyBaseUrl
+ ? `${proxyBaseUrl}/global/spend/models?limit=5`
+ : `/global/spend/models?limit=5`;
+
+ message.info("Making spend models request");
+ const response = await fetch(url, {
+ method: "GET",
+ headers: {
+ Authorization: `Bearer ${accessToken}`,
+ "Content-Type": "application/json",
+ },
+ });
+ if (!response.ok) {
+ const errorData = await response.text();
+ message.error(errorData);
+ throw new Error("Network response was not ok");
+ }
+
+ const data = await response.json();
+ console.log(data);
+ message.success("Spend Logs received");
+ return data;
+ } catch (error) {
+ console.error("Failed to create key:", error);
+ throw error;
+ }
+};
+
export const keyInfoCall = async (accessToken: String, keys: String[]) => {
try {
let url = proxyBaseUrl ? `${proxyBaseUrl}/v2/key/info` : `/v2/key/info`;
diff --git a/ui/litellm-dashboard/src/components/usage.tsx b/ui/litellm-dashboard/src/components/usage.tsx
index 53493eabce1..afc002fd548 100644
--- a/ui/litellm-dashboard/src/components/usage.tsx
+++ b/ui/litellm-dashboard/src/components/usage.tsx
@@ -2,7 +2,13 @@ import { BarChart, Card, Title } from "@tremor/react";
import React, { useState, useEffect } from "react";
import { Grid, Col, Text, LineChart } from "@tremor/react";
-import { userSpendLogsCall, keyInfoCall } from "./networking";
+import {
+ userSpendLogsCall,
+ keyInfoCall,
+ adminSpendLogsCall,
+ adminTopKeysCall,
+ adminTopModelsCall,
+} from "./networking";
import { start } from "repl";
interface UsagePageProps {
@@ -164,41 +170,61 @@ const UsagePage: React.FC = ({
if (accessToken && token && userRole && userID) {
const fetchData = async () => {
try {
- await userSpendLogsCall(
- accessToken,
- token,
- userRole,
- userID,
- startTime,
- endTime
- ).then(async (response) => {
- console.log("result from spend logs call", response);
- if ("daily_spend" in response) {
- // this is from clickhouse analytics
- //
- let daily_spend = response["daily_spend"];
- console.log("daily spend", daily_spend);
- setKeySpendData(daily_spend);
- let topApiKeys = response.top_api_keys;
- setTopKeys(topApiKeys);
- }
- else {
- const topKeysResponse = await keyInfoCall(
- accessToken,
- getTopKeys(response)
- );
- const filtered_keys = topKeysResponse["info"].map((k: any) => ({
- key: (k["key_name"] || k["key_alias"] || k["token"]).substring(
- 0,
- 7
- ),
- spend: k["spend"],
- }));
- setTopKeys(filtered_keys);
- setTopUsers(getTopUsers(response));
- setKeySpendData(response);
- }
- });
+ /**
+ * If user is Admin - query the global views endpoints
+ * If user is App Owner - use the normal spend logs call
+ */
+ console.log(`user role: ${userRole}`);
+ if (userRole == "Admin") {
+ const overall_spend = await adminSpendLogsCall(accessToken);
+ setKeySpendData(overall_spend);
+ const top_keys = await adminTopKeysCall(accessToken);
+ const filtered_keys = top_keys.map((k: any) => ({
+ key: (k["key_name"] || k["key_alias"] || k["api_key"]).substring(
+ 0,
+ 7
+ ),
+ spend: k["total_spend"],
+ }));
+ setTopKeys(filtered_keys);
+ const top_models = await adminTopModelsCall(accessToken);
+ } else if (userRole == "App Owner") {
+ await userSpendLogsCall(
+ accessToken,
+ token,
+ userRole,
+ userID,
+ startTime,
+ endTime
+ ).then(async (response) => {
+ console.log("result from spend logs call", response);
+ if ("daily_spend" in response) {
+ // this is from clickhouse analytics
+ //
+ let daily_spend = response["daily_spend"];
+ console.log("daily spend", daily_spend);
+ setKeySpendData(daily_spend);
+ let topApiKeys = response.top_api_keys;
+ setTopKeys(topApiKeys);
+ } else {
+ const topKeysResponse = await keyInfoCall(
+ accessToken,
+ getTopKeys(response)
+ );
+ const filtered_keys = topKeysResponse["info"].map((k: any) => ({
+ key: (
+ k["key_name"] ||
+ k["key_alias"] ||
+ k["token"]
+ ).substring(0, 7),
+ spend: k["spend"],
+ }));
+ setTopKeys(filtered_keys);
+ setTopUsers(getTopUsers(response));
+ setKeySpendData(response);
+ }
+ });
+ }
} catch (error) {
console.error("There was an error fetching the data", error);
// Optionally, update your UI to reflect the error state here as well
@@ -222,7 +248,7 @@ const UsagePage: React.FC = ({
valueFormatter={valueFormatter}
yAxisWidth={100}
tickGap={5}
- customTooltip={customTooltip}
+ // customTooltip={customTooltip}
/>