Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion src/elevenlabs/realtime/scribe.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ class RealtimeAudioOptions(typing.TypedDict, total=False):
min_silence_duration_ms: int
language_code: str
include_timestamps: bool
keyterms: typing.List[str]
no_verbatim: bool


class RealtimeUrlOptions(typing.TypedDict, total=False):
Expand All @@ -93,6 +95,8 @@ class RealtimeUrlOptions(typing.TypedDict, total=False):
min_silence_duration_ms: int
language_code: str
include_timestamps: bool
keyterms: typing.List[str]
no_verbatim: bool


class ScribeRealtime:
Expand Down Expand Up @@ -197,6 +201,8 @@ async def _connect_audio(self, options: RealtimeAudioOptions) -> RealtimeConnect
min_silence_duration_ms = options.get("min_silence_duration_ms")
language_code = options.get("language_code")
include_timestamps = options.get("include_timestamps", False)
keyterms = options.get("keyterms")
no_verbatim = options.get("no_verbatim")

if not audio_format or not sample_rate:
raise ValueError("audio_format and sample_rate are required for manual audio mode")
Expand All @@ -212,6 +218,8 @@ async def _connect_audio(self, options: RealtimeAudioOptions) -> RealtimeConnect
min_silence_duration_ms=min_silence_duration_ms,
language_code=language_code,
include_timestamps=include_timestamps,
keyterms=keyterms,
no_verbatim=no_verbatim,
)

# Connect to WebSocket
Expand Down Expand Up @@ -244,6 +252,8 @@ async def _connect_url(self, options: RealtimeUrlOptions) -> RealtimeConnection:
min_silence_duration_ms = options.get("min_silence_duration_ms")
language_code = options.get("language_code")
include_timestamps = options.get("include_timestamps", False)
keyterms = options.get("keyterms")
no_verbatim = options.get("no_verbatim")

if not url:
raise ValueError("url is required for URL mode")
Expand All @@ -263,6 +273,8 @@ async def _connect_url(self, options: RealtimeUrlOptions) -> RealtimeConnection:
min_silence_duration_ms=min_silence_duration_ms,
language_code=language_code,
include_timestamps=include_timestamps,
keyterms=keyterms,
no_verbatim=no_verbatim,
)

# Connect to WebSocket
Expand Down Expand Up @@ -365,7 +377,9 @@ def _build_websocket_url(
min_speech_duration_ms: typing.Optional[int] = None,
min_silence_duration_ms: typing.Optional[int] = None,
language_code: typing.Optional[str] = None,
include_timestamps: typing.Optional[bool] = None
include_timestamps: typing.Optional[bool] = None,
keyterms: typing.Optional[typing.List[str]] = None,
no_verbatim: typing.Optional[bool] = None,
) -> str:
"""Build the WebSocket URL with query parameters"""
params = [
Expand All @@ -384,6 +398,11 @@ def _build_websocket_url(
params.append((key, str(value)))
if include_timestamps is not None:
params.append(("include_timestamps", str(include_timestamps).lower()))
if keyterms is not None:
for term in keyterms:
params.append(("keyterms", term))
if no_verbatim is not None:
params.append(("no_verbatim", str(no_verbatim).lower()))

return build_ws_url(self.base_url, ["v1", "speech-to-text", "realtime"], params)

45 changes: 45 additions & 0 deletions tests/test_stt_realtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,51 @@ def test_url_converts_http_to_ws(self):

assert url.startswith("ws://localhost:8080")

def test_includes_keyterms_as_repeated_query_params(self):
"""Test that keyterms are included as repeated query params"""
url = self.scribe._build_websocket_url(
model_id="scribe_v2_realtime",
audio_format="pcm_16000",
commit_strategy="manual",
keyterms=["ElevenLabs", "Scribe"],
)

assert "keyterms=ElevenLabs" in url
assert "keyterms=Scribe" in url

def test_includes_no_verbatim_true(self):
"""Test that no_verbatim=true is included when set to True"""
url = self.scribe._build_websocket_url(
model_id="scribe_v2_realtime",
audio_format="pcm_16000",
commit_strategy="manual",
no_verbatim=True,
)

assert "no_verbatim=true" in url

def test_includes_no_verbatim_false(self):
"""Test that no_verbatim=false is included when set to False"""
url = self.scribe._build_websocket_url(
model_id="scribe_v2_realtime",
audio_format="pcm_16000",
commit_strategy="manual",
no_verbatim=False,
)

assert "no_verbatim=false" in url

def test_omits_keyterms_and_no_verbatim_when_not_specified(self):
"""Test that keyterms and no_verbatim are omitted when not specified"""
url = self.scribe._build_websocket_url(
model_id="scribe_v2_realtime",
audio_format="pcm_16000",
commit_strategy="manual",
)

assert "keyterms" not in url
assert "no_verbatim" not in url


class TestConnectValidation:
"""Tests for connect method validation"""
Expand Down