ReplyFlow / app /api /appointments.py
nvikou's picture
Initial commit
582520a verified
Raw History Blame Contribute Delete
2.98 kB
"""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,
)