{"slug": "how-my-google-voice-ai-agent-knows-when-to-talk-call-state-detection-groq-and", "title": "How My Google Voice AI Agent Knows When to Talk: Call-State Detection, Groq and TTS", "summary": "A developer built the Google Voice Dispatch Agent, an MIT-licensed outbound AI calling console for Windows that drives Google Voice inside a real Chrome window via Selenium rather than a telephony API. The project's core is a conservative call-state gate in src/google_voice.py that enforces a minimum ring time before accepting connected, ended or voicemail transitions and logs every decision, after which a conversation loop handles VAD-based audio capture, Groq-backed replies and Edge TTS playback with caching and a pyttsx3 fallback.", "body_md": "Most AI voice demos start with a telephony API. You get webhooks, clean call events and an audio stream, and the interesting problem is the conversation.\n\nMy Google Voice Dispatch Agent doesn't get any of that. It drives Google Voice inside a real Chrome window, and that changes where the hard work is. The AI reply turned out to be the easy part. The hard part was knowing, with confidence, whether someone had actually picked up.\n\nThis post walks through how the agent is put together, based on what's in the repo.\n\nRepo: [https://github.com/mafzalkalwardev/google-voice-dispatch-agent](https://github.com/mafzalkalwardev/google-voice-dispatch-agent) (MIT licensed)\n\nIn short, it's an outbound AI calling console for Windows:\n\nThe README describes the flow in ten steps, and I'll keep it close to that:\n\n`.env`, `dialer_config.json`, contacts and CRM data.` detect_call_state()` until connected, voicemail, no answer, ended or failed.\nStep 4 is small but matters a lot. If you generate the greeting after someone says \"hello\", they hear dead air and hang up. Pre-generating it means the agent can talk the moment the call is confirmed.\n\nHere's the thing about automating a web UI: the DOM is noisy. Buttons appear early, old \"call ended\" banners linger, and voicemail-looking cues can show up while the phone is still ringing. If you trust the first signal you see, the bot either talks over the ring tone or hangs up on a real person.\n\nSo the core of the project is a conservative gate in `src/google_voice.py`. The rules it enforces:\n\n`min_ring_seconds` has to pass before connected, ended or voicemail transitions are accepted.`max_ring_seconds` ends the attempt as no answer only after the ring timeout.\nEvery decision is logged too: current state, elapsed ring time, DOM cues, answered controls, call-active status, voicemail cues, the audio classifier result and the timeout reason. When a call goes wrong, I can read exactly why the agent thought what it thought.\n\nThe design principles in the README sum it up:\n\nOnce the gate says \"connected\", `conversation_loop.py` takes over. The modules split up cleanly:\n\n```\nsrc/\n  google_voice.py          Selenium Google Voice automation and call-state detection\n  call_session.py          Call session model and CallState transitions\n  conversation_loop.py     Realtime capture, VAD, STT, LLM, TTS, voicemail handoff\n  voicemail_detector.py    Audio classifier for greeting/beep/live-call signals\n  ai_groq.py               Groq-backed AI response behavior\n  realtime_tts.py          Edge TTS playback and cache integration\n  audio_capture.py         Input capture and VAD framing\n  audio_routing.py         Windows audio-device discovery and playback routing\n```\n\nThe loop works like this:\n\n`audio_capture.py` captures the caller's audio and frames it for voice activity detection, so the agent knows when the person has started and stopped talking.`ai_groq.py` generates the reply.`realtime_tts.py` speaks it with Edge TTS, with caching, and pyttsx3 as a fallback.\nSeveral knobs in `dialer_config.json` relate directly to this loop:\n\n```\n{\n  \"min_ring_seconds\": 2,\n  \"max_ring_seconds\": 45,\n  \"voicemail_detect_seconds\": 15,\n  \"silence_does_not_end_call\": true,\n  \"call_cooldown_seconds\": 10,\n  \"tts_warmup\": true,\n  \"stt_retry_count\": 2,\n  \"vad_silence_frames\": 12,\n  \"vad_speech_frames\": 2\n}\n```\n\n`silence_does_not_end_call` is a nice example of a lesson baked into config: people go quiet on the phone, and that shouldn't be read as a hang-up.\n\nThe minimum VB-CABLE setup from the README:\n\n`CABLE Input`\n`CABLE Output`\nFor unattended runs, the README recommends separate routes for TTS and inbound capture, and warns against capturing the same speaker output that plays the agent's voice. Otherwise the agent can end up transcribing itself. `CAPTURE_DEVICE=default` uses Windows speaker loopback, which is fine for testing but less reliable for nonstop calling.\n\nThere are CLI helpers for checking this before going live:\n\n```\npython -m src.main --list-audio-devices\npython -m src.main --audio-route-test\npython -m src.main --preflight\n```\n\nThe agent can also run more than one line. Each worker gets its own Chrome profile and pulls from one shared contact queue. The important safety rule: shared audio routes are rejected by default, \"because one AI response would otherwise be broadcast into multiple calls.\" Each slot needs its own loopback and capture pair, like `CABLE-A` and `CABLE-B`.\n\nGoogle Voice accounts can be managed from the console. Saved passwords are protected with Windows DPAPI and never returned by the web API, and MFA or CAPTCHA challenges still have to be completed by a human in the visible Chrome window.\n\nAnd please: anything that dials real people needs consent, Do Not Call compliance and call-recording disclosure where required. The README also recommends keeping `min_ring_seconds` above zero, using a cooldown, and not rapid-firing failed numbers.\n\nIf you're working on voice agents on top of tools you already use, I'd like to hear what broke first for you.\n\nOpen to freelance & remote work\n\nPortfolio: [https://mafzalkalwardev.github.io/#hire-me](https://mafzalkalwardev.github.io/#hire-me)\n\nGitHub: [https://github.com/mafzalkalwardev](https://github.com/mafzalkalwardev)\n\nWhatsApp: +92 307 9670503 — [https://wa.me/923079670503](https://wa.me/923079670503)", "url": "https://wpnews.pro/news/how-my-google-voice-ai-agent-knows-when-to-talk-call-state-detection-groq-and", "canonical_source": "https://dev.to/mafzalkalwardev/how-my-google-voice-ai-agent-knows-when-to-talk-call-state-detection-groq-and-tts-e5a", "published_at": "2026-10-29 22:34:41+00:00", "updated_at": "2026-10-29 22:47:53.668441+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "natural-language-processing"], "entities": ["Google Voice", "Groq", "Edge TTS", "Selenium", "pyttsx3", "VB-CABLE", "Chrome", "Windows"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/how-my-google-voice-ai-agent-knows-when-to-talk-call-state-detection-groq-and", "markdown": "https://wpnews.pro/news/how-my-google-voice-ai-agent-knows-when-to-talk-call-state-detection-groq-and.md", "text": "https://wpnews.pro/news/how-my-google-voice-ai-agent-knows-when-to-talk-call-state-detection-groq-and.txt", "jsonld": "https://wpnews.pro/news/how-my-google-voice-ai-agent-knows-when-to-talk-call-state-detection-groq-and.jsonld"}}