Metadata-Version: 2.5
Name: nkl-kokoro-tts-cli
Version: 0.1.9
Summary: Minimal, pipeline-first CLI for Kokoro TTS — stdin/stdout, wav/mp3, log levels
Project-URL: Homepage, https://github.com/nkl/kokoro-tts-cli
Project-URL: Repository, https://github.com/nkl/kokoro-tts-cli
Project-URL: Issues, https://github.com/nkl/kokoro-tts-cli/issues
Author: nkl
License: MIT
License-File: LICENSE
Keywords: cli,kokoro,pipeline,text-to-speech,tts
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
Requires-Python: >=3.10
Requires-Dist: huggingface-hub
Requires-Dist: kokoro>=0.9.4
Requires-Dist: loguru
Requires-Dist: misaki[en]>=0.9.4
Requires-Dist: numpy
Requires-Dist: soundfile
Requires-Dist: torch
Requires-Dist: transformers
Provides-Extra: dev
Requires-Dist: build; extra == 'dev'
Requires-Dist: pytest; extra == 'dev'
Requires-Dist: ruff; extra == 'dev'
Requires-Dist: twine; extra == 'dev'
Description-Content-Type: text/markdown

<h3 align="center">
  <img alt="Logo" src="https://raw.githubusercontent.com/NikolaM-Dev/base-repo_tmpl/main/docs/assets/logo.svg" width="100" />
  <br>
  nkl-kokoro-tts-cli 🗣️🤖
  <img alt="Gap" src="https://raw.githubusercontent.com/NikolaM-Dev/base-repo_tmpl/main/docs/assets/gap.svg" height="32" width="0"/>
</h3>

<p align="center">
  <a href="https://github.com/NikolaM-Dev/nkl-kokoro-tts-cli/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/github/license/NikolaM-Dev/nkl-kokoro-tts-cli?style=flat&colorA=32302f&colorB=54524c"></a>
  <a href="https://github.com/NikolaM-Dev/nkl-kokoro-tts-cli/contributors"><img alt="Contributors" src="https://img.shields.io/github/contributors/NikolaM-Dev/nkl-kokoro-tts-cli?style=flat&colorA=32302f&colorB=a9b665"></a>
  <a href="https://github.com/NikolaM-Dev/nkl-kokoro-tts-cli/stargazers"><img alt="Stars" src="https://img.shields.io/github/stars/NikolaM-Dev/nkl-kokoro-tts-cli?style=flat&colorA=32302f&colorB=d8a657"></a>
  <a href="https://github.com/NikolaM-Dev/nkl-kokoro-tts-cli/issues"><img src="https://img.shields.io/github/issues/NikolaM-Dev/nkl-kokoro-tts-cli?style=flat&colorA=32302f&colorB=ea6062"></a>
  <a href="https://github.com/NikolaM-Dev/nkl-kokoro-tts-cli/commits/main/"><img alt="Last Commit" src="https://img.shields.io/github/last-commit/NikolaM-Dev/nkl-kokoro-tts-cli?style=flat&colorA=32302f&colorB=fe8019"></a>
</p>

&nbsp;

<details><summary>👉 Table of Contents</summary>

