Merge branch 'main' into litellm_custom_pricing_ui_fix

This commit is contained in:
Krish Dholakia 2024-05-27 18:35:47 -07:00 committed by GitHub
commit dec482031b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 638 additions and 859 deletions

View file

@ -86,6 +86,8 @@ import type { UploadProps } from "antd";
import { Upload } from "antd";
import TimeToFirstToken from "./model_metrics/time_to_first_token";
import DynamicFields from "./model_add/dynamic_form";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
interface ModelDashboardProps {
accessToken: string | null;
token: string | null;
@ -269,6 +271,8 @@ const ModelDashboard: React.FC<ModelDashboardProps> = ({
const [selectedProvider, setSelectedProvider] = useState<String>("OpenAI");
const [healthCheckResponse, setHealthCheckResponse] = useState<string>("");
const [editModalVisible, setEditModalVisible] = useState<boolean>(false);
const [infoModalVisible, setInfoModalVisible] = useState<boolean>(false);
const [selectedModel, setSelectedModel] = useState<any>(null);
const [availableModelGroups, setAvailableModelGroups] = useState<
Array<string>
@ -297,6 +301,15 @@ const ModelDashboard: React.FC<ModelDashboardProps> = ({
useState<RetryPolicyObject | null>(null);
const [defaultRetry, setDefaultRetry] = useState<number>(0);
function formatCreatedAt(createdAt: string | null) {
if (createdAt) {
const date = new Date(createdAt);
const options = { month: 'long', day: 'numeric', year: 'numeric' };
return date.toLocaleDateString('en-US');
}
return null;
}
const EditModelModal: React.FC<EditModelModalProps> = ({
visible,
onCancel,
@ -423,11 +436,21 @@ const ModelDashboard: React.FC<ModelDashboardProps> = ({
setEditModalVisible(true);
};
const handleInfoClick = (model: any) => {
setSelectedModel(model);
setInfoModalVisible(true);
};
const handleEditCancel = () => {
setEditModalVisible(false);
setSelectedModel(null);
};
const handleInfoCancel = () => {
setInfoModalVisible(false);
setSelectedModel(null);
};
const handleEditSubmit = async (formValues: Record<string, any>) => {
// Call API to update team with teamId and values
@ -1039,7 +1062,6 @@ const ModelDashboard: React.FC<ModelDashboardProps> = ({
</div>
<Card>
<Table
className="mt-5"
style={{ maxWidth: "1500px", width: "100%" }}
>
<TableHead>
@ -1049,6 +1071,7 @@ const ModelDashboard: React.FC<ModelDashboardProps> = ({
maxWidth: "150px",
whiteSpace: "normal",
wordBreak: "break-word",
fontSize: "11px"
}}
>
Public Model Name
@ -1058,6 +1081,7 @@ const ModelDashboard: React.FC<ModelDashboardProps> = ({
maxWidth: "100px",
whiteSpace: "normal",
wordBreak: "break-word",
fontSize: "11px"
}}
>
Provider
@ -1068,25 +1092,18 @@ const ModelDashboard: React.FC<ModelDashboardProps> = ({
maxWidth: "150px",
whiteSpace: "normal",
wordBreak: "break-word",
fontSize: "11px"
}}
>
API Base
</TableHeaderCell>
)}
<TableHeaderCell
style={{
maxWidth: "200px",
whiteSpace: "normal",
wordBreak: "break-word",
}}
>
Extra litellm Params
</TableHeaderCell>
<TableHeaderCell
style={{
maxWidth: "85px",
whiteSpace: "normal",
wordBreak: "break-word",
fontSize: "11px"
}}
>
Input Price{" "}
@ -1099,6 +1116,7 @@ const ModelDashboard: React.FC<ModelDashboardProps> = ({
maxWidth: "85px",
whiteSpace: "normal",
wordBreak: "break-word",
fontSize: "11px"
}}
>
Output Price{" "}
@ -1106,24 +1124,45 @@ const ModelDashboard: React.FC<ModelDashboardProps> = ({
/1M Tokens ($)
</p>
</TableHeaderCell>
<TableHeaderCell
style={{
maxWidth: "120px",
maxWidth: "100px",
whiteSpace: "normal",
wordBreak: "break-word",
fontSize: "11px"
}}
>
Max Tokens
{
premiumUser ? "Created At" : <a href="https://forms.gle/W3U4PZpJGFHWtHyA9" target="_blank" style={{color: "#72bcd4" }}> Created At</a>
}
</TableHeaderCell>
<TableHeaderCell
style={{
maxWidth: "100px",
whiteSpace: "normal",
wordBreak: "break-word",
fontSize: "11px"
}}
>
{
premiumUser ? "Created By" : <a href="https://forms.gle/W3U4PZpJGFHWtHyA9" target="_blank" style={{color: "#72bcd4" }}> Created By</a>
}
</TableHeaderCell>
<TableHeaderCell
style={{
maxWidth: "50px",
whiteSpace: "normal",
wordBreak: "break-word",
fontSize: "11px"
}}
>
Status
</TableHeaderCell>
<TableHeaderCell>
</TableHeaderCell>
</TableRow>
</TableHead>
<TableBody>
@ -1137,15 +1176,17 @@ const ModelDashboard: React.FC<ModelDashboardProps> = ({
selectedModelGroup === ""
)
.map((model: any, index: number) => (
<TableRow key={index}>
<TableRow key={index} style={{ maxHeight: "1px", minHeight: "1px" }}>
<TableCell
style={{
maxWidth: "150px",
maxWidth: "100px",
whiteSpace: "normal",
wordBreak: "break-word",
}}
>
<Text>{model.model_name}</Text>
<p style={{ fontSize: "10px" }}>
{model.model_name || "-"}
</p>
</TableCell>
<TableCell
style={{
@ -1154,41 +1195,34 @@ const ModelDashboard: React.FC<ModelDashboardProps> = ({
wordBreak: "break-word",
}}
>
{model.provider}
<p style={{ fontSize: "10px" }}>
{model.provider || "-"}
</p>
</TableCell>
{userRole === "Admin" && (
<TableCell
style={{
maxWidth: "150px",
whiteSpace: "normal",
wordBreak: "break-word",
}}
>
{model.api_base}
</TableCell>
)}
<TableCell
style={{
maxWidth: "200px",
maxWidth: "150px",
whiteSpace: "normal",
wordBreak: "break-word",
}}
>
<Accordion>
<AccordionHeader>
<Text>Litellm params</Text>
</AccordionHeader>
<AccordionBody>
<pre>
{JSON.stringify(
model.cleanedLitellmParams,
null,
2
)}
</pre>
</AccordionBody>
</Accordion>
<Tooltip title={model && model.api_base}>
<pre
style={{
maxWidth: "150px",
whiteSpace: "normal",
wordBreak: "break-word",
fontSize: "10px",
}}
title={model && model.api_base ? model.api_base : ""}
>
{model && model.api_base ? model.api_base.slice(0, 20) : "-"}
</pre>
</Tooltip>
</TableCell>
)}
<TableCell
style={{
maxWidth: "80px",
@ -1196,6 +1230,7 @@ const ModelDashboard: React.FC<ModelDashboardProps> = ({
wordBreak: "break-word",
}}
>
<pre style={{ fontSize: "10px" }}>
{model.input_cost
? model.input_cost
: model.litellm_params.input_cost_per_token
@ -1205,6 +1240,7 @@ const ModelDashboard: React.FC<ModelDashboardProps> = ({
) * 1000000
).toFixed(2)
: null}
</pre>
</TableCell>
<TableCell
style={{
@ -1213,6 +1249,7 @@ const ModelDashboard: React.FC<ModelDashboardProps> = ({
wordBreak: "break-word",
}}
>
<pre style={{ fontSize: "10px" }}>
{model.output_cost
? model.output_cost
: model.litellm_params.output_cost_per_token
@ -1222,17 +1259,21 @@ const ModelDashboard: React.FC<ModelDashboardProps> = ({
) * 1000000
).toFixed(2)
: null}
</pre>
</TableCell>
<TableCell
style={{
maxWidth: "120px",
whiteSpace: "normal",
wordBreak: "break-word",
}}
>
<p style={{ fontSize: "10px" }}>
Max Tokens: {model.max_tokens} <br></br>
Max Input Tokens: {model.max_input_tokens}
<TableCell>
<p style={{ fontSize: "10px" }}>
{
premiumUser ? formatCreatedAt(model.model_info.created_at) || "-" : "-"
}
</p>
</TableCell>
<TableCell>
<p style={{ fontSize: "10px" }}>
{
premiumUser ? model.model_info.created_by || "-" : "-"
}
</p>
</TableCell>
<TableCell
@ -1248,7 +1289,7 @@ const ModelDashboard: React.FC<ModelDashboardProps> = ({
size="xs"
className="text-white"
>
<p style={{ fontSize: "10px" }}>DB Model</p>
<p style={{ fontSize: "8px" }}>DB Model</p>
</Badge>
) : (
<Badge
@ -1256,26 +1297,42 @@ const ModelDashboard: React.FC<ModelDashboardProps> = ({
size="xs"
className="text-black"
>
<p style={{ fontSize: "10px" }}>Config Model</p>
<p style={{ fontSize: "8px" }}>Config Model</p>
</Badge>
)}
</TableCell>
<TableCell
style={{
maxWidth: "100px",
maxWidth: "150px",
whiteSpace: "normal",
wordBreak: "break-word",
}}
>
<Grid numItems={3}>
<Col>
<Icon
icon={InformationCircleIcon}
size="sm"
onClick={() => handleInfoClick(model)}
/>
</Col>
<Col>
<Icon
icon={PencilAltIcon}
size="sm"
onClick={() => handleEditClick(model)}
/>
</Col>
<Col>
<DeleteModelButton
modelID={model.model_info.id}
accessToken={accessToken}
/>
</Col>
</Grid>
</TableCell>
</TableRow>
))}
@ -1289,6 +1346,20 @@ const ModelDashboard: React.FC<ModelDashboardProps> = ({
model={selectedModel}
onSubmit={handleEditSubmit}
/>
<Modal
title={selectedModel && selectedModel.model_name}
visible={infoModalVisible}
width={800}
footer={null}
onCancel={handleInfoCancel}
>
<Title>Model Info</Title>
<SyntaxHighlighter language="json" >
{selectedModel && JSON.stringify(selectedModel, null, 2)}
</SyntaxHighlighter>
</Modal>
</TabPanel>
<TabPanel className="h-full">
<Title2 level={2}>Add new model</Title2>

View file

@ -1,20 +1,26 @@
import React, { useEffect, useState } from 'react';
import React, { useEffect, useState } from "react";
import { modelHubCall } from "./networking";
import { Card, Text, Title, Grid, Button, Badge, Tab,
TabGroup,
TabList,
TabPanel,
TabPanels, } from "@tremor/react";
import {
Card,
Text,
Title,
Grid,
Button,
Badge,
Tab,
TabGroup,
TabList,
TabPanel,
TabPanels,
} from "@tremor/react";
import { RightOutlined, CopyOutlined } from '@ant-design/icons';
import { RightOutlined, CopyOutlined } from "@ant-design/icons";
import { Modal, Tooltip } from 'antd';
import { Modal, Tooltip } from "antd";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
interface ModelHubProps {
userID: string | null;
userRole: string | null;
@ -22,7 +28,6 @@ interface ModelHubProps {
accessToken: string | null;
keys: any; // Replace with the appropriate type for 'keys' prop
premiumUser: boolean;
}
interface ModelInfo {
@ -32,15 +37,13 @@ interface ModelInfo {
supports_vision: boolean;
max_input_tokens?: number;
max_output_tokens?: number;
// Add other properties if needed
}
supported_openai_params?: string[];
// Add other properties if needed
}
const ModelHub: React.FC<ModelHubProps> = ({
userID,
userRole,
@ -52,140 +55,80 @@ const ModelHub: React.FC<ModelHubProps> = ({
keys,
premiumUser,
}) => {
const [modelHubData, setModelHubData] = useState<ModelInfo[] | null>(null);
const [modelHubData, setModelHubData] = useState<ModelInfo[] | null>(null);
const [isModalVisible, setIsModalVisible] = useState(false);
const [selectedModel, setSelectedModel] = useState<null | ModelInfo>(null);
const [selectedModel, setSelectedModel] = useState<null | ModelInfo>(null);
useEffect(() => {
if (!accessToken || !token || !userRole || !userID) {
return;
}
const fetchData = async () => {
try {
const _modelHubData = await modelHubCall(accessToken, userID, userRole);
console.log("ModelHubData:", _modelHubData);
setModelHubData(_modelHubData.data);
} catch (error) {
console.error("There was an error fetching the model data", error);
}
};
fetchData();
}, [accessToken, token, userRole, userID]);
const showModal = (model: ModelInfo) => {
setSelectedModel(model);
setIsModalVisible(true);
};
const handleOk = () => {
setIsModalVisible(false);
setSelectedModel(null);
};
const handleCancel = () => {
setIsModalVisible(false);
setSelectedModel(null);
};
const copyToClipboard = (text: string) => {
navigator.clipboard.writeText(text);
};
return (
<div>
<div className="w-full m-2 mt-2 p-8">
<div className="relative w-full"></div>
<div className="w-full m-2 mt-2 p-8">
<div className="relative w-full">
</div>
<div className='flex items-center'>
<Title className='ml-8 text-center '>Model Hub</Title>
<Button className='ml-4'>
<a href="https://forms.gle/W3U4PZpJGFHWtHyA9" target="_blank">
Share
</a>
</Button>
<div className="flex items-center">
<Title className="ml-8 text-center ">Model Hub</Title>
<Button className="ml-4">
<a href="https://forms.gle/W3U4PZpJGFHWtHyA9" target="_blank">
Make Public
</a>
</Button>
</div>
<div className="grid grid-cols-2 gap-6 sm:grid-cols-3 lg:grid-cols-4">
{modelHubData && modelHubData.map((model: ModelInfo) => (
<Card
key={model.model_group}
className="mt-5 mx-8"
>
<pre className='flex justify-between'>
<Title>{model.model_group}</Title>
<Tooltip title={model.model_group}>
<CopyOutlined onClick={() => copyToClipboard(model.model_group)} style={{ cursor: 'pointer', marginRight: '10px' }} />
</Tooltip>
</pre>
{modelHubData &&
modelHubData.map((model: ModelInfo) => (
<Card key={model.model_group} className="mt-5 mx-8">
<pre className="flex justify-between">
<Title>{model.model_group}</Title>
<Tooltip title={model.model_group}>
<CopyOutlined
onClick={() => copyToClipboard(model.model_group)}
style={{ cursor: "pointer", marginRight: "10px" }}
/>
</Tooltip>
</pre>
<div className='my-5'>
<Text>Mode: {model.mode}</Text>
@ -193,52 +136,37 @@ const ModelHub: React.FC<ModelHubProps> = ({
<Text>Supports Vision: {model?.supports_vision == true ? "Yes" : "No"}</Text>
<Text>Max Input Tokens: {model?.max_input_tokens ? model?.max_input_tokens : "N/A"}</Text>
<Text>Max Output Tokens: {model?.max_output_tokens ? model?.max_output_tokens : "N/A"}</Text>
</div>
<div style={{ marginTop: 'auto', textAlign: 'right' }}>
<a href="#" onClick={() => showModal(model)} style={{ color: '#1890ff', fontSize: 'smaller' }}>
View more <RightOutlined />
</a>
</div>
</Card>
))}
<div style={{ marginTop: "auto", textAlign: "right" }}>
<a
href="#"
onClick={() => showModal(model)}
style={{ color: "#1890ff", fontSize: "smaller" }}
>
View more <RightOutlined />
</a>
</div>
</Card>
))}
</div>
</div>
<Modal
title="Model Usage"
title={selectedModel && selectedModel.model_group ? selectedModel.model_group : "Unknown Model"}
width={800}
visible={isModalVisible}
footer={null}
onOk={handleOk}
onCancel={handleCancel}
>
{selectedModel && (
<div>
<p><strong>Model Name:</strong> {selectedModel.model_group}</p>
<p className='mb-4'><strong>Model Information & Usage</strong></p>
<TabGroup>
<TabList>
<Tab>OpenAI Python SDK</Tab>
<Tab>Supported OpenAI Params</Tab>
<Tab>LlamaIndex</Tab>
<Tab>Langchain Py</Tab>
</TabList>
@ -267,8 +195,13 @@ print(response)
</SyntaxHighlighter>
</TabPanel>
<TabPanel>
<SyntaxHighlighter language="python">
{`
<SyntaxHighlighter language="python">
{`${selectedModel.supported_openai_params?.map((param) => `${param}\n`).join('')}`}
</SyntaxHighlighter>
</TabPanel>
<TabPanel>
<SyntaxHighlighter language="python">
{`
import os, dotenv
from llama_index.llms import AzureOpenAI
@ -300,11 +233,11 @@ response = query_engine.query("What did the author do growing up?")
print(response)
`}
</SyntaxHighlighter>
</TabPanel>
<TabPanel>
<SyntaxHighlighter language="python">
{`
</SyntaxHighlighter>
</TabPanel>
<TabPanel>
<SyntaxHighlighter language="python">
{`
from langchain.chat_models import ChatOpenAI
from langchain.prompts.chat import (
ChatPromptTemplate,
@ -332,27 +265,19 @@ response = chat(messages)
print(response)
`}
</SyntaxHighlighter>
</TabPanel>
</TabPanels>
</TabGroup>
</SyntaxHighlighter>
</TabPanel>
</TabPanels>
</TabGroup>
{/* <p><strong>Additional Params:</strong> {JSON.stringify(selectedModel.litellm_params)}</p> */}
{/* Add other model details here */}
</div>
)}
</Modal>
</div>
);
};
export default ModelHub;
export default ModelHub;

View file

@ -1,6 +1,10 @@
"use client";
import React, { useState, useEffect } from "react";
import { userInfoCall, modelAvailableCall, getTotalSpendCall } from "./networking";
import {
userInfoCall,
modelAvailableCall,
getTotalSpendCall,
} from "./networking";
import { Grid, Col, Card, Text, Title } from "@tremor/react";
import CreateKey from "./create_key_button";
import ViewKeyTable from "./view_key_table";
@ -19,7 +23,6 @@ type UserSpendData = {
max_budget?: number | null;
};
interface UserDashboardProps {
userID: string | null;
userRole: string | null;
@ -35,8 +38,8 @@ interface UserDashboardProps {
type TeamInterface = {
models: any[];
team_id: null;
team_alias: String
}
team_alias: String;
};
const UserDashboard: React.FC<UserDashboardProps> = ({
userID,
@ -63,10 +66,10 @@ const UserDashboard: React.FC<UserDashboardProps> = ({
const [teamSpend, setTeamSpend] = useState<number | null>(null);
const [userModels, setUserModels] = useState<string[]>([]);
const defaultTeam: TeamInterface = {
"models": [],
"team_alias": "Default Team",
"team_id": null
}
models: [],
team_alias: "Default Team",
team_id: null,
};
const [selectedTeam, setSelectedTeam] = useState<any | null>(
teams ? teams[0] : defaultTeam
);
@ -137,7 +140,14 @@ const UserDashboard: React.FC<UserDashboardProps> = ({
} else {
const fetchData = async () => {
try {
const response = await userInfoCall(accessToken, userID, userRole, false, null, null);
const response = await userInfoCall(
accessToken,
userID,
userRole,
false,
null,
null
);
console.log(
`received teams in user dashboard: ${Object.keys(
response
@ -152,12 +162,12 @@ const UserDashboard: React.FC<UserDashboardProps> = ({
}
setKeys(response["keys"]); // Assuming this is the correct path to your data
setTeams(response["teams"]);
const teamsArray = [...response['teams']];
const teamsArray = [...response["teams"]];
if (teamsArray.length > 0) {
console.log(`response['teams']: ${teamsArray}`);
setSelectedTeam(teamsArray[0]);
console.log(`response['teams']: ${teamsArray}`);
setSelectedTeam(teamsArray[0]);
} else {
setSelectedTeam(defaultTeam);
setSelectedTeam(defaultTeam);
}
sessionStorage.setItem(
"userData" + userID,
@ -194,22 +204,30 @@ const UserDashboard: React.FC<UserDashboardProps> = ({
fetchData();
}
}
}, [userID, token, accessToken, keys, userRole]);
useEffect(() => {
// This code will run every time selectedTeam changes
if (keys !== null && selectedTeam !== null && selectedTeam !== undefined) {
if (
keys !== null &&
selectedTeam !== null &&
selectedTeam !== undefined &&
selectedTeam.team_id !== null
) {
let sum = 0;
for (const key of keys) {
if (selectedTeam.hasOwnProperty('team_id') && key.team_id !== null && key.team_id === selectedTeam.team_id) {
if (
selectedTeam.hasOwnProperty("team_id") &&
key.team_id !== null &&
key.team_id === selectedTeam.team_id
) {
sum += key.spend;
}
}
setTeamSpend(sum);
} else if (keys !== null) {
// sum the keys which don't have team-id set (default team)
let sum = 0
let sum = 0;
for (const key of keys) {
sum += key.spend;
}
@ -245,9 +263,8 @@ const UserDashboard: React.FC<UserDashboardProps> = ({
}
console.log("inside user dashboard, selected team", selectedTeam);
console.log(`teamSpend: ${teamSpend}`)
return (
<div className="w-full mx-4">
<div className="w-full mx-4">
<Grid numItems={1} className="gap-2 p-8 h-[75vh] w-full mt-2">
<Col numColSpan={1}>
<ViewUserTeam
@ -261,8 +278,7 @@ const UserDashboard: React.FC<UserDashboardProps> = ({
userRole={userRole}
accessToken={accessToken}
userSpend={teamSpend}
selectedTeam = {selectedTeam ? selectedTeam : null}
selectedTeam={selectedTeam ? selectedTeam : null}
/>
<ViewKeyTable
@ -283,11 +299,15 @@ const UserDashboard: React.FC<UserDashboardProps> = ({
data={keys}
setData={setKeys}
/>
<DashboardTeam teams={teams} setSelectedTeam={setSelectedTeam} userRole={userRole}/>
<DashboardTeam
teams={teams}
setSelectedTeam={setSelectedTeam}
userRole={userRole}
/>
</Col>
</Grid>
</div>
);
};
export default UserDashboard;
export default UserDashboard;