Automated patient caller for the Pretty Good AI engineering challenge. The bot places an outbound phone call, listens to the test agent, generates realistic patient replies, speaks them back into the call, and saves transcripts.
The app uses Twilio for the outbound phone call and live Media Streams, Deepgram nova-3 for streaming speech-to-text, Anthropic Claude for patient persona responses, and Deepgram Aura TTS for the patient voice. A local FastAPI server exposes Twilio webhook endpoints; during local development, a tunnel such as ngrok makes that server reachable from Twilio.
The live loop is:
Twilio call audio -> FastAPI websocket -> Deepgram STT -> Claude persona -> Deepgram Aura TTS -> Twilio call audio
Create and activate a Python environment:
python -m venv .venv
source .venv/bin/activateInstall dependencies:
pip install -r requirements.txtInstall ffmpeg for audio conversion:
brew install ffmpegCopy the example environment file and fill in real values:
cp .env.example .envRequired environment variables:
ANTHROPIC_API_KEY=
DEEPGRAM_API_KEY=
DEEPGRAM_MODEL=nova-3
DEEPGRAM_TTS_MODEL=aura-asteria-en
TWILIO_ACCOUNT_SID=
TWILIO_AUTH_TOKEN=
TWILIO_PHONE_NUMBER=
TARGET_PHONE_NUMBER=
PUBLIC_URL=
DEEPGRAM_TTS_MODEL is optional. If omitted, the app uses the aura-asteria-en voice.
Start the FastAPI server:
uvicorn server:app --host 0.0.0.0 --port 8000In another terminal, expose it with ngrok:
ngrok http 8000Copy the ngrok HTTPS URL into .env:
PUBLIC_URL=https://your-ngrok-url.ngrok-free.app
Start a real call:
python main.py call --persona scheduler --call-number 1Run a local simulation instead:
python main.py simulate --persona scheduler --call-number 1Available personas:
scheduler # new patient appointment (back pain)
refill # prescription refill (Lisinopril)
cancel # cancel/reschedule existing appointment
insurance # coverage and office hours questions
edge_case # confused caller, unusual requests
urgent # same-day appointment for worsening symptoms
billing # unexpected bill or copay dispute
referral # referral to PT or specialist
results # test or imaging results status
records # medical records transfer request
Transcripts are written to final_calls/transcripts/. After each live call ends, the server automatically:
- Downloads the Twilio recording into
final_calls/recordings/(polls until ready) - Analyzes the transcript with Claude and appends new agent bugs to
bug_report.md
You can still fetch recordings manually:
python download_recordings.py --limit 10Only call the assessment number:
target phone number
Do not commit .env or any API keys.