- [📍 Overview](#-overview)
- [✨ Features](#-features)
- [📦 Installation](#-installation)
- [🔧 Development](#-development)
- [🚀 Usage](#-usage)
  - [Basic](#basic)
  - [Pipes (first-class)](#pipes-first-class)
  - [mpv pipeline](#mpv-pipeline)
  - [No `-o` defaults](#no--o-defaults)
  - [Formats](#formats)
  - [Voices & languages](#voices--languages)
  - [Verbosity (Unix standard)](#verbosity-unix-standard)
  - [Long texts & splitting](#long-texts--splitting)
  - [Model & device](#model--device)
- [🐛 Troubleshooting](#-troubleshooting)
- [📤 Publish](#-publish)
- [🫂 Acknowledgments](#-acknowledgments)

</details>

## 📍 Overview

Minimal, **pipeline-first** CLI for
[Kokoro TTS](https://github.com/hexgrad/kokoro) (`hexgrad/Kokoro-82M`).
Unix-philosophy: text in → `wav`/`mp3` out, logs to `stderr`, `stdout` stays
binary-clean.

## ✨ Features

- **Pipeline-first** — `stdin`/`stdout` everywhere.
  `echo "hi" | kokoro-tts -o - | mpv --no-video -` works, no temp file. Logs
  (`[INFO]`/`[WARN]`/`[ERROR]`) go to `stderr` only.
- **Always local model** — default `~/.cache/huggingface/hub` (or
  `$HF_HUB_CACHE`/`$KOKORO_MODEL_DIR`). First run auto-downloads
  `hexgrad/Kokoro-82M` (~340M) via `huggingface_hub`, then fully offline.
  `kokoro-tts download --model-dir ./kokoro-model` for a plain dir.
- **Unix verbosity** — default `WARN` (only warnings/errors). `-v` → `INFO`,
  `-vv` → `DEBUG`, `-q` → `ERROR` only, `--log-level` overrides. Quiet by
  default for `| mpv`.
- **Perf** — in-process pipeline + voice tensor cache (`cold 5.3s → warm 0.42s`
  12.5×), lazy `torch`/`kokoro` import so `--help` is instant, `CUDA` ~10× for
  long texts.
- **Audio** — `wav` default (no deps) via `soundfile` 24kHz, `mp3` via `ffmpeg`
  (`-f mp3`), `mpv` pipe friendly.
- **Voices & langs** — `am_echo` default, 50+ known (`af_`, `bf_`, `ef_`, `jf_`,
  `zf_`…), auto `lang` from voice prefix (`a` US, `b` GB, `e` es, `f` fr, `h`
  hi, `i` it, `p` pt-br, `j` ja, `z` zh), custom `.pt` voice.
- **Linux standards** — `uv` + `hatchling` `src/` layout, `pyproject.toml`,
  `requires-python >=3.10`, `kokoro-tts` entry point, `88` mocked tests,
  `SIGPIPE` safe.

## 📦 Installation

**System deps (recommended):**

```bash
# Debian/Ubuntu
sudo apt install espeak-ng ffmpeg mpv

# Arch
sudo pacman -S espeak-ng ffmpeg mpv
```

`espeak-ng` improves G2P fallback, `ffmpeg` needed for `mp3`, `mpv` for pipe
playback.

**User install:**

```bash
# uv tool (isolated, recommended)
uv tool install nkl-kokoro-tts-cli
kokoro-tts --help

# pip
pip install nkl-kokoro-tts-cli

# first run auto-downloads model to ~/.cache/huggingface/hub (~340M)
kokoro-tts "Hello world" -o hello.wav
```

**Pre-download (optional, for offline):**

```bash
kokoro-tts download                          # → ~/.cache/huggingface/hub
kokoro-tts download --model-dir ./kokoro-model  # → plain ./kokoro-model
KOKORO_MODEL_DIR=./kokoro-model kokoro-tts "Hi" -o out.wav
```

## 🔧 Development

```bash
git clone https://github.com/nkl/kokoro-tts-cli
cd kokoro-tts-cli

# env + deps (includes en_core_web_sm 3.8.0 via direct ref)
uv sync --extra dev
uv run kokoro-tts --help

# tests (70+ mocked, no GPU/HF needed)
uv run pytest -q          # 88 passed
uv run pytest -v
uv run pytest -k test_model_local

# lint / build / publish
uv run ruff check src tests
uv build
uv run twine check dist/*
uv tool install --force dist/nkl_kokoro_tts_cli-*.whl
```

Project layout: `src/nkl_kokoro_tts_cli/{cli,tts,logger}.py` (`cli` = pipe/arg
parsing, `tts` = Kokoro wrapper + pipeline/voice cache, `logger` = leveled
`stderr`), `tests/{test_cli,test_tts,test_logger,test_model_local}`.

## 🚀 Usage

```bash
kokoro-tts --help
kokoro-tts --list-voices
kokoro-tts --version
```

### Basic

```bash
kokoro-tts "Hello world, this is Kokoro." -o hello.wav
kokoro-tts "Hello" --voice am_echo --speed 1.0 -o hello.wav
kokoro-tts "Hello" --voice af_bella --lang a -o out.wav  # lang auto from voice
```

### Pipes (first-class)

```bash
echo "Hello from the pipeline" | kokoro-tts -o out.wav
cat book.txt | kokoro-tts --format mp3 -o book.mp3
kokoro-tts --input-file chapter.txt -o chapter.wav --speed 0.95
from_clipboard | kokoro-tts -o - | mpv --no-video -  # from_clipboard = xsel -ob
```

`kokoro-tts` writes `wav` to `stdout` when `-o -` or when `stdout` is piped and
no `-o` given.

### `mpv` pipeline

```bash
# wav (no ffmpeg)
echo "Hello, this is a test" | kokoro-tts --voice am_echo -o - | mpv --no-video -

# mp3 (needs ffmpeg)
echo "Hello" | kokoro-tts -o - --format mp3 | mpv -

# with speed / volume, silent logs
cat transcript.txt | kokoro-tts --voice af_bella --speed 0.95 -o - --log-level ERROR | mpv --no-video --volume=80 --really-quiet -
```

Tip: `mpv --no-video -` reads `stdin`. Our logs stay on `stderr`.

### No `-o` defaults

- `stdout` is a pipe → `wav` to `stdout` (`| mpv -` works without `-o -`)
- `stdout` is a TTY → `./output.wav` + `[WARN]`

### Formats

```bash
kokoro-tts "Hello" -o out.wav               # wav (default)
kokoro-tts "Hello" -o out.mp3 --format mp3  # mp3 (ffmpeg)
echo "hi" | kokoro-tts -o - --format mp3 | mpv -
```

### Voices & languages

```bash
kokoro-tts --list-voices                    # 50+ af_/am_/bf_/bm_/ef_/jf_/zf_...
kokoro-tts "Bonjour le monde" --voice ff_siwis -o fr.wav
kokoro-tts "Hola mundo" --voice ef_dora --lang e -o es.wav
kokoro-tts "Hello" --voice /path/to/custom.pt -o out.wav
kokoro-tts "Hi" --voice af_bella,af_nicole -o averaged.wav  # averaged
```

`--lang` auto-inferred from voice prefix; default `am_echo` → `a` (US).

### Verbosity (Unix standard)

```bash
kokoro-tts "Hello" -o out.wav               # default WARN (only WARN/ERROR)
kokoro-tts "Hello" -o out.wav -v            # INFO + WARN + ERROR
kokoro-tts "Hello" -o out.wav -vv           # DEBUG (adds chunk/ps debug)
kokoro-tts "Hello" -o out.wav -q            # ERROR only
kokoro-tts "Hello" -o out.wav --log-level DEBUG
```

### Long texts & splitting

Kokoro chunks at `510` phonemes. Override:

```bash
kokoro-tts --input-file long.txt --split-pattern '\n+' -o out.wav
```

### Model & device

```bash
# model (always local)
kokoro-tts download --model-dir ./kokoro-model  # plain dir
KOKORO_MODEL_DIR=./kokoro-model kokoro-tts "Hi" -o out.wav
# default HF cache: ~/.cache/huggingface/hub/models--hexgrad--Kokoro-82M

# device (auto picks CUDA if available)
kokoro-tts "Hello" -o out.wav --device auto -v  # [INFO] pipeline ready device='cuda:0' (hf-cache)
kokoro-tts "Hello" -o out.wav --device cpu
kokoro-tts "Hello" -o out.wav --device cuda
```

Long `2600 chars`: `CPU 40s` vs `CUDA 4s`.

## 🐛 Troubleshooting

- `ffmpeg not found` for `mp3` → `sudo apt install ffmpeg`
- `EspeakFallback not Enabled` → `sudo apt install espeak-ng`
- `Can't find model 'en_core_web_sm'` → fixed in `0.1.5+` via direct
  `en_core_web_sm 3.8.0` dep; `uv tool update nkl-kokoro-tts-cli`
- `unauthenticated requests to HF Hub` → suppressed in `0.1.5`; set
  `export HF_TOKEN=hf_xxx` to raise rate limits
- `CUDA requested but not available` → `--device cpu`

## 📤 Publish

```bash
uv build
uv run twine check dist/*
uv publish
```

Or with `just`:

```bash
just build   # uv build (runs tests first)
just publish # uv build + twine check + uv publish
```

`pyproject.toml` uses `hatchling`, `allow-direct-references` for
`en_core_web_sm`, entry `kokoro-tts = nkl_kokoro_tts_cli.cli:main`.

## 🫂 Acknowledgments

- [SUP3RMASS1VE/Ultimate-TTS-Studio-SUP3R-Edition](https://github.com/SUP3RMASS1VE/Ultimate-TTS-Studio-SUP3R-Edition), where I discovered the handy `kokoro-tts`.
- [hexgrad/kokoro](https://github.com/hexgrad/kokoroc), for the interface built on top of [Kokoro-82M](https://huggingface.co/hexgrad/Kokoro-82M).

&nbsp;

<p align="center"><img alt="Footer" src="https://raw.githubusercontent.com/NikolaM-Dev/base-repo_tmpl/main/docs/assets/footer.svg" /></p>

<p align="center">⭐ Hit the Star Button if You Found This Useful ⭐</p>
<p align="center">
  <a href="https://x.com/nikolam_dev" target="_blank"><img alt="X (Twitter) Icon" src="https://raw.githubusercontent.com/NikolaM-Dev/base-repo_tmpl/main/docs/assets/twitter-x.svg"></a>  <a href="https://www.linkedin.com/in/nikolam-dev" target="_blank"><img alt="LinkedIn Icon" src="https://raw.githubusercontent.com/NikolaM-Dev/base-repo_tmpl/main/docs/assets/linkedin.svg"></a>
  <a href="https://github.com/NikolaM-Dev" target="_blank"><img alt="GitHub Icon" src="https://raw.githubusercontent.com/NikolaM-Dev/base-repo_tmpl/main/docs/assets/github.svg"></a>
  <a href="#readme" target="_blank"><img alt="Go to Top Icon" src="https://raw.githubusercontent.com/NikolaM-Dev/base-repo_tmpl/main/docs/assets/top.svg"></a>
</p>
