import { BarChart, BarList, Card, Title, Table, TableHead, TableHeaderCell, TableRow, TableCell, TableBody, Metric, Subtitle } from "@tremor/react"; import React, { useState, useEffect } from "react"; import ViewUserSpend from "./view_user_spend"; import { ProxySettings } from "./user_dashboard"; import { Grid, Col, Text, LineChart, TabPanel, TabPanels, TabGroup, TabList, Tab, Select, SelectItem, DateRangePicker, DateRangePickerValue, DonutChart, AreaChart, Callout, Button, MultiSelect, MultiSelectItem, } from "@tremor/react"; import { Select as Select2 } from "antd"; import { userSpendLogsCall, keyInfoCall, adminSpendLogsCall, adminTopKeysCall, adminTopModelsCall, adminTopEndUsersCall, teamSpendLogsCall, tagsSpendLogsCall, allTagNamesCall, modelMetricsCall, modelAvailableCall, adminspendByProvider, adminGlobalActivity, adminGlobalActivityPerModel, getProxyUISettings } from "./networking"; import { start } from "repl"; console.log("process.env.NODE_ENV", process.env.NODE_ENV); const isLocal = process.env.NODE_ENV === "development"; const proxyBaseUrl = isLocal ? "http://localhost:4000" : null; if (isLocal !== true) { console.log = function() {}; } interface UsagePageProps { accessToken: string | null; token: string | null; userRole: string | null; userID: string | null; keys: any[] | null; premiumUser: boolean; } interface GlobalActivityData { sum_api_requests: number; sum_total_tokens: number; daily_data: { date: string; api_requests: number; total_tokens: number }[]; } 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"]; const entries: [string, number][] = Object.entries(model_values).map( ([key, value]) => [key, value as number] ); entries.sort((a, b) => b[1] - a[1]); const topEntries = entries.slice(0, 5); return (
{date} {topEntries.map(([key, value]) => (

{key} {":"} {" "} {value ? `$${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 isAdminOrAdminViewer = (role: string | null): boolean => { if (role === null) return false; return role === 'Admin' || role === 'Admin Viewer'; }; const UsagePage: React.FC = ({ accessToken, token, userRole, userID, keys, premiumUser, }) => { 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 [allTagNames, setAllTagNames] = useState([]); const [uniqueTeamIds, setUniqueTeamIds] = useState([]); const [totalSpendPerTeam, setTotalSpendPerTeam] = useState([]); const [spendByProvider, setSpendByProvider] = useState([]); const [globalActivity, setGlobalActivity] = useState({} as GlobalActivityData); const [globalActivityPerModel, setGlobalActivityPerModel] = useState([]); const [selectedKeyID, setSelectedKeyID] = useState(""); const [selectedTags, setSelectedTags] = useState(["all-tags"]); const [dateValue, setDateValue] = useState({ from: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), to: new Date(), }); const [proxySettings, setProxySettings] = useState(null); const [totalMonthlySpend, setTotalMonthlySpend] = useState(0); 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); console.log("premium user in usage", premiumUser); function valueFormatterNumbers(number: number) { const formatter = new Intl.NumberFormat('en-US', { maximumFractionDigits: 0, notation: 'compact', compactDisplay: 'short', }); return formatter.format(number); } const fetchProxySettings = async () => { if (accessToken) { try { const proxy_settings: ProxySettings = await getProxyUISettings(accessToken); console.log("usage tab: proxy_settings", proxy_settings); return proxy_settings; } catch (error) { console.error("Error fetching proxy settings:", error); } } }; useEffect(() => { updateTagSpendData(dateValue.from, dateValue.to); }, [dateValue, selectedTags]); const updateEndUserData = async (startTime: Date | undefined, endTime: Date | undefined, uiSelectedKey: string | null) => { if (!startTime || !endTime || !accessToken) { return; } // the endTime put it to the last hour of the selected date endTime.setHours(23, 59, 59, 999); // startTime put it to the first hour of the selected date startTime.setHours(0, 0, 0, 0); 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; } // we refetch because the state variable can be None when the user refreshes the page const proxy_settings: ProxySettings | undefined = await fetchProxySettings(); if (proxy_settings?.DISABLE_EXPENSIVE_DB_QUERIES) { return; // Don't run expensive DB queries - return out when SpendLogs has more than 1M rows } // the endTime put it to the last hour of the selected date endTime.setHours(23, 59, 59, 999); // startTime put it to the first hour of the selected date startTime.setHours(0, 0, 0, 0); let top_tags = await tagsSpendLogsCall( accessToken, startTime.toISOString(), endTime.toISOString(), selectedTags.length === 0 ? undefined : selectedTags ); 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) => `$ ${number.toFixed(2)}`; const fetchAndSetData = async ( fetchFunction: () => Promise, setStateFunction: React.Dispatch>, errorMessage: string ) => { try { const data = await fetchFunction(); setStateFunction(data); } catch (error) { console.error(errorMessage, error); // Optionally, update UI to reflect error state for this specific data } }; // Update the fillMissingDates function to handle different date formats const fillMissingDates = (data: any[], startDate: Date, endDate: Date, categories: string[]) => { const filledData = []; const currentDate = new Date(startDate); // Helper function to standardize date format const standardizeDate = (dateStr: string) => { if (dateStr.includes('-')) { // Already in YYYY-MM-DD format return dateStr; } else { // Convert "Jan 06" format const [month, day] = dateStr.split(' '); const year = new Date().getFullYear(); const monthIndex = new Date(`${month} 01 2024`).getMonth(); const fullDate = new Date(year, monthIndex, parseInt(day)); return fullDate.toISOString().split('T')[0]; } }; // Create a map of existing dates for quick lookup const existingDates = new Map( data.map(item => { const standardizedDate = standardizeDate(item.date); return [standardizedDate, { ...item, date: standardizedDate // Store standardized date format }]; }) ); // Iterate through each date in the range while (currentDate <= endDate) { const dateStr = currentDate.toISOString().split('T')[0]; if (existingDates.has(dateStr)) { // Use existing data if we have it filledData.push(existingDates.get(dateStr)); } else { // Create an entry with zero values const emptyEntry: any = { date: dateStr, api_requests: 0, total_tokens: 0 }; // Add zero values for each model/team if needed categories.forEach(category => { if (!emptyEntry[category]) { emptyEntry[category] = 0; } }); filledData.push(emptyEntry); } // Move to next day currentDate.setDate(currentDate.getDate() + 1); } return filledData; }; // Update the fetchOverallSpend function const fetchOverallSpend = async () => { if (!accessToken) { return; } try { const data = await adminSpendLogsCall(accessToken); // Get the first and last day of the current month const now = new Date(); const firstDay = new Date(now.getFullYear(), now.getMonth(), 1); const lastDay = new Date(now.getFullYear(), now.getMonth() + 1, 0); // Fill in missing dates const filledData = fillMissingDates(data, firstDay, lastDay, []); // Calculate total spend for the month and round to 2 decimal places const monthlyTotal = Number(filledData.reduce((sum, day) => sum + (day.spend || 0), 0).toFixed(2)); setTotalMonthlySpend(monthlyTotal); setKeySpendData(filledData); } catch (error) { console.error("Error fetching overall spend:", error); } }; const fetchProviderSpend = () => fetchAndSetData( () => accessToken && token ? adminspendByProvider(accessToken, token, startTime, endTime) : Promise.reject("No access token or token"), setSpendByProvider, "Error fetching provider spend" ); const fetchTopKeys = async () => { if (!accessToken) return; await fetchAndSetData( async () => { const top_keys = await adminTopKeysCall(accessToken); return top_keys.map((k: any) => ({ key: (k["key_alias"] || k["key_name"] || k["api_key"]).substring(0, 10), spend: Number(k["total_spend"].toFixed(2)), })); }, setTopKeys, "Error fetching top keys" ); }; const fetchTopModels = async () => { if (!accessToken) return; await fetchAndSetData( async () => { const top_models = await adminTopModelsCall(accessToken); return top_models.map((k: any) => ({ key: k["model"], spend: Number(k["total_spend"].toFixed(2)), })); }, setTopModels, "Error fetching top models" ); }; // Update the fetchTeamSpend function const fetchTeamSpend = async () => { if (!accessToken) return; await fetchAndSetData( async () => { const teamSpend = await teamSpendLogsCall(accessToken); // Get the first and last day of the current month const now = new Date(); const firstDay = new Date(now.getFullYear(), now.getMonth(), 1); const lastDay = new Date(now.getFullYear(), now.getMonth() + 1, 0); // Fill in missing dates with zero values for all teams const filledData = fillMissingDates( teamSpend.daily_spend, firstDay, lastDay, teamSpend.teams ); setTeamSpendData(filledData); setUniqueTeamIds(teamSpend.teams); return teamSpend.total_spend_per_team.map((tspt: any) => ({ name: tspt["team_id"] || "", value: Number(tspt["total_spend"] || 0).toFixed(2), })); }, setTotalSpendPerTeam, "Error fetching team spend" ); }; const fetchTagNames = () => { if (!accessToken) return; fetchAndSetData( async () => { const all_tag_names = await allTagNamesCall(accessToken); return all_tag_names.tag_names; }, setAllTagNames, "Error fetching tag names" ); }; const fetchTopTags = () => { if (!accessToken) return; fetchAndSetData( () => tagsSpendLogsCall(accessToken, dateValue.from?.toISOString(), dateValue.to?.toISOString(), undefined), (data) => setTopTagsData(data.spend_per_tag), "Error fetching top tags" ); }; const fetchTopEndUsers = () => { if (!accessToken) return; fetchAndSetData( () => adminTopEndUsersCall(accessToken, null, undefined, undefined), setTopUsers, "Error fetching top end users" ); }; // Update the fetchGlobalActivity function const fetchGlobalActivity = async () => { if (!accessToken) return; try { const data = await adminGlobalActivity(accessToken, startTime, endTime); // Get the date range from the current month const now = new Date(); const firstDay = new Date(now.getFullYear(), now.getMonth(), 1); const lastDay = new Date(now.getFullYear(), now.getMonth() + 1, 0); // Fill in missing dates for daily_data const filledDailyData = fillMissingDates( data.daily_data || [], firstDay, lastDay, ['api_requests', 'total_tokens'] ); setGlobalActivity({ ...data, daily_data: filledDailyData }); } catch (error) { console.error("Error fetching global activity:", error); } }; // Update the fetchGlobalActivityPerModel function const fetchGlobalActivityPerModel = async () => { if (!accessToken) return; try { const data = await adminGlobalActivityPerModel(accessToken, startTime, endTime); // Get the date range from the current month const now = new Date(); const firstDay = new Date(now.getFullYear(), now.getMonth(), 1); const lastDay = new Date(now.getFullYear(), now.getMonth() + 1, 0); // Fill in missing dates for each model's daily data const filledModelData = data.map((modelData: any) => ({ ...modelData, daily_data: fillMissingDates( modelData.daily_data || [], firstDay, lastDay, ['api_requests', 'total_tokens'] ) })); setGlobalActivityPerModel(filledModelData); } catch (error) { console.error("Error fetching global activity per model:", error); } }; useEffect(() => { const initlizeUsageData = async () => { if (accessToken && token && userRole && userID) { const proxy_settings: ProxySettings | undefined = await fetchProxySettings(); if (proxy_settings) { setProxySettings(proxy_settings); // saved in state so it can be used when rendering UI if (proxy_settings?.DISABLE_EXPENSIVE_DB_QUERIES) { return; // Don't run expensive UI queries - return out of initlizeUsageData at this point } } console.log("fetching data - valiue of proxySettings", proxySettings); fetchOverallSpend(); fetchProviderSpend(); fetchTopKeys(); fetchTopModels(); fetchGlobalActivity(); fetchGlobalActivityPerModel(); if (isAdminOrAdminViewer(userRole)) { fetchTeamSpend(); fetchTagNames(); fetchTopTags(); fetchTopEndUsers(); } } }; initlizeUsageData(); }, [accessToken, token, userRole, userID, startTime, endTime]); if (proxySettings?.DISABLE_EXPENSIVE_DB_QUERIES) { return (
Database Query Limit Reached SpendLogs in DB has {proxySettings.NUM_SPEND_LOGS_ROWS} rows.

Please follow our guide to view usage when SpendLogs has more than 1M rows.
); } return (
All Up {isAdminOrAdminViewer(userRole) ? ( <> Team Based Usage Customer Usage Tag Based Usage ) : ( <>
)}
Cost Activity Project Spend {new Date().toLocaleString('default', { month: 'long' })} 1 - {new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0).getDate()} Monthly Spend Top API Keys `$${value.toFixed(2)}`} /> Top Models `$${value.toFixed(2)}`} /> Spend by Provider <> `$${value.toFixed(2)}`} /> Provider Spend {spendByProvider.map((provider) => ( {provider.provider} {parseFloat(provider.spend.toFixed(2)) < 0.00001 ? "less than 0.00" : provider.spend.toFixed(2)} ))}
All Up API Requests { valueFormatterNumbers(globalActivity.sum_api_requests)} console.log(v)} /> Tokens { valueFormatterNumbers(globalActivity.sum_total_tokens)} console.log(v)} /> <> {globalActivityPerModel.map((globalActivity, index) => ( {globalActivity.model} API Requests {valueFormatterNumbers(globalActivity.sum_api_requests)} console.log(v)} /> Tokens {valueFormatterNumbers(globalActivity.sum_total_tokens)} console.log(v)} /> ))}
Total Spend Per Team Daily Spend Per Team

Customers 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 Customer 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 }} /> { premiumUser ? (
setSelectedTags(value as string[])} > setSelectedTags(["all-tags"])} > All Tags {allTagNames && allTagNames .filter((tag) => tag !== "all-tags") .map((tag: any, index: number) => { return ( {tag} ); })}
) : (
setSelectedTags(value as string[])} > setSelectedTags(["all-tags"])} > All Tags {allTagNames && allTagNames .filter((tag) => tag !== "all-tags") .map((tag: any, index: number) => { return ( ✨ {tag} (Enterprise only Feature) ); })}
) }
Spend Per Tag Get Started Tracking cost per tag here
); }; export default UsagePage;