Merge pull request #3624 from BerriAI/litellm_ui_cleanup_2

[UI] Filter Tag Spend by Date + Show Bar Chart
This commit is contained in:
Ishaan Jaff 2024-05-13 17:33:43 -07:00 committed by GitHub
commit 067749805b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 73 additions and 43 deletions

View file

@ -1,6 +1,7 @@
# Enterprise Proxy Util Endpoints # Enterprise Proxy Util Endpoints
from litellm._logging import verbose_logger from litellm._logging import verbose_logger
import collections import collections
from datetime import datetime
async def get_spend_by_tags(start_date=None, end_date=None, prisma_client=None): async def get_spend_by_tags(start_date=None, end_date=None, prisma_client=None):
@ -18,19 +19,26 @@ async def get_spend_by_tags(start_date=None, end_date=None, prisma_client=None):
return response return response
async def ui_get_spend_by_tags(start_date=None, end_date=None, prisma_client=None): async def ui_get_spend_by_tags(start_date: str, end_date: str, prisma_client):
response = await prisma_client.db.query_raw(
""" sql_query = """
SELECT SELECT
jsonb_array_elements_text(request_tags) AS individual_request_tag, jsonb_array_elements_text(request_tags) AS individual_request_tag,
DATE(s."startTime") AS spend_date, DATE(s."startTime") AS spend_date,
COUNT(*) AS log_count, COUNT(*) AS log_count,
SUM(spend) AS total_spend SUM(spend) AS total_spend
FROM "LiteLLM_SpendLogs" s FROM "LiteLLM_SpendLogs" s
WHERE s."startTime" >= current_date - interval '30 days' WHERE
DATE(s."startTime") >= $1::date
AND DATE(s."startTime") <= $2::date
GROUP BY individual_request_tag, spend_date GROUP BY individual_request_tag, spend_date
ORDER BY spend_date; ORDER BY spend_date
""" LIMIT 100;
"""
response = await prisma_client.db.query_raw(
sql_query,
start_date,
end_date,
) )
# print("tags - spend") # print("tags - spend")
@ -49,15 +57,18 @@ async def ui_get_spend_by_tags(start_date=None, end_date=None, prisma_client=Non
# convert to ui format # convert to ui format
ui_tags = [] ui_tags = []
for tag in sorted_tags: for tag in sorted_tags:
current_spend = tag[1]
if current_spend is not None and isinstance(current_spend, float):
current_spend = round(current_spend, 4)
ui_tags.append( ui_tags.append(
{ {
"name": tag[0], "name": tag[0],
"value": tag[1], "spend": current_spend,
"log_count": total_requests_per_tag[tag[0]], "log_count": total_requests_per_tag[tag[0]],
} }
) )
return {"top_10_tags": ui_tags} return {"spend_per_tag": ui_tags}
async def view_spend_logs_from_clickhouse( async def view_spend_logs_from_clickhouse(

View file

@ -5563,6 +5563,13 @@ async def global_view_spend_tags(
f"Database not connected. Connect a database to your proxy - https://docs.litellm.ai/docs/simple_proxy#managing-auth---virtual-keys" f"Database not connected. Connect a database to your proxy - https://docs.litellm.ai/docs/simple_proxy#managing-auth---virtual-keys"
) )
if end_date is None or start_date is None:
raise ProxyException(
message="Please provide start_date and end_date",
type="bad_request",
param=None,
code=status.HTTP_400_BAD_REQUEST,
)
response = await ui_get_spend_by_tags( response = await ui_get_spend_by_tags(
start_date=start_date, end_date=end_date, prisma_client=prisma_client start_date=start_date, end_date=end_date, prisma_client=prisma_client
) )

View file

@ -655,11 +655,20 @@ export const teamSpendLogsCall = async (accessToken: String) => {
}; };
export const tagsSpendLogsCall = async (accessToken: String) => { export const tagsSpendLogsCall = async (
accessToken: String,
startTime: String | undefined,
endTime: String | undefined
) => {
try { try {
const url = proxyBaseUrl let url = proxyBaseUrl
? `${proxyBaseUrl}/global/spend/tags` ? `${proxyBaseUrl}/global/spend/tags`
: `/global/spend/tags`; : `/global/spend/tags`;
if (startTime && endTime) {
url = `${url}?start_date=${startTime}&end_date=${endTime}`
}
console.log("in tagsSpendLogsCall:", url); console.log("in tagsSpendLogsCall:", url);
const response = await fetch(`${url}`, { const response = await fetch(`${url}`, {
method: "GET", method: "GET",

View file

@ -129,7 +129,7 @@ const Team: React.FC<TeamProps> = ({
name="team_alias" name="team_alias"
rules={[{ required: true, message: "Please input a team name" }]} rules={[{ required: true, message: "Please input a team name" }]}
> >
<Input /> <TextInput />
</Form.Item> </Form.Item>
<Form.Item label="Models" name="models"> <Form.Item label="Models" name="models">
<Select2 <Select2

View file

@ -153,6 +153,19 @@ const UsagePage: React.FC<UsagePageProps> = ({
console.log("End user data updated successfully", newTopUserData); console.log("End user data updated successfully", newTopUserData);
setTopUsers(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) { function formatDate(date: Date) {
@ -218,8 +231,8 @@ const UsagePage: React.FC<UsagePageProps> = ({
setTotalSpendPerTeam(total_spend_per_team); setTotalSpendPerTeam(total_spend_per_team);
//get top tags //get top tags
const top_tags = await tagsSpendLogsCall(accessToken); const top_tags = await tagsSpendLogsCall(accessToken, dateValue.from?.toISOString(), dateValue.to?.toISOString());
setTopTagsData(top_tags.top_10_tags); setTopTagsData(top_tags.spend_per_tag);
// get spend per end-user // get spend per end-user
let spend_user_call = await adminTopEndUsersCall(accessToken, null, undefined, undefined); let spend_user_call = await adminTopEndUsersCall(accessToken, null, undefined, undefined);
@ -459,38 +472,28 @@ const UsagePage: React.FC<UsagePageProps> = ({
<TabPanel> <TabPanel>
<Grid numItems={2} className="gap-2 h-[75vh] w-full mb-4"> <Grid numItems={2} className="gap-2 h-[75vh] w-full mb-4">
<Col numColSpan={2}> <Col numColSpan={2}>
<DateRangePicker
className="mb-4"
enableSelect={true}
value={dateValue}
onValueChange={(value) => {
setDateValue(value);
updateTagSpendData(value.from, value.to); // Call updateModelMetrics with the new date range
}}
/>
<Card> <Card>
<Title>Spend Per Tag - Last 30 Days</Title> <Title>Spend Per Tag</Title>
<Text>Get Started Tracking cost per tag <a href="https://docs.litellm.ai/docs/proxy/enterprise#tracking-spend-for-custom-tags" target="_blank">here</a></Text> <Text>Get Started Tracking cost per tag <a className="text-blue-500" href="https://docs.litellm.ai/docs/proxy/enterprise#tracking-spend-for-custom-tags" target="_blank">here</a></Text>
<Table> <BarChart
<TableHead> className="h-72"
<TableRow> data={topTagsData}
<TableHeaderCell>Tag</TableHeaderCell> index="name"
<TableHeaderCell>Spend</TableHeaderCell> categories={["spend"]}
<TableHeaderCell>Requests</TableHeaderCell> colors={["blue"]}
</TableRow> >
</TableHead>
<TableBody> </BarChart>
{topTagsData.map((tag) => (
<TableRow key={tag.name}>
<TableCell>{tag.name}</TableCell>
<TableCell>{tag.value}</TableCell>
<TableCell>{tag.log_count}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
{/* <BarChart
className="h-72"
data={teamSpendData}
showLegend={true}
index="date"
categories={uniqueTeamIds}
yAxisWidth={80}
stack={true}
/> */}
</Card> </Card>
</Col> </Col>
<Col numColSpan={2}> <Col numColSpan={2}>