From 414dfd2c8620927170dad462aee50de7de2552b8 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Sat, 25 May 2024 09:53:08 -0700 Subject: [PATCH 1/8] feat -basic activity layout --- ui/litellm-dashboard/src/components/usage.tsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ui/litellm-dashboard/src/components/usage.tsx b/ui/litellm-dashboard/src/components/usage.tsx index b0fdafd504a..9be20251af7 100644 --- a/ui/litellm-dashboard/src/components/usage.tsx +++ b/ui/litellm-dashboard/src/components/usage.tsx @@ -326,6 +326,14 @@ const UsagePage: React.FC = ({ End User Usage Tag Based Usage + + + + + + Cost + Activity + @@ -420,6 +428,10 @@ const UsagePage: React.FC = ({ + + + + From 93024ccff328eb5b31f706d735b4a73aaf04e032 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Sat, 25 May 2024 10:37:28 -0700 Subject: [PATCH 2/8] ui - show api requests, num tokens --- .../src/components/networking.tsx | 37 ++++++++++++++ ui/litellm-dashboard/src/components/usage.tsx | 51 +++++++++++++++++-- 2 files changed, 85 insertions(+), 3 deletions(-) diff --git a/ui/litellm-dashboard/src/components/networking.tsx b/ui/litellm-dashboard/src/components/networking.tsx index 4c21e7e911a..8642a624ddb 100644 --- a/ui/litellm-dashboard/src/components/networking.tsx +++ b/ui/litellm-dashboard/src/components/networking.tsx @@ -994,6 +994,7 @@ export const adminTopEndUsersCall = async ( throw error; } }; + export const adminspendByProvider = async (accessToken: String, keyToken: String | null, startTime: String | undefined, endTime: String | undefined) => { try { let url = proxyBaseUrl ? `${proxyBaseUrl}/global/spend/provider` : `/global/spend/provider`; @@ -1035,6 +1036,42 @@ export const adminspendByProvider = async (accessToken: String, keyToken: String } }; +export const adminGlobalActivity = async (accessToken: String, startTime: String | undefined, endTime: String | undefined) => { + try { + let url = proxyBaseUrl ? `${proxyBaseUrl}/global/activity` : `/global/activity`; + + if (startTime && endTime) { + url += `?start_date=${startTime}&end_date=${endTime}`; + } + + const requestOptions: { + method: string; + headers: { + Authorization: string; + }; + } = { + method: "GET", + headers: { + Authorization: `Bearer ${accessToken}`, + }, + }; + + const response = await fetch(url, requestOptions); + + if (!response.ok) { + const errorData = await response.text(); + throw new Error("Network response was not ok"); + } + const data = await response.json(); + console.log(data); + return data; + } catch (error) { + console.error("Failed to fetch spend data:", error); + throw error; + } +}; + + export const adminTopModelsCall = async (accessToken: String) => { try { let url = proxyBaseUrl diff --git a/ui/litellm-dashboard/src/components/usage.tsx b/ui/litellm-dashboard/src/components/usage.tsx index 9be20251af7..390de716671 100644 --- a/ui/litellm-dashboard/src/components/usage.tsx +++ b/ui/litellm-dashboard/src/components/usage.tsx @@ -1,9 +1,16 @@ -import { BarChart, BarList, Card, Title, Table, TableHead, TableHeaderCell, TableRow, TableCell, TableBody, Metric } from "@tremor/react"; +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 { Grid, Col, Text, LineChart, TabPanel, TabPanels, TabGroup, TabList, Tab, Select, SelectItem, DateRangePicker, DateRangePickerValue, DonutChart} from "@tremor/react"; +import { + Grid, Col, Text, + LineChart, TabPanel, TabPanels, + TabGroup, TabList, Tab, Select, SelectItem, + DateRangePicker, DateRangePickerValue, + DonutChart, + AreaChart, +} from "@tremor/react"; import { userSpendLogsCall, keyInfoCall, @@ -17,6 +24,7 @@ import { modelAvailableCall, modelInfoCall, adminspendByProvider, + adminGlobalActivity, } from "./networking"; import { start } from "repl"; @@ -117,6 +125,7 @@ const UsagePage: React.FC = ({ const [uniqueTeamIds, setUniqueTeamIds] = useState([]); const [totalSpendPerTeam, setTotalSpendPerTeam] = useState([]); const [spendByProvider, setSpendByProvider] = useState([]); + const [globalActivity, setGlobalActivity] = useState([]); const [selectedKeyID, setSelectedKeyID] = useState(""); const [dateValue, setDateValue] = useState({ from: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), @@ -265,6 +274,10 @@ const UsagePage: React.FC = ({ console.log("spend/user result", spend_user_call); + let global_activity_response = await adminGlobalActivity(accessToken, startTime, endTime); + setGlobalActivity(global_activity_response) + + } else if (userRole == "App Owner") { await userSpendLogsCall( accessToken, @@ -330,7 +343,7 @@ const UsagePage: React.FC = ({ - + Cost Activity @@ -429,6 +442,38 @@ const UsagePage: React.FC = ({ + + + + All Up + + + API Requests {globalActivity.sum_api_requests} + console.log(v)} + /> + + + + Tokens {globalActivity.sum_total_tokens} + console.log(v)} + /> + + + + + + + From 6d91ffd0506d9bff9d5f26286bc2f18fd83ea2f8 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Sat, 25 May 2024 10:40:26 -0700 Subject: [PATCH 3/8] backend - get all up global activ --- litellm/proxy/proxy_server.py | 97 +++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index 07c1f691493..c2605070a94 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -5883,6 +5883,103 @@ async def view_spend_tags( ) +@router.get( + "/global/activity", + tags=["Budget & Spend Tracking"], + dependencies=[Depends(user_api_key_auth)], + include_in_schema=False, + responses={ + 200: {"model": List[LiteLLM_SpendLogs]}, + }, +) +async def get_global_activity( + start_date: Optional[str] = fastapi.Query( + default=None, + description="Time from which to start viewing spend", + ), + end_date: Optional[str] = fastapi.Query( + default=None, + description="Time till which to view spend", + ), +): + """ + Get number of API Requests, total tokens through proxy + + { + "daily_data": [ + const chartdata = [ + { + date: 'Jan 22', + api_requests: 10, + total_tokens: 2000 + }, + { + date: 'Jan 23', + api_requests: 10, + total_tokens: 12 + }, + ], + "sum_api_requests": 20, + "sum_total_tokens": 2012 + } + """ + from collections import defaultdict + + if start_date is None or end_date is None: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail={"error": "Please provide start_date and end_date"}, + ) + + start_date_obj = datetime.strptime(start_date, "%Y-%m-%d") + end_date_obj = datetime.strptime(end_date, "%Y-%m-%d") + + global prisma_client, llm_router + try: + if prisma_client is None: + raise Exception( + f"Database not connected. Connect a database to your proxy - https://docs.litellm.ai/docs/simple_proxy#managing-auth---virtual-keys" + ) + + sql_query = """ + SELECT + date_trunc('day', "startTime") AS date, + COUNT(*) AS api_requests, + SUM(total_tokens) AS total_tokens + FROM "LiteLLM_SpendLogs" + WHERE "startTime" BETWEEN $1::date AND $2::date + interval '1 day' + GROUP BY date_trunc('day', "startTime") + """ + db_response = await prisma_client.db.query_raw( + sql_query, start_date_obj, end_date_obj + ) + + if db_response is None: + return [] + + sum_api_requests = 0 + sum_total_tokens = 0 + daily_data = [] + for row in db_response: + daily_data.append(row) + sum_api_requests += row.get("api_requests", 0) + sum_total_tokens += row.get("total_tokens", 0) + + data_to_return = { + "daily_data": daily_data, + "sum_api_requests": sum_api_requests, + "sum_total_tokens": sum_total_tokens, + } + + return data_to_return + + except Exception as e: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail={"error": str(e)}, + ) + + @router.get( "/global/spend/provider", tags=["Budget & Spend Tracking"], From 3bab323dccc1340dd832a8bbb87015d280622930 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Sat, 25 May 2024 10:51:36 -0700 Subject: [PATCH 4/8] fix - formatting on admin ui --- litellm/proxy/proxy_server.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index c2605070a94..dd56bf9165e 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -5961,6 +5961,10 @@ async def get_global_activity( sum_total_tokens = 0 daily_data = [] for row in db_response: + # cast date to datetime + _date_obj = datetime.fromisoformat(row["date"]) + row["date"] = _date_obj.strftime("%b %d") + daily_data.append(row) sum_api_requests += row.get("api_requests", 0) sum_total_tokens += row.get("total_tokens", 0) From aa50020bda2740c609b79a79da4b7bab5176ec53 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Sat, 25 May 2024 12:21:14 -0700 Subject: [PATCH 5/8] fix - backend sort by date + /global/activity/model --- litellm/proxy/proxy_server.py | 166 +++++++++++++++++++++++++++++++++- 1 file changed, 165 insertions(+), 1 deletion(-) diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index dd56bf9165e..690b4b9bfee 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -5887,7 +5887,6 @@ async def view_spend_tags( "/global/activity", tags=["Budget & Spend Tracking"], dependencies=[Depends(user_api_key_auth)], - include_in_schema=False, responses={ 200: {"model": List[LiteLLM_SpendLogs]}, }, @@ -5969,6 +5968,9 @@ async def get_global_activity( sum_api_requests += row.get("api_requests", 0) sum_total_tokens += row.get("total_tokens", 0) + # sort daily_data by date + daily_data = sorted(daily_data, key=lambda x: x["date"]) + data_to_return = { "daily_data": daily_data, "sum_api_requests": sum_api_requests, @@ -5984,6 +5986,168 @@ async def get_global_activity( ) +@router.get( + "/global/activity/model", + tags=["Budget & Spend Tracking"], + dependencies=[Depends(user_api_key_auth)], + responses={ + 200: {"model": List[LiteLLM_SpendLogs]}, + }, +) +async def get_global_activity_model( + start_date: Optional[str] = fastapi.Query( + default=None, + description="Time from which to start viewing spend", + ), + end_date: Optional[str] = fastapi.Query( + default=None, + description="Time till which to view spend", + ), +): + """ + Get number of API Requests, total tokens through proxy - Grouped by MODEL + + [ + { + "model": "gpt-4", + "daily_data": [ + const chartdata = [ + { + date: 'Jan 22', + api_requests: 10, + total_tokens: 2000 + }, + { + date: 'Jan 23', + api_requests: 10, + total_tokens: 12 + }, + ], + "sum_api_requests": 20, + "sum_total_tokens": 2012 + + }, + { + "model": "azure/gpt-4-turbo", + "daily_data": [ + const chartdata = [ + { + date: 'Jan 22', + api_requests: 10, + total_tokens: 2000 + }, + { + date: 'Jan 23', + api_requests: 10, + total_tokens: 12 + }, + ], + "sum_api_requests": 20, + "sum_total_tokens": 2012 + + }, + ] + """ + from collections import defaultdict + + if start_date is None or end_date is None: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail={"error": "Please provide start_date and end_date"}, + ) + + start_date_obj = datetime.strptime(start_date, "%Y-%m-%d") + end_date_obj = datetime.strptime(end_date, "%Y-%m-%d") + + """ + litellm/proxy/proxy_server.py:219: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs [annotation-unchecked] + litellm/proxy/proxy_server.py:6087: error: Need type annotation for "spend_by_model" (hint: "spend_by_model: Dict[, ] = ...") [var-annotated] + litellm/proxy/proxy_server.py:6105: error: "object" has no attribute "append" [attr-defined] + litellm/proxy/proxy_server.py:6113: error: Argument "key" to "sorted" has incompatible type "Callable[[tuple[Any, dict[str, object]]], object]"; expected "Callable[[tuple[Any, dict[str, object]]], SupportsDunderLT[Any] | SupportsDunderGT[Any]]" [arg-type] + litellm/proxy/proxy_server.py:6113: error: Incompatible return value type (got "object", expected "SupportsDunderLT[Any] | SupportsDunderGT[Any]") [return-value] + litellm/proxy/proxy_server.py:6121: error: No overload variant of "sorted" matches argument types "object", "Callable[[Any], Any]" [call-overload] + litellm/proxy/proxy_server.py:6121: note: Possible overload variants: + litellm/proxy/proxy_server.py:6121: note: def [SupportsRichComparisonT] sorted(Iterable[SupportsRichComparisonT], /, *, key: None = ..., reverse: bool = ...) -> list[SupportsRichComparisonT] + litellm/proxy/proxy_server.py:6121: note: def [_T] sorted(Iterable[_T], /, *, key: Callable[[_T], SupportsDunderLT[Any] | SupportsDunderGT[Any]], reverse: bool = ...) -> list[_T] + litellm/proxy/proxy_server.py:6121: error: Value of type Never is not indexable [index] + Found 6 errors in 1 file (checked 1 source file) + """ + + global prisma_client, llm_router, premium_user + try: + if prisma_client is None: + raise Exception( + f"Database not connected. Connect a database to your proxy - https://docs.litellm.ai/docs/simple_proxy#managing-auth---virtual-keys" + ) + + sql_query = """ + SELECT + model, + date_trunc('day', "startTime") AS date, + COUNT(*) AS api_requests, + SUM(total_tokens) AS total_tokens + FROM "LiteLLM_SpendLogs" + WHERE "startTime" BETWEEN $1::date AND $2::date + interval '1 day' + GROUP BY model, date_trunc('day', "startTime") + + """ + db_response = await prisma_client.db.query_raw( + sql_query, start_date_obj, end_date_obj + ) + if db_response is None: + return [] + + model_ui_data: dict = ( + {} + ) # {"gpt-4": {"daily_data": [], "sum_api_requests": 0, "sum_total_tokens": 0}} + + for row in db_response: + _model = row["model"] + if _model not in model_ui_data: + model_ui_data[_model] = { + "daily_data": [], + "sum_api_requests": 0, + "sum_total_tokens": 0, + } + _date_obj = datetime.fromisoformat(row["date"]) + row["date"] = _date_obj.strftime("%b %d") + + model_ui_data[_model]["daily_data"].append(row) + model_ui_data[_model]["sum_api_requests"] += row.get("api_requests", 0) + model_ui_data[_model]["sum_total_tokens"] += row.get("total_tokens", 0) + + # sort mode ui data by sum_api_requests -> get top 10 models + model_ui_data = dict( + sorted( + model_ui_data.items(), + key=lambda x: x[1]["sum_api_requests"], + reverse=True, + )[:10] + ) + + response = [] + + for model, data in model_ui_data.items(): + _sort_daily_data = sorted(data["daily_data"], key=lambda x: x["date"]) + + response.append( + { + "model": model, + "daily_data": _sort_daily_data, + "sum_api_requests": data["sum_api_requests"], + "sum_total_tokens": data["sum_total_tokens"], + } + ) + + return response + + except Exception as e: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail={"error": str(e)}, + ) + + @router.get( "/global/spend/provider", tags=["Budget & Spend Tracking"], From 9035d4d6afc9e0b75b5fa73cdaf75f320d5ba661 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Sat, 25 May 2024 12:22:10 -0700 Subject: [PATCH 6/8] ui - show global activity --- .../src/components/networking.tsx | 36 +++++++++++++++++ ui/litellm-dashboard/src/components/usage.tsx | 40 +++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/ui/litellm-dashboard/src/components/networking.tsx b/ui/litellm-dashboard/src/components/networking.tsx index 8642a624ddb..e7678ba10a7 100644 --- a/ui/litellm-dashboard/src/components/networking.tsx +++ b/ui/litellm-dashboard/src/components/networking.tsx @@ -1072,6 +1072,42 @@ export const adminGlobalActivity = async (accessToken: String, startTime: String }; +export const adminGlobalActivityPerModel = async (accessToken: String, startTime: String | undefined, endTime: String | undefined) => { + try { + let url = proxyBaseUrl ? `${proxyBaseUrl}/global/activity/model` : `/global/activity/model`; + + if (startTime && endTime) { + url += `?start_date=${startTime}&end_date=${endTime}`; + } + + const requestOptions: { + method: string; + headers: { + Authorization: string; + }; + } = { + method: "GET", + headers: { + Authorization: `Bearer ${accessToken}`, + }, + }; + + const response = await fetch(url, requestOptions); + + if (!response.ok) { + const errorData = await response.text(); + throw new Error("Network response was not ok"); + } + const data = await response.json(); + console.log(data); + return data; + } catch (error) { + console.error("Failed to fetch spend data:", error); + throw error; + } +}; + + export const adminTopModelsCall = async (accessToken: String) => { try { let url = proxyBaseUrl diff --git a/ui/litellm-dashboard/src/components/usage.tsx b/ui/litellm-dashboard/src/components/usage.tsx index 390de716671..3eb2bc25fbc 100644 --- a/ui/litellm-dashboard/src/components/usage.tsx +++ b/ui/litellm-dashboard/src/components/usage.tsx @@ -25,6 +25,7 @@ import { modelInfoCall, adminspendByProvider, adminGlobalActivity, + adminGlobalActivityPerModel, } from "./networking"; import { start } from "repl"; @@ -126,6 +127,7 @@ const UsagePage: React.FC = ({ const [totalSpendPerTeam, setTotalSpendPerTeam] = useState([]); const [spendByProvider, setSpendByProvider] = useState([]); const [globalActivity, setGlobalActivity] = useState([]); + const [globalActivityPerModel, setGlobalActivityPerModel] = useState([]); const [selectedKeyID, setSelectedKeyID] = useState(""); const [dateValue, setDateValue] = useState({ from: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), @@ -277,6 +279,10 @@ const UsagePage: React.FC = ({ let global_activity_response = await adminGlobalActivity(accessToken, startTime, endTime); setGlobalActivity(global_activity_response) + let global_activity_per_model = await adminGlobalActivityPerModel(accessToken, startTime, endTime); + console.log("global activity per model", global_activity_per_model); + setGlobalActivityPerModel(global_activity_per_model) + } else if (userRole == "App Owner") { await userSpendLogsCall( @@ -453,6 +459,7 @@ const UsagePage: React.FC = ({ className="h-40" data={globalActivity.daily_data} index="date" + colors={['cyan']} categories={['api_requests']} onValueChange={(v) => console.log(v)} /> @@ -464,6 +471,7 @@ const UsagePage: React.FC = ({ className="h-40" data={globalActivity.daily_data} index="date" + colors={['cyan']} categories={['total_tokens']} onValueChange={(v) => console.log(v)} /> @@ -472,6 +480,38 @@ const UsagePage: React.FC = ({ + + {globalActivityPerModel.map((globalActivity, index) => ( + + {globalActivity.model} + + + API Requests {globalActivity.sum_api_requests} + console.log(v)} + /> + + + Tokens {globalActivity.sum_total_tokens} + console.log(v)} + /> + + + + ))} + + From 1afc18f3716eb5af313122505963f526ffd84baa Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Sat, 25 May 2024 12:22:28 -0700 Subject: [PATCH 7/8] fix - clean up proxy.py --- litellm/proxy/proxy_server.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index 690b4b9bfee..4698249c9e9 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -6059,20 +6059,6 @@ async def get_global_activity_model( start_date_obj = datetime.strptime(start_date, "%Y-%m-%d") end_date_obj = datetime.strptime(end_date, "%Y-%m-%d") - """ - litellm/proxy/proxy_server.py:219: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs [annotation-unchecked] - litellm/proxy/proxy_server.py:6087: error: Need type annotation for "spend_by_model" (hint: "spend_by_model: Dict[, ] = ...") [var-annotated] - litellm/proxy/proxy_server.py:6105: error: "object" has no attribute "append" [attr-defined] - litellm/proxy/proxy_server.py:6113: error: Argument "key" to "sorted" has incompatible type "Callable[[tuple[Any, dict[str, object]]], object]"; expected "Callable[[tuple[Any, dict[str, object]]], SupportsDunderLT[Any] | SupportsDunderGT[Any]]" [arg-type] - litellm/proxy/proxy_server.py:6113: error: Incompatible return value type (got "object", expected "SupportsDunderLT[Any] | SupportsDunderGT[Any]") [return-value] - litellm/proxy/proxy_server.py:6121: error: No overload variant of "sorted" matches argument types "object", "Callable[[Any], Any]" [call-overload] - litellm/proxy/proxy_server.py:6121: note: Possible overload variants: - litellm/proxy/proxy_server.py:6121: note: def [SupportsRichComparisonT] sorted(Iterable[SupportsRichComparisonT], /, *, key: None = ..., reverse: bool = ...) -> list[SupportsRichComparisonT] - litellm/proxy/proxy_server.py:6121: note: def [_T] sorted(Iterable[_T], /, *, key: Callable[[_T], SupportsDunderLT[Any] | SupportsDunderGT[Any]], reverse: bool = ...) -> list[_T] - litellm/proxy/proxy_server.py:6121: error: Value of type Never is not indexable [index] - Found 6 errors in 1 file (checked 1 source file) - """ - global prisma_client, llm_router, premium_user try: if prisma_client is None: @@ -6126,7 +6112,6 @@ async def get_global_activity_model( ) response = [] - for model, data in model_ui_data.items(): _sort_daily_data = sorted(data["daily_data"], key=lambda x: x["date"]) From f3f8462f45f71a7c0acb08d8e3f9da0dd3f7d2d7 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Sat, 25 May 2024 12:36:17 -0700 Subject: [PATCH 8/8] feat - show activity on admin ui --- ui/litellm-dashboard/src/components/usage.tsx | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/ui/litellm-dashboard/src/components/usage.tsx b/ui/litellm-dashboard/src/components/usage.tsx index 3eb2bc25fbc..b236ae702ea 100644 --- a/ui/litellm-dashboard/src/components/usage.tsx +++ b/ui/litellm-dashboard/src/components/usage.tsx @@ -37,6 +37,13 @@ interface UsagePageProps { keys: any[] | null; } +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; @@ -126,7 +133,7 @@ const UsagePage: React.FC = ({ const [uniqueTeamIds, setUniqueTeamIds] = useState([]); const [totalSpendPerTeam, setTotalSpendPerTeam] = useState([]); const [spendByProvider, setSpendByProvider] = useState([]); - const [globalActivity, setGlobalActivity] = useState([]); + const [globalActivity, setGlobalActivity] = useState({} as GlobalActivityData); const [globalActivityPerModel, setGlobalActivityPerModel] = useState([]); const [selectedKeyID, setSelectedKeyID] = useState(""); const [dateValue, setDateValue] = useState({ @@ -454,7 +461,7 @@ const UsagePage: React.FC = ({ All Up - API Requests {globalActivity.sum_api_requests} + API Requests {globalActivity.sum_api_requests} = ({ - Tokens {globalActivity.sum_total_tokens} + Tokens {globalActivity.sum_total_tokens} = ({ {globalActivity.model} - API Requests {globalActivity.sum_api_requests} + API Requests {globalActivity.sum_api_requests} = ({ /> - Tokens {globalActivity.sum_total_tokens} + Tokens {globalActivity.sum_total_tokens}