Text-to-speech library bridging to Orpheus TTS model - bringing text to life
Project description
Eurydice 🎵
Named after Orpheus's wife in Greek mythology. Like Orpheus who tried to bring Eurydice back from the underworld, this library brings text to life through speech.
A Python library for text-to-speech using the Orpheus TTS model, featuring audio caching and provider abstraction.
Features
- 🎤 8 High-Quality Voices - tara, leah, jess, leo, dan, mia, zac, zoe
- ⚡ Audio Caching - Memory and filesystem caching to avoid regenerating audio
- 🔌 Multiple Providers - vLLM (CUDA), orpheus-cpp (CPU/Metal), embedded (transformers), LM Studio
- 🔍 Auto-Detection - Automatically selects the best available provider
- 🔄 Async-First - Built for async/await with sync wrappers for convenience
- 📦 Type Hints - Full type annotations throughout
- 🧪 Well Tested - Comprehensive test suite
Installation
# Basic installation (requires external LM Studio server)
uv add eurydice-tts
# With audio decoding support (recommended)
uv add eurydice-tts[audio]
# With embedded model support (transformers, requires GPU)
uv add eurydice-tts[embedded]
# With orpheus-cpp support (llama.cpp, fast CPU/Metal inference)
uv add eurydice-tts[cpp]
# With vLLM support (CUDA GPU, fastest inference)
uv add eurydice-tts[vllm]
# For development
uv add eurydice-tts[dev]
# All extras
uv add eurydice-tts[all]
Quick Start
Recommended: Auto-Detection
Eurydice can automatically detect and use the best available provider:
from eurydice import Eurydice, TTSConfig, Voice
# Auto-detect provider (vLLM > orpheus-cpp > embedded > lmstudio)
config = TTSConfig(provider="auto")
async with Eurydice(config) as tts:
audio = await tts.generate("Hello, world!", voice=Voice.LEO)
audio.save("hello.wav")
Alternative: LM Studio
If using LM Studio as your provider:
- Install LM Studio
- Download and load the Orpheus TTS model (
orpheus-3b-0.1-ft) - Start the LM Studio server (default:
http://localhost:1234)
Basic Usage
from eurydice import Eurydice, Voice
# Async usage (recommended)
async with Eurydice() as tts:
audio = await tts.generate("Hello, world!", voice=Voice.LEO)
audio.save("hello.wav")
print(f"Generated {audio.duration:.2f}s of audio")
# Sync usage
tts = Eurydice()
audio = tts.generate_sync("Hello, world!")
audio.save("hello.wav")
With Caching
from eurydice import Eurydice, TTSConfig, FilesystemCache
# Configure with filesystem cache for persistence
config = TTSConfig(cache_enabled=True)
cache = FilesystemCache("~/.eurydice/cache")
async with Eurydice(config, cache=cache) as tts:
# First call generates audio
audio1 = await tts.generate("Hello!")
print(f"Cached: {audio1.cached}") # False
# Second call returns cached audio instantly
audio2 = await tts.generate("Hello!")
print(f"Cached: {audio2.cached}") # True
Custom Configuration
from eurydice import Eurydice, TTSConfig, GenerationParams, Voice
config = TTSConfig(
provider="lmstudio",
server_url="http://localhost:1234/v1",
model="orpheus-3b-0.1-ft",
default_voice=Voice.TARA,
cache_enabled=True,
generation=GenerationParams(
temperature=0.7,
top_p=0.9,
repetition_penalty=1.1,
),
)
async with Eurydice(config) as tts:
audio = await tts.generate("Custom configuration example!")
print(f"Duration: {audio.duration:.2f}s")
Available Voices
| Voice | ID | Description |
|---|---|---|
| Tara | tara |
Female voice |
| Leah | leah |
Female voice |
| Jess | jess |
Female voice |
| Leo | leo |
Male voice (default) |
| Dan | dan |
Male voice |
| Mia | mia |
Female voice |
| Zac | zac |
Male voice |
| Zoe | zoe |
Female voice |
API Reference
Eurydice
Main client class for text-to-speech generation.
class Eurydice:
def __init__(
self,
config: Optional[TTSConfig] = None,
provider: Optional[Provider] = None,
cache: Optional[Cache] = None,
) -> None: ...
async def generate(
self,
text: str,
voice: Optional[Voice] = None,
params: Optional[GenerationParams] = None,
format: AudioFormat = AudioFormat.WAV,
use_cache: bool = True,
) -> AudioResult: ...
def generate_sync(self, text: str, **kwargs) -> AudioResult: ...
async def generate_to_file(
self, text: str, path: str, **kwargs
) -> AudioResult: ...
async def is_available(self) -> bool: ...
@staticmethod
def available_voices() -> list[Voice]: ...
AudioResult
Result object containing generated audio.
@dataclass
class AudioResult:
audio_data: bytes # Raw audio bytes
duration: float # Duration in seconds
format: AudioFormat # WAV or RAW
sample_rate: int # Sample rate (24000 Hz)
voice: Voice # Voice used
cached: bool # Whether result came from cache
def save(self, path: str) -> None: ...
def to_base64(self) -> str: ...
TTSConfig
Configuration for the TTS client.
@dataclass
class TTSConfig:
provider: str = "lmstudio"
server_url: Optional[str] = None
model: str = "orpheus-3b-0.1-ft"
default_voice: Voice = Voice.LEO
generation: GenerationParams = GenerationParams()
cache_enabled: bool = True
cache_ttl_seconds: Optional[int] = None
sample_rate: int = 24000
timeout: float = 120.0
Caching
Eurydice supports two caching backends:
MemoryCache
In-memory LRU cache (default when caching is enabled):
from eurydice import MemoryCache
cache = MemoryCache(
max_size=100, # Maximum items to store
default_ttl_seconds=3600, # 1 hour TTL (optional)
)
FilesystemCache
Persistent disk-based cache:
from eurydice import FilesystemCache
cache = FilesystemCache(
cache_dir="~/.eurydice/cache",
default_ttl_seconds=86400, # 24 hour TTL (optional)
)
Cache Keys
Cache keys are content-addressed using SHA256 of:
- Input text
- Voice selection
- Generation parameters (temperature, top_p, etc.)
- Model identifier
This ensures that different configurations produce different cache entries.
Providers
Auto-Detection (Recommended)
Let Eurydice automatically select the best available provider:
from eurydice import Eurydice, TTSConfig
# Auto-detect the best provider
config = TTSConfig(provider="auto")
async with Eurydice(config) as tts:
audio = await tts.generate("Hello with auto-detected provider!")
audio.save("hello.wav")
# Check what providers are available
print(Eurydice.available_providers())
# {'vllm': {'available': True, ...}, 'orpheus-cpp': {'available': False, ...}, ...}
# See which provider would be selected
print(Eurydice.detect_best_provider())
# 'vllm' (if CUDA available) or 'orpheus-cpp' (if installed) or 'embedded' or 'lmstudio'
Provider priority: vLLM (CUDA) > orpheus-cpp (CPU/Metal) > embedded (transformers) > LM Studio
vLLM Provider (Fastest, CUDA Required)
The fastest option for NVIDIA GPUs. Uses vLLM for optimized inference:
from eurydice import Eurydice, TTSConfig
# Using config
config = TTSConfig(provider="vllm")
async with Eurydice(config) as tts:
audio = await tts.generate("Hello from vLLM!")
audio.save("hello.wav")
# Or with custom options
from eurydice import VLLMProvider
provider = VLLMProvider(
model="canopylabs/orpheus-tts-0.1-finetune-prod",
max_model_len=8192,
dtype="bfloat16", # or "float16", "float32"
)
async with Eurydice(provider=provider) as tts:
audio = await tts.generate("Fast GPU inference!")
Requirements:
- Install with
uv add eurydice-tts[vllm] - NVIDIA GPU with CUDA support
- Sufficient VRAM (8GB+ recommended)
LM Studio (Default)
Uses the OpenAI-compatible API provided by LM Studio:
from eurydice import LMStudioProvider
provider = LMStudioProvider(
server_url="http://localhost:1234/v1",
model="orpheus-3b-0.1-ft",
timeout=120.0,
)
Embedded Provider
Run models locally without any external server. This provider loads the Orpheus model directly using transformers:
from eurydice import Eurydice, TTSConfig, EmbeddedProvider
# Using config
config = TTSConfig(provider="embedded")
async with Eurydice(config) as tts:
audio = await tts.generate("Hello from local model!")
audio.save("hello.wav")
# Or using provider directly
provider = EmbeddedProvider(
model="canopylabs/orpheus-3b-0.1-ft", # HuggingFace model ID
device="cuda", # or "mps" for Apple Silicon, "cpu" for CPU
torch_dtype="auto", # or "float16", "bfloat16", "float32"
)
async with Eurydice(provider=provider) as tts:
audio = await tts.generate("Hello!")
Requirements: Install with uv add eurydice-tts[embedded] to get the required dependencies (transformers, accelerate, torch).
Device auto-detection: If no device is specified, the provider automatically detects the best available device (CUDA > MPS > CPU).
Orpheus-cpp Provider (Recommended for CPU/Metal)
The fastest option for CPU and Apple Silicon. Uses llama.cpp under the hood with optimized GGUF models:
from eurydice import Eurydice, TTSConfig
# Using config
config = TTSConfig(provider="orpheus-cpp")
async with Eurydice(config) as tts:
audio = await tts.generate("Hello from llama.cpp!")
audio.save("hello.wav")
# Or with custom options
from eurydice import OrpheusCppProvider
provider = OrpheusCppProvider(
model_path="/path/to/model.gguf", # Optional, auto-downloads if not specified
verbose=False,
lang="en",
)
async with Eurydice(provider=provider) as tts:
audio = await tts.generate("Fast inference!")
Requirements: Install with uv add eurydice-tts[cpp]
Platform support:
- Linux/Windows: CPU inference
- macOS with Apple Silicon: Metal acceleration (very fast)
Examples
See the examples/ directory for more usage examples:
basic_usage.py- Simple text-to-speech generationwith_caching.py- Using the caching systembatch_generation.py- Generating audio for multiple textssync_usage.py- Synchronous API usage
Development
Setup
git clone https://github.com/mustafa-zidan/eurydice.git
cd eurydice
uv venv
source .venv/bin/activate
uv sync --all-extras
Running Tests
# Run all tests
uv run pytest tests/ -v
# With coverage
uv run pytest tests/ --cov=eurydice --cov-report=html
# Run specific test
uv run pytest tests/test_types.py -v
Linting
uv run ruff check .
uv run ruff format .
Contributing
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
- Orpheus TTS - The underlying TTS model
- SNAC - Neural audio codec
- vLLM - High-throughput LLM serving
- llama.cpp - CPU/Metal inference via orpheus-cpp
- LM Studio - Local LLM inference server
Made with ❤️ by Mustafa Abuelfadl
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file eurydice_tts-0.2.0.tar.gz.
File metadata
- Download URL: eurydice_tts-0.2.0.tar.gz
- Upload date:
- Size: 34.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
289c6c2b3003740d850f7f8e00f2e78edc15d30f5de1a6cc1d6cf35d45dee6a3
|
|
| MD5 |
66f739264205849d6992da789ebaa6aa
|
|
| BLAKE2b-256 |
a23b136fc9a31d9ca43df6efb77b0748b3147002afbd0a27678df241da6836d3
|
Provenance
The following attestation bundles were made for eurydice_tts-0.2.0.tar.gz:
Publisher:
release.yml on mustafa-zidan/eurydice
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
eurydice_tts-0.2.0.tar.gz -
Subject digest:
289c6c2b3003740d850f7f8e00f2e78edc15d30f5de1a6cc1d6cf35d45dee6a3 - Sigstore transparency entry: 975874677
- Sigstore integration time:
-
Permalink:
mustafa-zidan/eurydice@2464dadd54d67834700a786c0c5582d96af122d2 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/mustafa-zidan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@2464dadd54d67834700a786c0c5582d96af122d2 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file eurydice_tts-0.2.0-py3-none-any.whl.
File metadata
- Download URL: eurydice_tts-0.2.0-py3-none-any.whl
- Upload date:
- Size: 31.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4365ebe1b284ec2f97c3fa4fa8e66e7dbd8adb55248126cdfd42f541ea994141
|
|
| MD5 |
5bd3adc7b9c482b87e60114d274a79f3
|
|
| BLAKE2b-256 |
7fb3ebe280f6f5341a085e37e090b59972ea564c25f62abeb29f27392f723a09
|
Provenance
The following attestation bundles were made for eurydice_tts-0.2.0-py3-none-any.whl:
Publisher:
release.yml on mustafa-zidan/eurydice
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
eurydice_tts-0.2.0-py3-none-any.whl -
Subject digest:
4365ebe1b284ec2f97c3fa4fa8e66e7dbd8adb55248126cdfd42f541ea994141 - Sigstore transparency entry: 975874679
- Sigstore integration time:
-
Permalink:
mustafa-zidan/eurydice@2464dadd54d67834700a786c0c5582d96af122d2 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/mustafa-zidan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@2464dadd54d67834700a786c0c5582d96af122d2 -
Trigger Event:
workflow_dispatch
-
Statement type: