13. Appointment Scheduling

Chapter 13 of 18 · 20 min

Appointment scheduling involves matching patient needs with provider availability. AI assistance can match patients to appropriate visit types, suggest optimal times based on urgency, and handle routine scheduling requests.

Local AI enables scheduling interfaces that understand natural language requests, extract scheduling parameters, and interface with scheduling systems—all without patient data leaving the organization.

# appointment_scheduler.py
from dataclasses import dataclass
from typing import Optional, List
from datetime import datetime, timedelta
from enum import Enum

class VisitType(Enum):
    ROUTINE = "routine"
    URGENT = "urgent"
    FOLLOW_UP = "follow_up"
    WELLNESS = "wellness"
    PROCEDURE = "procedure"

@dataclass
class SchedulingRequest:
    patient_id: str
    visit_type: VisitType
    preferred_provider: Optional[str]
    preferred_dates: List[datetime]
    duration_minutes: int
    reason: str
    urgency_score: int  # 1-5, higher = more urgent

class AppointmentScheduler:
    """AI-assisted appointment scheduling."""
    
    def __init__(self, ollama_client, schedule_db_connection):
        self.ollama = ollama_client
        self.schedule_db = schedule_db_connection
        
    def parse_scheduling_request(self, text_request: str) -> SchedulingRequest:
        """Parse natural language scheduling request."""
        
        prompt = f"""Extract scheduling parameters from this request.
        
        Request: {text_request}
        
        Return JSON with:
        - visit_type: routine/urgent/follow_up/wellness/procedure
        - preferred_provider: provider name or null
        - preferred_dates: array of dates mentioned (YYYY-MM-DD format)
        - duration_minutes: estimated appointment length
        - reason: brief reason for visit
        - urgency_score: 1-5 where 5 is most urgent"""
        
        response = self.ollama.generate(prompt)
        
        try:
            import json
            data = json.loads(response)
            return SchedulingRequest(
                patient_id=data.get("patient_id", ""),
                visit_type=VisitType(data.get("visit_type", "routine")),
                preferred_provider=data.get("preferred_provider"),
                preferred_dates=[datetime.fromisoformat(d) for d in data.get("preferred_dates", [])],
                duration_minutes=data.get("duration_minutes", 30),
                reason=data.get("reason", ""),
                urgency_score=data.get("urgency_score", 3)
            )
        except:
            return self._fallback_parse(text_request)
    
    def suggest_appointments(self, request: SchedulingRequest) -> List[dict]:
        """Suggest optimal appointment slots."""
        
        # Get available slots
        available_slots = self._get_available_slots(
            request.visit_type,
            request.preferred_provider,
            request.preferred_dates,
            request.duration_minutes
        )
        
        # Rank by urgency and patient preference
        ranked_slots = self._rank_slots(available_slots, request)
        
        return ranked_slots
    
    def confirm_appointment(self, slot_id: str, patient_id: str) -> dict:
        """Confirm and book appointment."""
        
        # Verify slot still available
        slot = self._get_slot(slot_id)
        if not slot or slot["booked"]:
            return {"success": False, "error": "Slot no longer available"}
        
        # Book slot
        confirmation = self._book_slot(slot_id, patient_id)
        
        return {
            "success": True,
            "confirmation_number": confirmation["confirmation_id"],
            "datetime": slot["datetime"],
            "provider": slot["provider"],
            "location": slot["location"],
            "preparation_instructions": self._generate_prep_instructions(slot)
        }
    
    def handle_reschedule(self, current_appointment_id: str,
                          new_preferences: dict) -> dict:
        """Handle appointment rescheduling."""
        
        current = self._get_appointment(current_appointment_id)
        
        # Parse new preferences
        new_request = SchedulingRequest(
            patient_id=current["patient_id"],
            visit_type=VisitType(current["visit_type"]),
            preferred_provider=new_preferences.get("provider"),
            preferred_dates=new_preferences.get("dates", []),
            duration_minutes=current["duration"],
            reason="Reschedule",
            urgency_score=3
        )
        
        # Suggest new slots
        suggestions = self.suggest_appointments(new_request)
        
        return {
            "current_appointment": current,
            "suggested_slots": suggestions[:5]
        }
    
    def _get_available_slots(self, visit_type: VisitType,
                              provider: Optional[str],
                              preferred_dates: List[datetime],
                              duration: int) -> List[dict]:
        """Query schedule database for available slots."""
        # Implementation queries schedule database
        return []
    
    def _rank_slots(self, slots: List[dict], 
                    request: SchedulingRequest) -> List[dict]:
        """Rank appointment slots by fit with patient needs."""
        
        prompt = f"""Rank these appointment slots for the patient.
        Consider: urgency (higher urgency = sooner preference), 
        patient preference dates, provider preference.
        
        Patient urgency score: {request.urgency_score}
        Preferred dates: {[d.isoformat() for d in request.preferred_dates]}
        Preferred provider: {request.preferred_provider}
        
        Slots: {slots}
        
        Return ranked list with ranking explanation."""
        
        response = self.ollama.generate(prompt)
        # Parse and return ranked slots
        return slots
    
    def _get_slot(self, slot_id: str) -> dict:
        """Get slot details from schedule database."""
        pass
    
    def _book_slot(self, slot_id: str, patient_id: str) -> dict:
        """Book appointment slot."""
        pass
    
    def _generate_prep_instructions(self, slot: dict) -> str:
        """Generate appointment preparation instructions."""
        pass

Scheduling systems handle protected health information (appointment reason, provider seen). Local AI parsing keeps this data on-premises. Integration requires careful API design to prevent timing attacks that could infer health conditions from scheduling patterns.

EXERCISE

Design a scheduling conversation flow that handles: initial booking, rescheduling, cancellation, and waitlist management. Implement the natural language parsing component and test with 20 varied scheduling requests.