uncloseai-speech/CLAUDE.md
russell@unturf.com b315659be6 Make Qwen3-TTS the default engine, add CPU-only docker support
- Switch default TTS engine from Piper to Qwen3-TTS (1.7B params)
- Upgrade to Python 3.12
- Add docker-compose.cpu.yml for CPU-only deployments
- Improve GPU configuration with NVIDIA environment variables
- Comment out optional engines (Piper, XTTS, Silero, Kokoro) in requirements
- Update Makefile with local/local-cpu targets and venv support
- Simplify voice_to_speaker.default.yaml for Qwen3-TTS voices
- Update docs/MODELS.md with Qwen3-TTS documentation
- Add git commit guidelines to CLAUDE.md
2026-01-26 10:41:23 -05:00

10 KiB

Instructions for Claude Code

Project: uncloseai-speech - Raccoon Mission TTS System License: AGPL v3 (must provide source code to network service users)

Brand Identity

CRITICAL: Always use consistent naming across all files.

Project Name

  • Correct: uncloseai-speech (lowercase, hyphenated)
  • Wrong: "UncloseAI Speech", "Uncloseai Speech", "UncloseAI-Speech"

Organization Name

  • Correct: uncloseai (lowercase, one word)
  • Wrong: "UncloseAI", "Unclose AI", "UnClose AI"

Usage Guidelines

  • In code: Use uncloseai-speech for project references
  • In documentation: Use uncloseai-speech for project name
  • In comments: Use uncloseai-speech consistently
  • Repository URLs: uncloseai-speech (lowercase, hyphenated)
  • Docker images: uncloseai-speech (lowercase, hyphenated)
  • API responses: Use "owned_by": "uncloseai" (lowercase, one word)

Examples

# Correct
description='uncloseai-speech API Server'
owned_by = "uncloseai"

# Wrong
description='UncloseAI Speech API Server'
owned_by = "UncloseAI"
# Correct
# uncloseai-speech

**Raccoon Mission:** Rescue abandoned TTS models and integrate them into uncloseai-speech

# Wrong
# UncloseAI Speech

**Raccoon Mission:** Rescue abandoned TTS models and integrate them into UncloseAI Speech

Core Principles

1. Makefile-First Development

ALWAYS prefer Makefile targets over manual commands.

  • DO: make deploy, make voices, make test
  • DON'T: Manual ssh commands, docker commands, curl commands

When adding new functionality:

  1. Add it to the Makefile first
  2. Document it in make help
  3. Test it works from scratch
  4. Only then modify other files if needed

Makefile is the source of truth for all deployment and development tasks.

2. Work Locally, Deploy Remotely

  • Local development: /home/fox/git/uncloseai-speech/
  • Remote server: ai.foxhop.net (configured in vars.sh, gitignored)
  • Never create remote directories manually - let Makefile handle it
  • Always test from scratch - make clean then make deploy

3. Configuration Management

  • vars.sh - Deployment secrets (gitignored, never commit)
  • vars.sh.example - Template for users (commit this)
  • sample.env - Default environment (commit this)
  • speech.env - Runtime environment (created automatically by Makefile)

Never view or log secrets - source them and use them.

4. Git Commit Guidelines

  • Never add AI attribution - Do not use Co-Authored-By: Claude or similar in commit messages
  • Write clear, concise commit messages describing what changed and why
  • Use imperative mood ("Add feature" not "Added feature")

5. Documentation Requirements

When adding features, update ALL relevant docs:

  • Makefile help text
  • docs/MODELS.md for new TTS engines
  • docs/MIRRORS.md for binary downloads
  • docs/AUDIT.md for file changes
  • This file (docs/CLAUDE.md) for new patterns

Common Tasks

Full Deployment from Scratch

# 1. Clean everything
make clean

# 2. Deploy (syncs files, creates env, builds container)
make deploy

# 3. Download voices (Piper + XTTS samples)
make voices

# 4. Test
make test
make test-xtts

Adding a New TTS Engine

  1. Document it in docs/MODELS.md first
  2. Add download target to Makefile (e.g., voices-silero)
  3. Implement engine wrapper in speech.py or src/engines/
  4. Add test target (e.g., test-silero)
  5. Update make voices to include it
  6. Test full cycle: make clean && make deploy && make voices

Debugging Issues

make logs          # Tail live logs
make logs | grep ERROR  # Filter errors

Never use raw docker/ssh commands - extend Makefile if needed.

File Organization

Scripts vs Docs

  • scripts/ - Executable utilities (add_voice.py, download_samples.sh, etc.)
  • docs/ - Documentation ONLY (no executable code)
  • Dockerfiles, startup.sh - Root level (build artifacts)
  • Makefile - Root level (primary interface)

Never put executable scripts in docs/ directory.

Current Structure (as of 2025-11-09)

uncloseai-speech/
├── Makefile              # PRIMARY INTERFACE - always update first
├── vars.sh               # Secrets (gitignored)
├── vars.sh.example       # Template
├── speech.py             # Main server (will refactor to src/)
├── openedai.py           # API models
├── voice_to_speaker.default.yaml  # Voice config
├── docs/
│   ├── CLAUDE.md         # This file
│   ├── AUDIT.md          # Repository audit
│   ├── MODELS.md         # TTS engines
│   └── MIRRORS.md        # Binary mirror strategy
├── scripts/
│   ├── add_voice.py
│   ├── say.py
│   ├── test_voices.sh
│   └── download_samples.sh
├── Dockerfile
├── docker-compose.yml
└── startup.sh

