File size: 2,720 Bytes
582520a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
"""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
        ],
    )