Merge pull request #1949 from BerriAI/litellm_show_model_info_ui

[FEAT] ADMIN UI - Show Model Info
This commit is contained in:
Ishaan Jaff 2024-02-12 16:16:49 -08:00 committed by GitHub
commit 22917fe52a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 180 additions and 3 deletions

View file

@ -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

View file

@ -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" ? (
<ModelDashboard
userID={userID}
userRole={userRole}
token={token}
accessToken={accessToken}
/>
)
: (
<Usage
userID={userID}
userRole={userRole}

View file

@ -20,7 +20,10 @@ const Sidebar: React.FC<SidebarProps> = ({ setPage }) => {
<Menu.Item key="1" onClick={() => setPage("api-keys")}>
API Keys
</Menu.Item>
<Menu.Item key="2" onClick={() => setPage("usage")}>
<Menu.Item key="2" onClick={() => setPage("models")}>
Models
</Menu.Item>
<Menu.Item key="3" onClick={() => setPage("usage")}>
Usage
</Menu.Item>
</Menu>

View file

@ -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<ModelDashboardProps> = ({
accessToken,
token,
userRole,
userID,
}) => {
const [modelData, setModelData] = useState<any>({ 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 <div>Loading...</div>;
}
// 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 (
<div style={{ width: "100%" }}>
<Grid className="gap-2 p-10 h-[75vh] w-full">
<Card>
<Title>Available Models</Title>
<Table className="mt-5">
<TableHead>
<TableRow>
<TableCell>Model Name</TableCell>
<TableCell>Provider</TableCell>
<TableCell>Input Price per token ($)</TableCell>
<TableCell>Output Price per token ($)</TableCell>
<TableCell>Max Tokens</TableCell>
</TableRow>
</TableHead>
<TableBody>
{modelData.data.map((model: any) => (
<TableRow key={model.model_name}>
<TableCell><p>{model.model_name}</p></TableCell>
<TableCell>{model.provider}</TableCell>
<TableCell>{model.input_cost}</TableCell>
<TableCell>{model.output_cost}</TableCell>
<TableCell>{model.max_tokens}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</Card>
</Grid>
</div>
);
};
export default ModelDashboard;

View file

@ -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`;