TTS Engine Status

Default Model (Qwen3-TTS)

  • Qwen3-TTS (tts-1-qwen) - DEFAULT - 1.7B params, 10 languages, voice cloning, 97ms latency

Other Engines (disabled by default, enable in voice_to_speaker.yaml)

  • Piper TTS (tts-1) - 55 voices, fast CPU inference
  • XTTS v2 (tts-1-hd) - Voice cloning, multilingual
  • Silero TTS (tts-1-silero) - 142 voices, 5 languages, auto-downloads
  • Kokoro TTS (tts-1-kokoro) - 32 voices, lightweight (82M params)

Why Qwen3-TTS is Default

  • State-of-the-art quality with voice cloning
  • Actively maintained by Alibaba
  • Apache 2.0 license (commercial-friendly)
  • 10 languages: Chinese, English, Japanese, Korean, German, French, Russian, Portuguese, Spanish, Italian
  • Fast first-packet latency (97ms)
  • Easy voice cloning from 3-second samples

See docs/MODELS.md for complete roadmap and detailed model documentation.

Production Deployment

Production Server: ai.foxhop.net

  • URL: https://ai.foxhop.net (port 8000 internal)
  • Repo Location: /home/fox/git/uncloseai-speech
  • Container: uncloseai-speech-server-1 (image: uncloseai-speech:local)
  • tmux access: tmux send-keys -t 0:1 'command' Enter (window 1 is AI server)

Deployment Workflow

Local:
  /home/fox/git/uncloseai-speech/

  ↓ make deploy (rsync)

Remote (ai.foxhop.net):
  /home/fox/git/uncloseai-speech/

  ↓ docker compose up --build

Container:
  /app/
  ├── speech.py
  ├── voices/
  │   └── en/en_US/libritts_r/medium/*.onnx
  └── config/
      └── voice_to_speaker.yaml

Quick Production Commands

# Check container status
tmux send-keys -t 0:1 'docker ps' Enter

# View logs
tmux send-keys -t 0:1 'docker logs -f uncloseai-speech-server-1' Enter

# Restart container
tmux send-keys -t 0:1 'cd /home/fox/git/uncloseai-speech && docker compose restart' Enter

# Rebuild and redeploy
tmux send-keys -t 0:1 'cd /home/fox/git/uncloseai-speech && docker compose up --build -d' Enter

Testing Philosophy

Full stack testing workflow:

  1. make clean - Clean state
  2. make deploy - Fresh deploy
  3. make voices - Download voice models
  4. make test - Basic API test
  5. make hydrate - Test all 245 voices (sequential, safe)
  6. make load-test - 100 concurrent requests (stress test)

Never assume - always test from scratch after changes.

Raccoon Mission Values

  1. Resilience - Assume upstream dies, plan mirrors
  2. Simplicity - Makefile > manual commands
  3. Documentation - Write docs before code
  4. Liberation - Keep TTS libre (AGPL v3)
  5. Unification - All TTS engines, one API

AGPL v3 Compliance

This project is AGPL v3 licensed. The key obligation: anyone who uses this TTS service over a network must be able to access the source code.

What This Means

Unlike regular GPL, AGPL closes the "SaaS loophole". If you run uncloseai-speech as a service (even without distributing binaries), users have the right to request source code.

Requirements for Operators

When running uncloseai-speech as a network service, you must provide:

  • Complete source code of the running version
  • Any modifications you've made
  • Build instructions

How to Comply

  1. Link in API response - Add source URL to /v1/models or root endpoint
  2. Link in documentation - Include repository URL in service docs
  3. Host source code - Keep your fork in a public git repository

Example Implementation

# In API responses
"source_code": "https://github.com/uncloseai/uncloseai-speech"

Why AGPL?

  • Ensures forks remain open source
  • Community improvements flow back to the project
  • Prevents proprietary TTS services from using our work without sharing back
  • Aligns with Raccoon Mission: Keep TTS libre

Common Mistakes to Avoid

DON'T create directories with raw ssh DO add Makefile target for deployment

DON'T assume container has changes after rsync DO rebuild with make deploy (runs docker compose up --build)

DON'T put scripts in docs/ DO put scripts in scripts/, reference from docs

DON'T hardcode paths/hosts DO use vars.sh variables

DON'T forget to test from scratch DO run make clean && make deploy && make voices

When Things Break

  1. Check make logs for errors
  2. Verify Makefile was updated
  3. Test from clean state
  4. Check if container was rebuilt (make deploy does this)
  5. Verify voices downloaded (ls in container via make logs approach)

Multiprocess Architecture (uvicorn workers=4)

Key pattern: Worker processes spawn as fresh imports, don't run __main__ block.

Solutions implemented:

  1. Caches - Initialize in lifespan context manager (runs per worker)
  2. Args - Use DefaultArgs class at module level, override in __main__

See speech.py:23-113 for implementation.

Future Refactoring (Planned)

  • Move speech.py, openedai.py, audio_reader.pysrc/
  • Create engine abstraction layer in src/engines/
  • Unified voice config with engine selection
  • Binary mirror implementation (MinIO on ai.foxhop.net)

See docs/AUDIT.md for detailed refactoring plan.


Remember: Makefile first, documentation second, code third. Test from scratch every time.

🦝 Raccoon Mission: Keep TTS libre, rescue abandoned models, unify all engines.