Metadata-Version: 2.4
Name: doubao-tts
Version: 0.1.0
Summary: Python client and CLI for Volcengine/ByteDance Doubao seed-tts-2.0 bidirectional streaming TTS.
Project-URL: Homepage, https://github.com/Hypnus-Yuan/doubao-tts
Project-URL: Documentation, https://github.com/Hypnus-Yuan/doubao-tts#readme
Project-URL: Repository, https://github.com/Hypnus-Yuan/doubao-tts.git
Project-URL: Issues, https://github.com/Hypnus-Yuan/doubao-tts/issues
Project-URL: Changelog, https://github.com/Hypnus-Yuan/doubao-tts/releases
Author-email: Yuantao Wen <hypnus.yuan@gmail.com>
License-Expression: MIT
License-File: LICENSE
Keywords: bytedance,doubao,seed-tts,speech,text-to-speech,tts,volcengine
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: MacOS
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
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: Topic :: Multimedia :: Sound/Audio :: Speech
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: click>=8.1.7
Requires-Dist: pyyaml>=6.0.1
Requires-Dist: websockets<16,>=14.2
Provides-Extra: daemon
Requires-Dist: platformdirs>=4.3; extra == 'daemon'
Description-Content-Type: text/markdown

# doubao-tts

English | [中文](README.zh.md)

