diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py
index 4927f3db4ca..3faadfe5122 100644
--- a/litellm/proxy/proxy_server.py
+++ b/litellm/proxy/proxy_server.py
@@ -691,6 +691,7 @@ async def user_api_key_auth(
"/key",
"/spend",
"/user",
+ "/model/info",
]
# check if the current route startswith any of the allowed routes
if (
@@ -3953,7 +3954,6 @@ async def add_new_model(model_params: ModelParams):
)
-#### [BETA] - This is a beta endpoint, format might change based on user feedback https://github.com/BerriAI/litellm/issues/933. If you need a stable endpoint use /model/info
@router.get(
"/model/info",
description="Provides more info about each model in /models, including config.yaml descriptions (except api key and api base)",
@@ -3986,6 +3986,14 @@ async def model_info_v1(
# read litellm model_prices_and_context_window.json to get the following:
# input_cost_per_token, output_cost_per_token, max_tokens
litellm_model_info = get_litellm_model_info(model=model)
+ if litellm_model_info == {}:
+ # use litellm_param model_name to get model_info
+ litellm_params = model.get("litellm_params", {})
+ litellm_model = litellm_params.get("model", None)
+ try:
+ litellm_model_info = litellm.get_model_info(model=litellm_model)
+ except:
+ litellm_model_info = {}
for k, v in litellm_model_info.items():
if k not in model_info:
model_info[k] = v
diff --git a/ui/litellm-dashboard/src/app/page.tsx b/ui/litellm-dashboard/src/app/page.tsx
index 80a3b6940ab..02e72b57971 100644
--- a/ui/litellm-dashboard/src/app/page.tsx
+++ b/ui/litellm-dashboard/src/app/page.tsx
@@ -3,6 +3,7 @@ import React, { Suspense, useEffect, useState } from "react";
import { useSearchParams } from "next/navigation";
import Navbar from "../components/navbar";
import UserDashboard from "../components/user_dashboard";
+import ModelDashboard from "@/components/model_dashboard";
import Sidebar from "../components/leftnav";
import Usage from "../components/usage";
import { jwtDecode } from "jwt-decode";
@@ -80,7 +81,15 @@ const CreateKeyPage = () => {
userEmail={userEmail}
setUserEmail={setUserEmail}
/>
- ) : (
+ ) : page == "models" ? (
+
+ )
+ : (
= ({ setPage }) => {
setPage("api-keys")}>
API Keys
- setPage("usage")}>
+ setPage("models")}>
+ Models
+
+ setPage("usage")}>
Usage
diff --git a/ui/litellm-dashboard/src/components/model_dashboard.tsx b/ui/litellm-dashboard/src/components/model_dashboard.tsx
new file mode 100644
index 00000000000..a454399f09b
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/model_dashboard.tsx
@@ -0,0 +1,122 @@
+import React, { useState, useEffect } from "react";
+import { Card, Title, Subtitle, Table, TableHead, TableRow, TableCell, TableBody, Metric, Grid } from "@tremor/react";
+import { modelInfoCall } from "./networking";
+
+interface ModelDashboardProps {
+ accessToken: string;
+ token: string | null;
+ userRole: string | null;
+ userID: string | null;
+}
+
+const ModelDashboard: React.FC = ({
+ accessToken,
+ token,
+ userRole,
+ userID,
+}) => {
+ const [modelData, setModelData] = useState({ data: [] });
+
+ useEffect(() => {
+ const fetchData = async () => {
+ try {
+ // Replace with your actual API call for model data
+ const modelDataResponse = await modelInfoCall(accessToken, userID, userRole);
+ console.log("Model data response:", modelDataResponse.data);
+ setModelData(modelDataResponse);
+ } catch (error) {
+ console.error("There was an error fetching the model data", error);
+ }
+ };
+
+ if (accessToken && token && userRole && userID) {
+ fetchData();
+ }
+ }, [accessToken, token, userRole, userID]);
+
+ if (!modelData) {
+ return Loading...
;
+ }
+
+ // loop through model data and edit each row
+ for (let i = 0; i < modelData.data.length; i++) {
+ let curr_model = modelData.data[i];
+ let litellm_model_name = curr_model?.litellm_params?.model;
+
+ let model_info = curr_model?.model_info;
+
+ let defaultProvider = "openai";
+ let provider = "";
+ let input_cost = "Undefined"
+ let output_cost = "Undefined"
+ let max_tokens = "Undefined"
+
+ // Check if litellm_model_name is null or undefined
+ if (litellm_model_name) {
+ // Split litellm_model_name based on "/"
+ let splitModel = litellm_model_name.split("/");
+
+ // Get the first element in the split
+ let firstElement = splitModel[0];
+
+ // If there is only one element, default provider to openai
+ provider = splitModel.length === 1 ? defaultProvider : firstElement;
+
+ console.log("Provider:", provider);
+ } else {
+ // litellm_model_name is null or undefined, default provider to openai
+ provider = defaultProvider;
+ console.log("Provider:", provider);
+ }
+
+ if (model_info) {
+ input_cost = model_info?.input_cost_per_token;
+ output_cost = model_info?.output_cost_per_token;
+ max_tokens = model_info?.max_tokens;
+
+ }
+ modelData.data[i].provider = provider
+ modelData.data[i].input_cost = input_cost
+ modelData.data[i].output_cost = output_cost
+ modelData.data[i].max_tokens = max_tokens
+
+ }
+
+
+ return (
+
+
+
+ Available Models
+
+
+
+ Model Name
+ Provider
+ Input Price per token ($)
+ Output Price per token ($)
+ Max Tokens
+
+
+
+ {modelData.data.map((model: any) => (
+
+
+ {model.model_name}
+ {model.provider}
+ {model.input_cost}
+ {model.output_cost}
+ {model.max_tokens}
+
+
+
+ ))}
+
+
+
+
+
+ );
+};
+
+export default ModelDashboard;
diff --git a/ui/litellm-dashboard/src/components/networking.tsx b/ui/litellm-dashboard/src/components/networking.tsx
index 4521ca44661..7905ed7dbcd 100644
--- a/ui/litellm-dashboard/src/components/networking.tsx
+++ b/ui/litellm-dashboard/src/components/networking.tsx
@@ -137,6 +137,41 @@ export const userInfoCall = async (
}
};
+
+
+export const modelInfoCall = async (
+ accessToken: String,
+ userID: String,
+ userRole: String
+) => {
+ try {
+ let url = proxyBaseUrl ? `${proxyBaseUrl}/model/info` : `/model/info`;
+
+ message.info("Requesting model data");
+ 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();
+ message.info("Received model 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;
+ }
+};
+
export const keySpendLogsCall = async (accessToken: String, token: String) => {
try {
const url = proxyBaseUrl ? `${proxyBaseUrl}/spend/logs` : `/spend/logs`;