ReplyFlow / app /api /dashboard.py
nvikou's picture
Initial commit
582520a verified
Raw History Blame Contribute Delete
2.72 kB
"""Dashboard metrics API."""
from fastapi import APIRouter, Depends
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession
from app.db import get_db
from app.models import Conversation, Lead, UnansweredQuestion
from app.schemas import DashboardStats
router = APIRouter(prefix="/api/dashboard", tags=["dashboard"])
@router.get("/stats", response_model=DashboardStats)
async def dashboard_stats(
db: AsyncSession = Depends(get_db),
) -> DashboardStats:
"""Aggregate KPIs for the operator dashboard."""
total = await db.scalar(
select(func.count(Conversation.id))
) or 0
resolved = await db.scalar(
select(func.count(Conversation.id)).where(
Conversation.resolved_without_human.is_(True)
)
) or 0
appointments = await db.scalar(
select(func.count(Conversation.id)).where(
Conversation.appointment_booked.is_(True)
)
) or 0
handed = await db.scalar(
select(func.count(Conversation.id)).where(
Conversation.handed_off.is_(True)
)
) or 0
unanswered = await db.scalar(
select(func.count(UnansweredQuestion.id))
) or 0
leads_complete = await db.scalar(
select(func.count(Lead.id)).where(Lead.complete.is_(True))
) or 0
channel_rows = (
await db.execute(
select(
Conversation.channel,
func.count(Conversation.id),
).group_by(Conversation.channel)
)
).all()
language_rows = (
await db.execute(
select(
Conversation.language,
func.count(Conversation.id),
).group_by(Conversation.language)
)
).all()
recent = (
await db.execute(
select(UnansweredQuestion)
.order_by(UnansweredQuestion.created_at.desc())
.limit(10)
)
).scalars().all()
rate = (resolved / total * 100.0) if total else 0.0
return DashboardStats(
total_conversations=int(total),
resolved_without_human=int(resolved),
resolution_rate=round(rate, 1),
appointments_booked=int(appointments),
handed_off=int(handed),
unanswered_count=int(unanswered),
leads_complete=int(leads_complete),
by_channel={c: int(n) for c, n in channel_rows},
by_language={lang: int(n) for lang, n in language_rows},
recent_unanswered=[
{
"id": q.id,
"conversation_id": q.conversation_id,
"question": q.question,
"created_at": q.created_at.isoformat(),
}
for q in recent
],
)