Skip to content

Commit 3a7456a

Browse files
author
Aleksandr Shliakhov
committed
Token Auth
1 parent e1551e5 commit 3a7456a

17 files changed

Lines changed: 242 additions & 548 deletions

README.md

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,44 +16,36 @@ Palabra has three separate streaming APIs, and the client mirrors that at the to
1616
| [**Realtime Speech-to-Text API**](#speech-to-text-api) | `palabra.stt(...)` | transcription API: stream audio in, incremental text (and optional translations) out |
1717
| [**Realtime TTS API**](#realtime-tts-api) | `palabra.tts(...)` | speech synthesis API: stream text in (e.g. from an LLM), audio out |
1818

19-
Authentication, connection options, [errors](#errors) and [reconnection](#reconnection) are shared between the two.
19+
Authentication, regions, [errors](#errors) and [reconnection](#reconnection) are shared by all three.
2020

2121
## Authentication
2222

23-
Credentials come from the constructor or from the environment:
23+
Everything is driven by two values — an **API Key** and a **region**; all endpoints are derived from them automatically. Create your API Key on the [Palabra API Keys page](https://platform.palabra.dev/api-keys) and set it via the environment or the constructor:
2424

2525
```bash
26-
export PALABRA_CLIENT_ID=...
27-
export PALABRA_CLIENT_SECRET=...
26+
export PALABRA_API_KEY=...
27+
export PALABRA_REGION=eu # optional, defaults to "eu"
2828
```
2929

3030
```python
3131
from palabra_ai import Palabra
3232

33-
palabra = Palabra() # reads the env vars
34-
palabra = Palabra(client_id="...", client_secret="...") # or explicit
33+
palabra = Palabra() # reads the env vars
34+
palabra = Palabra(api_key="...", region="eu") # or explicit
3535
```
3636

37-
Credentials are only used for the REST API (session creation/deletion). They are **not required** for the direct-connection mode below.
37+
The API Key authorizes the WebSocket connection directly: a streaming session is created server-side when you connect and cleaned up when the connection ends — there is nothing to manage.
3838

39-
## Connection options
39+
## Regions
4040

41-
Both `translation()` and `tts()` accept the same three connection modes:
41+
Availability per region (more regions and endpoints are being added over time):
4242

43-
1. **Default** — a session is created via REST on `async with` and deleted on exit. Nothing to manage.
44-
2. **`session=`** — manually create `Session` with `await palabra.create_session()`; its lifecycle is yours (the client won't delete it).
45-
3. **`ws_url=` + `token=`** — debug option: connect directly with a direct `ws_url` and already issued `publisher` token. Here is an example:
43+
| Region | Speech-to-Speech Translation | Speech-to-Text | TTS |
44+
|--------|------------------------------|----------------|-----|
45+
| `eu` ||||
46+
| `us` ||||
4647

47-
```python
48-
palabra = Palabra() # credentials not required in this mode
49-
async with palabra.translation(
50-
source="en",
51-
targets=["es"],
52-
ws_url=ws_url,
53-
token=publisher_token
54-
) as session:
55-
...
56-
```
48+
Opening a stream for a product that is not available in the configured region raises `ValueError` with the list of regions where it is.
5749

5850
---
5951

@@ -99,7 +91,7 @@ async def main():
9991
asyncio.run(main())
10092
```
10193

102-
`async with palabra.translation(...)` does everything for you: creates a session via REST, connects the WebSocket, sends translation task, waits until the pipeline actually confirms the task, and cleans up on exit.
94+
`async with palabra.translation(...)` does everything for you: connects the WebSocket (your API Key authorizes it; a streaming session is created server-side automatically), sends the translation task, waits until the pipeline actually confirms it, and cleans up on exit.
10395

10496
Two rules for the input stream:
10597

@@ -291,7 +283,7 @@ async with palabra.tts(language="en", voice_id="default_low") as tts:
291283

292284
All `palabra.tts(...)` options (languages, voices, `speed`, output formats, sample rates), rate limits, and constraints are described in the [Realtime TTS API docs](https://docs.palabra.ai/docs/streaming_api/realtime_tts). Per-message voice overrides can be passed as keyword arguments of `send_text()`/`synthesize()`.
293285

294-
[Connection options](#connection-options) are the same as in `translation()`, including `ws_url=`/`token=`. Like the ASR endpoint, the TTS endpoint is a fixed address (`wss://stream.palabra.ai/tts-api/v1/text-to-speech/stream`), not taken from the session response.
286+
TTS is currently available in the `eu` and `us` [regions](#regions).
295287

296288
---
297289

@@ -301,12 +293,11 @@ All `palabra.tts(...)` options (languages, voices, `speed`, output formats, samp
301293

302294
Shared by all APIs:
303295

304-
- `AuthError` — missing/invalid credentials.
305-
- `SessionError`REST/WebSocket connection problems (including a crashed receive loop — the original exception is attached as `__cause__`).
296+
- `AuthError` — missing/invalid API Key.
297+
- `SessionError` — WebSocket connection problems (including a crashed receive loop — the original exception is attached as `__cause__`).
306298
- `NotReadyError` — the pipeline didn't confirm `set_task` in time (translation only).
307299
- `TaskError` — the server rejected `set_task` (raised immediately on `async with`, with the server's `code`/`desc`), or raised by `session.raise_on_error(event)` for server `error` messages; by default in-stream errors are delivered as `ServerError` events so a long-running stream survives recoverable errors.
308-
309-
REST session creation retries transient failures (network errors, 5xx) a few times with backoff; 4xx fails immediately.
300+
- `ValueError` — the requested product is not available in the configured [region](#regions), or an unknown region was set.
310301

311302
## Reconnection
312303

@@ -342,6 +333,15 @@ uv sync --dev # editable install + pytest/ruff
342333
make check # ruff check + tests + format check
343334
```
344335

336+
## Migrating from 1.x
337+
338+
| 1.x | 2.0 |
339+
|---|---|
340+
| `Palabra(client_id=..., client_secret=...)` / `PALABRA_CLIENT_ID`, `PALABRA_CLIENT_SECRET` | `Palabra(api_key=..., region=...)` / `PALABRA_API_KEY`, `PALABRA_REGION` — create the key at [platform.palabra.dev/api-keys](https://platform.palabra.dev/api-keys) |
341+
| REST session management: `create_session()` / `delete_session()` / `session=` / `Session` | removed — the API Key authorizes the WebSocket directly, sessions are managed server-side |
342+
| `Palabra(api_url=...)` | removed — endpoints are derived from `region` (see [Regions](#regions)) |
343+
| `ws_url=` + `token=` direct mode | removed |
344+
345345
## Migrating from 0.x
346346

347347
| 0.x (<= 0.6.x) | 1.0 |

examples/realtime_stt.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def on_mic(indata, frames, t, status):
2020
except queue.Full:
2121
pass
2222

23-
palabra = Palabra() # set your credentials here or vie ENV
23+
palabra = Palabra() # set PALABRA_API_KEY / PALABRA_REGION via ENV, or pass api_key=/region=
2424

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

examples/realtime_tts.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55

66
async def main():
7-
palabra = Palabra() # set your credentials here or vie ENV
7+
palabra = Palabra() # set PALABRA_API_KEY / PALABRA_REGION via ENV, or pass api_key=/region=
88

99
async with palabra.tts(language="en", voice_id="default_low") as tts:
1010
# one-shot: send text, collect all chunks

examples/sts_buffer_streaming.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ async def feed_source():
2525

2626

2727
async def main():
28-
palabra = Palabra() # set your credentials here or vie ENV
28+
palabra = Palabra() # set PALABRA_API_KEY / PALABRA_REGION via ENV, or pass api_key=/region=
2929

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

examples/sts_file_to_file.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from palabra_ai import Palabra
22

3-
palabra = Palabra() # set your credentials here or vie ENV
3+
palabra = Palabra() # set PALABRA_API_KEY / PALABRA_REGION via ENV, or pass api_key=/region=
44

55
palabra.translate_file(
66
"speech_en.wav",

examples/sts_mic_to_speakers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def on_spk(outdata, frames, t, status):
3535
else:
3636
outdata.fill(0)
3737

38-
palabra = Palabra() # set your credentials here or vie ENV
38+
palabra = Palabra() # set PALABRA_API_KEY / PALABRA_REGION via ENV, or pass api_key=/region=
3939
async with palabra.translation(source="en", targets=["es"]) as session:
4040

4141
async def feed():

examples/sts_multi_language.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from palabra_ai import Palabra
22

3-
palabra = Palabra() # set your credentials here or vie ENV
3+
palabra = Palabra() # set PALABRA_API_KEY / PALABRA_REGION via ENV, or pass api_key=/region=
44

55
results = palabra.translate_file(
66
"presentation.mp3", # mp3 needs: pip install palabra-ai[audio]

pyproject.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "palabra-ai"
7-
version = "1.0.2"
7+
version = "2.0.0"
88
description = "Simple Python client for Palabra AI APIs"
99
readme = "README.md"
1010
requires-python = ">=3.10"
@@ -21,7 +21,6 @@ classifiers = [
2121
"Typing :: Typed",
2222
]
2323
dependencies = [
24-
"httpx>=0.25",
2524
"websockets>=14",
2625
]
2726

src/palabra_ai/__init__.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@
22
33
from palabra_ai import Palabra
44
5+
# reads $PALABRA_API_KEY (create one at https://platform.palabra.dev/api-keys)
6+
# and $PALABRA_REGION (default "eu")
57
async with Palabra().translation(source="en", targets=["es"]) as session:
68
await session.send_audio(chunk) # PCM s16le 24kHz mono, ~320 ms
79
async for event in session: # Transcript / Audio / ...
810
...
911
"""
1012

1113
from .audio import CHUNK_MS, OUTPUT_SAMPLE_RATE, load_pcm, read_wav, write_wav
12-
from .client import Palabra, Session, TranslationSession
14+
from .client import REGIONS, Palabra, Region, TranslationSession
1315
from .events import (
1416
Audio,
1517
Event,
@@ -25,11 +27,12 @@
2527
from .task import build_task
2628
from .tts import TtsChunk, TtsSession
2729

28-
__version__ = "1.0.0"
30+
__version__ = "2.0.0"
2931

3032
__all__ = [
3133
"CHUNK_MS",
3234
"OUTPUT_SAMPLE_RATE",
35+
"REGIONS",
3336
"Audio",
3437
"AuthError",
3538
# events
@@ -39,9 +42,9 @@
3942
# errors
4043
"PalabraError",
4144
"Raw",
45+
"Region",
4246
"ServerError",
4347
"ServerWarning",
44-
"Session",
4548
"SessionError",
4649
"StreamEnd",
4750
"SttSession",

0 commit comments

Comments
 (0)