mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-10 03:28:53 +00:00
Honor explicit budget reset datetime for user
This commit is contained in:
parent
208027dc71
commit
6d1a2761ea
3 changed files with 46 additions and 10 deletions
|
|
@ -786,6 +786,7 @@ class GenerateRequestBase(LiteLLMPydanticObjectBase):
|
|||
rpm_limit: Optional[int] = None
|
||||
|
||||
budget_duration: Optional[str] = None
|
||||
budget_reset_at: Optional[datetime] = None
|
||||
allowed_cache_controls: Optional[list] = []
|
||||
config: Optional[dict] = {}
|
||||
permissions: Optional[dict] = {}
|
||||
|
|
|
|||
|
|
@ -306,6 +306,7 @@ async def new_user(
|
|||
- user_role: Optional[str] - Specify a user role - "proxy_admin", "proxy_admin_viewer", "internal_user", "internal_user_viewer", "team", "customer". Info about each role here: `https://github.com/BerriAI/litellm/litellm/proxy/_types.py#L20`
|
||||
- max_budget: Optional[float] - Specify max budget for a given user.
|
||||
- budget_duration: Optional[str] - Budget is reset at the end of specified duration. If not set, budget is never reset. You can set duration as seconds ("30s"), minutes ("30m"), hours ("30h"), days ("30d"), months ("1mo").
|
||||
- budget_reset_at: Optional[datetime] - Specify the exact datetime when the budget should first reset (ISO 8601 format, e.g., "2025-11-15T00:00:00Z"). If provided along with budget_duration, this value takes precedence for the initial reset; subsequent resets will follow the budget_duration interval.
|
||||
- models: Optional[list] - Model_name's a user is allowed to call. (if empty, key is allowed to call all models). Set to ['no-default-models'] to block all model access. Restricting user to only team-based model access.
|
||||
- tpm_limit: Optional[int] - Specify tpm limit for a given user (Tokens per minute)
|
||||
- rpm_limit: Optional[int] - Specify rpm limit for a given user (Requests per minute)
|
||||
|
|
@ -763,12 +764,26 @@ def _update_internal_user_params(
|
|||
if data.user_role == LitellmUserRoles.INTERNAL_USER:
|
||||
is_internal_user = True
|
||||
|
||||
if "budget_reset_at" in non_default_values and non_default_values["budget_reset_at"] is not None:
|
||||
_reset_at = non_default_values["budget_reset_at"]
|
||||
try:
|
||||
# convert to datetime if not already
|
||||
if not isinstance(_reset_at, datetime):
|
||||
_reset_at = datetime.fromisoformat(str(_reset_at).replace("Z", "+00:00"))
|
||||
# ensure timezone aware
|
||||
if _reset_at.tzinfo is None:
|
||||
_reset_at = _reset_at.replace(tzinfo=timezone.utc)
|
||||
except Exception:
|
||||
_reset_at = None
|
||||
non_default_values["budget_reset_at"] = _reset_at
|
||||
|
||||
if "budget_duration" in non_default_values:
|
||||
from litellm.proxy.common_utils.timezone_utils import get_budget_reset_time
|
||||
|
||||
non_default_values["budget_reset_at"] = get_budget_reset_time(
|
||||
budget_duration=non_default_values["budget_duration"]
|
||||
)
|
||||
# only auto-compute budget_reset_at if not explicitly provided
|
||||
if "budget_reset_at" not in non_default_values or non_default_values["budget_reset_at"] is None:
|
||||
non_default_values["budget_reset_at"] = get_budget_reset_time(
|
||||
budget_duration=non_default_values["budget_duration"]
|
||||
)
|
||||
|
||||
if "max_budget" not in non_default_values:
|
||||
if (
|
||||
|
|
@ -785,9 +800,11 @@ def _update_internal_user_params(
|
|||
)
|
||||
from litellm.proxy.common_utils.timezone_utils import get_budget_reset_time
|
||||
|
||||
non_default_values["budget_reset_at"] = get_budget_reset_time(
|
||||
budget_duration=non_default_values["budget_duration"]
|
||||
)
|
||||
# only auto-compute budget_reset_at if not explicitly provided
|
||||
if "budget_reset_at" not in non_default_values or non_default_values["budget_reset_at"] is None:
|
||||
non_default_values["budget_reset_at"] = get_budget_reset_time(
|
||||
budget_duration=non_default_values["budget_duration"]
|
||||
)
|
||||
|
||||
return non_default_values
|
||||
|
||||
|
|
|
|||
|
|
@ -2015,6 +2015,7 @@ async def generate_key_helper_fn( # noqa: PLR0915
|
|||
max_budget: Optional[float] = None, # max_budget is used to Budget Per user
|
||||
blocked: Optional[bool] = None,
|
||||
budget_duration: Optional[str] = None, # max_budget is used to Budget Per user
|
||||
budget_reset_at: Optional[datetime] = None, # manual override for initial user/key budget reset time
|
||||
token: Optional[str] = None,
|
||||
key: Optional[
|
||||
str
|
||||
|
|
@ -2076,10 +2077,27 @@ async def generate_key_helper_fn( # noqa: PLR0915
|
|||
else:
|
||||
key_reset_at = get_budget_reset_time(budget_duration=key_budget_duration)
|
||||
|
||||
if budget_duration is None: # one-time budget
|
||||
reset_at = None
|
||||
if budget_reset_at is not None:
|
||||
try:
|
||||
# try to parse budget_reset_at
|
||||
if isinstance(budget_reset_at, datetime):
|
||||
_reset_candidate = budget_reset_at
|
||||
else:
|
||||
_reset_candidate = datetime.fromisoformat(str(budget_reset_at).replace("Z", "+00:00"))
|
||||
# ensure tz-aware datetime
|
||||
if _reset_candidate.tzinfo is None:
|
||||
_reset_candidate = _reset_candidate.replace(tzinfo=timezone.utc)
|
||||
reset_at = _reset_candidate
|
||||
except Exception:
|
||||
if budget_duration is None: # fallback to one-time budget
|
||||
reset_at = None
|
||||
else:
|
||||
reset_at = get_budget_reset_time(budget_duration=budget_duration) # calculate based on budget duration
|
||||
else:
|
||||
reset_at = get_budget_reset_time(budget_duration=budget_duration)
|
||||
if budget_duration is None: # one-time budget
|
||||
reset_at = None
|
||||
else:
|
||||
reset_at = get_budget_reset_time(budget_duration=budget_duration) # calculate based on budget duration
|
||||
|
||||
aliases_json = json.dumps(aliases)
|
||||
config_json = json.dumps(config)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue