{"slug": "building-an-ai-outbound-calling-agent-on-google-voice-with-python-groq-and", "title": "Building an AI Outbound Calling Agent on Google Voice with Python, Groq and FastAPI", "summary": "A developer built google-voice-dispatch-agent, an open-source Python project that places real outbound calls through Google Voice in a Chrome browser using Selenium automation rather than a telephony API. The agent gates call-state transitions on a configurable minimum ring window, logs every DOM cue and audio-classifier result, and hands connected calls to a FastAPI-managed conversation loop that combines VAD, Groq-generated replies and Edge TTS playback routed through VB-CABLE on Windows. A voicemail classifier runs in the first seconds of a connected call to detect greeting and beep signals before switching to pre-generated voicemail playback.", "body_md": "Most AI voice-agent tutorials begin the same way: sign up for a telephony API, get a webhook when the call connects, then stream audio. **google-voice-dispatch-agent** works differently. It runs real outbound calls through Google Voice in a Chrome browser, and that changes which problems are hard.\n\nThis post walks through how it's built, based on the project's own README. Code: [https://github.com/mafzalkalwardev/google-voice-dispatch-agent](https://github.com/mafzalkalwardev/google-voice-dispatch-agent)\n\nA telephony API tells you when a call is answered. A browser doesn't. You read the page (the DOM), and the page is noisy: banners from the last call stay on screen, call controls can show up before anyone picks up, and voicemail cues can appear while the phone is still ringing.\n\nSo the AI is the easy part. The hard parts are:\n\nThe project is built around a few rules:\n\nThe most important logic is in `src/google_voice.py`. It's a conservative state gate:\n\n`min_ring_seconds` window has to pass before the agent accepts a connected, ended or voicemail transition.`max_ring_seconds` ends the attempt only after the configured ring timeout.\nEvery decision is logged: current state, elapsed ringing time, DOM cues, answered controls, call-active status, voicemail cues, the audio classifier's result and the timeout reason. When something goes wrong, you can see exactly why the agent did what it did.\n\nThe session model and its `CallState` transitions are kept in their own file, `call_session.py`, so state handling can be tested apart from the browser.\n\nOnce a call is confirmed connected, `conversation_loop.py` takes over:\n\n`audio_capture.py` records input and splits it into frames for voice activity detection (VAD), so the agent knows when the other person is talking.`ai_groq.py` generates the reply with Groq.`realtime_tts.py` plays the reply with Edge TTS, with caching, and falls back to pyttsx3.`audio_routing.py` finds Windows audio devices and sends playback into the call. VB-CABLE, sounddevice, soundcard and soundfile handle the audio plumbing.\nTwo details cut down awkward silence. The opening line and the voicemail message are **generated before dialing**, so they're ready the moment the state gate allows them. And `voicemail_detector.py` runs an audio classifier in the first seconds of a connected call, listening for greeting, beep and live-call signals. When it confirms voicemail, the loop hands off to voicemail playback instead of trying to hold a conversation with a recording.\n\nThe README describes this runtime flow:\n\n`.env`, `dialer_config.json`, the contacts and the CRM data.` detect_call_state()` until the call is connected, voicemail, no answer, ended or failed.\n`web_app.py` is a FastAPI app with Jinja2 templates and plain HTML, CSS and JavaScript. From one console an operator can:\n\n`crm.py` handles CRM enrichment and keeps separate archives for connected and failed calls. Contacts come from CSV or XLSX files and settings from JSON.\n\nThe agent is meant to run on a Windows desktop, so:\n\n`desktop_app.py` is the PyInstaller entry point, with a spec file in `packaging/`\n`scripts/` install a desktop shortcut and a Windows Startup shortcut`installer/`\nThe `tests/` folder covers state handling, mock dialing, the CRM, audio helpers, web routes and the realtime loop. It runs with pytest on GitHub Actions. With a browser-driven agent, mock dialing tests are what let you change the state gate without placing real calls.\n\n```\nsrc/\n  main.py               CLI runner, safe test, batch calling\n  google_voice.py       Selenium automation + call-state detection\n  call_session.py       Call session model and CallState transitions\n  conversation_loop.py  Capture, VAD, STT, LLM, TTS, voicemail handoff\n  voicemail_detector.py Greeting/beep/live-call classifier\n  ai_groq.py            Groq responses\n  realtime_tts.py       Edge TTS playback + cache\n  audio_capture.py      Input capture and VAD framing\n  audio_routing.py      Windows device discovery and routing\n  crm.py                CRM, archives, transcripts, recordings\n  web_app.py            FastAPI operator console\n  desktop_app.py        PyInstaller entry point\n```\n\nWhether calling through Google Voice fits your use case is up to you: Google's terms, consent and calling rules in your region are yours to check.\n\nSource: [https://github.com/mafzalkalwardev/google-voice-dispatch-agent](https://github.com/mafzalkalwardev/google-voice-dispatch-agent)\n\nMore about the call-state logic: [https://dev.to/mafzalkalwardev/how-my-google-voice-ai-agent-knows-when-to-talk-call-state-detection-groq-and-tts-e5a](https://dev.to/mafzalkalwardev/how-my-google-voice-ai-agent-knows-when-to-talk-call-state-detection-groq-and-tts-e5a)\n\n*Muhammad Afzal Kalwar, Python Automation Engineer & Founder, INDUS Web Agency. Portfolio: [https://mafzalkalwardev.github.io](https://mafzalkalwardev.github.io)*", "url": "https://wpnews.pro/news/building-an-ai-outbound-calling-agent-on-google-voice-with-python-groq-and", "canonical_source": "https://dev.to/mafzalkalwardev/building-an-ai-outbound-calling-agent-on-google-voice-with-python-groq-and-fastapi-1h6p", "published_at": "2026-11-01 02:13:34+00:00", "updated_at": "2026-11-01 02:21:51.998755+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "large-language-models", "ai-products"], "entities": ["Google Voice", "Groq", "FastAPI", "Selenium", "Edge TTS", "VB-CABLE", "PyInstaller", "GitHub"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/building-an-ai-outbound-calling-agent-on-google-voice-with-python-groq-and", "markdown": "https://wpnews.pro/news/building-an-ai-outbound-calling-agent-on-google-voice-with-python-groq-and.md", "text": "https://wpnews.pro/news/building-an-ai-outbound-calling-agent-on-google-voice-with-python-groq-and.txt", "jsonld": "https://wpnews.pro/news/building-an-ai-outbound-calling-agent-on-google-voice-with-python-groq-and.jsonld"}}