A conversational AI voice agent that books appointments, supports live monitoring, and performs warm transfers to human agents via Twilio.
πΉ Watch the full demo on Loom
Caller (Browser) βββΊ LiveKit Room βββ Python Agent (LiveKit Agents SDK)
β
βββββββββββββ΄ββββββββββββ
Groq API Twilio API
(LLM + STT + TTS) (warm transfer)
β
call_state.json
β
Monitor Dashboard (polls every 1s)
| Layer | Technology |
|---|---|
| Voice Agent | Python, LiveKit Agents SDK v1.6 |
| LLM | Groq β Llama 3.3 70B |
| STT | Groq β Whisper Large v3 Turbo |
| TTS | Cartesia |
| Frontend | Next.js 14, Tailwind CSS, LiveKit JS SDK |
| Telephony | Twilio (outbound call for warm transfer) |
| Storage | JSON files (appointments + call state) |
- Voice conversation β natural back-and-forth with AI receptionist "Alex"
- Appointment booking β collects name, reason, date/time, phone; checks availability; confirms and stores booking
- Live monitor dashboard β real-time transcript, agent state, and appointment details via polling (no auth required, no mic access)
- Warm transfer β triggered by keywords (billing, complaint, talk to a human); Twilio calls a real phone number, speaks a summary, connects on accept
- Post-call summary β Groq LLM summarizes the full conversation when call ends
- Node.js 18+
- Python 3.11β3.13 (3.14 may have dependency issues)
- ffmpeg β
brew install ffmpeg
git clone https://github.com/Keyur279/voice-agent.git
cd voice-agent
cp .env.example .env
# Fill in all values in .envcd backend
python3 -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txt
pip install livekit-plugins-cartesiacd frontend
npm installCreate a .env file in the root with:
# LiveKit Cloud β cloud.livekit.io
LIVEKIT_URL=wss://your-project.livekit.cloud
LIVEKIT_API_KEY=APIxxxxxxx
LIVEKIT_API_SECRET=your_api_secret
# Groq β console.groq.com (free)
GROQ_API_KEY=gsk_xxxxxxx
# Cartesia β play.cartesia.ai (free tier)
CARTESIA_API_KEY=sk_car_xxxxxxx
# Twilio β twilio.com (free trial)
TWILIO_ACCOUNT_SID=ACxxxxxxx
TWILIO_AUTH_TOKEN=your_auth_token
TWILIO_PHONE_NUMBER=+1xxxxxxxxxx # your purchased Twilio number
TRANSFER_TARGET_NUMBER=+91xxxxxxxxxx # phone to ring on warm transfercd backend
source venv/bin/activate
python server.pyRuns on http://localhost:8000
cd backend
source venv/bin/activate
python agent.py devcd frontend
npm run devRuns on http://localhost:3000
- Open http://localhost:3000
- Click Start Call, allow microphone
- Wait for Alex to greet you (~2 seconds)
- Say: "Hi, I'd like to book an appointment"
- Answer questions: name β reason β date/time β phone number
- Alex confirms and reads back the booking
Verify booking: http://localhost:8000/api/appointments
- Open http://localhost:3000/monitor in a separate tab
- Start a call in the first tab
- Watch transcript and agent state update live in the monitor tab (no login, no mic needed)
During a call, say any of:
- "I have a billing complaint"
- "I want to talk to a human"
- "Can I speak to a real person"
- "I want to speak to a manager"
Alex says "please hold" β your phone (TRANSFER_TARGET_NUMBER) rings from the Twilio number β call speaks a summary and asks to press 1 (accept) or 2 (decline).
Click Disconnect after any call. The summary appears automatically in the monitor dashboard.
- Caller clicks "Start Call" β gets a LiveKit token β joins the room
- Python agent connects to the same room and greets the caller
- Groq Whisper transcribes speech β Llama 3.3 generates responses
- Agent collects: name, reason, preferred date/time, contact number
check_availabilitytool confirms the slot is freebook_appointmenttool stores the booking inappointments.json- Agent reads the confirmation ID back to the caller
- Watcher opens
/monitorβ no login, no microphone access - Page polls
/api/call-stateevery second - Agent writes transcript, state, and appointment events to
call_state.json - Dashboard updates in real time with transcript, agent state, and booking details
- Caller mentions billing, complaint, or asks for a human
- Intent detected via keyword matching in the transcript
- Groq generates a short call summary
- Agent says "please hold" β Twilio dials
TRANSFER_TARGET_NUMBER - Twilio plays the summary and asks human agent to press 1 (accept) or 2 (decline)
- If accepted: agent tells caller they're connected and exits
- If declined: agent returns to caller β "our team isn't available right now"
- Generated by Groq LLM (Llama 3.3) from the full conversation transcript
- Written to
call_state.jsonwhen the call ends - Displayed automatically in the monitor dashboard
voice-agent/
βββ .env.example
βββ .gitignore
βββ README.md
βββ backend/
β βββ requirements.txt # Python dependencies
β βββ agent.py # LiveKit voice agent β conversation, booking, transfer
β βββ tools.py # check_availability + book_appointment tool calls
β βββ transfer.py # Twilio warm transfer logic
β βββ prompts.py # System prompt + summary prompt
β βββ server.py # FastAPI β token API, call state, appointments
βββ frontend/
βββ app/
β βββ page.tsx # Caller UI β Start Call, visualizer, disconnect
β βββ monitor/page.tsx # Monitor dashboard β transcript, state, summary
βββ components/
β βββ AgentStatus.tsx # Listening/Thinking/Speaking indicator
β βββ TranscriptFeed.tsx # Scrolling transcript bubbles
β βββ TakeoverButton.tsx # (available for future watcher takeover)
βββ lib/livekit.ts # Token fetch + event parsing helpers