wavoice 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
wavoice-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,254 @@
1
+ Metadata-Version: 2.3
2
+ Name: wavoice
3
+ Version: 0.1.0
4
+ Summary: One-command WhatsApp Voice AI with Pipecat and automated Cloudflare Quick Tunnels
5
+ Author: Amit Bhakt
6
+ Author-email: Amit Bhakt <yashubhakt@gmail.com>
7
+ Requires-Dist: aiohttp>=3.14.5
8
+ Requires-Dist: fastapi>=0.143.0
9
+ Requires-Dist: loguru>=0.7.3
10
+ Requires-Dist: pipecat-ai[google,webrtc]>=1.12.0
11
+ Requires-Dist: pydantic>=2.14.1
12
+ Requires-Dist: pydantic-settings>=2.15.0
13
+ Requires-Dist: python-dotenv>=1.2.4
14
+ Requires-Dist: rich>=15.0.0
15
+ Requires-Dist: typer>=0.27.3
16
+ Requires-Dist: uvicorn[standard]>=0.54.0
17
+ Requires-Python: >=3.12
18
+ Description-Content-Type: text/markdown
19
+
20
+ # WAVoice: Set Up WhatsApp Voice AI in 90 Seconds
21
+
22
+ [![Python 3.12](https://img.shields.io/badge/python-3.12-blue.svg)](https://www.python.org/)
23
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
24
+ [![Powered by Pipecat](https://img.shields.io/badge/powered%20by-Pipecat-green.svg)](https://github.com/pipecat-ai/pipecat)
25
+ [![Author: Amit Bhakt](https://img.shields.io/badge/creator-Amit%20Bhakt-orange.svg)](https://github.com/amitbhakt)
26
+
27
+ > **The zero-friction, one-command pipeline for WhatsApp Voice AI.**
28
+ > Go from zero to an active AI voice agent answering live WhatsApp calls in under **90 seconds**. No manual Meta dashboard clicking, no ngrok account setup, and no WebRTC configuration required.
29
+
30
+ Created by [Amit Bhakt](https://github.com/amitbhakt), `WAVoice` solves the hardest part of building WhatsApp voice agents: **the entire telephony and networking plumbing**.
31
+
32
+ ---
33
+
34
+ ## Why Developers Use WAVoice
35
+
36
+ Setting up WhatsApp voice calling traditionally requires hours of manual work: navigating Meta Business Manager, registering phone number IDs, manually creating ngrok tunnels, pasting webhook verification tokens, handling WebRTC SDP offer/answers, and diagnosing why audio drops over NAT.
37
+
38
+ **`WAVoice` collapses all of that into a single 90-second command (`wavoice init`):**
39
+
40
+ 1. **Automated Cloudflare Quick Tunnel**: Ephemeral public HTTPS TLS gateway with zero tokens or account sign-ups.
41
+ 2. **Auto-Discovery**: Extracts your WABA ID and Phone Number ID directly from your token via Meta Graph API.
42
+ 3. **Programmatic Calling Activation**: Enables WhatsApp Voice Calling and makes the Call button visible automatically.
43
+ 4. **Full 3-Tier Webhook Sync**: Programmatically configures Phone Number overrides, WABA subscriptions, and App subscriptions.
44
+ 5. **Production WebRTC Infrastructure**: Pre-configured STUN/TURN, SRTP audio handling, and atomic call claim locks (preventing duplicate webhook deliveries).
45
+
46
+ ---
47
+
48
+ ## How It Works: Instant Testing vs. Custom Pipelines
49
+
50
+ Whether you want a complete out-of-the-box agent or a custom multi-model architecture, `WAVoice` separates the **telephony infrastructure** from your **AI logic**:
51
+
52
+ ```
53
+ ┌────────────────────────────────────────┐
54
+ │ Telephony Infrastructure Layer │
55
+ │ (Handled automatically by WAVoice) │
56
+ │ │
57
+ │ - Cloudflare Quick Tunnel │
58
+ │ - Meta Graph API Webhooks │
59
+ │ - WebRTC SDP Offer / Answer │
60
+ │ - SRTP Audio Stream Decoupling │
61
+ └───────────────────┬────────────────────┘
62
+ │
63
+ ┌───────────────────┴────────────────────┐
64
+ ▼ ▼
65
+ ┌─────────────────────────────────┐ ┌─────────────────────────────────┐
66
+ │ Mode A: Out-of-the-Box (90s) │ │ Mode B: Custom Layers │
67
+ │ │ │ (Pluggable Pipecat Pipeline) │
68
+ │ Run: `wavoice start` │ │ │
69
+ │ Native Speech-to-Speech via │ │ - STT: Deepgram, Whisper, Groq │
70
+ │ Gemini 2.0 Flash Live │ │ - LLM: OpenAI, Claude, Ollama │
71
+ │ (~300ms latency, zero code) │ │ - TTS: Cartesia, ElevenLabs │
72
+ └─────────────────────────────────┘ └─────────────────────────────────┘
73
+ ```
74
+
75
+ ### How does the one-command setup help developers who want separate layers?
76
+ When you want to build a cascaded stack (**STT $\rightarrow$ LLM $\rightarrow$ TTS**), you still face the exact same frustrating hurdle: connecting WhatsApp's WebRTC audio stream to your server.
77
+
78
+ By running `wavoice init`, **your WhatsApp number and webhook plumbing are 100% configured in 90 seconds**. Then, instead of maintaining complex SIP/WebRTC servers, you simply write standard, modular Python:
79
+
80
+ ```python
81
+ from wavoice import WhatsAppVoiceApp
82
+
83
+ app = WhatsAppVoiceApp()
84
+
85
+ @app.on_call
86
+ async def handle_call(transport, call_info):
87
+ # 'transport' already receives raw audio from WhatsApp WebRTC
88
+ # Plug in any separate STT, LLM, or TTS processor:
89
+ pipeline = Pipeline([
90
+ transport.input(),
91
+ DeepgramSTTService(...),
92
+ OpenAILLMService(...),
93
+ CartesiaTTSService(...),
94
+ transport.output(),
95
+ ])
96
+ ...
97
+ ```
98
+
99
+ ---
100
+
101
+ ## 90-Second Quickstart
102
+
103
+ ### Step 1: Install
104
+ ```bash
105
+ git clone https://github.com/amitbhakt/wavoice.git
106
+ cd wavoice
107
+ uv sync
108
+ ```
109
+ *(Or install via `pip install wavoice`)*
110
+
111
+ ### Step 2: One-Command Setup
112
+ ```bash
113
+ uv run wavoice init
114
+ ```
115
+
116
+ The interactive wizard asks for only 3 credentials:
117
+ 1. `WHATSAPP_TOKEN`: Meta System User access token.
118
+ 2. `WHATSAPP_APP_SECRET`: Meta App Secret.
119
+ 3. `GEMINI_API_KEY`: Google Gemini API key.
120
+
121
+ `WAVoice` automatically discovers your business accounts, activates WhatsApp voice calling, saves `.env`, and starts the server immediately.
122
+
123
+ ### Step 3: Dial & Talk
124
+ Open WhatsApp on your phone and dial your business number. Your AI agent answers immediately.
125
+
126
+ ---
127
+
128
+ ## Pre-Flight Diagnostics
129
+
130
+ To inspect your setup, token scopes, voice calling flags, and webhook routing tiers at any time:
131
+
132
+ ```bash
133
+ uv run wavoice doctor
134
+ ```
135
+
136
+ Output:
137
+ ```text
138
+ ╦ ╦╔═╗╦ ╦╔═╗╦╔═╗╔═╗ WAVoice v0.1.0
139
+ ║║║╠═╣╚╗╔╝║ ║║║ ║╣ One-command WhatsApp Voice AI runtime
140
+ ╚╩╝╩ ╩ ╚╝ ╚═╝╩╚═╝╚═╝
141
+
142
+ ╭────────────────────────────────╮
143
+ │ WAVoice Pre-Flight Diagnostics │
144
+ ╰────────────────────────────────╯
145
+ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
146
+ ┃ Check ┃ Status ┃ Details ┃
147
+ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
148
+ │ Meta Credentials │ PASS │ Token & Phone ID configured │
149
+ │ Phone Number Reachability │ PASS │ Verified number: +1 555-188 │
150
+ │ WhatsApp Voice Calling API │ PASS │ Voice calling is ENABLED │
151
+ │ Tier 1: Phone Override │ ACTIVE │ Cloudflare Tunnel Verified │
152
+ │ Tier 2: WABA Subscription │ ACTIVE │ Webhook Subscribed │
153
+ │ Tier 3: App Subscriptions │ ACTIVE │ calls, messages Active │
154
+ │ Default AI Agent │ PASS │ Gemini 2.0 Flash Live ready │
155
+ └────────────────────────────────┴──────────────┴──────────────────────────────┘
156
+ ```
157
+
158
+ ---
159
+
160
+ ## Building Custom Multi-Model Pipelines
161
+
162
+ For developers building with independent STT, LLM, and TTS providers, `WAVoice` exposes the complete [Pipecat](https://github.com/pipecat-ai/pipecat) pipeline:
163
+
164
+ ```python
165
+ import os
166
+ from wavoice import WhatsAppVoiceApp
167
+ from pipecat.audio.vad.silero import SileroVADAnalyzer
168
+ from pipecat.pipeline.pipeline import Pipeline
169
+ from pipecat.pipeline.runner import PipelineRunner
170
+ from pipecat.pipeline.task import PipelineParams, PipelineTask
171
+ from pipecat.processors.aggregators.llm_context import LLMContext
172
+ from pipecat.processors.aggregators.llm_response_universal import (
173
+ LLMContextAggregatorPair,
174
+ LLMUserAggregatorParams,
175
+ )
176
+ from pipecat.services.deepgram import DeepgramSTTService
177
+ from pipecat.services.openai import OpenAILLMService
178
+ from pipecat.services.cartesia import CartesiaTTSService
179
+
180
+ app = WhatsAppVoiceApp()
181
+
182
+ @app.on_call
183
+ async def handle_incoming_call(transport, call_info):
184
+ caller = getattr(call_info, "from_", "caller")
185
+ print(f"Incoming call from {caller}")
186
+
187
+ # 1. Custom Layer Services
188
+ stt = DeepgramSTTService(api_key=os.environ["DEEPGRAM_API_KEY"])
189
+ llm = OpenAILLMService(api_key=os.environ["OPENAI_API_KEY"], model="gpt-4o-mini")
190
+ tts = CartesiaTTSService(api_key=os.environ["CARTESIA_API_KEY"], voice_id="...")
191
+
192
+ # 2. Context Aggregation & Silero Turn Detection
193
+ context = LLMContext([{"role": "system", "content": "You are a concise voice assistant."}])
194
+ user_agg, assistant_agg = LLMContextAggregatorPair(
195
+ context,
196
+ user_params=LLMUserAggregatorParams(vad_analyzer=SileroVADAnalyzer()),
197
+ )
198
+
199
+ # 3. Assemble Pipeline
200
+ pipeline = Pipeline([
201
+ transport.input(), # WebRTC Audio In from WhatsApp
202
+ stt, # Speech-to-Text
203
+ user_agg, # Turn Aggregator
204
+ llm, # Large Language Model
205
+ tts, # Text-to-Speech
206
+ transport.output(), # WebRTC Audio Out to WhatsApp
207
+ assistant_agg,
208
+ ])
209
+
210
+ task = PipelineTask(pipeline=pipeline, params=PipelineParams(allow_interruptions=True))
211
+ runner = PipelineRunner()
212
+ await runner.run(task)
213
+
214
+ if __name__ == "__main__":
215
+ app.run() # Launches tunnel, registers Meta webhooks, and serves pipeline
216
+ ```
217
+
218
+ *(See [examples/custom_stt_llm_tts.py](examples/custom_stt_llm_tts.py) for the complete runnable file)*
219
+
220
+ ---
221
+
222
+ ## CLI Command Reference
223
+
224
+ | Command | Description |
225
+ | :--- | :--- |
226
+ | `wavoice init` | Complete 90-second setup: prompts for 3 credentials, auto-discovers IDs, turns on voice calling, and launches. Pass `--no-telemetry` to opt out of usage metrics. |
227
+ | `wavoice doctor` | Runs diagnostics across Meta credentials, calling status, and 3-tier webhooks. |
228
+ | `wavoice start` | Starts the server, establishes the Cloudflare tunnel, and begins accepting calls. Pass `--no-telemetry` to run with telemetry disabled. |
229
+
230
+ ---
231
+
232
+ ## Technical Details
233
+
234
+ - **WebRTC Protocol**: WhatsApp Calling exchanges SDP offers/answers over HTTPS and streams media via SRTP over UDP. `WAVoice` uses `aiortc` and Pipecat's `SmallWebRTCTransport` to negotiate codecs and stream PCM audio.
235
+ - **Webhook Delivery Deduplication**: Meta delivers webhooks at least once, causing race conditions where multiple workers answer the same call. `WAVoice` uses atomic in-memory claiming per `call_id` to guarantee calls are answered exactly once.
236
+ - **Bi-directional Termination**: If the caller hangs up, `WAVoice` tears down the pipeline. If the bot hangs up or times out, `WAVoice` calls `POST /v21.0/{phone_number_id}/calls` with `action: "terminate"` to end the call on the user's phone.
237
+ - **Telemetry & Privacy**: WAVoice collects anonymous usage metrics (command runs, answered calls, and coarse country/timezone) to improve SDK stability. No personal info, phone numbers, tokens, or audio data are ever collected. Telemetry is enabled by default, and you can opt out at any time by:
238
+ - Running `wavoice init --no-telemetry` or `wavoice start --no-telemetry`
239
+ - Setting `WAVOICE_TELEMETRY=false` in `.env`
240
+ - Setting `DO_NOT_TRACK=1` in your environment
241
+
242
+ ---
243
+
244
+ ## Maintainer & Credits
245
+
246
+ Crafted by **Amit Bhakt** ([@amitbhakt](https://github.com/amitbhakt)).
247
+
248
+ Contributions, issues, and feature suggestions are welcome on GitHub at [https://github.com/amitbhakt/wavoice](https://github.com/amitbhakt/wavoice).
249
+
250
+ ---
251
+
252
+ ## License
253
+
254
+ MIT License. Copyright (c) 2026 Amit Bhakt.
@@ -0,0 +1,235 @@
1
+ # WAVoice: Set Up WhatsApp Voice AI in 90 Seconds
2
+
3
+ [![Python 3.12](https://img.shields.io/badge/python-3.12-blue.svg)](https://www.python.org/)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![Powered by Pipecat](https://img.shields.io/badge/powered%20by-Pipecat-green.svg)](https://github.com/pipecat-ai/pipecat)
6
+ [![Author: Amit Bhakt](https://img.shields.io/badge/creator-Amit%20Bhakt-orange.svg)](https://github.com/amitbhakt)
7
+
8
+ > **The zero-friction, one-command pipeline for WhatsApp Voice AI.**
9
+ > Go from zero to an active AI voice agent answering live WhatsApp calls in under **90 seconds**. No manual Meta dashboard clicking, no ngrok account setup, and no WebRTC configuration required.
10
+
11
+ Created by [Amit Bhakt](https://github.com/amitbhakt), `WAVoice` solves the hardest part of building WhatsApp voice agents: **the entire telephony and networking plumbing**.
12
+
13
+ ---
14
+
15
+ ## Why Developers Use WAVoice
16
+
17
+ Setting up WhatsApp voice calling traditionally requires hours of manual work: navigating Meta Business Manager, registering phone number IDs, manually creating ngrok tunnels, pasting webhook verification tokens, handling WebRTC SDP offer/answers, and diagnosing why audio drops over NAT.
18
+
19
+ **`WAVoice` collapses all of that into a single 90-second command (`wavoice init`):**
20
+
21
+ 1. **Automated Cloudflare Quick Tunnel**: Ephemeral public HTTPS TLS gateway with zero tokens or account sign-ups.
22
+ 2. **Auto-Discovery**: Extracts your WABA ID and Phone Number ID directly from your token via Meta Graph API.
23
+ 3. **Programmatic Calling Activation**: Enables WhatsApp Voice Calling and makes the Call button visible automatically.
24
+ 4. **Full 3-Tier Webhook Sync**: Programmatically configures Phone Number overrides, WABA subscriptions, and App subscriptions.
25
+ 5. **Production WebRTC Infrastructure**: Pre-configured STUN/TURN, SRTP audio handling, and atomic call claim locks (preventing duplicate webhook deliveries).
26
+
27
+ ---
28
+
29
+ ## How It Works: Instant Testing vs. Custom Pipelines
30
+
31
+ Whether you want a complete out-of-the-box agent or a custom multi-model architecture, `WAVoice` separates the **telephony infrastructure** from your **AI logic**:
32
+
33
+ ```
34
+ ┌────────────────────────────────────────┐
35
+ │ Telephony Infrastructure Layer │
36
+ │ (Handled automatically by WAVoice) │
37
+ │ │
38
+ │ - Cloudflare Quick Tunnel │
39
+ │ - Meta Graph API Webhooks │
40
+ │ - WebRTC SDP Offer / Answer │
41
+ │ - SRTP Audio Stream Decoupling │
42
+ └───────────────────┬────────────────────┘
43
+ │
44
+ ┌───────────────────┴────────────────────┐
45
+ ▼ ▼
46
+ ┌─────────────────────────────────┐ ┌─────────────────────────────────┐
47
+ │ Mode A: Out-of-the-Box (90s) │ │ Mode B: Custom Layers │
48
+ │ │ │ (Pluggable Pipecat Pipeline) │
49
+ │ Run: `wavoice start` │ │ │
50
+ │ Native Speech-to-Speech via │ │ - STT: Deepgram, Whisper, Groq │
51
+ │ Gemini 2.0 Flash Live │ │ - LLM: OpenAI, Claude, Ollama │
52
+ │ (~300ms latency, zero code) │ │ - TTS: Cartesia, ElevenLabs │
53
+ └─────────────────────────────────┘ └─────────────────────────────────┘
54
+ ```
55
+
56
+ ### How does the one-command setup help developers who want separate layers?
57
+ When you want to build a cascaded stack (**STT $\rightarrow$ LLM $\rightarrow$ TTS**), you still face the exact same frustrating hurdle: connecting WhatsApp's WebRTC audio stream to your server.
58
+
59
+ By running `wavoice init`, **your WhatsApp number and webhook plumbing are 100% configured in 90 seconds**. Then, instead of maintaining complex SIP/WebRTC servers, you simply write standard, modular Python:
60
+
61
+ ```python
62
+ from wavoice import WhatsAppVoiceApp
63
+
64
+ app = WhatsAppVoiceApp()
65
+
66
+ @app.on_call
67
+ async def handle_call(transport, call_info):
68
+ # 'transport' already receives raw audio from WhatsApp WebRTC
69
+ # Plug in any separate STT, LLM, or TTS processor:
70
+ pipeline = Pipeline([
71
+ transport.input(),
72
+ DeepgramSTTService(...),
73
+ OpenAILLMService(...),
74
+ CartesiaTTSService(...),
75
+ transport.output(),
76
+ ])
77
+ ...
78
+ ```
79
+
80
+ ---
81
+
82
+ ## 90-Second Quickstart
83
+
84
+ ### Step 1: Install
85
+ ```bash
86
+ git clone https://github.com/amitbhakt/wavoice.git
87
+ cd wavoice
88
+ uv sync
89
+ ```
90
+ *(Or install via `pip install wavoice`)*
91
+
92
+ ### Step 2: One-Command Setup
93
+ ```bash
94
+ uv run wavoice init
95
+ ```
96
+
97
+ The interactive wizard asks for only 3 credentials:
98
+ 1. `WHATSAPP_TOKEN`: Meta System User access token.
99
+ 2. `WHATSAPP_APP_SECRET`: Meta App Secret.
100
+ 3. `GEMINI_API_KEY`: Google Gemini API key.
101
+
102
+ `WAVoice` automatically discovers your business accounts, activates WhatsApp voice calling, saves `.env`, and starts the server immediately.
103
+
104
+ ### Step 3: Dial & Talk
105
+ Open WhatsApp on your phone and dial your business number. Your AI agent answers immediately.
106
+
107
+ ---
108
+
109
+ ## Pre-Flight Diagnostics
110
+
111
+ To inspect your setup, token scopes, voice calling flags, and webhook routing tiers at any time:
112
+
113
+ ```bash
114
+ uv run wavoice doctor
115
+ ```
116
+
117
+ Output:
118
+ ```text
119
+ ╦ ╦╔═╗╦ ╦╔═╗╦╔═╗╔═╗ WAVoice v0.1.0
120
+ ║║║╠═╣╚╗╔╝║ ║║║ ║╣ One-command WhatsApp Voice AI runtime
121
+ ╚╩╝╩ ╩ ╚╝ ╚═╝╩╚═╝╚═╝
122
+
123
+ ╭────────────────────────────────╮
124
+ │ WAVoice Pre-Flight Diagnostics │
125
+ ╰────────────────────────────────╯
126
+ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
127
+ ┃ Check ┃ Status ┃ Details ┃
128
+ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
129
+ │ Meta Credentials │ PASS │ Token & Phone ID configured │
130
+ │ Phone Number Reachability │ PASS │ Verified number: +1 555-188 │
131
+ │ WhatsApp Voice Calling API │ PASS │ Voice calling is ENABLED │
132
+ │ Tier 1: Phone Override │ ACTIVE │ Cloudflare Tunnel Verified │
133
+ │ Tier 2: WABA Subscription │ ACTIVE │ Webhook Subscribed │
134
+ │ Tier 3: App Subscriptions │ ACTIVE │ calls, messages Active │
135
+ │ Default AI Agent │ PASS │ Gemini 2.0 Flash Live ready │
136
+ └────────────────────────────────┴──────────────┴──────────────────────────────┘
137
+ ```
138
+
139
+ ---
140
+
141
+ ## Building Custom Multi-Model Pipelines
142
+
143
+ For developers building with independent STT, LLM, and TTS providers, `WAVoice` exposes the complete [Pipecat](https://github.com/pipecat-ai/pipecat) pipeline:
144
+
145
+ ```python
146
+ import os
147
+ from wavoice import WhatsAppVoiceApp
148
+ from pipecat.audio.vad.silero import SileroVADAnalyzer
149
+ from pipecat.pipeline.pipeline import Pipeline
150
+ from pipecat.pipeline.runner import PipelineRunner
151
+ from pipecat.pipeline.task import PipelineParams, PipelineTask
152
+ from pipecat.processors.aggregators.llm_context import LLMContext
153
+ from pipecat.processors.aggregators.llm_response_universal import (
154
+ LLMContextAggregatorPair,
155
+ LLMUserAggregatorParams,
156
+ )
157
+ from pipecat.services.deepgram import DeepgramSTTService
158
+ from pipecat.services.openai import OpenAILLMService
159
+ from pipecat.services.cartesia import CartesiaTTSService
160
+
161
+ app = WhatsAppVoiceApp()
162
+
163
+ @app.on_call
164
+ async def handle_incoming_call(transport, call_info):
165
+ caller = getattr(call_info, "from_", "caller")
166
+ print(f"Incoming call from {caller}")
167
+
168
+ # 1. Custom Layer Services
169
+ stt = DeepgramSTTService(api_key=os.environ["DEEPGRAM_API_KEY"])
170
+ llm = OpenAILLMService(api_key=os.environ["OPENAI_API_KEY"], model="gpt-4o-mini")
171
+ tts = CartesiaTTSService(api_key=os.environ["CARTESIA_API_KEY"], voice_id="...")
172
+
173
+ # 2. Context Aggregation & Silero Turn Detection
174
+ context = LLMContext([{"role": "system", "content": "You are a concise voice assistant."}])
175
+ user_agg, assistant_agg = LLMContextAggregatorPair(
176
+ context,
177
+ user_params=LLMUserAggregatorParams(vad_analyzer=SileroVADAnalyzer()),
178
+ )
179
+
180
+ # 3. Assemble Pipeline
181
+ pipeline = Pipeline([
182
+ transport.input(), # WebRTC Audio In from WhatsApp
183
+ stt, # Speech-to-Text
184
+ user_agg, # Turn Aggregator
185
+ llm, # Large Language Model
186
+ tts, # Text-to-Speech
187
+ transport.output(), # WebRTC Audio Out to WhatsApp
188
+ assistant_agg,
189
+ ])
190
+
191
+ task = PipelineTask(pipeline=pipeline, params=PipelineParams(allow_interruptions=True))
192
+ runner = PipelineRunner()
193
+ await runner.run(task)
194
+
195
+ if __name__ == "__main__":
196
+ app.run() # Launches tunnel, registers Meta webhooks, and serves pipeline
197
+ ```
198
+
199
+ *(See [examples/custom_stt_llm_tts.py](examples/custom_stt_llm_tts.py) for the complete runnable file)*
200
+
201
+ ---
202
+
203
+ ## CLI Command Reference
204
+
205
+ | Command | Description |
206
+ | :--- | :--- |
207
+ | `wavoice init` | Complete 90-second setup: prompts for 3 credentials, auto-discovers IDs, turns on voice calling, and launches. Pass `--no-telemetry` to opt out of usage metrics. |
208
+ | `wavoice doctor` | Runs diagnostics across Meta credentials, calling status, and 3-tier webhooks. |
209
+ | `wavoice start` | Starts the server, establishes the Cloudflare tunnel, and begins accepting calls. Pass `--no-telemetry` to run with telemetry disabled. |
210
+
211
+ ---
212
+
213
+ ## Technical Details
214
+
215
+ - **WebRTC Protocol**: WhatsApp Calling exchanges SDP offers/answers over HTTPS and streams media via SRTP over UDP. `WAVoice` uses `aiortc` and Pipecat's `SmallWebRTCTransport` to negotiate codecs and stream PCM audio.
216
+ - **Webhook Delivery Deduplication**: Meta delivers webhooks at least once, causing race conditions where multiple workers answer the same call. `WAVoice` uses atomic in-memory claiming per `call_id` to guarantee calls are answered exactly once.
217
+ - **Bi-directional Termination**: If the caller hangs up, `WAVoice` tears down the pipeline. If the bot hangs up or times out, `WAVoice` calls `POST /v21.0/{phone_number_id}/calls` with `action: "terminate"` to end the call on the user's phone.
218
+ - **Telemetry & Privacy**: WAVoice collects anonymous usage metrics (command runs, answered calls, and coarse country/timezone) to improve SDK stability. No personal info, phone numbers, tokens, or audio data are ever collected. Telemetry is enabled by default, and you can opt out at any time by:
219
+ - Running `wavoice init --no-telemetry` or `wavoice start --no-telemetry`
220
+ - Setting `WAVOICE_TELEMETRY=false` in `.env`
221
+ - Setting `DO_NOT_TRACK=1` in your environment
222
+
223
+ ---
224
+
225
+ ## Maintainer & Credits
226
+
227
+ Crafted by **Amit Bhakt** ([@amitbhakt](https://github.com/amitbhakt)).
228
+
229
+ Contributions, issues, and feature suggestions are welcome on GitHub at [https://github.com/amitbhakt/wavoice](https://github.com/amitbhakt/wavoice).
230
+
231
+ ---
232
+
233
+ ## License
234
+
235
+ MIT License. Copyright (c) 2026 Amit Bhakt.
@@ -0,0 +1,36 @@
1
+ [project]
2
+ name = "wavoice"
3
+ version = "0.1.0"
4
+ description = "One-command WhatsApp Voice AI with Pipecat and automated Cloudflare Quick Tunnels"
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ dependencies = [
8
+ "aiohttp>=3.14.5",
9
+ "fastapi>=0.143.0",
10
+ "loguru>=0.7.3",
11
+ "pipecat-ai[google,webrtc]>=1.12.0",
12
+ "pydantic>=2.14.1",
13
+ "pydantic-settings>=2.15.0",
14
+ "python-dotenv>=1.2.4",
15
+ "rich>=15.0.0",
16
+ "typer>=0.27.3",
17
+ "uvicorn[standard]>=0.54.0",
18
+ ]
19
+
20
+ [[project.authors]]
21
+ name = "Amit Bhakt"
22
+ email = "yashubhakt@gmail.com"
23
+
24
+ [project.scripts]
25
+ wavoice = "wavoice.cli:cli"
26
+
27
+ [build-system]
28
+ requires = ["uv_build>=0.12.13,<0.13.0"]
29
+ build-backend = "uv_build"
30
+
31
+ [dependency-groups]
32
+ dev = [
33
+ "httpx>=0.28.1",
34
+ "pytest>=9.1.1",
35
+ "pytest-asyncio>=1.4.0",
36
+ ]
@@ -0,0 +1,35 @@
1
+ [project]
2
+ name = "wavoice"
3
+ version = "0.1.0"
4
+ description = "One-command WhatsApp Voice AI with Pipecat and automated Cloudflare Quick Tunnels"
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "Amit Bhakt", email = "yashubhakt@gmail.com" }
8
+ ]
9
+ requires-python = ">=3.12"
10
+ dependencies = [
11
+ "aiohttp>=3.14.5",
12
+ "fastapi>=0.143.0",
13
+ "loguru>=0.7.3",
14
+ "pipecat-ai[google,webrtc]>=1.12.0",
15
+ "pydantic>=2.14.1",
16
+ "pydantic-settings>=2.15.0",
17
+ "python-dotenv>=1.2.4",
18
+ "rich>=15.0.0",
19
+ "typer>=0.27.3",
20
+ "uvicorn[standard]>=0.54.0",
21
+ ]
22
+
23
+ [project.scripts]
24
+ wavoice = "wavoice.cli:cli"
25
+
26
+ [build-system]
27
+ requires = ["uv_build>=0.12.13,<0.13.0"]
28
+ build-backend = "uv_build"
29
+
30
+ [dependency-groups]
31
+ dev = [
32
+ "httpx>=0.28.1",
33
+ "pytest>=9.1.1",
34
+ "pytest-asyncio>=1.4.0",
35
+ ]
@@ -0,0 +1,7 @@
1
+ """wa-voice: One-command WhatsApp Voice AI with Pipecat."""
2
+
3
+ from wavoice.core.config import Settings, settings
4
+ from wavoice.sdk import WhatsAppVoiceApp
5
+
6
+ __version__ = "0.1.0"
7
+ __all__ = ["WhatsAppVoiceApp", "Settings", "settings"]