8.1 KiB
Project Structure
Every folder has a single job. Every file at the root earns its place.
Layout
OmniVoice/
│
├── README.md ⟵ user-facing overview
├── ROADMAP.md ⟵ where this project is going
├── STRUCTURE.md ⟵ you are here
├── LICENSE
├── preview.png ⟵ referenced by README
│
├── pyproject.toml ⟵ Python project manifest
├── uv.lock ⟵ Python lockfile
├── package.json ⟵ monorepo manifest (Bun workspaces + Turborepo)
├── bun.lock ⟵ JS lockfile
├── turbo.json ⟵ turborepo pipeline
│
├── Dockerfile ⟵ single-stage CUDA image
├── docker-compose.yml ⟵ one-click local deployment
├── .dockerignore
├── backend.spec ⟵ pyinstaller spec (stays at root by pyinstaller 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 (arrives Phase 1)
│ │ └── 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
│
├── docs/ ⟵ developer and model documentation
│ ├── languages.md
│ ├── training.md
│ ├── data_preparation.md
│ ├── evaluation.md
│ └── voice-design.md
│
├── design/ ⟵ ASCII mockups of the target UX
│ ├── README.md
│ ├── 00-architecture.md
│ ├── 01-launchpad.md
│ ├── 02-dub-studio.md
│ ├── 03-voice-library.md
│ ├── 04-translation-workbench.md
│ ├── 05-batch-queue.md
│ ├── 06-export-center.md
│ ├── 07-tools.md
│ └── 08-settings.md
│
├── research/ ⟵ reference material, competitor analysis, archived code
│ ├── LEARNINGS.md competitive analysis, what to absorb
│ ├── TheWhisper/ vendored reference (read-only)
│ ├── voice-pro/ vendored reference
│ ├── voicebox/ 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.