[![PyPI](https://img.shields.io/pypi/v/doubao-tts.svg)](https://pypi.org/project/doubao-tts/)
[![Python](https://img.shields.io/pypi/pyversions/doubao-tts.svg)](https://pypi.org/project/doubao-tts/)
[![CI](https://github.com/Hypnus-Yuan/doubao-tts/actions/workflows/ci.yml/badge.svg)](https://github.com/Hypnus-Yuan/doubao-tts/actions/workflows/ci.yml)
[![Coverage](https://img.shields.io/badge/coverage-95%25-brightgreen.svg)](https://github.com/Hypnus-Yuan/doubao-tts/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Ruff](https://img.shields.io/badge/code%20style-ruff-46aef7.svg)](https://github.com/astral-sh/ruff)
[![uv](https://img.shields.io/badge/package%20manager-uv-de5fe9.svg)](https://github.com/astral-sh/uv)
[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen.svg)](https://pre-commit.com/)
[![mypy strict](https://img.shields.io/badge/mypy-strict-blue.svg)](http://mypy-lang.org/)
[![Downloads](https://static.pepy.tech/badge/doubao-tts/month)](https://pepy.tech/project/doubao-tts)

> A small, production-minded Python client and CLI for
> **Volcengine Doubao seed-tts-2.0** bidirectional streaming TTS —
> native-quality Chinese voices with emotion control, ready for agents,
> scripts, and serving pipelines.

## Why

`doubao-tts` is the first PyPI package targeting Volcengine's **seed-tts-2.0**
bidirectional-streaming endpoint. Existing Python TTS wrappers either:

- hit the older SAMI HTTP endpoint (no streaming, older voice quality), or
- aren't published to PyPI at all.

This package fills that gap with:

- A clean `synthesize(text, out_path)` interface
- A CLI that drops straight into agent frameworks (Hermes, Dify, LangChain, n8n, …)
- Strict mypy on every public module
- 95% unit test coverage, atomic output writes, proper credential redaction

## Install

```bash
pip install doubao-tts

# or with uv:
uv add doubao-tts

# CLI-only, installed as a standalone tool:
uv tool install doubao-tts
```

## Quick start

### Python

```python
from doubao_tts import synthesize

synthesize("你好，世界", "hello.mp3")
```

### Async

```python
from doubao_tts import synthesize_async

await synthesize_async(
    "Hello from Doubao seed-tts-2.0!",
    "hello.mp3",
    voice="en-female-assistant",
    speed=1.1,
)
```

### CLI

```bash
# simplest
doubao-tts say "你好" --out hello.mp3

# pick a voice + adjust speed
doubao-tts say "好激动！" --voice zh-female-warm --speed 1.2 --out excited.mp3

# read from a file
doubao-tts say --text-file script.txt --out narration.mp3

# browse available voices
doubao-tts list-voices --lang zh

# inspect resolved config (tokens are redacted)
doubao-tts config show
```

## Credentials

Credentials resolve in this order — first match wins:

1. Keyword arguments to `synthesize(...)`
2. Environment variables: `VOLCENGINE_APP_ID`, `VOLCENGINE_ACCESS_TOKEN`
   (also accepted as `DOUBAO_APP_ID`, `DOUBAO_ACCESS_TOKEN`)
3. `~/.doubao-tts/config.yaml`
4. Built-in defaults (speaker, audio format, sample rate)

Example `~/.doubao-tts/config.yaml`:

```yaml
app_id: "1234567890"
access_token: "volc_...."
speaker: zh_female_vv_uranus_bigtts
audio_format: mp3
sample_rate: 24000
```

Get your app ID and access token from the
[Volcengine Speech console](https://console.volcengine.com/speech/service).
You need the **seed-tts-2.0** product activated on your account.

## Integration: Hermes Agent

[Hermes Agent](https://github.com/NousResearch/hermes-agent) v0.x+ supports
declarative TTS command providers via its `tts.providers.<name>` config
block. Plug `doubao-tts` in:

```yaml
# ~/.hermes/config.yaml
tts:
  provider: doubao
  providers:
    doubao:
      type: command
      command: 'doubao-tts say --text-file {input_path} --out {output_path}'
```

That's it. Any Hermes voice-out path now routes through Doubao seed-tts-2.0.

## Voices

The CLI ships with a curated alias catalogue:

| Alias | Language | Gender | Style |
|---|---|---|---|
| `zh-female-warm` (default) | zh-CN | female | warm, conversational |
| `zh-female-reporter` | zh-CN | female | crisp, news-reporter |
| `zh-male-warm` | zh-CN | male | warm, narrator |
| `zh-male-energetic` | zh-CN | male | energetic host |
| `en-female-assistant` | en-US | female | assistant, neutral |
| `en-male-assistant` | en-US | male | assistant, neutral |

Volcengine publishes hundreds more speaker IDs. You can pass any raw
speaker ID to `voice=` directly — aliases are a convenience, not a gate.

## Emotion control

seed-tts-2.0 supports per-utterance emotion tags:

```python
synthesize(
    "好激动，我终于做到了！",
    "out.mp3",
    emotion="excited",
    emotion_scale=4.0,  # 0-5; higher = more intense
)
```

Model-supported emotions vary by voice; consult the Volcengine console
for the up-to-date list per speaker.

## Performance notes

- One `synthesize()` call opens a fresh WebSocket and tears it down at
  the end. End-to-end latency to a 24 kHz MP3 of ~2 seconds of speech
  is **~750 ms** on a healthy connection — network dominates.
- The seed-tts-2.0 `bidi-stream` session currently accepts **one**
  synthesis per session (empirically verified); connection reuse saves
  only TCP+TLS setup (~180 ms / call). A daemon mode with connection
  pooling is planned for a future release, but most users don't need it.
- `import doubao_tts` is cheap — ~3 ms — because `websockets` and
  `yaml` are only imported on first synthesis call.

## Error handling

All user-facing errors inherit from `DoubaoTTSError`:

```python
from doubao_tts import (
    DoubaoTTSError, DoubaoConfigError,
    DoubaoAuthError, DoubaoAPIError, DoubaoTimeoutError,
    synthesize,
)

try:
    synthesize("你好", "out.mp3")
except DoubaoAuthError:
    ...  # rotate your token
except DoubaoTimeoutError:
    ...  # retry or check network
except DoubaoTTSError as exc:
    ...  # catch-all
```

## Security

- Access tokens are redacted in all logs and CLI output — see
  [`SECURITY.md`](SECURITY.md) for the exact policy.
- User text is **not** logged by default. To troubleshoot protocol
  issues, opt in with `DOUBAO_TTS_TRACE_PAYLOADS=1`.
- `~/.doubao-tts/config.yaml` is user-scoped; the shipped `.gitignore`
  excludes `.env` files at the project level.
- Vulnerability reports: `hypnus.yuan@gmail.com` or a private GitHub
  security advisory.

## Development

```bash
git clone https://github.com/Hypnus-Yuan/doubao-tts.git
cd doubao-tts

uv sync --all-extras --group dev
uv run pre-commit install
uv run pytest
```

See [`CONTRIBUTING.md`](CONTRIBUTING.md) for the full workflow.

## Roadmap

- **v0.2** — connection-reuse daemon (saves ~180 ms / call on
  chained requests), streaming callback API, richer voice metadata.
- **v0.3** — integration recipes for LangChain, LlamaIndex, Dify.
- **v1.0** — API frozen, semver guarantees.

## License

MIT — see [`LICENSE`](LICENSE).

## Credits

Protocol framing extracted and hardened from
[Hermes Agent](https://github.com/NousResearch/hermes-agent) community
work. Thanks to the Volcengine Speech team for the seed-tts-2.0
bidirectional-streaming API.
