Skip to content
Closed
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
2 changes: 1 addition & 1 deletion examples/realtime_stt.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def on_mic(indata, frames, t, status):
except queue.Full:
pass

palabra = Palabra() # set your credentials here or vie ENV
palabra = Palabra() # set your credentials here or vie ENV

async with palabra.stt(language="ru", translate_languages=["es", "en"]) as stt:

Expand Down
2 changes: 1 addition & 1 deletion examples/realtime_tts.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@


async def main():
palabra = Palabra() # set your credentials here or vie ENV
palabra = Palabra() # set your credentials here or vie ENV

async with palabra.tts(language="en", voice_id="default_low") as tts:
# one-shot: send text, collect all chunks
Expand Down
2 changes: 1 addition & 1 deletion examples/sts_buffer_streaming.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ async def feed_source():


async def main():
palabra = Palabra() # set your credentials here or vie ENV
palabra = Palabra() # set your credentials here or vie ENV

async with palabra.translation(source="en", targets=["es"]) as session:

Expand Down
2 changes: 1 addition & 1 deletion examples/sts_file_to_file.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from palabra_ai import Palabra

palabra = Palabra() # set your credentials here or vie ENV
palabra = Palabra() # set your credentials here or vie ENV

palabra.translate_file(
"speech_en.wav",
Expand Down
2 changes: 1 addition & 1 deletion examples/sts_mic_to_speakers.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def on_spk(outdata, frames, t, status):
else:
outdata.fill(0)

palabra = Palabra() # set your credentials here or vie ENV
palabra = Palabra() # set your credentials here or vie ENV
async with palabra.translation(source="en", targets=["es"]) as session:

async def feed():
Expand Down
2 changes: 1 addition & 1 deletion examples/sts_multi_language.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from palabra_ai import Palabra

palabra = Palabra() # set your credentials here or vie ENV
palabra = Palabra() # set your credentials here or vie ENV

results = palabra.translate_file(
"presentation.mp3", # mp3 needs: pip install palabra-ai[audio]
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "palabra-ai"
version = "1.0.2"
version = "1.0.3"
description = "Simple Python client for Palabra AI APIs"
readme = "README.md"
requires-python = ">=3.10"
Expand Down
16 changes: 11 additions & 5 deletions src/palabra_ai/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
GET_TASK_INTERVAL = 2.1 # server allows 1 get_task per 2s
SESSION_RETRIES = 3 # create_session attempts on network errors / 5xx
RETRY_BACKOFF = 0.5 # seconds; doubles per attempt (0.5, 1.0)
S2S_SESSION_INTENT = "api"


@dataclass(frozen=True)
Expand Down Expand Up @@ -69,12 +70,19 @@ def _headers(self) -> dict[str, str]:
)
return {"ClientID": self.client_id, "ClientSecret": self.client_secret}

async def create_session(self) -> Session:
async def create_session(self, *, intent: str | None = None) -> Session:
"""Create a streaming session via REST.

intent is the session kind sent as data.intent; session-storage routes
and bills by it. Each product hardcodes its own value (s2s "api",
tts "tts_api", stt "stt") — not a user choice. Omitted when None.

Transient failures (network errors, 5xx) are retried up to
SESSION_RETRIES times with backoff; 4xx fails immediately.
"""
data: dict[str, Any] = {}
if intent is not None:
data["intent"] = intent
last_error: Exception | None = None
for attempt in range(SESSION_RETRIES):
if attempt:
Expand All @@ -84,9 +92,7 @@ async def create_session(self) -> Session:
resp = await client.post(
f"{self.api_url}/session-storage/session",
headers=self._headers(),
json={
"data": {}
},
json={"data": data},
)
except httpx.TransportError as e:
last_error = e
Expand Down Expand Up @@ -332,7 +338,7 @@ def task(self) -> dict[str, Any]:

async def __aenter__(self) -> TranslationSession:
if self._session is None:
self._session = await self._palabra.create_session()
self._session = await self._palabra.create_session(intent=S2S_SESSION_INTENT)
url = f"{self._session.ws_url}?token={self._session.publisher}"
try:
self._ws = await websockets.connect(url, ping_interval=10, ping_timeout=30, max_size=None)
Expand Down
3 changes: 2 additions & 1 deletion src/palabra_ai/stt.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from .client import Palabra, Session

ASR_STREAM_PATH = "/asr/v1/speech-to-text/stream"
SESSION_INTENT = "stt" # session kind for billing routing
DEFAULT_SAMPLE_RATE = 16000 # ASR recommended/default input rate (translation/TTS use 24k)

_STT_TRANSCRIPT_TYPES = frozenset({"transcription", "translated_transcription"})
Expand Down Expand Up @@ -110,7 +111,7 @@ async def __aenter__(self) -> SttSession:
base, token = self._direct
else:
if self._session is None:
self._session = await self._palabra.create_session()
self._session = await self._palabra.create_session(intent=SESSION_INTENT)
base = _asr_ws_url(self._palabra.api_url)
token = self._session.publisher
url = f"{base}?{urlencode({'token': token, **self._params}, safe=',')}"
Expand Down
3 changes: 2 additions & 1 deletion src/palabra_ai/tts.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

# The Realtime TTS endpoint is fixed (not taken from the session response).
TTS_STREAM_URL = "wss://stream.palabra.ai/tts-api/v1/text-to-speech/stream"
SESSION_INTENT = "tts_api" # session kind for billing routing


@dataclass(frozen=True)
Expand Down Expand Up @@ -80,7 +81,7 @@ async def __aenter__(self) -> TtsSession:
url = f"{self._direct[0]}?token={self._direct[1]}"
else:
if self._session is None:
self._session = await self._palabra.create_session()
self._session = await self._palabra.create_session(intent=SESSION_INTENT)
url = f"{TTS_STREAM_URL}?token={self._session.publisher}"
try:
self._ws = await websockets.connect(url, ping_interval=10, ping_timeout=30, max_size=None)
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading