File size: 2,975 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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
"""Appointment booking API."""

from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload

from app.db import get_db
from app.models import Appointment, Conversation, Message
from app.schemas import AppointmentResponse, BookAppointmentRequest
from app.services import calcom

router = APIRouter(prefix="/api/appointments", tags=["appointments"])


@router.get("/slots")
async def list_slots() -> dict:
    """List next available slots."""
    slots = await calcom.get_available_slots(3)
    return {"slots": slots}


@router.post("/book", response_model=AppointmentResponse)
async def book_appointment(
    body: BookAppointmentRequest,
    db: AsyncSession = Depends(get_db),
) -> AppointmentResponse:
    """Book a selected slot for a conversation."""
    result = await db.execute(
        select(Conversation)
        .where(Conversation.id == body.conversation_id)
        .options(
            selectinload(Conversation.lead),
            selectinload(Conversation.appointment),
        )
    )
    conv = result.scalar_one_or_none()
    if conv is None:
        raise HTTPException(status_code=404, detail="Not found")

    if conv.appointment is not None:
        raise HTTPException(
            status_code=400, detail="Already booked"
        )

    name = body.attendee_name
    email = body.attendee_email
    if conv.lead:
        name = name or conv.lead.name
        email = email or conv.lead.email

    booked = await calcom.book_slot(
        slot_start=body.slot_start,
        slot_end=body.slot_end,
        attendee_name=name,
        attendee_email=email,
    )

    appt = Appointment(
        conversation_id=conv.id,
        slot_start=booked["slot_start"],
        slot_end=booked["slot_end"],
        attendee_name=name,
        attendee_email=email,
        external_id=booked.get("external_id"),
        status=booked.get("status", "confirmed"),
    )
    conv.appointment_booked = True
    db.add(appt)

    confirm = {
        "en": (
            f"Your meeting is confirmed for "
            f"{body.slot_start}. See you then!"
        ),
        "fr": (
            f"Votre rendez-vous est confirmé pour "
            f"{body.slot_start}. À bientôt !"
        ),
        "ru": (
            f"Встреча подтверждена на {body.slot_start}. "
            f"До связи!"
        ),
    }
    lang = conv.language if conv.language in confirm else "en"
    message = confirm[lang]
    db.add(
        Message(
            conversation_id=conv.id,
            role="assistant",
            content=message,
            language=lang,
            grounded=True,
        )
    )
    await db.commit()
    await db.refresh(appt)

    return AppointmentResponse(
        id=appt.id,
        slot_start=appt.slot_start,
        slot_end=appt.slot_end,
        status=appt.status,
        message=message,
    )