Skip to content

Commit 44692f8

Browse files
committed
add location
1 parent 43da410 commit 44692f8

3 files changed

Lines changed: 96 additions & 9 deletions

File tree

src/elevenlabs/conversational_ai/conversation.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from ..version import __version__
1616
from .base_connection import ConnectionType, BaseConnection
1717
from .connection_factory import create_connection, determine_connection_type
18+
from .location_utils import Location, get_origin_for_location
1819

1920

2021
class ClientToOrchestratorEvent(str, Enum):
@@ -299,6 +300,7 @@ def __init__(
299300
user_id: Optional[str] = None,
300301
connection_type: Optional[ConnectionType] = None,
301302
conversation_token: Optional[str] = None,
303+
location: Optional[Location] = None,
302304
livekit_url: Optional[str] = None,
303305
api_origin: Optional[str] = None,
304306
webrtc_overrides: Optional[dict] = None,
@@ -310,6 +312,7 @@ def __init__(
310312
self.user_id = user_id
311313
self.connection_type = connection_type
312314
self.conversation_token = conversation_token
315+
self.location = location
313316
self.livekit_url = livekit_url
314317
self.api_origin = api_origin
315318
self.webrtc_overrides = webrtc_overrides or {}
@@ -343,8 +346,12 @@ def __init__(
343346
self._connection: Optional[BaseConnection] = None
344347

345348
def _get_wss_url(self):
346-
base_http_url = self.client._client_wrapper.get_base_url()
347-
base_ws_url = base_http_url.replace("https://", "wss://").replace("http://", "ws://")
349+
# Use location-based URL if location is specified
350+
if self.config.location is not None:
351+
base_ws_url = get_origin_for_location(self.config.location)
352+
else:
353+
base_http_url = self.client._client_wrapper.get_base_url()
354+
base_ws_url = base_http_url.replace("https://", "wss://").replace("http://", "ws://")
348355
return f"{base_ws_url}/v1/convai/conversation?agent_id={self.agent_id}&source=python_sdk&version={__version__}"
349356

350357
def _get_signed_url(self):

src/elevenlabs/conversational_ai/conversation_factory.py

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
)
1212
from .webrtc_conversation import WebRTCConversation
1313
from .base_connection import ConnectionType
14+
from .location_utils import Location, get_origin_for_location, get_livekit_url_for_location
1415

1516

1617
def create_conversation(
@@ -21,6 +22,7 @@ def create_conversation(
2122
connection_type: ConnectionType = ConnectionType.WEBSOCKET,
2223
conversation_token: Optional[str] = None,
2324
requires_auth: bool = True,
25+
location: Optional[Location] = None,
2426
audio_interface: Optional[Union[AudioInterface, AsyncAudioInterface]] = None,
2527
config: Optional[ConversationInitiationData] = None,
2628
client_tools: Optional[ClientTools] = None,
@@ -46,6 +48,7 @@ def create_conversation(
4648
connection_type: Type of connection (websocket or webrtc)
4749
conversation_token: Token for WebRTC authentication
4850
requires_auth: Whether authentication is required
51+
location: Data residency location (us, eu-residency, in-residency, global)
4952
audio_interface: Audio interface for the conversation
5053
config: Conversation configuration
5154
client_tools: Client tools for handling agent calls
@@ -63,23 +66,22 @@ def create_conversation(
6366
audio_interface=your_audio_interface
6467
)
6568
66-
# WebRTC conversation
69+
# WebRTC conversation with EU residency
6770
conversation = create_conversation(
6871
client=client,
6972
agent_id="your-agent-id",
7073
connection_type=ConnectionType.WEBRTC,
71-
conversation_token="your-token", # Optional, will fetch if not provided
74+
location=Location.EU_RESIDENCY,
7275
audio_interface=your_async_audio_interface,
7376
async_callback_agent_response=your_response_handler
7477
)
7578
76-
# Public agent (no auth required)
79+
# WebSocket conversation with specific location
7780
conversation = create_conversation(
7881
client=client,
79-
agent_id="public-agent-id",
80-
connection_type=ConnectionType.WEBRTC,
81-
requires_auth=False,
82-
audio_interface=your_async_audio_interface
82+
agent_id="your-agent-id",
83+
location=Location.IN_RESIDENCY,
84+
audio_interface=your_audio_interface
8385
)
8486
"""
8587

@@ -90,17 +92,29 @@ def create_conversation(
9092
config.connection_type = connection_type
9193
if conversation_token:
9294
config.conversation_token = conversation_token
95+
if location is not None:
96+
config.location = location
9397

9498
if connection_type == ConnectionType.WEBRTC:
9599
# Create WebRTC conversation
96100
if not isinstance(audio_interface, AsyncAudioInterface) and audio_interface is not None:
97101
raise ValueError("WebRTC conversations require an AsyncAudioInterface")
98102

103+
# Determine URLs based on location
104+
livekit_url = None
105+
api_origin = None
106+
if location is not None:
107+
livekit_url = get_livekit_url_for_location(location)
108+
# Convert WSS to HTTPS for API origin
109+
api_origin = get_origin_for_location(location).replace("wss://", "https://")
110+
99111
return WebRTCConversation(
100112
client=client,
101113
agent_id=agent_id,
102114
user_id=user_id,
103115
conversation_token=conversation_token,
116+
livekit_url=livekit_url,
117+
api_origin=api_origin,
104118
audio_interface=audio_interface,
105119
config=config,
106120
client_tools=client_tools,
@@ -169,6 +183,7 @@ def create_webrtc_conversation(
169183
user_id: Optional[str] = None,
170184
*,
171185
conversation_token: Optional[str] = None,
186+
location: Optional[Location] = None,
172187
livekit_url: Optional[str] = None,
173188
api_origin: Optional[str] = None,
174189
webrtc_overrides: Optional[dict] = None,
@@ -185,7 +200,17 @@ def create_webrtc_conversation(
185200
"""Create a WebRTC conversation.
186201
187202
Convenience function for creating WebRTC conversations with type safety.
203+
204+
Args:
205+
location: Data residency location. If provided, overrides livekit_url and api_origin.
206+
livekit_url: Custom LiveKit URL (overridden by location if provided).
207+
api_origin: Custom API origin (overridden by location if provided).
188208
"""
209+
# Determine URLs based on location if provided
210+
if location is not None:
211+
livekit_url = get_livekit_url_for_location(location)
212+
api_origin = get_origin_for_location(location).replace("wss://", "https://")
213+
189214
return WebRTCConversation(
190215
client=client,
191216
agent_id=agent_id,
@@ -212,6 +237,7 @@ def create_websocket_conversation(
212237
user_id: Optional[str] = None,
213238
*,
214239
requires_auth: bool = True,
240+
location: Optional[Location] = None,
215241
audio_interface: Optional[AudioInterface] = None,
216242
config: Optional[ConversationInitiationData] = None,
217243
client_tools: Optional[ClientTools] = None,
@@ -224,13 +250,17 @@ def create_websocket_conversation(
224250
"""Create a WebSocket conversation.
225251
226252
Convenience function for creating WebSocket conversations with type safety.
253+
254+
Args:
255+
location: Data residency location (us, eu-residency, in-residency, global)
227256
"""
228257
result = create_conversation(
229258
client=client,
230259
agent_id=agent_id,
231260
user_id=user_id,
232261
connection_type=ConnectionType.WEBSOCKET,
233262
requires_auth=requires_auth,
263+
location=location,
234264
audio_interface=audio_interface,
235265
config=config,
236266
client_tools=client_tools,
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
from enum import Enum
2+
from typing import Dict
3+
4+
5+
class Location(Enum):
6+
"""Location enum for data residency and region selection."""
7+
US = "us"
8+
EU_RESIDENCY = "eu-residency"
9+
IN_RESIDENCY = "in-residency"
10+
GLOBAL = "global"
11+
12+
13+
def get_origin_for_location(location: Location) -> str:
14+
"""
15+
Get the WebSocket API origin URL for a given location.
16+
17+
Args:
18+
location: The location enum value
19+
20+
Returns:
21+
The WebSocket URL for the specified location
22+
"""
23+
origin_map: Dict[Location, str] = {
24+
Location.US: "wss://api.elevenlabs.io",
25+
Location.EU_RESIDENCY: "wss://api.eu.residency.elevenlabs.io",
26+
Location.IN_RESIDENCY: "wss://api.in.residency.elevenlabs.io",
27+
Location.GLOBAL: "wss://api.elevenlabs.io",
28+
}
29+
30+
return origin_map[location]
31+
32+
33+
def get_livekit_url_for_location(location: Location) -> str:
34+
"""
35+
Get the LiveKit WebRTC URL for a given location.
36+
37+
Args:
38+
location: The location enum value
39+
40+
Returns:
41+
The LiveKit URL for the specified location
42+
"""
43+
livekit_url_map: Dict[Location, str] = {
44+
Location.US: "wss://livekit.rtc.elevenlabs.io",
45+
Location.EU_RESIDENCY: "wss://livekit.rtc.eu.residency.elevenlabs.io",
46+
Location.IN_RESIDENCY: "wss://livekit.rtc.in.residency.elevenlabs.io",
47+
Location.GLOBAL: "wss://livekit.rtc.elevenlabs.io",
48+
}
49+
50+
return livekit_url_map[location]

0 commit comments

Comments
 (0)