Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions litellm/proxy/spend_tracking/spend_management_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
),
Expand Down Expand Up @@ -1871,6 +1874,9 @@ def parse_date(date_str: str) -> datetime:
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:
Expand Down Expand Up @@ -1994,6 +2000,7 @@ def parse_date(date_str: str) -> datetime:
("request_id", "request_id"),
("model", "model"),
("model_id", "model_id"),
("model_group", "model_group"),
("end_user", "end_user"),
]:
val = where_conditions.get(wc_key)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1621,6 +1621,71 @@ def filter_by_model_id(where):
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 = [
Expand Down
Loading