mirror of
https://github.com/BerriAI/litellm.git
synced 2025-04-26 03:04:13 +00:00
fix(proxy_server.py): actual implementation of slack soft budget alerting
This commit is contained in:
parent
b30cbd0d55
commit
ac085a4643
5 changed files with 142 additions and 9 deletions
|
@ -222,6 +222,7 @@ class ProxyLogging:
|
|||
"user_and_proxy_budget",
|
||||
"failed_budgets",
|
||||
"failed_tracking",
|
||||
"projected_limit_exceeded",
|
||||
],
|
||||
user_max_budget: float,
|
||||
user_current_spend: float,
|
||||
|
@ -255,6 +256,23 @@ class ProxyLogging:
|
|||
level="High",
|
||||
)
|
||||
return
|
||||
elif type == "projected_limit_exceeded" and user_info is not None:
|
||||
"""
|
||||
Input variables:
|
||||
user_info = {
|
||||
"key_alias": key_alias,
|
||||
"projected_spend": projected_spend,
|
||||
"projected_exceeded_date": projected_exceeded_date,
|
||||
}
|
||||
user_max_budget=soft_limit,
|
||||
user_current_spend=new_spend
|
||||
"""
|
||||
message = f"""\n🚨 `ProjectedLimitExceededError` 💸\n\n`Key Alias:` {user_info["key_alias"]} \n`Expected Day of Error`: {user_info["projected_exceeded_date"]} \n`Current Spend`: {user_current_spend} \n`Projected Spend at end of month`: {user_info["projected_spend"]} \n`Soft Limit`: {user_max_budget}"""
|
||||
await self.alerting_handler(
|
||||
message=message,
|
||||
level="High",
|
||||
)
|
||||
return
|
||||
else:
|
||||
user_info = str(user_info)
|
||||
# percent of max_budget left to spend
|
||||
|
@ -748,7 +766,8 @@ class PrismaClient:
|
|||
detail={"error": f"No token passed in. Token={token}"},
|
||||
)
|
||||
response = await self.db.litellm_verificationtoken.find_unique(
|
||||
where={"token": hashed_token}
|
||||
where={"token": hashed_token},
|
||||
include={"litellm_budget_table": True},
|
||||
)
|
||||
if response is not None:
|
||||
# for prisma we need to cast the expires time to str
|
||||
|
@ -758,7 +777,8 @@ class PrismaClient:
|
|||
response.expires = response.expires.isoformat()
|
||||
elif query_type == "find_all" and user_id is not None:
|
||||
response = await self.db.litellm_verificationtoken.find_many(
|
||||
where={"user_id": user_id}
|
||||
where={"user_id": user_id},
|
||||
include={"litellm_budget_table": True},
|
||||
)
|
||||
if response is not None and len(response) > 0:
|
||||
for r in response:
|
||||
|
@ -766,7 +786,8 @@ class PrismaClient:
|
|||
r.expires = r.expires.isoformat()
|
||||
elif query_type == "find_all" and team_id is not None:
|
||||
response = await self.db.litellm_verificationtoken.find_many(
|
||||
where={"team_id": team_id}
|
||||
where={"team_id": team_id},
|
||||
include={"litellm_budget_table": True},
|
||||
)
|
||||
if response is not None and len(response) > 0:
|
||||
for r in response:
|
||||
|
@ -809,7 +830,9 @@ class PrismaClient:
|
|||
hashed_tokens.append(t)
|
||||
where_filter["token"]["in"] = hashed_tokens
|
||||
response = await self.db.litellm_verificationtoken.find_many(
|
||||
order={"spend": "desc"}, where=where_filter # type: ignore
|
||||
order={"spend": "desc"},
|
||||
where=where_filter, # type: ignore
|
||||
include={"litellm_budget_table": True},
|
||||
)
|
||||
if response is not None:
|
||||
return response
|
||||
|
@ -1728,6 +1751,69 @@ async def _read_request_body(request):
|
|||
return {}
|
||||
|
||||
|
||||
def _is_projected_spend_over_limit(
|
||||
current_spend: float, soft_budget_limit: Optional[float]
|
||||
):
|
||||
from datetime import date
|
||||
|
||||
if soft_budget_limit is None:
|
||||
# If there's no limit, we can't exceed it.
|
||||
return False
|
||||
|
||||
today = date.today()
|
||||
|
||||
# Finding the first day of the next month, then subtracting one day to get the end of the current month.
|
||||
if today.month == 12: # December edge case
|
||||
end_month = date(today.year + 1, 1, 1) - timedelta(days=1)
|
||||
else:
|
||||
end_month = date(today.year, today.month + 1, 1) - timedelta(days=1)
|
||||
|
||||
remaining_days = (end_month - today).days
|
||||
|
||||
# Check for the start of the month to avoid division by zero
|
||||
if today.day == 1:
|
||||
daily_spend_estimate = current_spend
|
||||
else:
|
||||
daily_spend_estimate = current_spend / (today.day - 1)
|
||||
|
||||
# Total projected spend for the month
|
||||
projected_spend = current_spend + (daily_spend_estimate * remaining_days)
|
||||
|
||||
if projected_spend > soft_budget_limit:
|
||||
print_verbose("Projected spend exceeds soft budget limit!")
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _get_projected_spend_over_limit(
|
||||
current_spend: float, soft_budget_limit: Optional[float]
|
||||
) -> Optional[tuple]:
|
||||
import datetime
|
||||
|
||||
if soft_budget_limit is None:
|
||||
return None
|
||||
|
||||
today = datetime.date.today()
|
||||
end_month = datetime.date(today.year, today.month + 1, 1) - datetime.timedelta(
|
||||
days=1
|
||||
)
|
||||
remaining_days = (end_month - today).days
|
||||
|
||||
daily_spend = current_spend / (
|
||||
today.day - 1
|
||||
) # assuming the current spend till today (not including today)
|
||||
projected_spend = daily_spend * remaining_days
|
||||
|
||||
if projected_spend > soft_budget_limit:
|
||||
approx_days = soft_budget_limit / daily_spend
|
||||
limit_exceed_date = today + datetime.timedelta(days=approx_days)
|
||||
|
||||
# return the projected spend and the date it will exceeded
|
||||
return projected_spend, limit_exceed_date
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def _is_valid_team_configs(team_id=None, team_config=None, request_data=None):
|
||||
if team_id is None or team_config is None or request_data is None:
|
||||
return
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue