项目结构¶
每个文件夹都有单一职责。根目录下的每个文件都应有其存在价值。
目录结构¶
VoiceStudio/
│
├── README.md ⟵ user-facing overview (translations: docs/readme/README_*.md)
├── CHANGELOG.md ⟵ release history; Electron releases use the tagged section
├── CLAUDE.md / AGENTS.md ⟵ matching copies of the agent operating rules
├── LICENSE / LICENSE-NOTICE.md / SPONSORS.md ⟵ legal terms, required notices, supporters
│
├── pyproject.toml ⟵ Python metadata plus the pytest and lint settings
├── uv.lock ⟵ Python lockfile
├── package.json ⟵ monorepo manifest (Bun workspaces) and THE app
│ version (pyproject.toml + backend/core/version.py mirror it)
├── bun.lock ⟵ JS lockfile — repo-root, covers the electron/ workspace
├── flake.nix, flake.lock ⟵ community Nix dev shells + NixOS FHS env (docs/install/nix.md)
│
├── .coderabbit.yaml / greptile.json ⟵ bot-review setup; CLAUDE.md supplies both rule sets
├── skills-lock.json ⟵ records the origin and digest of each .agents/skills/ copy
├── .gitleaks.toml ⟵ repository secret-detection policy
├── .gitmodules ⟵ registers omnivoice-gallery
├── .python-version ⟵ interpreter selection for Python tooling
├── .dockerignore ⟵ Docker build context filter
├── alembic.ini ⟵ DB migration config (stays at root by alembic convention)
│
├── .gitignore ⟵ excludes a checkout-local .env; Settings persists user choices in
│ ~/.config/omnivoice/env through backend/core/user_env.py
│
├── backend/ ⟵ FastAPI server
│ ├── main.py sole process entry; its annotated startup sequence must retain its order
│ ├── api/routers/ 44 routers, auto-included; HTTP/WS adaptation stays thin here
│ │ └── setup/ setup-wizard endpoints and model acquisition
│ ├── core/ shared infrastructure: configuration, persistence, job/event plumbing,
│ │ auth and CSRF, safe paths, analytics consent, version and diagnostics
│ ├── services/ 116 modules of business logic spanning speech, dubbing, DSP, GPU dispatch,
│ │ engine selection and loaded-model ownership
│ ├── engines/ per-engine adapters: audiocpp, confucius4, cosyvoice_gguf,
│ │ cosyvoice_subprocess, dots_tts, indextts, moss_tts_nano_subprocess,
│ │ moss_tts_v15, omnivoice_gguf, omnivoice_subprocess, pockettts,
│ │ supertonic3, voxcpm2_subprocess, whisper_cpp, _asr_sidecar, _echo
│ ├── schemas/ Pydantic types at the request/response boundary
│ ├── config/models.yaml catalogue of selectable models
│ ├── migrations/versions/ mandatory Alembic home for database evolution
│ ├── plugins/ extension landing area; contract lives in services/plugin_sdk.py
│ ├── mcp_shim/ MCP launch surface documented by docs/mcp.md
│ ├── speech_client/ client entry for the speech sidecar
│ └── tests/ separately collected backend test session (details below)
│
├── electron/ ⟵ the only desktop app and web UI (Electron + React 19)
│ ├── src/main/ lifecycle, backend supervisor, runtime setup, updater, native IPC
│ ├── src/preload/ typed contextBridge → window.voicestudio
│ ├── src/renderer/ desktop React app: routes/, features/, components/, i18n/locales/
│ ├── src/shared/ modules shared by the desktop and browser builds (api/, i18n/,
│ │ store/, ui/, utils/) — not a runnable app
│ ├── tests/ packaged-app, installer and workflow smoke tests
│ ├── build/ packaging inputs: icons, entitlements, Info.plist
│ ├── scripts/ dev launcher, AppImage update-info embedding
│ ├── vite.web.config.ts browser build (`bun run build:web`) → frontend/dist/
│ └── electron-builder.config.mjs installers: DMG/zip, NSIS, AppImage + deb
│
├── native/desktop-bridge/ ⟵ Rust helper used by Electron
│
├── frontend/dist/ ⟵ build output of `bun run build:web` (gitignored): the web UI
│ the backend serves in Docker and, from Electron packages, to LAN devices
│
├── 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/ ⟵ default pytest collection selected by pyproject.toml `testpaths`
│ ├── conftest.py redirects OMNIVOICE_DATA_DIR to disposable state for the whole session
│ ├── backend/ / scripts/ path-shaped coverage for those source areas
│ ├── smoke/ quick end-to-end gates; isolated CI job runs with HF_HUB_OFFLINE=1
│ ├── evals/ evals.yml-driven output-quality checks
│ ├── probe/ / fixtures/ diagnostic probes and reusable inputs
│ └── frontend/ retained node:test suite for utilities and developer tooling
│
├── scripts/ ⟵ development, packaging and release commands (sh, Python, mjs)
│ ├── install.sh / install.ps1 installers delivered from voicestudio.sh/install
│ ├── dev-backend.mjs supervisor behind `bun run dev:api`
│ ├── setup.py platform finishing step for `bun run setup:api`, including ROCm opt-in
│ ├── electron-smoke-test.mjs packaged-launch probe invoked by `bun run smoke-test`
│ ├── prepare_electron_release.py, check_electron_release_assets.py artifact verification
│ ├── check-docs-drift.py checks docs-drift.yml against authoritative docs/features.yaml
│ └── build-omnivoice-tts.sh produces the sidecars stored under bin/
│
├── bin/ ⟵ one precompiled omnivoice-tts sidecar for each supported platform
├── .agents/skills/ ⟵ real-file canonical skills whose revisions are locked in skills-lock.json
├── skills/ ⟵ distributable voicestudio and voicestudio-maintainer skill packages
│
├── deploy/ ⟵ container delivery plus the hosted installer worker
│ ├── Dockerfile CUDA baseline; BASE_IMAGE and GPU_FLAVOR let CI build ROCm too
│ ├── docker-compose.yml local one-command stack
│ ├── torch-constraints.txt image-specific torch-family lock
│ ├── dockerhub-overview.md release-synchronised Docker Hub description
│ └── install-worker/ Cloudflare worker serving voicestudio.sh/install; embeds both installers
│ from scripts/ (see docs/install/script.md)
│
├── docs/ ⟵ engineering references, product imagery and brand material
│ ├── STRUCTURE.md this map
│ ├── ROADMAP.md planned direction
│ ├── RELEASING.md complete multi-channel shipping checklist
│ ├── features.yaml source inventory consumed by docs-drift.yml
│ ├── adr/ durable architectural decisions
│ ├── agents/ tracker, triage-role and domain instructions for agents
│ ├── engines/ dubbing/ install/ setup/ migration/ features/ playbooks/ specs/
│ ├── media/ screenshots/ supporting media and captured UI
│ ├── preview.png / logo.* repository preview and logo assets
│ └── languages.md training.md data_preparation.md evaluation.md voice-design.md
│
├── examples/ ⟵ executable samples and inputs, including agentic/ and config/
├── notebooks/ ⟵ contains OmniVoice_Studio_Colab.ipynb
├── omnivoice-gallery/ ⟵ submodule that publishes the voice gallery
│
├── omnivoice_data/ ⟵ Docker bind-mount target (gitignored)
│ DB + HF cache live here when running via compose
│
├── .github/workflows/ ⟵ ci, electron-build, electron-release, docker, security,
│ docs-drift, evals, install-smoke, build-omnivoice-tts,
│ cla, commit-identity, cosyvoice-dependencies
└── .git/
根目录规则¶
-
根目录中不应存在任何运行时产物。 输出文件、临时文件、本地 DB、崩溃日志——全部放入
~/Library/Application Support/OmniVoice/(或操作系统等效路径),绝不放入仓库。唯一的例外是omnivoice_data/,它作为 Docker 的绑定挂载锚点存在。 -
根目录不放置临时脚本或测试。 将一次性调试工具放入
scripts/;测试归属于下面三个归属地之一。 -
每个子目录只承担一种职责。 如果你无法用一句话说清某个目录里放什么,那这个目录就是错的。
-
各个包独立声明依赖。
backend/、electron/和omnivoice/各有自己的pyproject.toml或package.json,可以单独测试。Bun 工作区共享一个根级bun.lock;Docker 使用冻结安装,宁可失败也不修改它。
测试的存放位置¶
ci.yml 中的单个 test 任务会调用三个独立的运行器。有意让它们的测试收集边界保持分离。
| 位置 | 运行器 | 为何独立 |
|---|---|---|
tests/ |
pytest tests/(同时也是 testpaths 的默认值) |
主要 Python 测试收集位置。其 fixture 将 OMNIVOICE_DATA_DIR 重定向到临时存储,避免接触开发者数据(#878)。 |
backend/tests/ |
pytest backend/tests/;CI 步骤:“Run pytest (backend/tests, isolated)” |
在全新会话中验证后端的 bare-import 模式,并使用自己的临时数据根目录。禁止在收集期伪造 sys.modules,因为这种伪造会逃出自身文件并污染合并运行。 |
electron/src/**/*.test.{ts,tsx} |
使用 Vitest/jsdom 的 bun run test;CI 通过 bun run check:electron 进入 |
UI 测试与实现代码放在一起。打包和工作流冒烟测试覆盖属于 electron/tests/;较旧的辅助工具/开发脚本 node:test 用例位于 tests/frontend/,并使用 bun run test:frontend 运行。 |
内容存放位置¶
| 内容类型 | 存放位置 |
|---|---|
| 面向用户的产品代码 | backend/、electron/ |
| TTS 模型(独立于 VoiceStudio) | omnivoice/ |
| 新的 TTS/ASR 引擎适配器 | backend/engines/<engine>/ |
| 所有可执行但不面向用户的内容 | scripts/ |
| 预构建的平台 sidecar | bin/ |
| Python 测试 | tests/(或需要隔离时放入 backend/tests/) |
| Electron / UI 单元测试 | 与模块同处,命名为 *.test.ts(x) |
| 开发者和用户文档(Markdown) | docs/ |
| 架构决策记录(ADR) | docs/adr/ |
| 面向 Agent 的文档 | docs/agents/ |
| 可运行的演示与示例数据 | examples/ |
| 运行时数据(绝不提交) | Mac 上的 ~/Library/Application Support/OmniVoice/ |
不再位于根目录的内容¶
以下内容在清理过程中被移除:
| 文件 | 原本存在的原因 | 去向 |
|---|---|---|
test_crash.py, test_server.py, test_whisper.py, test_mock.py, test_pyannote.py |
4 月 14 日崩溃调查期间的一次性调试脚本。导入的符号在 router 重构后已不存在。 | 已删除(原本已被 gitignore,且引用了死代码)。 |
benchmark.py |
另一个过时的调试脚本;导入了已不存在的 backend.main._get_db。 |
已删除。 |
output.wav, test.wav |
运行时产物。 | 已删除 / 已移出。 |
crash_log.txt |
运行时日志。现在写入 $DATA_DIR/crash_log.txt。 |
已删除。 |
omnivoice.zip (148 MB) |
项目自身的离线参考归档。 | 移出仓库,放到 ../omnivoice.zip.bak。 |
data/ |
只包含 .DS_Store。 |
已删除。 |
legacy_gradio/ |
React 之前的 Gradio UI。保留作历史参考。 | 先归档到 research/legacy_gradio/,后在 2026-07-12 清理中移除(见 git 历史)。 |
散落的 .DS_Store 文件 |
macOS Finder 残留。 | 已从每个未被忽略的目录中删除。 |
在 2026-07-12 清理中移除(全部保留在 git 历史中):
| 目录 | 原本存在的原因 | 去向 |
|---|---|---|
.planning/ (74 files) |
GSD 时代的规划存档:阶段、快速计划、问题集群。GSD 工作流已于 2026-07-08 退役。 | 已删除;四份关键决策文档移至 docs/adr/。 |
design/ |
React 之前目标 UX 的 ASCII 线框图,已被正式发布的应用取代。 | 已删除。 |
research/ |
归档的旧 Gradio UI + 2026 年 4 月竞争对手笔记。 | 已删除。 |
.agents/ |
原先属于一个已退役的第三方 agent 工具。 | 已移除,后为 skills-lock.json 锁定的规范技能副本重建。 |
扩展路径(提议,尚未执行)¶
当前的扁平布局对当前规模来说运作良好。如果项目扩展到包含更多应用(移动端配套应用、插件 SDK、多个后端),则迁移到 Turborepo 风格的 monorepo:
VoiceStudio/
├── apps/
│ ├── api/ ← was backend/
│ └── desktop/ ← was electron/ (desktop + browser UI)
├── packages/
│ ├── omnivoice-model/ ← was omnivoice/
│ └── tts-adapters/ ← new; the pluggable TTS interface from ROADMAP phase 3
├── config/
│ └── docker/
├── tests/
└── docs/
没有专门的 PR,不要执行此迁移。 它会破坏:
pyproject.toml的[tool.hatch.build.targets.{sdist,wheel}]路径package.json的 workspaces 与 scriptsDockerfile、docker-compose.yml的路径- Electron Builder、native-helper、updater 和 packaged-smoke 路径
- 所有
from backend.main import …导入(测试、脚本) - 根级
package.json作为版本事实来源及其镜像
在添加第二个 apps/* 或第二个 packages/* 时再迁移。不要提前。
约定¶
- 文件名: Python 使用 snake_case,JS/TS 组件使用 kebab-case 或 PascalCase,Markdown 使用小写。
- 一次性脚本 放入
scripts/,命名要具有描述性,而不是放在根目录下命名为test_*.py。 - 新增顶级目录 需要一个更新本文件的 PR。
- 测试位置: 镜像测试套件跟随源码路径(
tests/backend/镜像api/、core/、engines/和services/;例如,backend/services/ffmpeg_utils.py对应tests/backend/services/test_ffmpeg_utils.py)。否则,后端全局测试平铺在tests/backend/,横切测试平铺在tests/,React 组件测试与其组件放在一起。
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 om/VoiceStudio