mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-12 23:01:41 +00:00
feat(proxy): add model_group filter to /spend/logs/v2 endpoint
Add an optional `model_group` query parameter to the `/spend/logs/v2` and `/spend/logs/ui` endpoints, allowing users to filter spend logs by model group. This is consistent with the existing `model` and `model_id` filters and requires no schema changes since `model_group` is already a column in the `LiteLLM_SpendLogs` table. Supersedes #24782 (rebased onto latest main).
This commit is contained in:
parent
26fcbc93e5
commit
19bc1c237e
2 changed files with 72 additions and 0 deletions
|
|
@ -1740,6 +1740,9 @@ async def ui_view_spend_logs( # noqa: PLR0915
|
|||
default=None,
|
||||
description="Filter logs by model ID (litellm model deployment id)",
|
||||
),
|
||||
model_group: Optional[str] = fastapi.Query(
|
||||
default=None, description="Filter logs by model group"
|
||||
),
|
||||
key_alias: Optional[str] = fastapi.Query(
|
||||
default=None, description="Filter logs by key alias"
|
||||
),
|
||||
|
|
@ -1869,6 +1872,9 @@ async def ui_view_spend_logs( # noqa: PLR0915
|
|||
if model_id is not None:
|
||||
where_conditions["model_id"] = model_id
|
||||
|
||||
if model_group is not None:
|
||||
where_conditions["model_group"] = model_group
|
||||
|
||||
# Build metadata filters
|
||||
metadata_filters = []
|
||||
if key_alias is not None:
|
||||
|
|
@ -1992,6 +1998,7 @@ async def ui_view_spend_logs( # noqa: PLR0915
|
|||
("request_id", "request_id"),
|
||||
("model", "model"),
|
||||
("model_id", "model_id"),
|
||||
("model_group", "model_group"),
|
||||
("end_user", "end_user"),
|
||||
]:
|
||||
val = where_conditions.get(wc_key)
|
||||
|
|
|
|||
|
|
@ -1373,6 +1373,71 @@ async def test_ui_view_spend_logs_with_model_id(client, monkeypatch):
|
|||
app.dependency_overrides.pop(ps.user_api_key_auth, None)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_ui_view_spend_logs_with_model_group(client, monkeypatch):
|
||||
"""Test that the model_group query param filters spend logs by model group."""
|
||||
mock_spend_logs = [
|
||||
{
|
||||
"id": "log1",
|
||||
"request_id": "req1",
|
||||
"api_key": "sk-test-key",
|
||||
"user": "test_user_1",
|
||||
"team_id": "team1",
|
||||
"spend": 0.05,
|
||||
"startTime": datetime.datetime.now(timezone.utc).isoformat(),
|
||||
"model": "gpt-3.5-turbo",
|
||||
"model_group": "gpt-3.5-turbo",
|
||||
"status": "success",
|
||||
},
|
||||
{
|
||||
"id": "log2",
|
||||
"request_id": "req2",
|
||||
"api_key": "sk-test-key",
|
||||
"user": "test_user_2",
|
||||
"team_id": "team1",
|
||||
"spend": 0.10,
|
||||
"startTime": datetime.datetime.now(timezone.utc).isoformat(),
|
||||
"model": "gpt-4-0613",
|
||||
"model_group": "gpt-4",
|
||||
"status": "success",
|
||||
},
|
||||
]
|
||||
|
||||
def filter_by_model_group(where):
|
||||
if "model_group" in where and where["model_group"] == "gpt-4":
|
||||
return [mock_spend_logs[1]]
|
||||
return mock_spend_logs
|
||||
|
||||
monkeypatch.setattr(
|
||||
"litellm.proxy.proxy_server.prisma_client",
|
||||
make_ui_spend_logs_mock_prisma(mock_spend_logs, filter_by_model_group),
|
||||
)
|
||||
|
||||
start_date, end_date = _default_date_range()
|
||||
|
||||
app.dependency_overrides[ps.user_api_key_auth] = lambda: UserAPIKeyAuth(
|
||||
user_role=LitellmUserRoles.PROXY_ADMIN
|
||||
)
|
||||
try:
|
||||
response = client.get(
|
||||
"/spend/logs/ui",
|
||||
params={
|
||||
"model_group": "gpt-4",
|
||||
"start_date": start_date,
|
||||
"end_date": end_date,
|
||||
},
|
||||
headers={"Authorization": "Bearer sk-test"},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["total"] == 1
|
||||
assert len(data["data"]) == 1
|
||||
assert data["data"][0]["model_group"] == "gpt-4"
|
||||
finally:
|
||||
app.dependency_overrides.pop(ps.user_api_key_auth, None)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_ui_view_spend_logs_with_key_hash(client, monkeypatch):
|
||||
mock_spend_logs = [
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue