import { BarChart, BarList, Card, Title, Table, TableHead, TableHeaderCell, TableRow, TableCell, TableBody, Metric } from "@tremor/react"; import React, { useState, useEffect } from "react"; import ViewUserSpend from "./view_user_spend"; import { Grid, Col, Text, LineChart, TabPanel, TabPanels, TabGroup, TabList, Tab, Select, SelectItem, DateRangePicker, DateRangePickerValue } from "@tremor/react"; import { userSpendLogsCall, keyInfoCall, adminSpendLogsCall, adminTopKeysCall, adminTopModelsCall, adminTopEndUsersCall, teamSpendLogsCall, tagsSpendLogsCall, modelMetricsCall, modelAvailableCall, modelInfoCall, } from "./networking"; import { start } from "repl"; interface UsagePageProps { accessToken: string | null; token: string | null; userRole: string | null; userID: string | null; keys: any[] | null; } type CustomTooltipTypeBar = { payload: any; active: boolean | undefined; label: any; }; const customTooltip = (props: CustomTooltipTypeBar) => { const { payload, active } = props; if (!active || !payload) return null; const value = payload[0].payload; const date = value["startTime"]; const model_values = value["models"]; // Convert the object into an array of key-value pairs const entries: [string, number][] = Object.entries(model_values).map( ([key, value]) => [key, value as number] ); // Type assertion to specify the value as number // Sort the array based on the float value in descending order entries.sort((a, b) => b[1] - a[1]); // Get the top 5 key-value pairs const topEntries = entries.slice(0, 5); return (
{date} {topEntries.map(([key, value]) => (

{key} {":"} {" "} {value ? (value < 0.01 ? "<$0.01" : value.toFixed(2)) : ""}

))}
); }; function getTopKeys(data: Array<{ [key: string]: unknown }>): any[] { const spendKeys: { key: string; spend: unknown }[] = []; data.forEach((dict) => { Object.entries(dict).forEach(([key, value]) => { if ( key !== "spend" && key !== "startTime" && key !== "models" && key !== "users" ) { spendKeys.push({ key, spend: value }); } }); }); spendKeys.sort((a, b) => Number(b.spend) - Number(a.spend)); const topKeys = spendKeys.slice(0, 5).map((k) => k.key); console.log(`topKeys: ${Object.keys(topKeys[0])}`); return topKeys; } type DataDict = { [key: string]: unknown }; type UserData = { user_id: string; spend: number }; const UsagePage: React.FC = ({ accessToken, token, userRole, userID, keys, }) => { const currentDate = new Date(); const [keySpendData, setKeySpendData] = useState([]); const [topKeys, setTopKeys] = useState([]); const [topModels, setTopModels] = useState([]); const [topUsers, setTopUsers] = useState([]); const [teamSpendData, setTeamSpendData] = useState([]); const [topTagsData, setTopTagsData] = useState([]); const [uniqueTeamIds, setUniqueTeamIds] = useState([]); const [totalSpendPerTeam, setTotalSpendPerTeam] = useState([]); const [selectedKeyID, setSelectedKeyID] = useState(""); const [dateValue, setDateValue] = useState({ from: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), to: new Date(), }); const firstDay = new Date( currentDate.getFullYear(), currentDate.getMonth(), 1 ); const lastDay = new Date( currentDate.getFullYear(), currentDate.getMonth() + 1, 0 ); let startTime = formatDate(firstDay); let endTime = formatDate(lastDay); console.log("keys in usage", keys); const updateEndUserData = async (startTime: Date | undefined, endTime: Date | undefined, uiSelectedKey: string | null) => { if (!startTime || !endTime || !accessToken) { return; } console.log("uiSelectedKey", uiSelectedKey); let newTopUserData = await adminTopEndUsersCall( accessToken, uiSelectedKey, startTime.toISOString(), endTime.toISOString() ) console.log("End user data updated successfully", newTopUserData); setTopUsers(newTopUserData); } const updateTagSpendData = async (startTime: Date | undefined, endTime: Date | undefined) => { if (!startTime || !endTime || !accessToken) { return; } let top_tags = await tagsSpendLogsCall(accessToken, startTime.toISOString(), endTime.toISOString()); setTopTagsData(top_tags.spend_per_tag); console.log("Tag spend data updated successfully"); } function formatDate(date: Date) { const year = date.getFullYear(); let month = date.getMonth() + 1; // JS month index starts from 0 let day = date.getDate(); // Pad with 0 if month or day is less than 10 const monthStr = month < 10 ? "0" + month : month; const dayStr = day < 10 ? "0" + day : day; return `${year}-${monthStr}-${dayStr}`; } console.log(`Start date is ${startTime}`); console.log(`End date is ${endTime}`); const valueFormatter = (number: number) => `$ ${new Intl.NumberFormat("us").format(number).toString()}`; useEffect(() => { if (accessToken && token && userRole && userID) { const fetchData = async () => { try { /** * If user is Admin - query the global views endpoints * If user is App Owner - use the normal spend logs call */ console.log(`user role: ${userRole}`); if (userRole == "Admin" || userRole == "Admin Viewer") { const overall_spend = await adminSpendLogsCall(accessToken); setKeySpendData(overall_spend); const top_keys = await adminTopKeysCall(accessToken); const filtered_keys = top_keys.map((k: any) => ({ key: (k["key_name"] || k["key_alias"] || k["api_key"]).substring( 0, 10 ), spend: k["total_spend"], })); setTopKeys(filtered_keys); const top_models = await adminTopModelsCall(accessToken); const filtered_models = top_models.map((k: any) => ({ key: k["model"], spend: k["total_spend"], })); setTopModels(filtered_models); const teamSpend = await teamSpendLogsCall(accessToken); console.log("teamSpend", teamSpend); setTeamSpendData(teamSpend.daily_spend); setUniqueTeamIds(teamSpend.teams) let total_spend_per_team = teamSpend.total_spend_per_team; // in total_spend_per_team, replace null team_id with "" and replace null total_spend with 0 total_spend_per_team = total_spend_per_team.map((tspt: any) => { tspt["name"] = tspt["team_id"] || ""; tspt["value"] = tspt["total_spend"] || 0; return tspt; }) setTotalSpendPerTeam(total_spend_per_team); //get top tags const top_tags = await tagsSpendLogsCall(accessToken, dateValue.from?.toISOString(), dateValue.to?.toISOString()); setTopTagsData(top_tags.spend_per_tag); // get spend per end-user let spend_user_call = await adminTopEndUsersCall(accessToken, null, undefined, undefined); setTopUsers(spend_user_call); console.log("spend/user result", spend_user_call); } else if (userRole == "App Owner") { await userSpendLogsCall( accessToken, token, userRole, userID, startTime, endTime ).then(async (response) => { console.log("result from spend logs call", response); if ("daily_spend" in response) { // this is from clickhouse analytics // let daily_spend = response["daily_spend"]; console.log("daily spend", daily_spend); setKeySpendData(daily_spend); let topApiKeys = response.top_api_keys; setTopKeys(topApiKeys); } else { const topKeysResponse = await keyInfoCall( accessToken, getTopKeys(response) ); const filtered_keys = topKeysResponse["info"].map((k: any) => ({ key: ( k["key_name"] || k["key_alias"] ).substring(0, 10), spend: k["spend"], })); setTopKeys(filtered_keys); setKeySpendData(response); } }); } } catch (error) { console.error("There was an error fetching the data", error); // Optionally, update your UI to reflect the error state here as well } }; fetchData(); } }, [accessToken, token, userRole, userID, startTime, endTime]); return (
All Up Team Based Usage End User Usage Tag Based Usage Monthly Spend Top API Keys Top Models Total Spend Per Team Daily Spend Per Team

End-Users of your LLM API calls. Tracked when a `user` param is passed in your LLM calls docs here

Select Time Range { setDateValue(value); updateEndUserData(value.from, value.to, null); // Call updateModelMetrics with the new date range }} /> Select Key End User Spend Total Events {topUsers?.map((user: any, index: number) => ( {user.end_user} {user.total_spend?.toFixed(4)} {user.total_count} ))}
{ setDateValue(value); updateTagSpendData(value.from, value.to); // Call updateModelMetrics with the new date range }} /> Spend Per Tag Get Started Tracking cost per tag here
); }; export default UsagePage;