Skip to content

Commit bb38bd9

Browse files
kraenhansenclaude
andcommitted
fix: use typing.List/Tuple for Python 3.8 compatibility
Replace PEP 585 lowercase generics (list[tuple[...]]) with typing.List[typing.Tuple[...]] to avoid TypeError on Python 3.8. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 2163d22 commit bb38bd9

3 files changed

Lines changed: 28 additions & 19 deletions

File tree

src/elevenlabs/conversational_ai/conversation.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -422,22 +422,22 @@ def _get_wss_url(self):
422422
return self.on_prem_config.on_prem_conversation_url
423423

424424
base_http_url = self.client._client_wrapper.get_base_url()
425-
base_ws_url = (
426-
urllib.parse.urlparse(base_http_url)
427-
._replace(scheme="wss" if base_http_url.startswith("https") else "ws")
428-
.geturl()
425+
parsed = urllib.parse.urlparse(base_http_url)._replace(
426+
scheme="wss" if base_http_url.startswith("https") else "ws",
429427
)
430-
# Ensure base URL ends with '/' for proper joining
431-
if not base_ws_url.endswith("/"):
432-
base_ws_url += "/"
433-
params: list[tuple[str, str]] = [
428+
params = [
434429
("agent_id", self.agent_id),
435430
("source", "python_sdk"),
436431
("version", __version__),
437432
]
438433
if self.environment:
439434
params.append(("environment", self.environment))
440-
return f"{base_ws_url}v1/convai/conversation?{urllib.parse.urlencode(params)}"
435+
# Ensure base path ends with '/' so urljoin appends rather than replaces
436+
base_path = parsed.path if parsed.path.endswith("/") else parsed.path + "/"
437+
return urllib.parse.urlunparse(parsed._replace(
438+
path=base_path + "v1/convai/conversation",
439+
query=urllib.parse.urlencode(params),
440+
))
441441

442442
def _get_signed_url(self):
443443
response = self.client.conversational_ai.conversations.get_signed_url(

src/elevenlabs/realtime/scribe.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -368,18 +368,21 @@ def _build_websocket_url(
368368
include_timestamps: typing.Optional[bool] = None
369369
) -> str:
370370
"""Build the WebSocket URL with query parameters"""
371-
# Extract base domain
372-
base = self.base_url.replace("https://", "wss://").replace("http://", "ws://")
371+
parsed = urllib.parse.urlparse(self.base_url)._replace(
372+
scheme="wss" if self.base_url.startswith("https") else
373+
"ws" if self.base_url.startswith("http") else
374+
urllib.parse.urlparse(self.base_url).scheme,
375+
)
373376

374377
# Build query parameters
375-
params: list[tuple[str, str]] = [
378+
params = [
376379
("model_id", model_id),
377380
("audio_format", audio_format),
378381
("commit_strategy", commit_strategy),
379382
]
380383

381384
# Add optional parameters
382-
optional: list[tuple[str, typing.Any]] = [
385+
optional = [
383386
("vad_silence_threshold_secs", vad_silence_threshold_secs),
384387
("vad_threshold", vad_threshold),
385388
("min_speech_duration_ms", min_speech_duration_ms),
@@ -393,6 +396,9 @@ def _build_websocket_url(
393396
if include_timestamps is not None:
394397
params.append(("include_timestamps", str(include_timestamps).lower()))
395398

396-
query_string = urllib.parse.urlencode(params)
397-
return f"{base}/v1/speech-to-text/realtime?{query_string}"
399+
base_path = parsed.path if parsed.path.endswith("/") else parsed.path + "/"
400+
return urllib.parse.urlunparse(parsed._replace(
401+
path=base_path + "v1/speech-to-text/realtime",
402+
query=urllib.parse.urlencode(params),
403+
))
398404

src/elevenlabs/realtime_tts.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,14 @@ def get_text() -> typing.Iterator[str]:
9191
),
9292
)
9393
"""
94+
parsed = urllib.parse.urlparse(self._ws_base_url)
95+
base_path = parsed.path if parsed.path.endswith("/") else parsed.path + "/"
96+
ws_url = urllib.parse.urlunparse(parsed._replace(
97+
path=base_path + f"v1/text-to-speech/{jsonable_encoder(voice_id)}/stream-input",
98+
query=urllib.parse.urlencode({"model_id": model_id, "output_format": output_format}),
99+
))
94100
with connect(
95-
urllib.parse.urljoin(
96-
self._ws_base_url,
97-
f"v1/text-to-speech/{jsonable_encoder(voice_id)}/stream-input?{urllib.parse.urlencode({"model_id": model_id, "output_format": output_format})}"
98-
),
101+
ws_url,
99102
additional_headers=jsonable_encoder(
100103
remove_none_from_dict(
101104
{

0 commit comments

Comments
 (0)