diff --git a/litellm/caching.py b/litellm/caching.py index 38174c2abbc..257bb1ca549 100644 --- a/litellm/caching.py +++ b/litellm/caching.py @@ -61,6 +61,10 @@ class InMemoryCache(BaseCache): self.cache_dict.clear() self.ttl_dict.clear() + def delete_cache(self, key): + self.cache_dict.pop(key, None) + self.ttl_dict.pop(key, None) + class RedisCache(BaseCache): def __init__(self, host=None, port=None, password=None, **kwargs): @@ -117,6 +121,9 @@ class RedisCache(BaseCache): def flush_cache(self): self.redis_client.flushall() + def delete_cache(self, key): + self.redis_client.delete(key) + class S3Cache(BaseCache): def __init__( @@ -304,6 +311,12 @@ class DualCache(BaseCache): if self.redis_cache is not None: self.redis_cache.flush_cache() + def delete_cache(self, key): + if self.in_memory_cache is not None: + self.in_memory_cache.delete_cache(key) + if self.redis_cache is not None: + self.redis_cache.delete_cache(key) + #### LiteLLM.Completion / Embedding Cache #### class Cache: diff --git a/litellm/proxy/_experimental/out/404.html b/litellm/proxy/_experimental/out/404.html index adedbe62c65..56852eeb12e 100644 --- a/litellm/proxy/_experimental/out/404.html +++ b/litellm/proxy/_experimental/out/404.html @@ -1 +1 @@ -404: This page could not be found.Create Next App

404

This page could not be found.

\ No newline at end of file +404: This page could not be found.Create Next App

404

This page could not be found.

\ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/9KvKBLd4AqpwRy9Epc-98/_buildManifest.js b/litellm/proxy/_experimental/out/_next/static/B4oAVsVV35eL3Y1bPepKW/_buildManifest.js similarity index 100% rename from litellm/proxy/_experimental/out/_next/static/9KvKBLd4AqpwRy9Epc-98/_buildManifest.js rename to litellm/proxy/_experimental/out/_next/static/B4oAVsVV35eL3Y1bPepKW/_buildManifest.js diff --git a/litellm/proxy/_experimental/out/_next/static/9KvKBLd4AqpwRy9Epc-98/_ssgManifest.js b/litellm/proxy/_experimental/out/_next/static/B4oAVsVV35eL3Y1bPepKW/_ssgManifest.js similarity index 100% rename from litellm/proxy/_experimental/out/_next/static/9KvKBLd4AqpwRy9Epc-98/_ssgManifest.js rename to litellm/proxy/_experimental/out/_next/static/B4oAVsVV35eL3Y1bPepKW/_ssgManifest.js diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/app/page-cf0440186224a114.js b/litellm/proxy/_experimental/out/_next/static/chunks/app/page-cf0440186224a114.js deleted file mode 100644 index da9b6b57020..00000000000 --- a/litellm/proxy/_experimental/out/_next/static/chunks/app/page-cf0440186224a114.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[931],{8598:function(e,t,r){Promise.resolve().then(r.t.bind(r,5250,23)),Promise.resolve().then(r.bind(r,3239))},3239:function(e,t,r){"use strict";r.r(t),r.d(t,{default:function(){return F}});var l=r(3827),s=r(4090),a=r(588);let n=async(e,t,r)=>{try{if(console.log("Form Values in keyCreateCall:",r),r.metadata)try{r.metadata=JSON.parse(r.metadata)}catch(e){a.ZP.error("Failed to parse metadata: "+e)}let l=await fetch("/key/generate",{method:"POST",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({user_id:t,...r})});if(!l.ok){let e=await l.text();throw a.ZP.error("Failed to create key: "+e),console.error("Error response from the server:",e),Error("Network response was not ok")}let s=await l.json();return console.log("API Response:",s),s}catch(e){throw console.error("Failed to create key:",e),e}},o=async(e,t)=>{try{let r=await fetch("/key/delete",{method:"POST",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({keys:[t]})});if(!r.ok)throw Error("Network response was not ok");let l=await r.json();return console.log(l),l}catch(e){throw console.error("Failed to create key:",e),e}},i=async(e,t)=>{try{let r=await fetch("/user/info?user_id=".concat(t),{method:"GET",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!r.ok)throw Error("Network response was not ok");let l=await r.json();return console.log(l),l}catch(e){throw console.error("Failed to create key:",e),e}};var c=r(384),d=r(6453),h=r(2179),u=r(1801),x=r(6776),m=r(2902),j=r(7171),y=r(9714),Z=r(8707),p=r(1861);let{Option:k}=x.default;var g=e=>{let{userID:t,accessToken:r,data:o,setData:i}=e,[x]=m.Z.useForm(),[k,g]=(0,s.useState)(!1),[f,w]=(0,s.useState)(null),b=()=>{g(!1),x.resetFields()},C=()=>{g(!1),w(null),x.resetFields()},S=async e=>{try{a.ZP.info("Making API Call"),e.models&&""!==e.models.trim()?e.models=e.models.split(",").map(e=>e.trim()):e.models=[],g(!0);let l=await n(r,t,e);i(e=>e?[...e,l]:[l]),w(l.key),a.ZP.success("API Key Created"),x.resetFields()}catch(e){console.error("Error creating the key:",e)}};return(0,l.jsxs)("div",{children:[(0,l.jsx)(h.Z,{className:"mx-auto",onClick:()=>g(!0),children:"+ Create New Key"}),(0,l.jsx)(j.Z,{title:"Create Key",visible:k,width:800,footer:null,onOk:b,onCancel:C,children:(0,l.jsxs)(m.Z,{form:x,onFinish:S,labelCol:{span:6},wrapperCol:{span:16},labelAlign:"left",children:[(0,l.jsx)(m.Z.Item,{label:"Key Name",name:"key_alias",children:(0,l.jsx)(y.Z,{})}),(0,l.jsx)(m.Z.Item,{label:"Models (Comma Separated). Eg: gpt-3.5-turbo,gpt-4",name:"models",children:(0,l.jsx)(y.Z,{placeholder:"gpt-4,gpt-3.5-turbo"})}),(0,l.jsx)(m.Z.Item,{label:"Max Budget (USD)",name:"max_budget",children:(0,l.jsx)(Z.Z,{step:.01,precision:2,width:200})}),(0,l.jsx)(m.Z.Item,{label:"Duration (eg: 30s, 30h, 30d)",name:"duration",children:(0,l.jsx)(y.Z,{})}),(0,l.jsx)(m.Z.Item,{label:"Team ID",name:"team_id",children:(0,l.jsx)(y.Z,{placeholder:"ai_team"})}),(0,l.jsx)(m.Z.Item,{label:"Metadata",name:"metadata",children:(0,l.jsx)(y.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 Key"})})]})}),f&&(0,l.jsx)(j.Z,{title:"Save your key",visible:k,onOk:b,onCancel:C,footer:null,children:(0,l.jsxs)(d.Z,{numItems:1,className:"gap-2 w-full",children:[(0,l.jsx)(c.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)(c.Z,{numColSpan:1,children:null!=f?(0,l.jsxs)(u.Z,{children:["API Key: ",f]}):(0,l.jsx)(u.Z,{children:"Key being created, this might take 30s"})})]})})]})},f=r(3393),w=r(3810),b=r(1244),C=r(827),S=r(3851),I=r(2044),N=r(4167),E=r(4480),v=r(2287),_=r(2440),P=e=>{let{userID:t,accessToken:r,data:s,setData:a}=e,n=async e=>{if(null!=s)try{await o(r,e);let t=s.filter(t=>t.token!==e);a(t)}catch(e){console.error("Error deleting the key:",e)}};if(null!=s)return console.log("RERENDER TRIGGERED"),(0,l.jsxs)(w.Z,{className:"w-full mx-auto flex-auto overflow-y-auto max-h-[50vh] mb-4",children:[(0,l.jsx)(_.Z,{children:"API Keys"}),(0,l.jsxs)(C.Z,{className:"mt-5",children:[(0,l.jsx)(N.Z,{children:(0,l.jsxs)(v.Z,{children:[(0,l.jsx)(E.Z,{children:"Secret Key"}),(0,l.jsx)(E.Z,{children:"Spend (USD)"}),(0,l.jsx)(E.Z,{children:"Key Budget (USD)"}),(0,l.jsx)(E.Z,{children:"Team ID"}),(0,l.jsx)(E.Z,{children:"Metadata"}),(0,l.jsx)(E.Z,{children:"Expires"})]})}),(0,l.jsx)(S.Z,{children:s.map(e=>(console.log(e),(0,l.jsxs)(v.Z,{children:[(0,l.jsx)(I.Z,{children:null!=e.key_alias?(0,l.jsx)(u.Z,{children:e.key_alias}):(0,l.jsx)(u.Z,{children:e.token})}),(0,l.jsx)(I.Z,{children:(0,l.jsx)(u.Z,{children:e.spend})}),(0,l.jsx)(I.Z,{children:null!=e.max_budget?(0,l.jsx)(u.Z,{children:e.max_budget}):(0,l.jsx)(u.Z,{children:"Unlimited Budget"})}),(0,l.jsx)(I.Z,{children:(0,l.jsx)(u.Z,{children:e.team_id})}),(0,l.jsx)(I.Z,{children:(0,l.jsx)(u.Z,{children:JSON.stringify(e.metadata)})}),(0,l.jsx)(I.Z,{children:null!=e.expires?(0,l.jsx)(u.Z,{children:e.expires}):(0,l.jsx)(u.Z,{children:"Never expires"})}),(0,l.jsx)(I.Z,{children:(0,l.jsx)(b.Z,{onClick:()=>n(e.token),icon:f.Z,size:"xs"})})]},e.token)))})]})]})},D=r(7907),T=r(7963),F=()=>{let[e,t]=(0,s.useState)(null),r=(0,D.useSearchParams)(),a=r.get("userID"),n=r.get("token"),[o,h]=(0,s.useState)(null);return((0,s.useEffect)(()=>{if(n){let e=(0,T.o)(n);e&&(console.log("Decoded token:",e),console.log("Decoded key:",e.key),h(e.key))}a&&o&&!e&&(async()=>{try{let e=await i(o,a);t(e.keys)}catch(e){console.error("There was an error fetching the data",e)}})()},[a,n,o,e]),null==a||null==n)?(window.location.href="/sso/key/generate",null):null==o?null:(0,l.jsx)(d.Z,{numItems:1,className:"gap-0 p-10 h-[75vh] w-full",children:(0,l.jsxs)(c.Z,{numColSpan:1,children:[(0,l.jsx)(P,{userID:a,accessToken:o,data:e,setData:t}),(0,l.jsx)(g,{userID:a,accessToken:o,data:e,setData:t})]})})}}},function(e){e.O(0,[448,971,69,744],function(){return e(e.s=8598)}),_N_E=e.O()}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/app/page-e5227a95293777d5.js b/litellm/proxy/_experimental/out/_next/static/chunks/app/page-e5227a95293777d5.js new file mode 100644 index 00000000000..d5999b73b85 --- /dev/null +++ b/litellm/proxy/_experimental/out/_next/static/chunks/app/page-e5227a95293777d5.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[931],{8598:function(e,t,l){Promise.resolve().then(l.t.bind(l,5250,23)),Promise.resolve().then(l.bind(l,3239))},3239:function(e,t,l){"use strict";l.r(t),l.d(t,{default:function(){return F}});var r=l(3827),s=l(4090),a=l(588);let n=async(e,t,l)=>{try{if(console.log("Form Values in keyCreateCall:",l),l.metadata)try{l.metadata=JSON.parse(l.metadata)}catch(e){a.ZP.error("Failed to parse metadata: "+e)}let r=await fetch("/key/generate",{method:"POST",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({user_id:t,...l})});if(!r.ok){let e=await r.text();throw a.ZP.error("Failed to create key: "+e),console.error("Error response from the server:",e),Error("Network response was not ok")}let s=await r.json();return console.log("API Response:",s),s}catch(e){throw console.error("Failed to create key:",e),e}},o=async(e,t)=>{try{console.log("in keyDeleteCall:",t);let l=await fetch("/key/delete",{method:"POST",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({keys:[t]})});if(!l.ok){let e=await l.text();throw a.ZP.error("Failed to delete key: "+e),Error("Network response was not ok")}let r=await l.json();return console.log(r),a.ZP.success("API Key Deleted"),r}catch(e){throw console.error("Failed to create key:",e),e}},i=async(e,t)=>{try{let l="/user/info";console.log("in userInfoCall:",l);let r=await fetch("".concat(l,"/?user_id=").concat(t),{method:"GET",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw a.ZP.error(e),Error("Network response was not ok")}let s=await r.json();return console.log(s),s}catch(e){throw console.error("Failed to create key:",e),e}};var c=l(384),d=l(6453),h=l(2179),u=l(1801),x=l(6776),m=l(2902),j=l(7171),y=l(9714),Z=l(8707),p=l(1861);let{Option:k}=x.default;var g=e=>{let{userID:t,accessToken:l,data:o,setData:i}=e,[x]=m.Z.useForm(),[k,g]=(0,s.useState)(!1),[f,w]=(0,s.useState)(null),b=()=>{g(!1),x.resetFields()},C=()=>{g(!1),w(null),x.resetFields()},S=async e=>{try{a.ZP.info("Making API Call"),e.models&&""!==e.models.trim()?e.models=e.models.split(",").map(e=>e.trim()):e.models=[],g(!0);let r=await n(l,t,e);i(e=>e?[...e,r]:[r]),w(r.key),a.ZP.success("API Key Created"),x.resetFields()}catch(e){console.error("Error creating the key:",e)}};return(0,r.jsxs)("div",{children:[(0,r.jsx)(h.Z,{className:"mx-auto",onClick:()=>g(!0),children:"+ Create New Key"}),(0,r.jsx)(j.Z,{title:"Create Key",visible:k,width:800,footer:null,onOk:b,onCancel:C,children:(0,r.jsxs)(m.Z,{form:x,onFinish:S,labelCol:{span:6},wrapperCol:{span:16},labelAlign:"left",children:[(0,r.jsx)(m.Z.Item,{label:"Key Name",name:"key_alias",children:(0,r.jsx)(y.Z,{})}),(0,r.jsx)(m.Z.Item,{label:"Models (Comma Separated). Eg: gpt-3.5-turbo,gpt-4",name:"models",children:(0,r.jsx)(y.Z,{placeholder:"gpt-4,gpt-3.5-turbo"})}),(0,r.jsx)(m.Z.Item,{label:"Max Budget (USD)",name:"max_budget",children:(0,r.jsx)(Z.Z,{step:.01,precision:2,width:200})}),(0,r.jsx)(m.Z.Item,{label:"Duration (eg: 30s, 30h, 30d)",name:"duration",children:(0,r.jsx)(y.Z,{})}),(0,r.jsx)(m.Z.Item,{label:"Team ID",name:"team_id",children:(0,r.jsx)(y.Z,{placeholder:"ai_team"})}),(0,r.jsx)(m.Z.Item,{label:"Metadata",name:"metadata",children:(0,r.jsx)(y.Z.TextArea,{rows:4,placeholder:"Enter metadata as JSON"})}),(0,r.jsx)("div",{style:{textAlign:"right",marginTop:"10px"},children:(0,r.jsx)(p.ZP,{htmlType:"submit",children:"Create Key"})})]})}),f&&(0,r.jsx)(j.Z,{title:"Save your key",visible:k,onOk:b,onCancel:C,footer:null,children:(0,r.jsxs)(d.Z,{numItems:1,className:"gap-2 w-full",children:[(0,r.jsx)(c.Z,{numColSpan:1,children:(0,r.jsxs)("p",{children:["Please save this secret key somewhere safe and accessible. For security reasons, ",(0,r.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,r.jsx)(c.Z,{numColSpan:1,children:null!=f?(0,r.jsxs)(u.Z,{children:["API Key: ",f]}):(0,r.jsx)(u.Z,{children:"Key being created, this might take 30s"})})]})})]})},f=l(3393),w=l(3810),b=l(1244),C=l(827),S=l(3851),I=l(2044),N=l(4167),P=l(4480),E=l(2287),_=l(2440),v=e=>{let{userID:t,accessToken:l,data:s,setData:a}=e,n=async e=>{if(null!=s)try{await o(l,e);let t=s.filter(t=>t.token!==e);a(t)}catch(e){console.error("Error deleting the key:",e)}};if(null!=s)return console.log("RERENDER TRIGGERED"),(0,r.jsxs)(w.Z,{className:"w-full mx-auto flex-auto overflow-y-auto max-h-[50vh] mb-4",children:[(0,r.jsx)(_.Z,{children:"API Keys"}),(0,r.jsxs)(C.Z,{className:"mt-5",children:[(0,r.jsx)(N.Z,{children:(0,r.jsxs)(E.Z,{children:[(0,r.jsx)(P.Z,{children:"Key Alias"}),(0,r.jsx)(P.Z,{children:"Secret Key"}),(0,r.jsx)(P.Z,{children:"Spend (USD)"}),(0,r.jsx)(P.Z,{children:"Key Budget (USD)"}),(0,r.jsx)(P.Z,{children:"Team ID"}),(0,r.jsx)(P.Z,{children:"Metadata"}),(0,r.jsx)(P.Z,{children:"Expires"})]})}),(0,r.jsx)(S.Z,{children:s.map(e=>(console.log(e),"litellm-dashboard"===e.team_id)?null:(0,r.jsxs)(E.Z,{children:[(0,r.jsx)(I.Z,{children:null!=e.key_alias?(0,r.jsx)(u.Z,{children:e.key_alias}):(0,r.jsx)(u.Z,{children:"Not Set"})}),(0,r.jsx)(I.Z,{children:(0,r.jsx)(u.Z,{children:e.key_name})}),(0,r.jsx)(I.Z,{children:(0,r.jsx)(u.Z,{children:e.spend})}),(0,r.jsx)(I.Z,{children:null!=e.max_budget?(0,r.jsx)(u.Z,{children:e.max_budget}):(0,r.jsx)(u.Z,{children:"Unlimited Budget"})}),(0,r.jsx)(I.Z,{children:(0,r.jsx)(u.Z,{children:e.team_id})}),(0,r.jsx)(I.Z,{children:(0,r.jsx)(u.Z,{children:JSON.stringify(e.metadata)})}),(0,r.jsx)(I.Z,{children:null!=e.expires?(0,r.jsx)(u.Z,{children:e.expires}):(0,r.jsx)(u.Z,{children:"Never expires"})}),(0,r.jsx)(I.Z,{children:(0,r.jsx)(b.Z,{onClick:()=>n(e.token),icon:f.Z,size:"xs"})})]},e.token))})]})]})},D=l(7907),T=l(7963),F=()=>{let[e,t]=(0,s.useState)(null),l=(0,D.useSearchParams)(),a=l.get("userID"),n=l.get("token"),[o,h]=(0,s.useState)(null);if((0,s.useEffect)(()=>{if(n){let e=(0,T.o)(n);e&&(console.log("Decoded token:",e),console.log("Decoded key:",e.key),h(e.key))}a&&o&&!e&&(async()=>{try{let e=await i(o,a);t(e.keys)}catch(e){console.error("There was an error fetching the data",e)}})()},[a,n,o,e]),null==a||null==n){let e="/sso/key/generate";return console.log("Full URL:",e),window.location.href=e,null}return null==o?null:(0,r.jsx)(d.Z,{numItems:1,className:"gap-0 p-10 h-[75vh] w-full",children:(0,r.jsxs)(c.Z,{numColSpan:1,children:[(0,r.jsx)(v,{userID:a,accessToken:o,data:e,setData:t}),(0,r.jsx)(g,{userID:a,accessToken:o,data:e,setData:t})]})})}}},function(e){e.O(0,[448,971,69,744],function(){return e(e.s=8598)}),_N_E=e.O()}]); \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/index.html b/litellm/proxy/_experimental/out/index.html index fe26a9f0ba4..7ad6dd2c0b6 100644 --- a/litellm/proxy/_experimental/out/index.html +++ b/litellm/proxy/_experimental/out/index.html @@ -1 +1 @@ -Create Next App
Loading...
\ No newline at end of file +Create Next App
Loading...
\ No newline at end of file diff --git a/litellm/proxy/_experimental/out/index.txt b/litellm/proxy/_experimental/out/index.txt index 1cec7f58a76..d31c7af9252 100644 --- a/litellm/proxy/_experimental/out/index.txt +++ b/litellm/proxy/_experimental/out/index.txt @@ -1,8 +1,8 @@ 2:"$Sreact.suspense" -3:I[5250,["448","static/chunks/448-cd38799829cf7b57.js","931","static/chunks/app/page-cf0440186224a114.js"],""] -4:I[3239,["448","static/chunks/448-cd38799829cf7b57.js","931","static/chunks/app/page-cf0440186224a114.js"],""] +3:I[5250,["448","static/chunks/448-cd38799829cf7b57.js","931","static/chunks/app/page-e5227a95293777d5.js"],""] +4:I[3239,["448","static/chunks/448-cd38799829cf7b57.js","931","static/chunks/app/page-e5227a95293777d5.js"],""] 5:I[5613,[],""] 6:I[1778,[],""] -0:["9KvKBLd4AqpwRy9Epc-98",[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",{"children":["__PAGE__",{},["$L1",["$","$2",null,{"fallback":["$","div",null,{"children":"Loading..."}],"children":["$","div",null,{"className":"flex min-h-screen flex-col items-center","children":[["$","nav",null,{"className":"left-0 right-0 top-0 flex justify-between items-center h-12","children":[["$","div",null,{"className":"text-left mx-4 my-2 absolute top-0 left-0","children":["$","div",null,{"className":"flex flex-col items-center","children":["$","$L3",null,{"href":"/","children":["$","button",null,{"className":"text-gray-800 text-2xl px-4 py-1 rounded text-center","children":"🚅 LiteLLM"}]}]}]}],["$","div",null,{"className":"text-right mx-4 my-2 absolute top-0 right-0","children":[["$","a",null,{"href":"https://docs.litellm.ai/docs/","target":"_blank","rel":"noopener noreferrer","children":["$","button",null,{"className":"border border-gray-800 rounded-lg text-gray-800 text-xl px-4 py-1 rounded p-1 mr-2 text-center","children":"Docs"}]}],["$","a",null,{"href":"https://calendly.com/d/4mp-gd3-k5k/berriai-1-1-onboarding-litellm-hosted-version","target":"_blank","rel":"noopener noreferrer","children":["$","button",null,{"className":"border border-gray-800 rounded-lg text-gray-800 text-xl px-4 py-1 rounded p-1 text-center","children":"Schedule Demo"}]}]]}]]}],["$","$L4",null,{}]]}]}],null]]},[null,["$","html",null,{"lang":"en","children":["$","body",null,{"className":"__className_c23dc8","children":["$","$L5",null,{"parallelRouterKey":"children","segmentPath":["children"],"loading":"$undefined","loadingStyles":"$undefined","loadingScripts":"$undefined","hasLoading":false,"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L6",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/7384ba6288e79f81.css","precedence":"next","crossOrigin":""}]],"$L7"]]]] +0:["B4oAVsVV35eL3Y1bPepKW",[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",{"children":["__PAGE__",{},["$L1",["$","$2",null,{"fallback":["$","div",null,{"children":"Loading..."}],"children":["$","div",null,{"className":"flex min-h-screen flex-col items-center","children":[["$","nav",null,{"className":"left-0 right-0 top-0 flex justify-between items-center h-12","children":[["$","div",null,{"className":"text-left mx-4 my-2 absolute top-0 left-0","children":["$","div",null,{"className":"flex flex-col items-center","children":["$","$L3",null,{"href":"/","children":["$","button",null,{"className":"text-gray-800 text-2xl px-4 py-1 rounded text-center","children":"🚅 LiteLLM"}]}]}]}],["$","div",null,{"className":"text-right mx-4 my-2 absolute top-0 right-0","children":[["$","a",null,{"href":"https://docs.litellm.ai/docs/","target":"_blank","rel":"noopener noreferrer","children":["$","button",null,{"className":"border border-gray-800 rounded-lg text-gray-800 text-xl px-4 py-1 rounded p-1 mr-2 text-center","children":"Docs"}]}],["$","a",null,{"href":"https://calendly.com/d/4mp-gd3-k5k/berriai-1-1-onboarding-litellm-hosted-version","target":"_blank","rel":"noopener noreferrer","children":["$","button",null,{"className":"border border-gray-800 rounded-lg text-gray-800 text-xl px-4 py-1 rounded p-1 text-center","children":"Schedule Demo"}]}]]}]]}],["$","$L4",null,{}]]}]}],null]]},[null,["$","html",null,{"lang":"en","children":["$","body",null,{"className":"__className_c23dc8","children":["$","$L5",null,{"parallelRouterKey":"children","segmentPath":["children"],"loading":"$undefined","loadingStyles":"$undefined","loadingScripts":"$undefined","hasLoading":false,"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L6",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/7384ba6288e79f81.css","precedence":"next","crossOrigin":""}]],"$L7"]]]] 7:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Create Next App"}],["$","meta","3",{"name":"description","content":"Generated by create next app"}],["$","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 dd8124285c0..9170305dff4 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -1452,11 +1452,14 @@ async def generate_key_helper_fn( saved_token["expires"], datetime ): saved_token["expires"] = saved_token["expires"].isoformat() - user_api_key_cache.set_cache( - key=key_data["token"], - value=LiteLLM_VerificationToken(**saved_token), # type: ignore - ttl=60, - ) + if key_data["token"] is not None and isinstance(key_data["token"], str): + hashed_token = hash_token(key_data["token"]) + saved_token["token"] = hashed_token + user_api_key_cache.set_cache( + key=hashed_token, + value=LiteLLM_VerificationToken(**saved_token), # type: ignore + ttl=60, + ) if prisma_client is not None: ## CREATE USER (If necessary) verbose_proxy_logger.debug(f"prisma_client: Creating User={user_data}") @@ -2672,13 +2675,32 @@ async def delete_key_fn(data: DeleteKeyRequest): HTTPException: If an error occurs during key deletion. """ try: + global user_api_key_cache keys = data.keys + if len(keys) == 0: + raise ProxyException( + message=f"No keys provided, passed in: keys={keys}", + type="auth_error", + param="keys", + code=status.HTTP_400_BAD_REQUEST, + ) result = await delete_verification_token(tokens=keys) verbose_proxy_logger.debug("/key/delete - deleted_keys=", result) number_deleted_keys = len(result["deleted_keys"]) assert len(keys) == number_deleted_keys + + for key in keys: + user_api_key_cache.delete_cache(key) + # remove hash token from cache + hashed_token = hash_token(key) + user_api_key_cache.delete_cache(hashed_token) + + verbose_proxy_logger.debug( + f"/keys/delete - cache after delete: {user_api_key_cache.in_memory_cache.cache_dict}" + ) + return {"deleted_keys": keys} except Exception as e: if isinstance(e, HTTPException): @@ -3165,9 +3187,16 @@ async def login(request: Request): ): user_id = username # User is Authe'd in - generate key for the UI to access Proxy - response = await generate_key_helper_fn( - **{"duration": "1hr", "key_max_budget": 0, "models": [], "aliases": {}, "config": {}, "spend": 0, "user_id": user_id, "team_id": "litellm-dashboard"} # type: ignore - ) + + if os.getenv("DATABASE_URL") is not None: + response = await generate_key_helper_fn( + **{"duration": "1hr", "key_max_budget": 0, "models": [], "aliases": {}, "config": {}, "spend": 0, "user_id": user_id, "team_id": "litellm-dashboard"} # type: ignore + ) + else: + response = { + "token": "sk-gm", + "user_id": "litellm-dashboard", + } key = response["token"] # type: ignore user_id = response["user_id"] # type: ignore diff --git a/litellm/tests/test_key_generate_prisma.py b/litellm/tests/test_key_generate_prisma.py index 55bc3cec82b..140d638e880 100644 --- a/litellm/tests/test_key_generate_prisma.py +++ b/litellm/tests/test_key_generate_prisma.py @@ -104,6 +104,8 @@ def test_generate_and_call_with_valid_key(prisma_client): async def test(): await litellm.proxy.proxy_server.prisma_client.connect() + from litellm.proxy.proxy_server import user_api_key_cache + request = NewUserRequest() key = await new_user(request) print(key) @@ -111,6 +113,26 @@ def test_generate_and_call_with_valid_key(prisma_client): generated_key = key.key bearer_token = "Bearer " + generated_key + assert generated_key not in user_api_key_cache.in_memory_cache.cache_dict + assert ( + hash_token(generated_key) + in user_api_key_cache.in_memory_cache.cache_dict + ) + + cached_value = user_api_key_cache.in_memory_cache.cache_dict[ + hash_token(generated_key) + ] + + print("cached value=", cached_value) + print("cached token", cached_value.token) + + value_from_prisma = valid_token = await prisma_client.get_data( + token=generated_key, + ) + print("token from prisma", value_from_prisma) + + assert value_from_prisma.token == cached_value.token + request = Request(scope={"type": "http"}) request._url = URL(url="/chat/completions") @@ -618,6 +640,8 @@ def test_delete_key(prisma_client): async def test(): await litellm.proxy.proxy_server.prisma_client.connect() + from litellm.proxy.proxy_server import user_api_key_cache + request = NewUserRequest() key = await new_user(request) print(key) @@ -632,6 +656,12 @@ def test_delete_key(prisma_client): print("result from delete key", result_delete_key) assert result_delete_key == {"deleted_keys": [generated_key]} + assert generated_key not in user_api_key_cache.in_memory_cache.cache_dict + assert ( + hash_token(generated_key) + not in user_api_key_cache.in_memory_cache.cache_dict + ) + asyncio.run(test()) except Exception as e: pytest.fail(f"An exception occurred - {str(e)}") @@ -648,6 +678,8 @@ def test_delete_key_auth(prisma_client): async def test(): await litellm.proxy.proxy_server.prisma_client.connect() + from litellm.proxy.proxy_server import user_api_key_cache + request = NewUserRequest() key = await new_user(request) print(key) @@ -666,6 +698,12 @@ def test_delete_key_auth(prisma_client): request = Request(scope={"type": "http"}, receive=None) request._url = URL(url="/chat/completions") + assert generated_key not in user_api_key_cache.in_memory_cache.cache_dict + assert ( + hash_token(generated_key) + not in user_api_key_cache.in_memory_cache.cache_dict + ) + # use generated key to auth in result = await user_api_key_auth(request=request, api_key=bearer_token) print("got result", result) diff --git a/tests/test_keys.py b/tests/test_keys.py index 75baf966eba..9cbcc25e16b 100644 --- a/tests/test_keys.py +++ b/tests/test_keys.py @@ -234,7 +234,9 @@ async def get_key_info(session, call_key, get_key=None): return status else: print(f"call_key: {call_key}; get_key: {get_key}") - raise Exception(f"Request did not return a 200 status code: {status}") + raise Exception( + f"Request did not return a 200 status code: {status}. Responses {response_text}" + ) return await response.json() @@ -282,7 +284,7 @@ async def get_spend_logs(session, request_id): @pytest.mark.asyncio async def test_key_info_spend_values(): """ - Test to ensure spend is correctly calculated. + Test to ensure spend is correctly calculated - create key - make completion call - assert cost is expected value diff --git a/ui/litellm-dashboard/out/404.html b/ui/litellm-dashboard/out/404.html index adedbe62c65..56852eeb12e 100644 --- a/ui/litellm-dashboard/out/404.html +++ b/ui/litellm-dashboard/out/404.html @@ -1 +1 @@ -404: This page could not be found.Create Next App

404

This page could not be found.

\ No newline at end of file +404: This page could not be found.Create Next App

404

This page could not be found.

\ No newline at end of file diff --git a/ui/litellm-dashboard/out/_next/static/9KvKBLd4AqpwRy9Epc-98/_buildManifest.js b/ui/litellm-dashboard/out/_next/static/B4oAVsVV35eL3Y1bPepKW/_buildManifest.js similarity index 100% rename from ui/litellm-dashboard/out/_next/static/9KvKBLd4AqpwRy9Epc-98/_buildManifest.js rename to ui/litellm-dashboard/out/_next/static/B4oAVsVV35eL3Y1bPepKW/_buildManifest.js diff --git a/ui/litellm-dashboard/out/_next/static/9KvKBLd4AqpwRy9Epc-98/_ssgManifest.js b/ui/litellm-dashboard/out/_next/static/B4oAVsVV35eL3Y1bPepKW/_ssgManifest.js similarity index 100% rename from ui/litellm-dashboard/out/_next/static/9KvKBLd4AqpwRy9Epc-98/_ssgManifest.js rename to ui/litellm-dashboard/out/_next/static/B4oAVsVV35eL3Y1bPepKW/_ssgManifest.js diff --git a/ui/litellm-dashboard/out/_next/static/chunks/app/page-cf0440186224a114.js b/ui/litellm-dashboard/out/_next/static/chunks/app/page-cf0440186224a114.js deleted file mode 100644 index da9b6b57020..00000000000 --- a/ui/litellm-dashboard/out/_next/static/chunks/app/page-cf0440186224a114.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[931],{8598:function(e,t,r){Promise.resolve().then(r.t.bind(r,5250,23)),Promise.resolve().then(r.bind(r,3239))},3239:function(e,t,r){"use strict";r.r(t),r.d(t,{default:function(){return F}});var l=r(3827),s=r(4090),a=r(588);let n=async(e,t,r)=>{try{if(console.log("Form Values in keyCreateCall:",r),r.metadata)try{r.metadata=JSON.parse(r.metadata)}catch(e){a.ZP.error("Failed to parse metadata: "+e)}let l=await fetch("/key/generate",{method:"POST",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({user_id:t,...r})});if(!l.ok){let e=await l.text();throw a.ZP.error("Failed to create key: "+e),console.error("Error response from the server:",e),Error("Network response was not ok")}let s=await l.json();return console.log("API Response:",s),s}catch(e){throw console.error("Failed to create key:",e),e}},o=async(e,t)=>{try{let r=await fetch("/key/delete",{method:"POST",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({keys:[t]})});if(!r.ok)throw Error("Network response was not ok");let l=await r.json();return console.log(l),l}catch(e){throw console.error("Failed to create key:",e),e}},i=async(e,t)=>{try{let r=await fetch("/user/info?user_id=".concat(t),{method:"GET",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!r.ok)throw Error("Network response was not ok");let l=await r.json();return console.log(l),l}catch(e){throw console.error("Failed to create key:",e),e}};var c=r(384),d=r(6453),h=r(2179),u=r(1801),x=r(6776),m=r(2902),j=r(7171),y=r(9714),Z=r(8707),p=r(1861);let{Option:k}=x.default;var g=e=>{let{userID:t,accessToken:r,data:o,setData:i}=e,[x]=m.Z.useForm(),[k,g]=(0,s.useState)(!1),[f,w]=(0,s.useState)(null),b=()=>{g(!1),x.resetFields()},C=()=>{g(!1),w(null),x.resetFields()},S=async e=>{try{a.ZP.info("Making API Call"),e.models&&""!==e.models.trim()?e.models=e.models.split(",").map(e=>e.trim()):e.models=[],g(!0);let l=await n(r,t,e);i(e=>e?[...e,l]:[l]),w(l.key),a.ZP.success("API Key Created"),x.resetFields()}catch(e){console.error("Error creating the key:",e)}};return(0,l.jsxs)("div",{children:[(0,l.jsx)(h.Z,{className:"mx-auto",onClick:()=>g(!0),children:"+ Create New Key"}),(0,l.jsx)(j.Z,{title:"Create Key",visible:k,width:800,footer:null,onOk:b,onCancel:C,children:(0,l.jsxs)(m.Z,{form:x,onFinish:S,labelCol:{span:6},wrapperCol:{span:16},labelAlign:"left",children:[(0,l.jsx)(m.Z.Item,{label:"Key Name",name:"key_alias",children:(0,l.jsx)(y.Z,{})}),(0,l.jsx)(m.Z.Item,{label:"Models (Comma Separated). Eg: gpt-3.5-turbo,gpt-4",name:"models",children:(0,l.jsx)(y.Z,{placeholder:"gpt-4,gpt-3.5-turbo"})}),(0,l.jsx)(m.Z.Item,{label:"Max Budget (USD)",name:"max_budget",children:(0,l.jsx)(Z.Z,{step:.01,precision:2,width:200})}),(0,l.jsx)(m.Z.Item,{label:"Duration (eg: 30s, 30h, 30d)",name:"duration",children:(0,l.jsx)(y.Z,{})}),(0,l.jsx)(m.Z.Item,{label:"Team ID",name:"team_id",children:(0,l.jsx)(y.Z,{placeholder:"ai_team"})}),(0,l.jsx)(m.Z.Item,{label:"Metadata",name:"metadata",children:(0,l.jsx)(y.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 Key"})})]})}),f&&(0,l.jsx)(j.Z,{title:"Save your key",visible:k,onOk:b,onCancel:C,footer:null,children:(0,l.jsxs)(d.Z,{numItems:1,className:"gap-2 w-full",children:[(0,l.jsx)(c.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)(c.Z,{numColSpan:1,children:null!=f?(0,l.jsxs)(u.Z,{children:["API Key: ",f]}):(0,l.jsx)(u.Z,{children:"Key being created, this might take 30s"})})]})})]})},f=r(3393),w=r(3810),b=r(1244),C=r(827),S=r(3851),I=r(2044),N=r(4167),E=r(4480),v=r(2287),_=r(2440),P=e=>{let{userID:t,accessToken:r,data:s,setData:a}=e,n=async e=>{if(null!=s)try{await o(r,e);let t=s.filter(t=>t.token!==e);a(t)}catch(e){console.error("Error deleting the key:",e)}};if(null!=s)return console.log("RERENDER TRIGGERED"),(0,l.jsxs)(w.Z,{className:"w-full mx-auto flex-auto overflow-y-auto max-h-[50vh] mb-4",children:[(0,l.jsx)(_.Z,{children:"API Keys"}),(0,l.jsxs)(C.Z,{className:"mt-5",children:[(0,l.jsx)(N.Z,{children:(0,l.jsxs)(v.Z,{children:[(0,l.jsx)(E.Z,{children:"Secret Key"}),(0,l.jsx)(E.Z,{children:"Spend (USD)"}),(0,l.jsx)(E.Z,{children:"Key Budget (USD)"}),(0,l.jsx)(E.Z,{children:"Team ID"}),(0,l.jsx)(E.Z,{children:"Metadata"}),(0,l.jsx)(E.Z,{children:"Expires"})]})}),(0,l.jsx)(S.Z,{children:s.map(e=>(console.log(e),(0,l.jsxs)(v.Z,{children:[(0,l.jsx)(I.Z,{children:null!=e.key_alias?(0,l.jsx)(u.Z,{children:e.key_alias}):(0,l.jsx)(u.Z,{children:e.token})}),(0,l.jsx)(I.Z,{children:(0,l.jsx)(u.Z,{children:e.spend})}),(0,l.jsx)(I.Z,{children:null!=e.max_budget?(0,l.jsx)(u.Z,{children:e.max_budget}):(0,l.jsx)(u.Z,{children:"Unlimited Budget"})}),(0,l.jsx)(I.Z,{children:(0,l.jsx)(u.Z,{children:e.team_id})}),(0,l.jsx)(I.Z,{children:(0,l.jsx)(u.Z,{children:JSON.stringify(e.metadata)})}),(0,l.jsx)(I.Z,{children:null!=e.expires?(0,l.jsx)(u.Z,{children:e.expires}):(0,l.jsx)(u.Z,{children:"Never expires"})}),(0,l.jsx)(I.Z,{children:(0,l.jsx)(b.Z,{onClick:()=>n(e.token),icon:f.Z,size:"xs"})})]},e.token)))})]})]})},D=r(7907),T=r(7963),F=()=>{let[e,t]=(0,s.useState)(null),r=(0,D.useSearchParams)(),a=r.get("userID"),n=r.get("token"),[o,h]=(0,s.useState)(null);return((0,s.useEffect)(()=>{if(n){let e=(0,T.o)(n);e&&(console.log("Decoded token:",e),console.log("Decoded key:",e.key),h(e.key))}a&&o&&!e&&(async()=>{try{let e=await i(o,a);t(e.keys)}catch(e){console.error("There was an error fetching the data",e)}})()},[a,n,o,e]),null==a||null==n)?(window.location.href="/sso/key/generate",null):null==o?null:(0,l.jsx)(d.Z,{numItems:1,className:"gap-0 p-10 h-[75vh] w-full",children:(0,l.jsxs)(c.Z,{numColSpan:1,children:[(0,l.jsx)(P,{userID:a,accessToken:o,data:e,setData:t}),(0,l.jsx)(g,{userID:a,accessToken:o,data:e,setData:t})]})})}}},function(e){e.O(0,[448,971,69,744],function(){return e(e.s=8598)}),_N_E=e.O()}]); \ No newline at end of file diff --git a/ui/litellm-dashboard/out/_next/static/chunks/app/page-e5227a95293777d5.js b/ui/litellm-dashboard/out/_next/static/chunks/app/page-e5227a95293777d5.js new file mode 100644 index 00000000000..d5999b73b85 --- /dev/null +++ b/ui/litellm-dashboard/out/_next/static/chunks/app/page-e5227a95293777d5.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[931],{8598:function(e,t,l){Promise.resolve().then(l.t.bind(l,5250,23)),Promise.resolve().then(l.bind(l,3239))},3239:function(e,t,l){"use strict";l.r(t),l.d(t,{default:function(){return F}});var r=l(3827),s=l(4090),a=l(588);let n=async(e,t,l)=>{try{if(console.log("Form Values in keyCreateCall:",l),l.metadata)try{l.metadata=JSON.parse(l.metadata)}catch(e){a.ZP.error("Failed to parse metadata: "+e)}let r=await fetch("/key/generate",{method:"POST",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({user_id:t,...l})});if(!r.ok){let e=await r.text();throw a.ZP.error("Failed to create key: "+e),console.error("Error response from the server:",e),Error("Network response was not ok")}let s=await r.json();return console.log("API Response:",s),s}catch(e){throw console.error("Failed to create key:",e),e}},o=async(e,t)=>{try{console.log("in keyDeleteCall:",t);let l=await fetch("/key/delete",{method:"POST",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"},body:JSON.stringify({keys:[t]})});if(!l.ok){let e=await l.text();throw a.ZP.error("Failed to delete key: "+e),Error("Network response was not ok")}let r=await l.json();return console.log(r),a.ZP.success("API Key Deleted"),r}catch(e){throw console.error("Failed to create key:",e),e}},i=async(e,t)=>{try{let l="/user/info";console.log("in userInfoCall:",l);let r=await fetch("".concat(l,"/?user_id=").concat(t),{method:"GET",headers:{Authorization:"Bearer ".concat(e),"Content-Type":"application/json"}});if(!r.ok){let e=await r.text();throw a.ZP.error(e),Error("Network response was not ok")}let s=await r.json();return console.log(s),s}catch(e){throw console.error("Failed to create key:",e),e}};var c=l(384),d=l(6453),h=l(2179),u=l(1801),x=l(6776),m=l(2902),j=l(7171),y=l(9714),Z=l(8707),p=l(1861);let{Option:k}=x.default;var g=e=>{let{userID:t,accessToken:l,data:o,setData:i}=e,[x]=m.Z.useForm(),[k,g]=(0,s.useState)(!1),[f,w]=(0,s.useState)(null),b=()=>{g(!1),x.resetFields()},C=()=>{g(!1),w(null),x.resetFields()},S=async e=>{try{a.ZP.info("Making API Call"),e.models&&""!==e.models.trim()?e.models=e.models.split(",").map(e=>e.trim()):e.models=[],g(!0);let r=await n(l,t,e);i(e=>e?[...e,r]:[r]),w(r.key),a.ZP.success("API Key Created"),x.resetFields()}catch(e){console.error("Error creating the key:",e)}};return(0,r.jsxs)("div",{children:[(0,r.jsx)(h.Z,{className:"mx-auto",onClick:()=>g(!0),children:"+ Create New Key"}),(0,r.jsx)(j.Z,{title:"Create Key",visible:k,width:800,footer:null,onOk:b,onCancel:C,children:(0,r.jsxs)(m.Z,{form:x,onFinish:S,labelCol:{span:6},wrapperCol:{span:16},labelAlign:"left",children:[(0,r.jsx)(m.Z.Item,{label:"Key Name",name:"key_alias",children:(0,r.jsx)(y.Z,{})}),(0,r.jsx)(m.Z.Item,{label:"Models (Comma Separated). Eg: gpt-3.5-turbo,gpt-4",name:"models",children:(0,r.jsx)(y.Z,{placeholder:"gpt-4,gpt-3.5-turbo"})}),(0,r.jsx)(m.Z.Item,{label:"Max Budget (USD)",name:"max_budget",children:(0,r.jsx)(Z.Z,{step:.01,precision:2,width:200})}),(0,r.jsx)(m.Z.Item,{label:"Duration (eg: 30s, 30h, 30d)",name:"duration",children:(0,r.jsx)(y.Z,{})}),(0,r.jsx)(m.Z.Item,{label:"Team ID",name:"team_id",children:(0,r.jsx)(y.Z,{placeholder:"ai_team"})}),(0,r.jsx)(m.Z.Item,{label:"Metadata",name:"metadata",children:(0,r.jsx)(y.Z.TextArea,{rows:4,placeholder:"Enter metadata as JSON"})}),(0,r.jsx)("div",{style:{textAlign:"right",marginTop:"10px"},children:(0,r.jsx)(p.ZP,{htmlType:"submit",children:"Create Key"})})]})}),f&&(0,r.jsx)(j.Z,{title:"Save your key",visible:k,onOk:b,onCancel:C,footer:null,children:(0,r.jsxs)(d.Z,{numItems:1,className:"gap-2 w-full",children:[(0,r.jsx)(c.Z,{numColSpan:1,children:(0,r.jsxs)("p",{children:["Please save this secret key somewhere safe and accessible. For security reasons, ",(0,r.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,r.jsx)(c.Z,{numColSpan:1,children:null!=f?(0,r.jsxs)(u.Z,{children:["API Key: ",f]}):(0,r.jsx)(u.Z,{children:"Key being created, this might take 30s"})})]})})]})},f=l(3393),w=l(3810),b=l(1244),C=l(827),S=l(3851),I=l(2044),N=l(4167),P=l(4480),E=l(2287),_=l(2440),v=e=>{let{userID:t,accessToken:l,data:s,setData:a}=e,n=async e=>{if(null!=s)try{await o(l,e);let t=s.filter(t=>t.token!==e);a(t)}catch(e){console.error("Error deleting the key:",e)}};if(null!=s)return console.log("RERENDER TRIGGERED"),(0,r.jsxs)(w.Z,{className:"w-full mx-auto flex-auto overflow-y-auto max-h-[50vh] mb-4",children:[(0,r.jsx)(_.Z,{children:"API Keys"}),(0,r.jsxs)(C.Z,{className:"mt-5",children:[(0,r.jsx)(N.Z,{children:(0,r.jsxs)(E.Z,{children:[(0,r.jsx)(P.Z,{children:"Key Alias"}),(0,r.jsx)(P.Z,{children:"Secret Key"}),(0,r.jsx)(P.Z,{children:"Spend (USD)"}),(0,r.jsx)(P.Z,{children:"Key Budget (USD)"}),(0,r.jsx)(P.Z,{children:"Team ID"}),(0,r.jsx)(P.Z,{children:"Metadata"}),(0,r.jsx)(P.Z,{children:"Expires"})]})}),(0,r.jsx)(S.Z,{children:s.map(e=>(console.log(e),"litellm-dashboard"===e.team_id)?null:(0,r.jsxs)(E.Z,{children:[(0,r.jsx)(I.Z,{children:null!=e.key_alias?(0,r.jsx)(u.Z,{children:e.key_alias}):(0,r.jsx)(u.Z,{children:"Not Set"})}),(0,r.jsx)(I.Z,{children:(0,r.jsx)(u.Z,{children:e.key_name})}),(0,r.jsx)(I.Z,{children:(0,r.jsx)(u.Z,{children:e.spend})}),(0,r.jsx)(I.Z,{children:null!=e.max_budget?(0,r.jsx)(u.Z,{children:e.max_budget}):(0,r.jsx)(u.Z,{children:"Unlimited Budget"})}),(0,r.jsx)(I.Z,{children:(0,r.jsx)(u.Z,{children:e.team_id})}),(0,r.jsx)(I.Z,{children:(0,r.jsx)(u.Z,{children:JSON.stringify(e.metadata)})}),(0,r.jsx)(I.Z,{children:null!=e.expires?(0,r.jsx)(u.Z,{children:e.expires}):(0,r.jsx)(u.Z,{children:"Never expires"})}),(0,r.jsx)(I.Z,{children:(0,r.jsx)(b.Z,{onClick:()=>n(e.token),icon:f.Z,size:"xs"})})]},e.token))})]})]})},D=l(7907),T=l(7963),F=()=>{let[e,t]=(0,s.useState)(null),l=(0,D.useSearchParams)(),a=l.get("userID"),n=l.get("token"),[o,h]=(0,s.useState)(null);if((0,s.useEffect)(()=>{if(n){let e=(0,T.o)(n);e&&(console.log("Decoded token:",e),console.log("Decoded key:",e.key),h(e.key))}a&&o&&!e&&(async()=>{try{let e=await i(o,a);t(e.keys)}catch(e){console.error("There was an error fetching the data",e)}})()},[a,n,o,e]),null==a||null==n){let e="/sso/key/generate";return console.log("Full URL:",e),window.location.href=e,null}return null==o?null:(0,r.jsx)(d.Z,{numItems:1,className:"gap-0 p-10 h-[75vh] w-full",children:(0,r.jsxs)(c.Z,{numColSpan:1,children:[(0,r.jsx)(v,{userID:a,accessToken:o,data:e,setData:t}),(0,r.jsx)(g,{userID:a,accessToken:o,data:e,setData:t})]})})}}},function(e){e.O(0,[448,971,69,744],function(){return e(e.s=8598)}),_N_E=e.O()}]); \ No newline at end of file diff --git a/ui/litellm-dashboard/out/index.html b/ui/litellm-dashboard/out/index.html index fe26a9f0ba4..7ad6dd2c0b6 100644 --- a/ui/litellm-dashboard/out/index.html +++ b/ui/litellm-dashboard/out/index.html @@ -1 +1 @@ -Create Next App
Loading...
\ No newline at end of file +Create Next App
Loading...
\ No newline at end of file diff --git a/ui/litellm-dashboard/out/index.txt b/ui/litellm-dashboard/out/index.txt index 1cec7f58a76..d31c7af9252 100644 --- a/ui/litellm-dashboard/out/index.txt +++ b/ui/litellm-dashboard/out/index.txt @@ -1,8 +1,8 @@ 2:"$Sreact.suspense" -3:I[5250,["448","static/chunks/448-cd38799829cf7b57.js","931","static/chunks/app/page-cf0440186224a114.js"],""] -4:I[3239,["448","static/chunks/448-cd38799829cf7b57.js","931","static/chunks/app/page-cf0440186224a114.js"],""] +3:I[5250,["448","static/chunks/448-cd38799829cf7b57.js","931","static/chunks/app/page-e5227a95293777d5.js"],""] +4:I[3239,["448","static/chunks/448-cd38799829cf7b57.js","931","static/chunks/app/page-e5227a95293777d5.js"],""] 5:I[5613,[],""] 6:I[1778,[],""] -0:["9KvKBLd4AqpwRy9Epc-98",[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",{"children":["__PAGE__",{},["$L1",["$","$2",null,{"fallback":["$","div",null,{"children":"Loading..."}],"children":["$","div",null,{"className":"flex min-h-screen flex-col items-center","children":[["$","nav",null,{"className":"left-0 right-0 top-0 flex justify-between items-center h-12","children":[["$","div",null,{"className":"text-left mx-4 my-2 absolute top-0 left-0","children":["$","div",null,{"className":"flex flex-col items-center","children":["$","$L3",null,{"href":"/","children":["$","button",null,{"className":"text-gray-800 text-2xl px-4 py-1 rounded text-center","children":"🚅 LiteLLM"}]}]}]}],["$","div",null,{"className":"text-right mx-4 my-2 absolute top-0 right-0","children":[["$","a",null,{"href":"https://docs.litellm.ai/docs/","target":"_blank","rel":"noopener noreferrer","children":["$","button",null,{"className":"border border-gray-800 rounded-lg text-gray-800 text-xl px-4 py-1 rounded p-1 mr-2 text-center","children":"Docs"}]}],["$","a",null,{"href":"https://calendly.com/d/4mp-gd3-k5k/berriai-1-1-onboarding-litellm-hosted-version","target":"_blank","rel":"noopener noreferrer","children":["$","button",null,{"className":"border border-gray-800 rounded-lg text-gray-800 text-xl px-4 py-1 rounded p-1 text-center","children":"Schedule Demo"}]}]]}]]}],["$","$L4",null,{}]]}]}],null]]},[null,["$","html",null,{"lang":"en","children":["$","body",null,{"className":"__className_c23dc8","children":["$","$L5",null,{"parallelRouterKey":"children","segmentPath":["children"],"loading":"$undefined","loadingStyles":"$undefined","loadingScripts":"$undefined","hasLoading":false,"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L6",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/7384ba6288e79f81.css","precedence":"next","crossOrigin":""}]],"$L7"]]]] +0:["B4oAVsVV35eL3Y1bPepKW",[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",{"children":["__PAGE__",{},["$L1",["$","$2",null,{"fallback":["$","div",null,{"children":"Loading..."}],"children":["$","div",null,{"className":"flex min-h-screen flex-col items-center","children":[["$","nav",null,{"className":"left-0 right-0 top-0 flex justify-between items-center h-12","children":[["$","div",null,{"className":"text-left mx-4 my-2 absolute top-0 left-0","children":["$","div",null,{"className":"flex flex-col items-center","children":["$","$L3",null,{"href":"/","children":["$","button",null,{"className":"text-gray-800 text-2xl px-4 py-1 rounded text-center","children":"🚅 LiteLLM"}]}]}]}],["$","div",null,{"className":"text-right mx-4 my-2 absolute top-0 right-0","children":[["$","a",null,{"href":"https://docs.litellm.ai/docs/","target":"_blank","rel":"noopener noreferrer","children":["$","button",null,{"className":"border border-gray-800 rounded-lg text-gray-800 text-xl px-4 py-1 rounded p-1 mr-2 text-center","children":"Docs"}]}],["$","a",null,{"href":"https://calendly.com/d/4mp-gd3-k5k/berriai-1-1-onboarding-litellm-hosted-version","target":"_blank","rel":"noopener noreferrer","children":["$","button",null,{"className":"border border-gray-800 rounded-lg text-gray-800 text-xl px-4 py-1 rounded p-1 text-center","children":"Schedule Demo"}]}]]}]]}],["$","$L4",null,{}]]}]}],null]]},[null,["$","html",null,{"lang":"en","children":["$","body",null,{"className":"__className_c23dc8","children":["$","$L5",null,{"parallelRouterKey":"children","segmentPath":["children"],"loading":"$undefined","loadingStyles":"$undefined","loadingScripts":"$undefined","hasLoading":false,"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L6",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/7384ba6288e79f81.css","precedence":"next","crossOrigin":""}]],"$L7"]]]] 7:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Create Next App"}],["$","meta","3",{"name":"description","content":"Generated by create next app"}],["$","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 dcc48de380a..6384005c1af 100644 --- a/ui/litellm-dashboard/src/components/networking.tsx +++ b/ui/litellm-dashboard/src/components/networking.tsx @@ -3,10 +3,12 @@ */ import { message } from 'antd'; +const proxyBaseUrl = null + export const keyCreateCall = async ( accessToken: string, userID: string, - formValues: Record // Assuming formValues is an object + formValues: Record, // Assuming formValues is an object ) => { try { console.log("Form Values in keyCreateCall:", formValues); // Log the form values before making the API call @@ -20,8 +22,8 @@ export const keyCreateCall = async ( message.error("Failed to parse metadata: " + error); } } - - const response = await fetch(`/key/generate`, { + const url = proxyBaseUrl ? `${proxyBaseUrl}/key/generate` : `/key/generate`; + const response = await fetch(url, { method: "POST", headers: { Authorization: `Bearer ${accessToken}`, @@ -56,7 +58,10 @@ export const keyDeleteCall = async ( user_key: String ) => { try { - const response = await fetch(`/key/delete`, { + const url = proxyBaseUrl ? `${proxyBaseUrl}/key/delete` : `/key/delete`; + console.log("in keyDeleteCall:", user_key) + + const response = await fetch(url, { method: "POST", headers: { Authorization: `Bearer ${accessToken}`, @@ -68,11 +73,14 @@ export const keyDeleteCall = async ( }); if (!response.ok) { + const errorData = await response.text(); + message.error("Failed to delete key: " + errorData); throw new Error("Network response was not ok"); } const data = await response.json(); console.log(data); + message.success("API Key Deleted"); return data; // Handle success - you might want to update some state or UI based on the created key } catch (error) { @@ -86,8 +94,10 @@ export const userInfoCall = async ( userID: String ) => { try { + const url = proxyBaseUrl ? `${proxyBaseUrl}/user/info` : `/user/info`; + console.log("in userInfoCall:", url) const response = await fetch( - `/user/info?user_id=${userID}`, + `${url}/?user_id=${userID}`, { method: "GET", headers: { @@ -98,6 +108,8 @@ export const userInfoCall = async ( ); if (!response.ok) { + const errorData = await response.text(); + message.error(errorData); throw new Error("Network response was not ok"); } diff --git a/ui/litellm-dashboard/src/components/user_dashboard.tsx b/ui/litellm-dashboard/src/components/user_dashboard.tsx index dccbd21dbfd..4a0a72e189d 100644 --- a/ui/litellm-dashboard/src/components/user_dashboard.tsx +++ b/ui/litellm-dashboard/src/components/user_dashboard.tsx @@ -8,6 +8,8 @@ import EnterProxyUrl from "./enter_proxy_url"; import { useSearchParams } from "next/navigation"; import { jwtDecode } from "jwt-decode"; +const proxyBaseUrl = null + const UserDashboard = () => { const [data, setData] = useState(null); // Keep the initialization of state here // Assuming useSearchParams() hook exists and works in your setup @@ -53,8 +55,8 @@ const UserDashboard = () => { // Now you can construct the full URL - const url = `/sso/key/generate`; - + const url = proxyBaseUrl ? `${proxyBaseUrl}/sso/key/generate` : `/sso/key/generate`; + console.log("Full URL:", url); window.location.href = url; return null; diff --git a/ui/litellm-dashboard/src/components/view_key_table.tsx b/ui/litellm-dashboard/src/components/view_key_table.tsx index bcfa8a23e6f..e7e2cc967b4 100644 --- a/ui/litellm-dashboard/src/components/view_key_table.tsx +++ b/ui/litellm-dashboard/src/components/view_key_table.tsx @@ -67,6 +67,10 @@ const ViewKeyTable: React.FC = ({ {data.map((item) => { console.log(item); + // skip item if item.team_id == "litellm-dashboard" + if (item.team_id === "litellm-dashboard") { + return null; + } return (