dv-pipecat-ai 0.0.82.dev816__py3-none-any.whl → 0.0.82.dev866__py3-none-any.whl

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.

Potentially problematic release.


This version of dv-pipecat-ai might be problematic. Click here for more details.

Files changed (118) hide show
  1. {dv_pipecat_ai-0.0.82.dev816.dist-info → dv_pipecat_ai-0.0.82.dev866.dist-info}/METADATA +8 -3
  2. {dv_pipecat_ai-0.0.82.dev816.dist-info → dv_pipecat_ai-0.0.82.dev866.dist-info}/RECORD +118 -79
  3. pipecat/adapters/base_llm_adapter.py +44 -6
  4. pipecat/adapters/services/anthropic_adapter.py +302 -2
  5. pipecat/adapters/services/aws_nova_sonic_adapter.py +40 -2
  6. pipecat/adapters/services/bedrock_adapter.py +40 -2
  7. pipecat/adapters/services/gemini_adapter.py +276 -6
  8. pipecat/adapters/services/open_ai_adapter.py +88 -7
  9. pipecat/adapters/services/open_ai_realtime_adapter.py +39 -1
  10. pipecat/audio/dtmf/__init__.py +0 -0
  11. pipecat/audio/dtmf/dtmf-0.wav +0 -0
  12. pipecat/audio/dtmf/dtmf-1.wav +0 -0
  13. pipecat/audio/dtmf/dtmf-2.wav +0 -0
  14. pipecat/audio/dtmf/dtmf-3.wav +0 -0
  15. pipecat/audio/dtmf/dtmf-4.wav +0 -0
  16. pipecat/audio/dtmf/dtmf-5.wav +0 -0
  17. pipecat/audio/dtmf/dtmf-6.wav +0 -0
  18. pipecat/audio/dtmf/dtmf-7.wav +0 -0
  19. pipecat/audio/dtmf/dtmf-8.wav +0 -0
  20. pipecat/audio/dtmf/dtmf-9.wav +0 -0
  21. pipecat/audio/dtmf/dtmf-pound.wav +0 -0
  22. pipecat/audio/dtmf/dtmf-star.wav +0 -0
  23. pipecat/audio/dtmf/types.py +47 -0
  24. pipecat/audio/dtmf/utils.py +70 -0
  25. pipecat/audio/filters/aic_filter.py +199 -0
  26. pipecat/audio/utils.py +9 -7
  27. pipecat/extensions/ivr/__init__.py +0 -0
  28. pipecat/extensions/ivr/ivr_navigator.py +452 -0
  29. pipecat/frames/frames.py +156 -43
  30. pipecat/pipeline/llm_switcher.py +76 -0
  31. pipecat/pipeline/parallel_pipeline.py +3 -3
  32. pipecat/pipeline/service_switcher.py +144 -0
  33. pipecat/pipeline/task.py +68 -28
  34. pipecat/pipeline/task_observer.py +10 -0
  35. pipecat/processors/aggregators/dtmf_aggregator.py +2 -2
  36. pipecat/processors/aggregators/llm_context.py +277 -0
  37. pipecat/processors/aggregators/llm_response.py +48 -15
  38. pipecat/processors/aggregators/llm_response_universal.py +840 -0
  39. pipecat/processors/aggregators/openai_llm_context.py +3 -3
  40. pipecat/processors/dtmf_aggregator.py +0 -2
  41. pipecat/processors/filters/stt_mute_filter.py +0 -2
  42. pipecat/processors/frame_processor.py +18 -11
  43. pipecat/processors/frameworks/rtvi.py +17 -10
  44. pipecat/processors/metrics/sentry.py +2 -0
  45. pipecat/runner/daily.py +137 -36
  46. pipecat/runner/run.py +1 -1
  47. pipecat/runner/utils.py +7 -7
  48. pipecat/serializers/asterisk.py +19 -4
  49. pipecat/serializers/exotel.py +1 -1
  50. pipecat/serializers/plivo.py +1 -1
  51. pipecat/serializers/telnyx.py +1 -1
  52. pipecat/serializers/twilio.py +1 -1
  53. pipecat/services/__init__.py +2 -2
  54. pipecat/services/anthropic/llm.py +113 -28
  55. pipecat/services/asyncai/tts.py +4 -0
  56. pipecat/services/aws/llm.py +82 -8
  57. pipecat/services/aws/tts.py +0 -10
  58. pipecat/services/aws_nova_sonic/aws.py +5 -0
  59. pipecat/services/cartesia/tts.py +28 -16
  60. pipecat/services/cerebras/llm.py +15 -10
  61. pipecat/services/deepgram/stt.py +8 -0
  62. pipecat/services/deepseek/llm.py +13 -8
  63. pipecat/services/fireworks/llm.py +13 -8
  64. pipecat/services/fish/tts.py +8 -6
  65. pipecat/services/gemini_multimodal_live/gemini.py +5 -0
  66. pipecat/services/gladia/config.py +7 -1
  67. pipecat/services/gladia/stt.py +23 -15
  68. pipecat/services/google/llm.py +159 -59
  69. pipecat/services/google/llm_openai.py +18 -3
  70. pipecat/services/grok/llm.py +2 -1
  71. pipecat/services/llm_service.py +38 -3
  72. pipecat/services/mem0/memory.py +2 -1
  73. pipecat/services/mistral/llm.py +5 -6
  74. pipecat/services/nim/llm.py +2 -1
  75. pipecat/services/openai/base_llm.py +88 -26
  76. pipecat/services/openai/image.py +6 -1
  77. pipecat/services/openai_realtime_beta/openai.py +5 -2
  78. pipecat/services/openpipe/llm.py +6 -8
  79. pipecat/services/perplexity/llm.py +13 -8
  80. pipecat/services/playht/tts.py +9 -6
  81. pipecat/services/rime/tts.py +1 -1
  82. pipecat/services/sambanova/llm.py +18 -13
  83. pipecat/services/sarvam/tts.py +415 -10
  84. pipecat/services/speechmatics/stt.py +4 -4
  85. pipecat/services/tavus/video.py +1 -1
  86. pipecat/services/tts_service.py +12 -5
  87. pipecat/services/vistaar/llm.py +0 -1
  88. pipecat/transports/base_input.py +32 -19
  89. pipecat/transports/base_output.py +39 -5
  90. pipecat/transports/daily/__init__.py +0 -0
  91. pipecat/transports/daily/transport.py +2371 -0
  92. pipecat/transports/daily/utils.py +410 -0
  93. pipecat/transports/livekit/__init__.py +0 -0
  94. pipecat/transports/livekit/transport.py +1042 -0
  95. pipecat/transports/network/fastapi_websocket.py +12 -546
  96. pipecat/transports/network/small_webrtc.py +12 -922
  97. pipecat/transports/network/webrtc_connection.py +9 -595
  98. pipecat/transports/network/websocket_client.py +12 -481
  99. pipecat/transports/network/websocket_server.py +12 -487
  100. pipecat/transports/services/daily.py +9 -2334
  101. pipecat/transports/services/helpers/daily_rest.py +12 -396
  102. pipecat/transports/services/livekit.py +12 -975
  103. pipecat/transports/services/tavus.py +12 -757
  104. pipecat/transports/smallwebrtc/__init__.py +0 -0
  105. pipecat/transports/smallwebrtc/connection.py +612 -0
  106. pipecat/transports/smallwebrtc/transport.py +936 -0
  107. pipecat/transports/tavus/__init__.py +0 -0
  108. pipecat/transports/tavus/transport.py +770 -0
  109. pipecat/transports/websocket/__init__.py +0 -0
  110. pipecat/transports/websocket/client.py +494 -0
  111. pipecat/transports/websocket/fastapi.py +559 -0
  112. pipecat/transports/websocket/server.py +500 -0
  113. pipecat/transports/whatsapp/__init__.py +0 -0
  114. pipecat/transports/whatsapp/api.py +345 -0
  115. pipecat/transports/whatsapp/client.py +364 -0
  116. {dv_pipecat_ai-0.0.82.dev816.dist-info → dv_pipecat_ai-0.0.82.dev866.dist-info}/WHEEL +0 -0
  117. {dv_pipecat_ai-0.0.82.dev816.dist-info → dv_pipecat_ai-0.0.82.dev866.dist-info}/licenses/LICENSE +0 -0
  118. {dv_pipecat_ai-0.0.82.dev816.dist-info → dv_pipecat_ai-0.0.82.dev866.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,410 @@
1
+ #
2
+ # Copyright (c) 2024–2025, Daily
3
+ #
4
+ # SPDX-License-Identifier: BSD 2-Clause License
5
+ #
6
+
7
+ """Daily REST Helpers.
8
+
9
+ Methods that wrap the Daily API to create rooms, check room URLs, and get meeting tokens.
10
+ """
11
+
12
+ import time
13
+ from typing import Dict, List, Literal, Optional
14
+ from urllib.parse import urlparse
15
+
16
+ import aiohttp
17
+ from pydantic import BaseModel, Field, ValidationError
18
+
19
+
20
+ class DailyRoomSipParams(BaseModel):
21
+ """SIP configuration parameters for Daily rooms.
22
+
23
+ Parameters:
24
+ display_name: Name shown for the SIP endpoint.
25
+ video: Whether video is enabled for SIP.
26
+ sip_mode: SIP connection mode, typically 'dial-in'.
27
+ num_endpoints: Number of allowed SIP endpoints.
28
+ codecs: Codecs to support for audio and video. If None, uses Daily defaults.
29
+ Example: {"audio": ["OPUS"], "video": ["H264"]}
30
+ """
31
+
32
+ display_name: str = "sw-sip-dialin"
33
+ video: bool = False
34
+ sip_mode: str = "dial-in"
35
+ num_endpoints: int = 1
36
+ codecs: Optional[Dict[str, List[str]]] = None
37
+
38
+
39
+ class RecordingsBucketConfig(BaseModel):
40
+ """Configuration for storing Daily recordings in a custom S3 bucket.
41
+
42
+ Refer to the Daily API documentation for more information:
43
+ https://docs.daily.co/guides/products/live-streaming-recording/storing-recordings-in-a-custom-s3-bucket
44
+
45
+ Parameters:
46
+ bucket_name: Name of the S3 bucket for storing recordings.
47
+ bucket_region: AWS region where the S3 bucket is located.
48
+ assume_role_arn: ARN of the IAM role to assume for S3 access.
49
+ allow_api_access: Whether to allow API access to the recordings.
50
+ """
51
+
52
+ bucket_name: str
53
+ bucket_region: str
54
+ assume_role_arn: str
55
+ allow_api_access: bool = False
56
+
57
+
58
+ class TranscriptionBucketConfig(BaseModel):
59
+ """Configuration for storing Daily transcription in a custom S3 bucket.
60
+
61
+ Refer to the Daily API documentation for more information:
62
+ https://docs.daily.co/guides/products/live-streaming-recording/storing-recordings-in-a-custom-s3-bucket
63
+
64
+ Parameters:
65
+ bucket_name: Name of the S3 bucket for storing transcription.
66
+ bucket_region: AWS region where the S3 bucket is located.
67
+ assume_role_arn: ARN of the IAM role to assume for S3 access.
68
+ allow_api_access: Whether to allow API access to the transcription.
69
+ """
70
+
71
+ bucket_name: str
72
+ bucket_region: str
73
+ assume_role_arn: str
74
+ allow_api_access: bool = False
75
+
76
+
77
+ class DailyRoomProperties(BaseModel, extra="allow"):
78
+ """Properties for configuring a Daily room.
79
+
80
+ Reference: https://docs.daily.co/reference/rest-api/rooms/create-room#properties
81
+
82
+ Parameters:
83
+ exp: Optional Unix epoch timestamp for room expiration (e.g., time.time() + 300 for 5 minutes).
84
+ enable_chat: Whether chat is enabled in the room.
85
+ enable_prejoin_ui: Whether the pre-join UI is enabled.
86
+ enable_emoji_reactions: Whether emoji reactions are enabled.
87
+ eject_at_room_exp: Whether to remove participants when room expires.
88
+ enable_dialout: Whether SIP dial-out is enabled.
89
+ enable_recording: Recording settings ('cloud', 'local', 'raw-tracks').
90
+ enable_transcription_storage: Whether transcription storage is enabled.
91
+ geo: Geographic region for room.
92
+ max_participants: Maximum number of participants allowed in the room.
93
+ recordings_bucket: Configuration for custom S3 bucket recordings.
94
+ transcription_bucket: Configuration for custom S3 bucket transcription.
95
+ sip: SIP configuration parameters.
96
+ sip_uri: SIP URI information returned by Daily.
97
+ start_video_off: Whether video is off by default.
98
+ """
99
+
100
+ exp: Optional[float] = None
101
+ enable_chat: bool = False
102
+ enable_prejoin_ui: bool = False
103
+ enable_emoji_reactions: bool = False
104
+ eject_at_room_exp: bool = False
105
+ enable_dialout: Optional[bool] = None
106
+ enable_recording: Optional[Literal["cloud", "local", "raw-tracks"]] = None
107
+ enable_transcription_storage: Optional[bool] = None
108
+ geo: Optional[str] = None
109
+ max_participants: Optional[int] = None
110
+ recordings_bucket: Optional[RecordingsBucketConfig] = None
111
+ transcription_bucket: Optional[TranscriptionBucketConfig] = None
112
+ sip: Optional[DailyRoomSipParams] = None
113
+ sip_uri: Optional[dict] = None
114
+ start_video_off: bool = False
115
+
116
+ @property
117
+ def sip_endpoint(self) -> str:
118
+ """Get the SIP endpoint URI if available.
119
+
120
+ Returns:
121
+ SIP endpoint URI or empty string if not available.
122
+ """
123
+ if not self.sip_uri:
124
+ return ""
125
+ else:
126
+ return "sip:%s" % self.sip_uri["endpoint"]
127
+
128
+
129
+ class DailyRoomParams(BaseModel):
130
+ """Parameters for creating a Daily room.
131
+
132
+ Parameters:
133
+ name: Optional custom name for the room.
134
+ privacy: Room privacy setting ('private' or 'public').
135
+ properties: Room configuration properties.
136
+ """
137
+
138
+ name: Optional[str] = None
139
+ privacy: Literal["private", "public"] = "public"
140
+ properties: DailyRoomProperties = Field(default_factory=DailyRoomProperties)
141
+
142
+
143
+ class DailyRoomObject(BaseModel):
144
+ """Represents a Daily room returned by the API.
145
+
146
+ Parameters:
147
+ id: Unique room identifier.
148
+ name: Room name.
149
+ api_created: Whether room was created via API.
150
+ privacy: Room privacy setting ('private' or 'public').
151
+ url: Full URL for joining the room.
152
+ created_at: Timestamp of room creation in ISO 8601 format (e.g., "2019-01-26T09:01:22.000Z").
153
+ config: Room configuration properties.
154
+ """
155
+
156
+ id: str
157
+ name: str
158
+ api_created: bool
159
+ privacy: str
160
+ url: str
161
+ created_at: str
162
+ config: DailyRoomProperties
163
+
164
+
165
+ class DailyMeetingTokenProperties(BaseModel):
166
+ """Properties for configuring a Daily meeting token.
167
+
168
+ Refer to the Daily API documentation for more information:
169
+ https://docs.daily.co/reference/rest-api/meeting-tokens/create-meeting-token#properties
170
+
171
+ Parameters:
172
+ room_name: The room for which this token is valid. If not set, the token is valid for all rooms in your domain.
173
+ eject_at_token_exp: If True, the user will be ejected from the room when the token expires.
174
+ eject_after_elapsed: The number of seconds after which the user will be ejected from the room.
175
+ nbf: Not before timestamp - users cannot join with this token before this time.
176
+ exp: Expiration time (unix timestamp in seconds). Strongly recommended for security.
177
+ is_owner: If True, the token will grant owner privileges in the room.
178
+ user_name: The name of the user. This will be added to the token payload.
179
+ user_id: A unique identifier for the user. This will be added to the token payload.
180
+ enable_screenshare: If True, the user will be able to share their screen.
181
+ start_video_off: If True, the user's video will be turned off when they join the room.
182
+ start_audio_off: If True, the user's audio will be turned off when they join the room.
183
+ enable_recording: Recording settings for the token. Must be one of 'cloud', 'local' or 'raw-tracks'.
184
+ enable_prejoin_ui: If True, the user will see the prejoin UI before joining the room.
185
+ start_cloud_recording: Start cloud recording when the user joins the room.
186
+ permissions: Specifies the initial default permissions for a non-meeting-owner participant.
187
+ """
188
+
189
+ room_name: Optional[str] = None
190
+ eject_at_token_exp: Optional[bool] = None
191
+ eject_after_elapsed: Optional[int] = None
192
+ nbf: Optional[int] = None
193
+ exp: Optional[int] = None
194
+ is_owner: Optional[bool] = None
195
+ user_name: Optional[str] = None
196
+ user_id: Optional[str] = None
197
+ enable_screenshare: Optional[bool] = None
198
+ start_video_off: Optional[bool] = None
199
+ start_audio_off: Optional[bool] = None
200
+ enable_recording: Optional[Literal["cloud", "local", "raw-tracks"]] = None
201
+ enable_prejoin_ui: Optional[bool] = None
202
+ start_cloud_recording: Optional[bool] = None
203
+ permissions: Optional[dict] = None
204
+
205
+
206
+ class DailyMeetingTokenParams(BaseModel):
207
+ """Parameters for creating a Daily meeting token.
208
+
209
+ Refer to the Daily API documentation for more information:
210
+ https://docs.daily.co/reference/rest-api/meeting-tokens/create-meeting-token#body-params
211
+
212
+ Parameters:
213
+ properties: Meeting token configuration properties.
214
+ """
215
+
216
+ properties: DailyMeetingTokenProperties = Field(default_factory=DailyMeetingTokenProperties)
217
+
218
+
219
+ class DailyRESTHelper:
220
+ """Helper class for interacting with Daily's REST API.
221
+
222
+ Provides methods for creating, managing, and accessing Daily rooms.
223
+ """
224
+
225
+ def __init__(
226
+ self,
227
+ *,
228
+ daily_api_key: str,
229
+ daily_api_url: str = "https://api.daily.co/v1",
230
+ aiohttp_session: aiohttp.ClientSession,
231
+ ):
232
+ """Initialize the Daily REST helper.
233
+
234
+ Args:
235
+ daily_api_key: Your Daily API key.
236
+ daily_api_url: Daily API base URL (e.g. "https://api.daily.co/v1").
237
+ aiohttp_session: Async HTTP session for making requests.
238
+ """
239
+ self.daily_api_key = daily_api_key
240
+ self.daily_api_url = daily_api_url
241
+ self.aiohttp_session = aiohttp_session
242
+
243
+ def get_name_from_url(self, room_url: str) -> str:
244
+ """Extract room name from a Daily room URL.
245
+
246
+ Args:
247
+ room_url: Full Daily room URL.
248
+
249
+ Returns:
250
+ Room name portion of the URL.
251
+ """
252
+ return urlparse(room_url).path[1:]
253
+
254
+ async def get_room_from_url(self, room_url: str) -> DailyRoomObject:
255
+ """Get room details from a Daily room URL.
256
+
257
+ Args:
258
+ room_url: Full Daily room URL.
259
+
260
+ Returns:
261
+ DailyRoomObject instance for the room.
262
+ """
263
+ room_name = self.get_name_from_url(room_url)
264
+ return await self._get_room_from_name(room_name)
265
+
266
+ async def create_room(self, params: DailyRoomParams) -> DailyRoomObject:
267
+ """Create a new Daily room.
268
+
269
+ Args:
270
+ params: Room configuration parameters.
271
+
272
+ Returns:
273
+ DailyRoomObject instance for the created room.
274
+
275
+ Raises:
276
+ Exception: If room creation fails or response is invalid.
277
+ """
278
+ headers = {"Authorization": f"Bearer {self.daily_api_key}"}
279
+ json = params.model_dump(exclude_none=True)
280
+ async with self.aiohttp_session.post(
281
+ f"{self.daily_api_url}/rooms", headers=headers, json=json
282
+ ) as r:
283
+ if r.status != 200:
284
+ text = await r.text()
285
+ raise Exception(f"Unable to create room (status: {r.status}): {text}")
286
+
287
+ data = await r.json()
288
+
289
+ try:
290
+ room = DailyRoomObject(**data)
291
+ except ValidationError as e:
292
+ raise Exception(f"Invalid response: {e}")
293
+
294
+ return room
295
+
296
+ async def get_token(
297
+ self,
298
+ room_url: str,
299
+ expiry_time: float = 60 * 60,
300
+ eject_at_token_exp: bool = False,
301
+ owner: bool = True,
302
+ params: Optional[DailyMeetingTokenParams] = None,
303
+ ) -> str:
304
+ """Generate a meeting token for user to join a Daily room.
305
+
306
+ Args:
307
+ room_url: Daily room URL.
308
+ expiry_time: Token validity duration in seconds (default: 1 hour).
309
+ eject_at_token_exp: Whether to eject user when token expires.
310
+ owner: Whether token has owner privileges.
311
+ params: Optional additional token properties. Note that room_name,
312
+ exp, and is_owner will be set based on the other function
313
+ parameters regardless of values in params.
314
+
315
+ Returns:
316
+ Meeting token.
317
+
318
+ Raises:
319
+ Exception: If token generation fails or room URL is missing.
320
+ """
321
+ if not room_url:
322
+ raise Exception(
323
+ "No Daily room specified. You must specify a Daily room in order a token to be generated."
324
+ )
325
+
326
+ expiration: int = int(time.time() + expiry_time)
327
+
328
+ room_name = self.get_name_from_url(room_url)
329
+
330
+ headers = {"Authorization": f"Bearer {self.daily_api_key}"}
331
+
332
+ if params is None:
333
+ params = DailyMeetingTokenParams(
334
+ properties=DailyMeetingTokenProperties(
335
+ room_name=room_name,
336
+ is_owner=owner,
337
+ exp=expiration,
338
+ eject_at_token_exp=eject_at_token_exp,
339
+ )
340
+ )
341
+ else:
342
+ params.properties.room_name = room_name
343
+ params.properties.exp = expiration
344
+ params.properties.eject_at_token_exp = eject_at_token_exp
345
+ params.properties.is_owner = owner
346
+
347
+ json = params.model_dump(exclude_none=True)
348
+
349
+ async with self.aiohttp_session.post(
350
+ f"{self.daily_api_url}/meeting-tokens", headers=headers, json=json
351
+ ) as r:
352
+ if r.status != 200:
353
+ text = await r.text()
354
+ raise Exception(f"Failed to create meeting token (status: {r.status}): {text}")
355
+
356
+ data = await r.json()
357
+
358
+ return data["token"]
359
+
360
+ async def delete_room_by_url(self, room_url: str) -> bool:
361
+ """Delete a room using its URL.
362
+
363
+ Args:
364
+ room_url: Daily room URL.
365
+
366
+ Returns:
367
+ True if deletion was successful.
368
+ """
369
+ room_name = self.get_name_from_url(room_url)
370
+ return await self.delete_room_by_name(room_name)
371
+
372
+ async def delete_room_by_name(self, room_name: str) -> bool:
373
+ """Delete a room using its name.
374
+
375
+ Args:
376
+ room_name: Name of the room to delete.
377
+
378
+ Returns:
379
+ True if deletion was successful.
380
+
381
+ Raises:
382
+ Exception: If deletion fails (excluding 404 Not Found).
383
+ """
384
+ headers = {"Authorization": f"Bearer {self.daily_api_key}"}
385
+ async with self.aiohttp_session.delete(
386
+ f"{self.daily_api_url}/rooms/{room_name}", headers=headers
387
+ ) as r:
388
+ if r.status != 200 and r.status != 404:
389
+ text = await r.text()
390
+ raise Exception(f"Failed to delete room [{room_name}] (status: {r.status}): {text}")
391
+
392
+ return True
393
+
394
+ async def _get_room_from_name(self, room_name: str) -> DailyRoomObject:
395
+ """Internal method to get room details by name."""
396
+ headers = {"Authorization": f"Bearer {self.daily_api_key}"}
397
+ async with self.aiohttp_session.get(
398
+ f"{self.daily_api_url}/rooms/{room_name}", headers=headers
399
+ ) as r:
400
+ if r.status != 200:
401
+ raise Exception(f"Room not found: {room_name}")
402
+
403
+ data = await r.json()
404
+
405
+ try:
406
+ room = DailyRoomObject(**data)
407
+ except ValidationError as e:
408
+ raise Exception(f"Invalid response: {e}")
409
+
410
+ return room
File without changes