diff --git a/litellm/proxy/proxy_cli.py b/litellm/proxy/proxy_cli.py
index 584ad98c1..6583dbed1 100644
--- a/litellm/proxy/proxy_cli.py
+++ b/litellm/proxy/proxy_cli.py
@@ -190,17 +190,27 @@ def run_server(
global feature_telemetry
args = locals()
if local:
- from proxy_server import app, save_worker_config, usage_telemetry
+ from proxy_server import app, save_worker_config, usage_telemetry, ProxyConfig
else:
try:
- from .proxy_server import app, save_worker_config, usage_telemetry
+ from .proxy_server import (
+ app,
+ save_worker_config,
+ usage_telemetry,
+ ProxyConfig,
+ )
except ImportError as e:
if "litellm[proxy]" in str(e):
# user is missing a proxy dependency, ask them to pip install litellm[proxy]
raise e
else:
# this is just a local/relative import error, user git cloned litellm
- from proxy_server import app, save_worker_config, usage_telemetry
+ from proxy_server import (
+ app,
+ save_worker_config,
+ usage_telemetry,
+ ProxyConfig,
+ )
feature_telemetry = usage_telemetry
if version == True:
pkg_version = importlib.metadata.version("litellm")
@@ -373,16 +383,16 @@ def run_server(
read from there and save it to os.env['DATABASE_URL']
"""
try:
- import yaml
+ import yaml, asyncio
except:
raise ImportError(
"yaml needs to be imported. Run - `pip install 'litellm[proxy]'`"
)
- if os.path.exists(config):
- with open(config, "r") as config_file:
- config = yaml.safe_load(config_file)
- general_settings = config.get("general_settings", {})
+ proxy_config = ProxyConfig()
+ _, _, general_settings = asyncio.run(
+ proxy_config.load_config(router=None, config_file_path=config)
+ )
database_url = general_settings.get("database_url", None)
if database_url and database_url.startswith("os.environ/"):
original_dir = os.getcwd()
diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py
index 4a854ec76..0a17b8ecd 100644
--- a/litellm/proxy/proxy_server.py
+++ b/litellm/proxy/proxy_server.py
@@ -515,11 +515,15 @@ async def user_api_key_auth(
)
if (
- (route.startswith("/key/") or route.startswith("/user/"))
- or route.startswith("/model/")
- and not is_master_key_valid
- and general_settings.get("allow_user_auth", False) != True
+ (
+ route.startswith("/key/")
+ or route.startswith("/user/")
+ or route.startswith("/model/")
+ )
+ and (not is_master_key_valid)
+ and (not general_settings.get("allow_user_auth", False))
):
+ assert not general_settings.get("allow_user_auth", False)
if route == "/key/info":
# check if user can access this route
query_params = request.query_params
@@ -546,7 +550,7 @@ async def user_api_key_auth(
pass
else:
raise Exception(
- f"If master key is set, only master key can be used to generate, delete, update or get info for new keys/users"
+ f"only master key can be used to generate, delete, update or get info for new keys/users."
)
return UserAPIKeyAuth(api_key=api_key, **valid_token_dict)
diff --git a/litellm/utils.py b/litellm/utils.py
index ed86f2fae..bbc4e651c 100644
--- a/litellm/utils.py
+++ b/litellm/utils.py
@@ -2190,7 +2190,6 @@ def client(original_function):
result = original_function(*args, **kwargs)
end_time = datetime.datetime.now()
if "stream" in kwargs and kwargs["stream"] == True:
- # TODO: Add to cache for streaming
if (
"complete_response" in kwargs
and kwargs["complete_response"] == True
diff --git a/ui/litellm-dashboard/src/app/page.tsx b/ui/litellm-dashboard/src/app/page.tsx
index ac8ce4ad5..ad5f35227 100644
--- a/ui/litellm-dashboard/src/app/page.tsx
+++ b/ui/litellm-dashboard/src/app/page.tsx
@@ -1,22 +1,13 @@
-import React from 'react';
-import CreateKey from "../components/create_key_button"
-import ViewKeyTable from "../components/view_key_table"
-import Navbar from "../components/navbar"
-import { Grid, Col } from "@tremor/react";
-
+import React from "react";
+import Navbar from "../components/navbar";
+import UserDashboard from "../components/user_dashboard";
const CreateKeyPage = () => {
-
return (
-
-
-
-
-
-
-
-
+
+
+
);
};
-export default CreateKeyPage;
\ No newline at end of file
+export default CreateKeyPage;
diff --git a/ui/litellm-dashboard/src/components/create_key_button.tsx b/ui/litellm-dashboard/src/components/create_key_button.tsx
index 2dfc6b1d8..f785b0b80 100644
--- a/ui/litellm-dashboard/src/components/create_key_button.tsx
+++ b/ui/litellm-dashboard/src/components/create_key_button.tsx
@@ -1,21 +1,40 @@
-'use client';
+"use client";
-import React from 'react';
-import { Button, TextInput } from '@tremor/react';
+import React, { use } from "react";
+import { Button, TextInput } from "@tremor/react";
import { Card, Metric, Text } from "@tremor/react";
+import { createKeyCall } from "./networking";
+// Define the props type
+interface CreateKeyProps {
+ userID: string;
+ accessToken: string;
+ proxyBaseUrl: string;
+}
-export default function CreateKey() {
+const CreateKey: React.FC = ({
+ userID,
+ accessToken,
+ proxyBaseUrl,
+}) => {
const handleClick = () => {
- console.log('Hello World');
+ console.log("Hello World");
};
return (
- //
- // Key Name
- //
-
- //
-
+
);
-}
\ No newline at end of file
+};
+
+export default CreateKey;
diff --git a/ui/litellm-dashboard/src/components/networking.tsx b/ui/litellm-dashboard/src/components/networking.tsx
new file mode 100644
index 000000000..a8534b662
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/networking.tsx
@@ -0,0 +1,65 @@
+/**
+ * Helper file for calls being made to proxy
+ */
+
+export const createKeyCall = async (
+ proxyBaseUrl: String,
+ accessToken: String,
+ userID: String
+) => {
+ try {
+ const response = await fetch(`${proxyBaseUrl}/key/generate`, {
+ method: "POST",
+ headers: {
+ Authorization: `Bearer ${accessToken}`,
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ team_id: "core-infra-4",
+ max_budget: 10,
+ user_id: userID,
+ }),
+ });
+
+ if (!response.ok) {
+ throw new Error("Network response was not ok");
+ }
+
+ const data = await response.json();
+ console.log(data);
+ // Handle success - you might want to update some state or UI based on the created key
+ } catch (error) {
+ console.error("Failed to create key:", error);
+ }
+};
+
+export const userInfoCall = async (
+ proxyBaseUrl: String,
+ accessToken: String,
+ userID: String
+) => {
+ try {
+ const response = await fetch(
+ `${proxyBaseUrl}/user/info?user_id=${userID}`,
+ {
+ method: "GET",
+ headers: {
+ Authorization: `Bearer ${accessToken}`,
+ "Content-Type": "application/json",
+ },
+ }
+ );
+
+ if (!response.ok) {
+ throw new Error("Network response was not ok");
+ }
+
+ const data = await response.json();
+ console.log(data);
+ return data;
+ // Handle success - you might want to update some state or UI based on the created key
+ } catch (error) {
+ console.error("Failed to create key:", error);
+ throw error;
+ }
+};
diff --git a/ui/litellm-dashboard/src/components/user_dashboard.tsx b/ui/litellm-dashboard/src/components/user_dashboard.tsx
new file mode 100644
index 000000000..c7acd3640
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/user_dashboard.tsx
@@ -0,0 +1,42 @@
+"use client";
+import React from "react";
+import { Grid, Col, Card, Text } from "@tremor/react";
+import CreateKey from "./create_key_button";
+import ViewKeyTable from "./view_key_table";
+import { useSearchParams } from "next/navigation";
+
+export default function UserDashboard() {
+ const searchParams = useSearchParams();
+ const userID = searchParams.get("userID");
+ const accessToken = searchParams.get("accessToken");
+ const proxyBaseUrl = searchParams.get("proxyBaseUrl");
+
+ if (userID == null || accessToken == null || proxyBaseUrl == null) {
+ return (
+
+ Login to create/delete keys
+
+ );
+ }
+
+ return (
+
+
+
+
+
+
+ );
+}
diff --git a/ui/litellm-dashboard/src/components/view_key_table.tsx b/ui/litellm-dashboard/src/components/view_key_table.tsx
index ecf5a4329..50ef6a534 100644
--- a/ui/litellm-dashboard/src/components/view_key_table.tsx
+++ b/ui/litellm-dashboard/src/components/view_key_table.tsx
@@ -1,4 +1,6 @@
-'use client';
+"use client";
+import React, { useEffect, useState } from "react";
+import { userInfoCall } from "./networking";
import { StatusOnlineIcon } from "@heroicons/react/outline";
import {
Badge,
@@ -13,69 +15,105 @@ import {
Title,
} from "@tremor/react";
+// Define the props type
+interface ViewKeyTableProps {
+ userID: string;
+ accessToken: string;
+ proxyBaseUrl: string;
+}
+
const data = [
{
key_alias: "my test key",
key_name: "sk-...hd74",
spend: 23.0,
expires: "active",
- token: "23902dwojd90"
+ token: "23902dwojd90",
},
{
key_alias: "my test key",
key_name: "sk-...hd74",
spend: 23.0,
expires: "active",
- token: "23902dwojd90"
+ token: "23902dwojd90",
},
{
key_alias: "my test key",
key_name: "sk-...hd74",
spend: 23.0,
expires: "active",
- token: "23902dwojd90"
+ token: "23902dwojd90",
},
{
key_alias: "my test key",
key_name: "sk-...hd74",
spend: 23.0,
expires: "active",
- token: "23902dwojd90"
+ token: "23902dwojd90",
},
];
-export default function ViewKeyTable() {
-
- return (
-
- API Keys
-
-
-
- Alias
- Secret Key
- Spend
- Status
-
-
-
- {data.map((item) => (
-
- {item.key_alias}
-
- {item.key_name}
-
-
- {item.spend}
-
-
-
- {item.expires}
-
-
+const ViewKeyTable: React.FC = ({
+ userID,
+ accessToken,
+ proxyBaseUrl,
+}) => {
+ const [data, setData] = useState(null); // State to store the data from the API
+
+ useEffect(() => {
+ const fetchData = async () => {
+ try {
+ const response = await userInfoCall(
+ (proxyBaseUrl = proxyBaseUrl),
+ (accessToken = accessToken),
+ (userID = userID)
+ );
+ setData(response["keys"]); // Update state with the fetched data
+ } catch (error) {
+ console.error("There was an error fetching the data", error);
+ // Optionally, update your UI to reflect the error state
+ }
+ };
+
+ fetchData(); // Call the async function to fetch data
+ }, []); // Empty dependency array
+
+ if (data == null) {
+ return;
+ }
+ return (
+
+ API Keys
+
+
+
+ Alias
+ Secret Key
+ Spend
+ Status
- ))}
-
-
-
-)};
\ No newline at end of file
+
+
+ {data.map((item) => (
+
+ {item.key_alias}
+
+ {item.key_name}
+
+
+ {item.spend}
+
+
+
+ {item.expires}
+
+
+
+ ))}
+
+