55 lines
2.0 KiB
Python
55 lines
2.0 KiB
Python
from __future__ import annotations
|
|
|
|
from sqlalchemy import func, select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.models.llm_billing.call_attempt import LlmCallAttempt
|
|
from app.models.llm_billing.execution import LlmBillingExecution
|
|
|
|
|
|
async def list_executions_with_calls(
|
|
db: AsyncSession,
|
|
*,
|
|
page: int = 1,
|
|
page_size: int = 20,
|
|
scene_code: str | None = None,
|
|
status: str | None = None,
|
|
user_id: str | None = None,
|
|
) -> tuple[list[dict], int]:
|
|
filters = []
|
|
if scene_code:
|
|
filters.append(LlmBillingExecution.scene_code == scene_code)
|
|
if status:
|
|
filters.append(LlmBillingExecution.status == status)
|
|
if user_id:
|
|
filters.append(LlmBillingExecution.user_id == user_id)
|
|
total_result = await db.execute(select(func.count(LlmBillingExecution.id)).where(*filters))
|
|
total = int(total_result.scalar_one() or 0)
|
|
result = await db.execute(
|
|
select(LlmBillingExecution)
|
|
.where(*filters)
|
|
.order_by(LlmBillingExecution.created_at.desc(), LlmBillingExecution.id.desc())
|
|
.offset((page - 1) * page_size)
|
|
.limit(page_size)
|
|
)
|
|
executions = list(result.scalars().all())
|
|
ids = [item.id for item in executions]
|
|
calls_by_execution: dict[str, list[LlmCallAttempt]] = {item_id: [] for item_id in ids}
|
|
if ids:
|
|
call_result = await db.execute(
|
|
select(LlmCallAttempt)
|
|
.where(LlmCallAttempt.billing_execution_id.in_(ids))
|
|
.order_by(LlmCallAttempt.billing_execution_id, LlmCallAttempt.call_sequence)
|
|
)
|
|
for call in call_result.scalars().all():
|
|
calls_by_execution.setdefault(call.billing_execution_id, []).append(call)
|
|
items = []
|
|
for execution in executions:
|
|
data = {
|
|
column.name: getattr(execution, column.name)
|
|
for column in LlmBillingExecution.__table__.columns
|
|
}
|
|
data["calls"] = calls_by_execution.get(execution.id, [])
|
|
items.append(data)
|
|
return items, total
|