Metadata-Version: 2.4
Name: ringglabs
Version: 0.0.5
Summary: Production-grade Python SDK for RinggLabs STT over REST and WebSocket.
Author-email: RinggLabs <support@ringg.ai>
License-Expression: MIT
Project-URL: Homepage, https://github.com/Stonkr/ringglabs-sdk
Project-URL: Documentation, https://github.com/Stonkr/ringglabs-sdk/tree/main/docs
Project-URL: Repository, https://github.com/Stonkr/ringglabs-sdk
Project-URL: Issues, https://github.com/Stonkr/ringglabs-sdk/issues
Keywords: stt,speech-to-text,asr,websocket,ringglabs
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: POSIX :: Linux
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx<1.0.0,>=0.27.0
Requires-Dist: websockets<16.0,>=12.0
Provides-Extra: dev
Requires-Dist: pytest<9.0,>=8.0; extra == "dev"
Requires-Dist: pytest-asyncio<1.0,>=0.23; extra == "dev"
Dynamic: license-file

# RinggLabs Python SDK

`ringglabs` is the official Python SDK for RinggLabs-compatible speech-to-text services over:
- HTTP file transcription
- WebSocket real-time streaming

The SDK exposes a small public surface for fast integration and keeps proxy-specific complexity hidden.

## Installation

```bash
pip install ringglabs
```

## Compatibility

- Python: `3.10+`
- Windows: `10+`
- macOS: `11+`
- Ubuntu: `20.04+`

## Quickstart

### Sync file transcription

```python
from ringglabs.stt import Client

client = Client(base_url="localhost:7860", api_key="rk_live_xxx")
result = client.transcribe("sample.wav", language="en", enable_cap_punc=True)
print(result.transcription)
```

### Async file transcription

```python
import asyncio
from ringglabs.stt import AsyncClient

async def main():
    async with AsyncClient(base_url="localhost:7860", api_key="rk_live_xxx") as client:
        result = await client.transcribe("sample.wav", language="hi")
        print(result.transcription)

asyncio.run(main())
```

### Sync streaming

```python
from ringglabs.stt import Client

with Client(base_url="localhost:7860", api_key="rk_live_xxx").stream(
    language="en",
    mode="stream",
    accept_client_vad_events=False,
) as session:
    session.send_audio(b"...pcm chunk...")
    session.end()
    for event in session.events():
        print(event.type, event.raw)
```

## Client Initialization

```python
Client(
    base_url: str | None = "prod-api.ringg.ai",
    api_key: str | None = None,
    timeout: TimeoutConfig | None = None,
    default_headers: dict[str, str] | None = None,
)
```

`AsyncClient(...)` uses the same constructor parameters.

## REST API

### Method

```python
Client.transcribe(
    source,
    *,
    language: str = "hi",
    enable_cap_punc: bool = True,
    api_key: str | None = None,
    filename: str | None = None,
    content_type: str = "audio/wav",
)
```

`AsyncClient.transcribe(...)` has the same signature.

### Supported `source` types

- `str` / `pathlib.Path` (file path)
- `bytes` / `bytearray`
- `BinaryIO` (open file object)

### Parameters

| Parameter | Type | Default | Description |
|---|---|---|---|
| `language` | `str` | `"hi"` | Language hint passed to proxy. |
| `enable_cap_punc` | `bool` | `True` | Enable punctuation/capitalization post-processing. |
| `api_key` | `str \| None` | `None` | Per-request API key override. |
| `filename` | `str \| None` | auto-detected (`"audio.wav"` fallback) | Multipart filename. |
| `content_type` | `str` | `"audio/wav"` | Multipart content type. |

### Return type

`RestTranscriptionResult`:
- `status`
- `transcription`
- `is_final`
- `language`
- `duration_seconds`
- `processing_time_seconds`
- `request_id`
- `raw` (full JSON payload from proxy)

## Streaming API

### Open a stream

```python
session = Client(...).stream(
    sample_rate=16000,
    encoding="int16",
    language="hi",
    mode="stream",
    vad_tail_sil_ms=200,
    vad_confidence=0.55,
    enable_cap_punc=True,
    accept_client_vad_events=False,
    api_key=None,
)
```

Same options are available on `AsyncClient.stream(...)`.

### Stream options

| Parameter | Type | Default | Description |
|---|---|---|---|
| `sample_rate` | `int` | `16000` | PCM sample rate sent in `start` message. |
| `encoding` | `str` | `"int16"` | Audio encoding (`int16`, `linear16`, `float32`, `int32`). |
| `language` | `str` | `"hi"` | Language hint. |
| `mode` | `str` | `"stream"` | `stream` or `on_final`. |
| `vad_tail_sil_ms` | `int` | `200` | Server VAD tail silence (ms). |
| `vad_confidence` | `float` | `0.55` | Server VAD confidence threshold. |
| `enable_cap_punc` | `bool` | `True` | Enable punctuation/capitalization in output path. |
| `accept_client_vad_events` | `bool` | `False` | Whether client sends speech boundary events. |
| `api_key` | `str \| None` | `None` | Per-session API key override. |

### Session methods (sync)

- `send_audio(bytes)`
- `send_vad_event(state)`
- `start_speaking()`
- `stop_speaking()`
- `ping()`
- `end(command="end")`
- `recv_event()`
- `events()` iterator
- context manager (`with ... as session:`)

Async equivalents are available on `AsyncStreamSession`.

### Streaming behavior

- `mode="stream"`:
  - Segment results are delivered as transcript events during session.
- `mode="on_final"`:
  - Segment updates are emitted and final transcript events are emitted at finalization boundaries.
- `accept_client_vad_events=True`:
  - Call `start_speaking()` / `stop_speaking()` to explicitly mark utterance boundaries.

## WebSocket Event Types

The SDK parses messages into typed events:
- `ready`
- `transcript`
- `ack`
- `pong`
- `error`

Every event includes `.raw` for the original proxy payload.

`transcript` events may include:
- `transcription`
- `is_final`
- `language`
- `request_id`
- `segment_idx`
- `segments`
- `compute_latency_ms`
- `audio_duration_sec`
- `transcribed_audio_duration_sec`
- `processing_time_ms`

## Health Check

```python
from ringglabs.stt import Client

client = Client(base_url="localhost:7860")
health = client.health()
print(health)
```

Async:

```python
health = await AsyncClient(base_url="localhost:7860").health()
```

## Errors and Exceptions

Common SDK exceptions:
- `ApiError` (includes `status_code`, `code`, `payload`)
- `AuthenticationError` (401/402 proxy auth failures)
- `TimeoutError`
- `TransportError`
- `ProtocolError`

Example:

```python
from ringglabs.stt import Client, ApiError, TimeoutError, TransportError

client = Client(base_url="localhost:7860", api_key="rk_live_xxx")

try:
    result = client.transcribe("sample.wav")
except TimeoutError:
    print("request timed out")
except TransportError:
    print("network/connection failure")
except ApiError as exc:
    print(exc.status_code, exc.code, exc.message)
```

## Production Usage Guidance

- Reuse client instances per process/service worker.
- Set explicit timeout budgets via `TimeoutConfig`.
- Log `result.raw` and `event.raw` for debugging and support.
- Use retries only for idempotent operations and transport-level failures.
- For async services, use `AsyncClient` end-to-end (avoid sync calls in event loop handlers).

## Public API Summary

- `Client`: sync REST + sync streaming
- `AsyncClient`: async REST + async streaming
- `TimeoutConfig`: connect/read/write/pool/ws_open/ws_recv/ws_close controls
- `retry` / `async_retry`: opt-in helper wrappers

