Metadata-Version: 2.4
Name: black_boltx
Version: 1.0.1
Summary: Word-level speech transcription with Sarvam, Deepgram, OpenAI, or local Whisper.
Author: Black Bolt
License: BSD-2-Clause
Requires-Python: <3.15,>=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx==0.28.1
Requires-Dist: numpy==2.5.2
Requires-Dist: nltk==3.10.3
Requires-Dist: pandas==3.0.5
Provides-Extra: align
Requires-Dist: torch==2.13.0; extra == "align"
Requires-Dist: torchaudio==2.11.0; extra == "align"
Requires-Dist: transformers==5.15.0; extra == "align"
Provides-Extra: vad
Requires-Dist: torch==2.13.0; extra == "vad"
Requires-Dist: pyannote-audio==4.0.7; extra == "vad"
Requires-Dist: huggingface-hub==1.27.0; extra == "vad"
Provides-Extra: opensource
Requires-Dist: black_boltx[align,vad]; extra == "opensource"
Requires-Dist: ctranslate2==4.8.1; extra == "opensource"
Requires-Dist: faster-whisper==1.2.1; extra == "opensource"
Requires-Dist: omegaconf==2.3.1; extra == "opensource"
Provides-Extra: all
Requires-Dist: black_boltx[opensource]; extra == "all"
Provides-Extra: dev
Requires-Dist: pytest==9.1.1; extra == "dev"
Requires-Dist: respx==0.23.1; extra == "dev"
Dynamic: license-file

# Black Bolt

Word-level speech transcription with a choice of ASR backend:

| `--provider` | Who transcribes the words | Word times |
|---|---|---|
| `sarvam` | [Sarvam](https://docs.sarvam.ai/api-reference/speech-to-text/transcribe) `saaras` (Indic + English) | wav2vec2 alignment (Sarvam REST has no word timestamps) |
| `deepgram` | [Deepgram](https://developers.deepgram.com/reference/speech-to-text/listen-pre-recorded) Listen | native words, optionally re-aligned |
| `openai` | OpenAI `whisper-1` / `gpt-4o-transcribe` | native words on `whisper-1`, otherwise alignment |
| `opensource` | local faster-whisper (the original WhisperX ASR) | wav2vec2 alignment |

The rest of the pipeline is the same for every provider:

1. Load audio as 16 kHz mono
2. Voice-activity detection, then merge speech into **≤30 s** chunks (Sarvam REST max)
3. Send each chunk to the chosen provider
4. Force-align the transcript onto the waveform with wav2vec2 → per-word `start` / `end`

Alignment, VAD (pyannote/silero), and the local Whisper path are adapted from [WhisperX](https://github.com/m-bain/whisperX).

## Install

Cloud providers only (energy VAD, no GPU stack):

```bash
pip install -e .
```

Word alignment (required for Sarvam and opensource word times):

```bash
pip install -e '.[align]'
```

Pyannote VAD (same detector WhisperX uses):

```bash
pip install -e '.[vad]'
```

Local Whisper + alignment + pyannote:

```bash
pip install -e '.[opensource]'
```

`ffmpeg` must be on `PATH`.

## CLI

```bash
export SARVAM_API_KEY=...
black-bolt talk.wav --provider sarvam --language hi

export DEEPGRAM_API_KEY=...
black-bolt talk.wav --provider deepgram --model nova-3

export OPENAI_API_KEY=...
black-bolt talk.wav --provider openai --model whisper-1

black-bolt talk.wav --provider opensource --model large-v2 --device cuda
```

Useful flags:

- `--no_align` — skip wav2vec2; Deepgram / OpenAI `whisper-1` still emit native word times
- `--vad_method auto|energy|pyannote|silero|fixed`
- `--chunk_size 30` — hard-capped at 30 s
- `--mode transcribe|translate|verbatim|translit|codemix` — Sarvam only
- `-f json|srt|vtt|txt|tsv|all`

## Python

```python
from black_bolt import transcribe

result = transcribe(
    "talk.wav",
    provider="sarvam",
    language="hi",
    api_key="...",          # or SARVAM_API_KEY
)
for word in result["word_segments"]:
    print(f"{word['start']:.2f}-{word['end']:.2f} {word['word']}")
```

`result["segments"]` is sentence-level after alignment. Each segment has a `words` list.

## Environment

| Provider | Env var |
|---|---|
| Sarvam | `SARVAM_API_KEY` |
| Deepgram | `DEEPGRAM_API_KEY` |
| OpenAI | `OPENAI_API_KEY` |
| pyannote VAD / diarization | `HF_TOKEN` (or `--hf_token`) |

## Publish to PyPI

Pushes to `main` run [`.github/workflows/publish.yml`](.github/workflows/publish.yml): tests, then `python -m build`, then upload to [pypi.org](https://pypi.org). The same version is not uploaded twice (`skip-existing`).

**Auth (pick one):**

1. **Trusted publishing (recommended).** On [pypi.org → Publishing](https://pypi.org/manage/account/publishing/), add a GitHub pending publisher:
   - PyPI project name: `black_boltx`
   - Owner / repo: your GitHub org and `black_bolt`
   - Workflow: `publish.yml`
   - Environment: `pypi`
2. **API token.** Create a PyPI token and add it to the repo as the `PYPI_API_TOKEN` secret. The workflow already reads that secret.

Bump `version` in `pyproject.toml` before a release, or PyPI will skip the upload.

## Notes

- Sarvam REST does **not** return word timestamps (only phrase spans). Black Bolt always runs wav2vec2 after Sarvam to get word times.
- Translated text (`--mode translate` on Sarvam, or English translation in general) cannot be force-aligned to the original audio. Use `--no_align`.
- Overlapping speakers are still a weak point, same as WhisperX.
