fix: enable end user tracking on ui

This commit is contained in:
Krrish Dholakia 2024-02-29 16:30:12 -08:00
parent c371009faf
commit 7f2e12cd10
4 changed files with 130 additions and 25 deletions

View file

@ -4113,6 +4113,28 @@ async def global_spend_keys(
return response return response
@router.get(
"/global/spend/end_users",
tags=["Budget & Spend Tracking"],
dependencies=[Depends(user_api_key_auth)],
)
async def global_spend_end_users():
"""
[BETA] This is a beta endpoint. It will change.
Use this to get the top 'n' keys with the highest spend, ordered by spend.
"""
global prisma_client
if prisma_client is None:
raise HTTPException(status_code=500, detail={"error": "No db connected"})
sql_query = f"""SELECT * FROM "Last30dTopEndUsersSpend";"""
response = await prisma_client.db.query_raw(query=sql_query)
return response
@router.get( @router.get(
"/global/spend/models", "/global/spend/models",
tags=["Budget & Spend Tracking"], tags=["Budget & Spend Tracking"],

View file

@ -593,6 +593,26 @@ class PrismaClient:
print("Last30dModelsBySpend Created!") # noqa print("Last30dModelsBySpend Created!") # noqa
try:
await self.db.query_raw(
"""SELECT 1 FROM "Last30dTopEndUsersSpend" LIMIT 1"""
)
print("Last30dTopEndUsersSpend Exists!") # noqa
except Exception as e:
sql_query = """
CREATE VIEW "Last30dTopEndUsersSpend" AS
SELECT end_user, SUM(spend) AS total_spend
FROM "LiteLLM_SpendLogs"
WHERE end_user <> '' AND end_user <> user
AND "startTime" >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY end_user
ORDER BY total_spend DESC
LIMIT 100;
"""
await self.db.execute_raw(query=sql_query)
print("Last30dTopEndUsersSpend Created!") # noqa
return return
@backoff.on_exception( @backoff.on_exception(

View file

@ -404,13 +404,13 @@ export const adminTopKeysCall = async (accessToken: String) => {
} }
}; };
export const adminTopModelsCall = async (accessToken: String) => { export const adminTopEndUsersCall = async (accessToken: String) => {
try { try {
let url = proxyBaseUrl let url = proxyBaseUrl
? `${proxyBaseUrl}/global/spend/models?limit=5` ? `${proxyBaseUrl}/global/spend/end_users`
: `/global/spend/models?limit=5`; : `/global/spend/end_users`;
message.info("Making spend models request"); message.info("Making top end users request");
const response = await fetch(url, { const response = await fetch(url, {
method: "GET", method: "GET",
headers: { headers: {
@ -426,7 +426,37 @@ export const adminTopModelsCall = async (accessToken: String) => {
const data = await response.json(); const data = await response.json();
console.log(data); console.log(data);
message.success("Spend Logs received"); message.success("Top End users received");
return data;
} catch (error) {
console.error("Failed to create key:", error);
throw error;
}
};
export const adminTopModelsCall = async (accessToken: String) => {
try {
let url = proxyBaseUrl
? `${proxyBaseUrl}/global/spend/models?limit=5`
: `/global/spend/models?limit=5`;
message.info("Making top models request");
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();
console.log(data);
message.success("Top Models received");
return data; return data;
} catch (error) { } catch (error) {
console.error("Failed to create key:", error); console.error("Failed to create key:", error);

View file

@ -8,6 +8,9 @@ import {
TableRow, TableRow,
TableCell, TableCell,
TableBody, TableBody,
Tab,
TabGroup,
TabList,
Metric, Metric,
Grid, Grid,
} from "@tremor/react"; } from "@tremor/react";
@ -29,8 +32,9 @@ const ViewUserDashboard: React.FC<ViewUserDashboardProps> = ({
userRole, userRole,
userID, userID,
}) => { }) => {
const [userData, setuserData] = useState<null | any[]>(null); const [userData, setUserData] = useState<null | any[]>(null);
const [pendingRequests, setPendingRequests] = useState<any[]>([]); const [currentPage, setCurrentPage] = useState(1);
const defaultPageSize = 25;
useEffect(() => { useEffect(() => {
if (!accessToken || !token || !userRole || !userID) { if (!accessToken || !token || !userRole || !userID) {
@ -46,7 +50,7 @@ const ViewUserDashboard: React.FC<ViewUserDashboardProps> = ({
true true
); );
console.log("user data response:", userDataResponse); console.log("user data response:", userDataResponse);
setuserData(userDataResponse); setUserData(userDataResponse);
} catch (error) { } catch (error) {
console.error("There was an error fetching the model data", error); console.error("There was an error fetching the model data", error);
} }
@ -65,11 +69,49 @@ const ViewUserDashboard: React.FC<ViewUserDashboardProps> = ({
return <div>Loading...</div>; return <div>Loading...</div>;
} }
function renderPagination() {
if (!userData) return null;
const totalPages = Math.ceil(userData.length / defaultPageSize);
const startItem = (currentPage - 1) * defaultPageSize + 1;
const endItem = Math.min(currentPage * defaultPageSize, userData.length);
return (
<div className="flex justify-between items-center">
<div>
Showing {startItem} {endItem} of {userData.length}
</div>
<div className="flex">
<button
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-l focus:outline-none"
disabled={currentPage === 1}
onClick={() => setCurrentPage(currentPage - 1)}
>
&larr; Prev
</button>
<button
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-r focus:outline-none"
disabled={currentPage === totalPages}
onClick={() => setCurrentPage(currentPage + 1)}
>
Next &rarr;
</button>
</div>
</div>
);
}
return ( return (
<div style={{ width: "100%" }}> <div style={{ width: "100%" }}>
<Grid className="gap-2 p-10 h-[75vh] w-full"> <Grid className="gap-2 p-10 h-[75vh] w-full">
<CreateUser userID={userID} accessToken={accessToken} /> <CreateUser userID={userID} accessToken={accessToken} />
<Card> <Card>
<TabGroup>
<TabList variant="line" defaultValue="1">
<Tab value="1">Key Owners</Tab>
<Tab value="2">End-Users</Tab>
</TabList>
</TabGroup>
<Table className="mt-5"> <Table className="mt-5">
<TableHead> <TableHead>
<TableRow> <TableRow>
@ -93,34 +135,25 @@ const ViewUserDashboard: React.FC<ViewUserDashboardProps> = ({
<TableBody> <TableBody>
{userData.map((user: any) => ( {userData.map((user: any) => (
<TableRow key={user.user_id}> <TableRow key={user.user_id}>
<TableCell>{user.user_id}</TableCell>
<TableCell> <TableCell>
<Title>{user.user_id}</Title> {user.user_role ? user.user_role : "app_owner"}
</TableCell> </TableCell>
<TableCell> <TableCell>
<Title> {user.models && user.models.length > 0
{user.user_role ? user.user_role : "app_user"} ? user.models
</Title> : "All Models"}
</TableCell> </TableCell>
<TableCell>{user.spend ? user.spend : 0}</TableCell>
<TableCell> <TableCell>
<Title> {user.max_budget ? user.max_budget : "Unlimited"}
{user.models && user.models.length > 0
? user.models
: "All Models"}
</Title>
</TableCell>
<TableCell>
<Title>{user.spend ? user.spend : 0}</Title>
</TableCell>
<TableCell>
<Title>
{user.max_budget ? user.max_budget : "Unlimited"}
</Title>
</TableCell> </TableCell>
</TableRow> </TableRow>
))} ))}
</TableBody> </TableBody>
</Table> </Table>
</Card> </Card>
{renderPagination()}
</Grid> </Grid>
</div> </div>
); );