Spaces:
Sleeping
Project Structure
Every folder has a single job. Every file at the root earns its place.
Layout
OmniVoice/
β
βββ README.md β΅ user-facing overview
βββ CHANGELOG.md β΅ release history
βββ LICENSE
β
βββ pyproject.toml β΅ Python project manifest
βββ uv.lock β΅ Python lockfile
βββ package.json β΅ monorepo manifest (Bun workspaces + Turborepo)
βββ bun.lock β΅ JS lockfile
βββ turbo.json β΅ turborepo pipeline
β
βββ .dockerignore β΅ Docker build context filter
βββ backend.spec β΅ pyinstaller spec (stays at root by pyinstaller convention)
βββ alembic.ini β΅ DB migration config (stays at root by alembic convention)
β
βββ .env β΅ user config; gitignored, .env.example is the template
βββ .gitignore
β
βββ backend/ β΅ FastAPI server
β βββ main.py
β βββ api/routers/ HTTP endpoints (thin)
β βββ core/ config, db, task queue, metrics
β βββ services/ business logic
β βββ schemas/ pydantic request/response shapes
β
βββ frontend/ β΅ React 19 + Vite + Tauri desktop
β βββ src/
β β βββ pages/ one file per top-level view
β β βββ components/ reusable UI
β β βββ api/ typed API clients
β β βββ store/ Zustand slices
β β βββ hooks/ custom React hooks
β β βββ utils/
β βββ src-tauri/ Rust desktop shell
β βββ public/
β
βββ omnivoice/ β΅ the underlying TTS model package
β βββ models/
β βββ cli/ CLI entry points (omnivoice-infer, etc.)
β βββ data/ data utilities used by the model
β βββ eval/ evaluation scripts
β βββ scripts/ one-off utilities that ship with the package
β βββ training/
β βββ utils/
β
βββ tests/ β΅ all tests live here, no exceptions
β βββ conftest.py
β βββ test_api.py
β βββ test_dub_*.py
β βββ test_job_queue.py
β βββ test_segmentation.py
β βββ frontend/ Node-based frontend tests
β
βββ scripts/ β΅ dev / build / release shell + python scripts
β βββ install.sh universal installer
β βββ run.sh universal launcher
β βββ smoke-test.sh end-to-end validation
β βββ desktop-prod.sh production desktop build
β
βββ deploy/ β΅ Docker deployment configs
β βββ Dockerfile single-stage CUDA image
β βββ docker-compose.yml one-click local deployment
β
βββ docs/ β΅ developer docs, screenshots, branding
β βββ ROADMAP.md where this project is going
β βββ STRUCTURE.md you are here
β βββ mcp.json MCP config template
β βββ preview.png README hero image
β βββ logo.png, logo.svg branding assets
β βββ screenshot-*.png feature screenshots
β βββ languages.md
β βββ training.md
β βββ data_preparation.md
β βββ evaluation.md
β βββ voice-design.md
β
βββ design/ β΅ ASCII mockups of the target UX
β βββ README.md
β βββ 00β08-*.md per-feature specs
β
βββ research/ β΅ reference material, competitor analysis, archived code
β βββ LEARNINGS.md competitive analysis, what to absorb
β βββ TheWhisper/ vendored reference (read-only)
β βββ voice-pro/ vendored reference
β βββ legacy_gradio/ archived Gradio UI (pre-React rewrite)
β
βββ examples/ β΅ runnable demos + sample inputs
β
βββ omnivoice_data/ β΅ Docker bind-mount target (gitignored)
β DB + HF cache live here when running via compose
β
βββ .git/
Rules of the root
Nothing at the root is a runtime artifact. Outputs, temp files, local DBs, crash logs β all go to
~/Library/Application Support/OmniVoice/(or the OS equivalent), never into the repo. The one exception isomnivoice_data/, which exists as a bind-mount anchor for Docker.No ad-hoc scripts at the root. One-off debug scripts live in
scripts/. Tests live intests/. Benchmarks live inscripts/benchmarks/(when we create them).Each subdirectory owns one concern. If you can't describe what goes in a directory in one sentence, it's wrong.
Every package has a manifest.
backend/,frontend/,omnivoice/each have their own deps declared viapyproject.toml/package.jsonβ they are independently testable.
What lives where
| Kind of thing | Goes in |
|---|---|
| User-facing product code | backend/, frontend/ |
| The TTS model (independent of the studio) | omnivoice/ |
| Everything executable but not user-facing | scripts/ |
| Tests | tests/ |
| Developer + user docs (Markdown) | docs/ |
| Target-state mockups | design/ |
| Competitor clones, legacy code, ref material | research/ |
| Runnable demos and sample data | examples/ |
| Runtime data (never committed) | ~/Library/Application Support/OmniVoice/ on Mac |
What doesn't live at the root anymore
Removed in the cleanup pass:
| File | Why it was there | Where it went |
|---|---|---|
test_crash.py, test_server.py, test_whisper.py, test_mock.py, test_pyannote.py |
One-off debug scripts from an April 14 crash investigation. Imported symbols that no longer exist after the router refactor. | Deleted (already gitignored, referenced dead code). |
benchmark.py |
Another stale debug script; imported backend.main._get_db which no longer exists. |
Deleted. |
output.wav, test.wav |
Runtime artifacts. | Deleted / moved out. |
crash_log.txt |
Runtime log. Now written to $DATA_DIR/crash_log.txt. |
Deleted. |
omnivoice.zip (148 MB) |
Offline reference archive of the project itself. | Moved out of the repo to ../omnivoice.zip.bak. |
data/ |
Only contained .DS_Store. |
Deleted. |
legacy_gradio/ |
The pre-React Gradio UI. Kept for historical reference. | Archived to research/legacy_gradio/. |
Scattered .DS_Store files |
macOS Finder droppings. | Deleted from every non-ignored directory. |
Scaling path (proposed, not yet executed)
The current flat layout works fine for the current size. If the project grows to include additional apps (a mobile companion, a plugin SDK, multiple backends), migrate to a Turborepo-style monorepo:
OmniVoice/
βββ apps/
β βββ api/ β was backend/
β βββ web/ β was frontend/
β βββ desktop/ β could extract src-tauri/ here later
βββ packages/
β βββ omnivoice-model/ β was omnivoice/
β βββ tts-adapters/ β new; the pluggable TTS interface from ROADMAP phase 3
βββ config/
β βββ docker/
β βββ pyinstaller/
βββ tests/
βββ docs/
βββ design/
βββ research/
Do not execute this migration without a dedicated PR. It breaks:
pyproject.toml[tool.hatch.build.targets.{sdist,wheel}]pathspackage.jsonworkspaces and scriptsturbo.json,Dockerfile,docker-compose.ymlpathsbackend.spec(['backend/main.py'],pathex=['.'])frontend/src-tauri/tauri.*.conf.jsonsidecar paths- every import that reads
from backend.main import β¦(tests, scripts)
Migrate when adding the second apps/* or the second packages/*. Not before.
Conventions
- Filenames: snake_case for Python, kebab-case or PascalCase for JS/TS components, lowercase for Markdown.
- Tests mirror source paths.
backend/services/dub_pipeline.pyβtests/services/test_dub_pipeline.py. - One-off scripts go into
scripts/with a descriptive name, nottest_*.pyat the root. - New top-level directories require a PR that updates this file.