* fix: resolve 7 open GitHub issues (#46 #43 #42 #45 #44 #35 #4) #46 — Discord invite expired: - Replace discord.gg/aRRdVj3de7 with discord.gg/bzQavDfVV9 across README, CONTRIBUTING, EnterprisePage, LogsFooter #43 — Docker image crashes with 'No module named core': - Add PYTHONPATH=/app/backend to Dockerfile so bare imports resolve - Add sys.path safety net in backend/main.py (belt-and-suspenders) #42 — IndexTTS not compatible (transformers version conflict): - Catch ImportError + generic Exception in IndexTTS2Backend.is_available() - Return actionable error explaining transformers<5 vs >=5.3 conflict - Update install docs: recommend 'uv pip install -e .' not 'uv sync --all-extras' #45 — Improve pip install tooltips: - Add install_hint field to list_backends() API response - Show hints as tooltips on engine rows in Settings > Engines - Add models-row__hint CSS with hover reveal #44, #35, #4 — Response-only issues (need GitHub comments) * test: add 20 unit tests for issue batch fixes (#46 #43 #42 #45) Coverage: - Discord link sweep: parametrized per-file + repo-wide glob - Docker fix: sys.path insertion in main.py, PYTHONPATH in Dockerfile - IndexTTS: is_available() tuple shape, conflict detection mock, docstring - install_hint: presence, non-empty, registry coverage, backward compat - Regression: minimum engine count, all backends return (bool, str) * fix: address CodeRabbit review — voxcpm package name, bootstrap test isolation - Fix _INSTALL_HINTS: 'pip install voxcpm2' → 'pip install voxcpm' (correct PyPI name) - Replace test_core_config_importable with test_main_py_bootstrap_adds_backend_dir that validates main.py's preamble directly instead of relying on conftest.py - Add test_voxcpm_install_hint_uses_correct_package_name regression guard * fix: align install hints with backend reality (MOSS not on PyPI, VoxCPM supports CPU/MPS) - MOSS-TTS-Nano: not on PyPI, must install from GitHub repo - VoxCPM2: CPU/MPS supported, CUDA recommended (not required)
202 lines
5.8 KiB
Markdown
202 lines
5.8 KiB
Markdown
# Contributing to OmniVoice Studio
|
|
|
|
Thanks for your interest in improving OmniVoice Studio! This guide covers everything you need to get started.
|
|
|
|
## Quick Links
|
|
|
|
| | |
|
|
|---|---|
|
|
| 💬 **Chat** | [Discord](https://discord.gg/bzQavDfVV9) |
|
|
| 🐛 **Bugs** | [GitHub Issues](https://github.com/debpalash/OmniVoice-Studio/issues) |
|
|
| 🏷️ **Good First Issues** | [Filtered list](https://github.com/debpalash/OmniVoice-Studio/labels/good%20first%20issue) |
|
|
| 📋 **Roadmap** | [README → Roadmap](README.md#roadmap) |
|
|
|
|
---
|
|
|
|
## Development Setup
|
|
|
|
### Prerequisites
|
|
|
|
- [Git](https://git-scm.com/)
|
|
- [Bun](https://bun.sh/) (frontend package manager)
|
|
- [uv](https://docs.astral.sh/uv/) (Python environment manager)
|
|
- [ffmpeg](https://ffmpeg.org/) (audio/video processing)
|
|
- Python 3.10+ (managed automatically by `uv`)
|
|
|
|
### Clone & Run
|
|
|
|
```bash
|
|
git clone https://github.com/debpalash/OmniVoice-Studio.git
|
|
cd OmniVoice-Studio
|
|
bun install
|
|
bun run dev
|
|
```
|
|
|
|
This starts both services:
|
|
|
|
| Service | URL | What it does |
|
|
|---------|-----|---|
|
|
| **Backend** | `localhost:3900` | FastAPI server — TTS, ASR, diarization, dubbing pipeline |
|
|
| **Frontend** | `localhost:3901` | React + Vite UI |
|
|
|
|
### Desktop App (Tauri)
|
|
|
|
```bash
|
|
bun run desktop
|
|
```
|
|
|
|
Requires [Rust](https://rustup.rs/) and platform-specific Tauri dependencies — see the [Tauri prerequisites](https://v2.tauri.app/start/prerequisites/).
|
|
|
|
---
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
OmniVoice-Studio/
|
|
├── backend/ # Python FastAPI server
|
|
│ ├── api/ # Route handlers
|
|
│ ├── core/ # Config, prefs, constants
|
|
│ └── services/ # TTS engines, ASR, dubbing, audio DSP
|
|
│ └── tts_backend.py # ← Multi-engine TTS registry
|
|
├── frontend/ # React + Vite
|
|
│ ├── src/
|
|
│ │ ├── components/ # UI components
|
|
│ │ ├── hooks/ # Custom React hooks
|
|
│ │ ├── stores/ # Zustand state slices
|
|
│ │ └── utils/ # Shared utilities
|
|
│ └── src-tauri/ # Rust/Tauri desktop shell
|
|
├── deploy/ # Docker, CI configs
|
|
├── docs/ # Screenshots, MCP config
|
|
└── scripts/ # Build & release scripts
|
|
```
|
|
|
|
---
|
|
|
|
## How to Contribute
|
|
|
|
### Bug Reports
|
|
|
|
Open an [issue](https://github.com/debpalash/OmniVoice-Studio/issues/new) with:
|
|
|
|
1. **What happened** vs **what you expected**
|
|
2. **Steps to reproduce**
|
|
3. **OS, GPU, and Python version** (find in Settings → Logs)
|
|
4. **Error logs** (Settings → Logs → copy relevant lines)
|
|
|
|
### Pull Requests
|
|
|
|
1. **Fork** the repo and create a branch from `main`
|
|
2. **Keep PRs focused** — one feature or fix per PR
|
|
3. **Run tests** before pushing:
|
|
```bash
|
|
# Backend tests
|
|
uv run pytest backend/ -x -q
|
|
|
|
# Frontend build check
|
|
cd frontend && npx vite build --mode development
|
|
```
|
|
4. **Write a clear PR title** — it becomes the squash-merge commit message
|
|
5. **Don't include** local machine stats, file paths, or private system info in PR descriptions
|
|
|
|
### Adding a New TTS Engine
|
|
|
|
OmniVoice's TTS backend is a plugin registry. Adding a new engine takes ~50 lines:
|
|
|
|
1. Open `backend/services/tts_backend.py`
|
|
2. Create a class extending `TTSBackend`:
|
|
|
|
```python
|
|
class MyEngineBackend(TTSBackend):
|
|
id = "my-engine"
|
|
display_name = "My Engine (description)"
|
|
|
|
@classmethod
|
|
def is_available(cls) -> tuple[bool, str]:
|
|
try:
|
|
import my_engine # noqa: F401
|
|
return True, "ready"
|
|
except ImportError:
|
|
return False, "my_engine not installed. pip install my-engine"
|
|
|
|
@property
|
|
def sample_rate(self) -> int:
|
|
return 24000
|
|
|
|
@property
|
|
def supported_languages(self) -> list[str]:
|
|
return ["en", "zh"]
|
|
|
|
def generate(self, text: str, **kw) -> torch.Tensor:
|
|
# ... call your engine, return [1, num_samples] tensor
|
|
```
|
|
|
|
3. Register it in `_REGISTRY` at the bottom of the file
|
|
4. That's it — it auto-appears in Settings → TTS Engine
|
|
|
|
---
|
|
|
|
## Code Style
|
|
|
|
### Python (Backend)
|
|
|
|
- **Formatter**: We don't enforce one globally — match the style of the file you're editing
|
|
- **Logging**: Use `logger.warning()` / `logger.error()`, never bare `print()`
|
|
- **Exceptions**: Avoid bare `except: pass` — catch specific exceptions
|
|
- **Type hints**: Use them for public API functions and class methods
|
|
|
|
### JavaScript/React (Frontend)
|
|
|
|
- **Components**: Functional components with hooks
|
|
- **State**: Zustand stores in `src/stores/`, organized by slice
|
|
- **CSS**: Vanilla CSS in component-level files — no Tailwind
|
|
- **Naming**: `PascalCase` for components, `camelCase` for hooks and utils
|
|
|
|
### Rust (Tauri)
|
|
|
|
- **Format**: `cargo fmt` before committing
|
|
- **Modules**: One concern per file (`bootstrap.rs`, `tools.rs`, `config.rs`, `commands.rs`)
|
|
|
|
---
|
|
|
|
## Commit Messages
|
|
|
|
Write clear, concise messages. The PR title becomes the squash-merge commit.
|
|
|
|
```
|
|
good: fix: prevent CUDA OOM during concurrent transcription + TTS
|
|
good: feat: add CosyVoice 3 TTS backend adapter
|
|
good: docs: add platform compatibility matrix to README
|
|
|
|
bad: fixed stuff
|
|
bad: update
|
|
bad: WIP
|
|
```
|
|
|
|
---
|
|
|
|
## Testing
|
|
|
|
```bash
|
|
# Run all backend tests
|
|
uv run pytest backend/ -x -q
|
|
|
|
# Run a specific test file
|
|
uv run pytest backend/tests/test_api.py -x -q
|
|
|
|
# Frontend build validation (no test suite yet)
|
|
cd frontend && npx vite build --mode development
|
|
|
|
# Tauri shell check (requires Rust)
|
|
cd frontend/src-tauri && cargo check
|
|
```
|
|
|
|
---
|
|
|
|
## Need Help?
|
|
|
|
- **Stuck on setup?** Ask in [Discord #help](https://discord.gg/bzQavDfVV9)
|
|
- **Not sure where to start?** Check [good first issues](https://github.com/debpalash/OmniVoice-Studio/labels/good%20first%20issue)
|
|
- **Want to discuss a big change?** Open a [discussion](https://github.com/debpalash/OmniVoice-Studio/discussions) or Discord thread before coding
|
|
|
|
Thank you for contributing! 🎙️
|