Phase 1 Wave 2: per-OS install docs + Settings UI + error→docs deeplinks - #94
Conversation
📝 WalkthroughWalkthroughAdds per-OS installation docs and README updates; a CI validator ensuring docs' validated code blocks match scripts/desktop-prod.sh; backend repo/DEEPLINK URL and error-docs mapping; settings storage and perf toggle API; centralized engine env builder and sonitranslate integration; frontend ErrorBoundary docs action; ApiKeys and Performance settings UIs; and tests across layers. ChangesPhase 1 Wave 2: Installation, Error UX, Settings
🎯 4 (Complex) | ⏱️ ~60 minutes Possibly Related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (2)
tests/scripts/test_validate_install_docs.py (1)
75-94: ⚡ Quick winLock the file+line diagnostic contract with an explicit line-number assertion.
This test should also assert the exact
:lineto prevent regressions in drift-location reporting.Proposed assertion addition
def test_drift_introduced_fails(validator_module, tmp_path, capsys): @@ assert code == 1 assert "macos.md" in out.err + assert "docs/install/macos.md:5" in out.err assert "this-line-does-not-exist-in-the-script" in out.err🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/scripts/test_validate_install_docs.py` around lines 75 - 94, Update the test_drift_introduced_fails to assert the exact file:line diagnostic by checking the stderr contains the specific line number for the failing snippet; locate the test function test_drift_introduced_fails and after calling validator_module.main(root=...) and reading capsys.readouterr(), add an assertion that out.err includes the "macos.md:NN" pattern (replace NN with the expected line number where the invalid line appears in the generated diagnostic) so the file+line contract is locked down and regressions in drift-location reporting are prevented.backend/services/sonitranslate.py (1)
150-158: ⚡ Quick winAvoid duplicate HF token resolution in
start().
build_engine_env()already resolves/injects HF token by default, so resolving again here duplicates work and can add startup latency.♻️ Proposed fix
- from services import engine_env, token_resolver - resolved = token_resolver.resolve() - env = engine_env.build_engine_env() + from services import engine_env, token_resolver + resolved = token_resolver.resolve() + env = engine_env.build_engine_env(inject_hf_token=False)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/services/sonitranslate.py` around lines 150 - 158, Remove the redundant token resolution in start(): drop the call to token_resolver.resolve() and the conditional block that sets env["HF_TOKEN"] and env["YOUR_HF_TOKEN"], and rely on engine_env.build_engine_env() to populate HF token already; update the start() function to only call env = engine_env.build_engine_env() (keeping a brief comment if desired) and ensure downstream code reads HF_TOKEN from env rather than resolving again.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
@.planning/phases/01-install-token-persistence-docs-scaffolding-error-ux/01-02-SUMMARY.md:
- Line 17: Update the DOCS-02 closure note (the table row labelled "DOCS-02") so
its description reflects the actual scope: replace "Per-OS install pages live
and end-to-end." with wording about implementing error→docs mapping and deeplink
support (e.g., "Error-to-docs mapping and deeplink support implemented and
validated"). Ensure you edit the table cell for DOCS-02 in the SUMMARY.md so it
accurately describes the error→docs/deeplink work.
In @.planning/REQUIREMENTS.md:
- Around line 221-223: Update the requirements table to fix traceability:
replace the current note for DOCS-02 so it describes the "error→docs map"
requirement instead of "per-OS install pages" (ensure the DOCS-02 cell text
matches the intended error-to-documentation mapping), and remove or reconcile
the duplicate INST-12 entry so there's a single INST-12 row with the correct
status (choose either Done or Pending as the authoritative status and delete the
other duplicate row or merge notes). Ensure the table remains syntactically
valid after editing.
In `@docs/install/linux.md`:
- Around line 106-127: Update the Restricted networks section to include an
Aliyun fallback and explicit Russia guidance: add a second UV_DEFAULT_INDEX
example pointing to https://mirrors.aliyun.com/pypi/simple as a China fallback
alongside the existing Tsinghua mirror, keep the UV_PYTHON_INSTALL_MIRROR,
UV_PYTHON_PREFERENCE, UV_HTTP_TIMEOUT and UV_HTTP_RETRIES lines as-is, and
append a short note that Russia currently has no blessed PyPI mirror and users
should tunnel via VPN/proxy (or use an organization-approved internal mirror) to
reach the default PyPI index.
In `@frontend/src/components/settings/PerformancePanel.test.jsx`:
- Around line 46-49: The test currently clicks the 'torch-compile-toggle'
immediately after waiting for its existence which can be disabled initially;
update the test to wait until the toggle is enabled before clicking by changing
the waitFor call that now only checks getByTestId to assert the element is not
disabled (e.g., waitFor(() =>
expect(screen.getByTestId('torch-compile-toggle')).not.toBeDisabled())) and then
call fireEvent.click on screen.getByTestId('torch-compile-toggle'); keep
references to the same testid and functions (screen.getByTestId, waitFor,
fireEvent.click) so the PUT will fire reliably.
In `@scripts/validate-install-docs.py`:
- Around line 100-108: The code records block_start from the marker line
(pending_marker[0]) so reported drift line numbers point to the marker rather
than the first command line; change the logic so you capture the first body line
number (e.g., set body_start = i before appending the first element to
block_lines) and append body_start (not block_start) to blocks along with the
joined block_lines and skip flag; apply the same change to the duplicate
occurrence around the block handling at the other location referenced (the
similar code at lines 167-168).
---
Nitpick comments:
In `@backend/services/sonitranslate.py`:
- Around line 150-158: Remove the redundant token resolution in start(): drop
the call to token_resolver.resolve() and the conditional block that sets
env["HF_TOKEN"] and env["YOUR_HF_TOKEN"], and rely on
engine_env.build_engine_env() to populate HF token already; update the start()
function to only call env = engine_env.build_engine_env() (keeping a brief
comment if desired) and ensure downstream code reads HF_TOKEN from env rather
than resolving again.
In `@tests/scripts/test_validate_install_docs.py`:
- Around line 75-94: Update the test_drift_introduced_fails to assert the exact
file:line diagnostic by checking the stderr contains the specific line number
for the failing snippet; locate the test function test_drift_introduced_fails
and after calling validator_module.main(root=...) and reading
capsys.readouterr(), add an assertion that out.err includes the "macos.md:NN"
pattern (replace NN with the expected line number where the invalid line appears
in the generated diagnostic) so the file+line contract is locked down and
regressions in drift-location reporting are prevented.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 610288f7-e06e-4600-89ac-2bdff1e93599
📒 Files selected for processing (37)
.github/workflows/ci.yml.gitignore.planning/REQUIREMENTS.md.planning/phases/01-install-token-persistence-docs-scaffolding-error-ux/01-02-SUMMARY.mdREADME.mdbackend/api/routers/settings.pybackend/core/error_docs_map.pybackend/core/links.pybackend/services/engine_env.pybackend/services/settings_store.pybackend/services/sonitranslate.pydocs/engines/cosyvoice.mddocs/features/diarization.mddocs/install/docker.mddocs/install/linux.mddocs/install/macos.mddocs/install/troubleshooting.mddocs/install/windows.mddocs/setup/huggingface-token.mdfrontend/src/components/ErrorBoundary.jsxfrontend/src/components/ErrorBoundary.test.jsxfrontend/src/components/WaveformErrorBoundary.cssfrontend/src/components/settings/ApiKeysPanel.cssfrontend/src/components/settings/ApiKeysPanel.jsxfrontend/src/components/settings/ApiKeysPanel.test.jsxfrontend/src/components/settings/PerformancePanel.cssfrontend/src/components/settings/PerformancePanel.jsxfrontend/src/components/settings/PerformancePanel.test.jsxfrontend/src/pages/Settings.jsxfrontend/src/utils/errorDocsMap.test.tsfrontend/src/utils/errorDocsMap.tsscripts/validate-install-docs.pytests/backend/core/test_error_docs_map.pytests/backend/core/test_links.pytests/backend/test_perf_settings.pytests/scripts/__init__.pytests/scripts/test_validate_install_docs.py
| | INST-06 | Done | `scripts/validate-install-docs.py` + CI gate (`.github/workflows/ci.yml` new "Validate install docs" step). | | ||
| | INST-12 | Done (full) | Windows torch.compile OOM docs in `windows.md#torch-compile-oom` + Settings → Performance toggle (backend `/api/settings/perf/torch-compile-disabled` + frontend `PerformancePanel`). Honoured by `backend/services/engine_env.build_engine_env()` on win32. | | ||
| | DOCS-01 | Done | `docs/install/troubleshooting.md` ships 10 entries with cause / fix / linked-issue. | | ||
| | DOCS-02 | Done | Per-OS install pages live and end-to-end. | |
There was a problem hiding this comment.
Correct DOCS-02 closure note to match the actual requirement.
DOCS-02 is the error→docs mapping/deeplink work, not per-OS install pages.
Proposed wording fix
-| DOCS-02 | Done | Per-OS install pages live and end-to-end. |
+| DOCS-02 | Done | Error→docs mapping shipped (`backend/core/error_docs_map.py` + `frontend/src/utils/errorDocsMap.ts`) and wired into UI deeplinks. |📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| | DOCS-02 | Done | Per-OS install pages live and end-to-end. | | |
| | DOCS-02 | Done | Error→docs mapping shipped (`backend/core/error_docs_map.py` + `frontend/src/utils/errorDocsMap.ts`) and wired into UI deeplinks. | |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
@.planning/phases/01-install-token-persistence-docs-scaffolding-error-ux/01-02-SUMMARY.md
at line 17, Update the DOCS-02 closure note (the table row labelled "DOCS-02")
so its description reflects the actual scope: replace "Per-OS install pages live
and end-to-end." with wording about implementing error→docs mapping and deeplink
support (e.g., "Error-to-docs mapping and deeplink support implemented and
validated"). Ensure you edit the table cell for DOCS-02 in the SUMMARY.md so it
accurately describes the error→docs/deeplink work.
| | INST-12 | Phase 1 | Done (Wave 2 — Disable torch.compile (Windows) toggle, backend + UI) | | ||
| | DOCS-01 | Phase 1 | Done (Wave 2 — troubleshooting.md top-10 entries) | | ||
| | DOCS-02 | Phase 1 | Done (Wave 2 — per-OS install pages) | |
There was a problem hiding this comment.
Fix traceability inconsistencies for DOCS-02 and duplicate INST-12.
DOCS-02 is the error→docs map requirement, but its note currently describes per-OS install pages. Also, INST-12 is listed twice with conflicting statuses (Done and Pending).
Proposed correction
-| DOCS-02 | Phase 1 | Done (Wave 2 — per-OS install pages) |
+| DOCS-02 | Phase 1 | Done (Wave 2 — error→docs URL map + contextual deeplink button) |
@@
-| INST-12 | Phase 1 | Pending |Also applies to: 252-252
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.planning/REQUIREMENTS.md around lines 221 - 223, Update the requirements
table to fix traceability: replace the current note for DOCS-02 so it describes
the "error→docs map" requirement instead of "per-OS install pages" (ensure the
DOCS-02 cell text matches the intended error-to-documentation mapping), and
remove or reconcile the duplicate INST-12 entry so there's a single INST-12 row
with the correct status (choose either Done or Pending as the authoritative
status and delete the other duplicate row or merge notes). Ensure the table
remains syntactically valid after editing.
| ## Restricted networks (China / Russia) | ||
|
|
||
| If `uv` times out fetching the python-build-standalone tarball or PyPI: | ||
|
|
||
| ```bash | ||
| # Use a faster Python source mirror (China only — verify a current mirror) | ||
| export UV_PYTHON_INSTALL_MIRROR=https://ghproxy.com/https://github.com/astral-sh/python-build-standalone/releases/download | ||
|
|
||
| # Use a PyPI mirror | ||
| export UV_DEFAULT_INDEX=https://pypi.tuna.tsinghua.edu.cn/simple | ||
|
|
||
| # Or skip the download entirely if you have a compatible system Python | ||
| export UV_PYTHON_PREFERENCE=only-system | ||
|
|
||
| # Be tolerant of slow links | ||
| export UV_HTTP_TIMEOUT=120 | ||
| export UV_HTTP_RETRIES=5 | ||
| ``` | ||
|
|
||
| The Phase 3 install milestone (INST-07..11) ships an OS-level mirror cascade | ||
| that picks these defaults automatically; for v0.3 set them by hand. | ||
|
|
There was a problem hiding this comment.
Add Aliyun fallback and explicit Russia VPN guidance in restricted-network instructions.
Line 106 onward documents UV_PYTHON_INSTALL_MIRROR and Tsinghua, but it doesn’t include the required Aliyun fallback or explicit guidance that Russia has no blessed PyPI mirror and users should tunnel via VPN.
Suggested doc patch
## Restricted networks (China / Russia)
If `uv` times out fetching the python-build-standalone tarball or PyPI:
```bash
# Use a faster Python source mirror (China only — verify a current mirror)
export UV_PYTHON_INSTALL_MIRROR=https://ghproxy.com/https://github.com/astral-sh/python-build-standalone/releases/download
-# Use a PyPI mirror
+# Use a PyPI mirror (China primary)
export UV_DEFAULT_INDEX=https://pypi.tuna.tsinghua.edu.cn/simple
+
+# Fallback mirror (China)
+export UV_DEFAULT_INDEX=https://mirrors.aliyun.com/pypi/simple
# Or skip the download entirely if you have a compatible system Python
export UV_PYTHON_PREFERENCE=only-system
# Be tolerant of slow links
export UV_HTTP_TIMEOUT=120
export UV_HTTP_RETRIES=5+For Russia: there is currently no blessed PyPI mirror. Use a VPN/proxy tunnel to
+reach the default PyPI index (or your organization-approved internal mirror).
</details>
As per coding guidelines, "Installation documentation: Document `UV_PYTHON_INSTALL_MIRROR` and region-specific PyPI mirrors (Tsinghua for China, Aliyun fallback) with explicit guidance that Russia has no blessed PyPI mirror and users should tunnel via VPN".
<details>
<summary>🤖 Prompt for AI Agents</summary>
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @docs/install/linux.md around lines 106 - 127, Update the Restricted networks
section to include an Aliyun fallback and explicit Russia guidance: add a second
UV_DEFAULT_INDEX example pointing to https://mirrors.aliyun.com/pypi/simple as a
China fallback alongside the existing Tsinghua mirror, keep the
UV_PYTHON_INSTALL_MIRROR, UV_PYTHON_PREFERENCE, UV_HTTP_TIMEOUT and
UV_HTTP_RETRIES lines as-is, and append a short note that Russia currently has
no blessed PyPI mirror and users should tunnel via VPN/proxy (or use an
organization-approved internal mirror) to reach the default PyPI index.
</details>
<!-- fingerprinting:phantom:triton:hawk -->
<!-- This is an auto-generated comment by CodeRabbit -->
c071645 to
06b32d7
Compare
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
tests/backend/core/test_links.py (1)
55-55: 💤 Low valueMove import to module level.
For consistency with Python conventions, import
jsonat the module level (lines 12-15) rather than inside the test function.♻️ Suggested refactor
At module level:
from __future__ import annotations import importlib +import json import sysIn the test:
links = _fresh_links_module() monkeypatch.setattr(links, "_TAURI_CONF", tmp_path / "tauri.conf.json") - import json (tmp_path / "tauri.conf.json").write_text(json.dumps(fake_conf), encoding="utf-8")🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/backend/core/test_links.py` at line 55, The test currently imports json inside a test function in tests/backend/core/test_links.py; move that import to the module level alongside the other imports at the top of the file (so json is imported once for the module), and remove the in-function import; this applies to the test function that contains the inline `import json` statement.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/engines/cosyvoice.md`:
- Around line 7-21: The CosyVoice install doc only covers the in-app installer
but must also include the manual source-setup steps required by issue `#55`;
update docs/engines/cosyvoice.md to add instructions to clone the CosyVoice repo
with submodules (git clone --recursive), install Python dependencies (pip
install -r requirements.txt), install SoX on the host OS, and document setting
the OMNIVOICE_COSYVOICE_MODEL environment variable (showing both POSIX export
and Windows PowerShell forms) pointing to the
pretrained_models/CosyVoice-300M-Instruct directory so OmniVoice can find the
model.
In `@docs/install/troubleshooting.md`:
- Line 107: The documentation line references an internal planning tag "Plan
01-03" which should be removed or replaced; edit the sentence containing
`window.location.host` and remove "Plan 01-03" (or replace it with the
appropriate public release version such as "v0.3.1") so the troubleshooting text
contains only user-facing information without internal planning references.
- Around line 82-84: The troubleshooting entry currently points to linux.md but
lacks the explicit Russia guidance required by the docs guideline; update the
text around the existing env var note (UV_PYTHON_INSTALL_MIRROR,
UV_HTTP_TIMEOUT, UV_HTTP_RETRIES, UV_PYTHON_PREFERENCE) to add a short inline
sentence stating that Russia has no officially blessed PyPI mirror and users
must tunnel via a VPN to reach mirrors (e.g., use the same env vars as shown) so
readers get immediate, actionable guidance without following the linux.md link.
In `@tests/backend/core/test_links.py`:
- Line 23: Remove the obsolete noqa comment on the re-import line `import
core.links as links # noqa: WPS433 — needed for re-import` so it becomes a
plain re-import and similarly remove the identical `# noqa: WPS433` comment
found in `backend/tests/test_tts_backend_lifecycle.py`; the re-import is
intentional for cache-clearing tests and Ruff does not use WPS codes, so simply
delete the trailing `# noqa: WPS433` comments.
---
Nitpick comments:
In `@tests/backend/core/test_links.py`:
- Line 55: The test currently imports json inside a test function in
tests/backend/core/test_links.py; move that import to the module level alongside
the other imports at the top of the file (so json is imported once for the
module), and remove the in-function import; this applies to the test function
that contains the inline `import json` statement.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 81bc9199-8612-49ef-9999-f89dc24f6edf
📒 Files selected for processing (37)
.github/workflows/ci.yml.gitignore.planning/REQUIREMENTS.md.planning/phases/01-install-token-persistence-docs-scaffolding-error-ux/01-02-SUMMARY.mdREADME.mdbackend/api/routers/settings.pybackend/core/error_docs_map.pybackend/core/links.pybackend/services/engine_env.pybackend/services/settings_store.pybackend/services/sonitranslate.pydocs/engines/cosyvoice.mddocs/features/diarization.mddocs/install/docker.mddocs/install/linux.mddocs/install/macos.mddocs/install/troubleshooting.mddocs/install/windows.mddocs/setup/huggingface-token.mdfrontend/src/components/ErrorBoundary.jsxfrontend/src/components/ErrorBoundary.test.jsxfrontend/src/components/WaveformErrorBoundary.cssfrontend/src/components/settings/ApiKeysPanel.cssfrontend/src/components/settings/ApiKeysPanel.jsxfrontend/src/components/settings/ApiKeysPanel.test.jsxfrontend/src/components/settings/PerformancePanel.cssfrontend/src/components/settings/PerformancePanel.jsxfrontend/src/components/settings/PerformancePanel.test.jsxfrontend/src/pages/Settings.jsxfrontend/src/utils/errorDocsMap.test.tsfrontend/src/utils/errorDocsMap.tsscripts/validate-install-docs.pytests/backend/core/test_error_docs_map.pytests/backend/core/test_links.pytests/backend/test_perf_settings.pytests/scripts/__init__.pytests/scripts/test_validate_install_docs.py
✅ Files skipped from review due to trivial changes (5)
- docs/features/diarization.md
- docs/install/windows.md
- .planning/REQUIREMENTS.md
- docs/install/macos.md
- docs/install/linux.md
🚧 Files skipped from review as they are similar to previous changes (21)
- .gitignore
- frontend/src/components/WaveformErrorBoundary.css
- frontend/src/components/ErrorBoundary.jsx
- frontend/src/components/ErrorBoundary.test.jsx
- frontend/src/components/settings/ApiKeysPanel.css
- .github/workflows/ci.yml
- frontend/src/components/settings/PerformancePanel.test.jsx
- frontend/src/pages/Settings.jsx
- backend/services/engine_env.py
- docs/setup/huggingface-token.md
- tests/backend/core/test_error_docs_map.py
- frontend/src/components/settings/PerformancePanel.jsx
- frontend/src/utils/errorDocsMap.test.ts
- tests/backend/test_perf_settings.py
- backend/core/error_docs_map.py
- backend/services/settings_store.py
- frontend/src/components/settings/ApiKeysPanel.jsx
- frontend/src/utils/errorDocsMap.ts
- backend/services/sonitranslate.py
- frontend/src/components/settings/ApiKeysPanel.test.jsx
- tests/scripts/test_validate_install_docs.py
| ## Install | ||
|
|
||
| CosyVoice is installed *per-engine* from the in-app **Settings → Engines** tab: | ||
|
|
||
| 1. Open **Settings → Engines**. | ||
| 2. Click **Install** next to "CosyVoice". | ||
| 3. The app fetches the engine source, creates a dedicated venv, syncs deps, | ||
| and downloads model weights (~2 GB). | ||
| 4. Once installed, the engine appears in the **Voice Cloning** and | ||
| **Voice Design** engine picker dropdowns. | ||
|
|
||
| The dedicated venv keeps CosyVoice's transformer pins from clashing with | ||
| IndexTTS / ChatterboxTTS / SonicTranslate (see | ||
| [troubleshooting.md](../install/troubleshooting.md#10-indextts--cosyvoice--chatterboxtts-clash)). | ||
|
|
There was a problem hiding this comment.
Missing required #55 setup steps in the CosyVoice install doc.
The install section currently documents only the in-app flow, but this PR’s stated objective for #55 requires explicit source-setup steps (git clone --recursive, pip install -r requirements.txt, SoX install, and OMNIVOICE_COSYVOICE_MODEL configuration).
Proposed doc patch
## Install
CosyVoice is installed *per-engine* from the in-app **Settings → Engines** tab:
@@
4. Once installed, the engine appears in the **Voice Cloning** and
**Voice Design** engine picker dropdowns.
+### Manual/source setup (Issue `#55` compatibility path)
+
+If you are running OmniVoice from source and need to prepare CosyVoice manually:
+
+```bash
+git clone --recursive https://github.com/FunAudioLLM/CosyVoice.git
+cd CosyVoice
+pip install -r requirements.txt
+```
+
+Install SoX on your OS (required by CosyVoice audio tooling), then point OmniVoice to the model directory:
+
+```bash
+export OMNIVOICE_COSYVOICE_MODEL=/path/to/CosyVoice/pretrained_models/CosyVoice-300M-Instruct
+```
+
+Windows (PowerShell):
+
+```powershell
+$env:OMNIVOICE_COSYVOICE_MODEL="C:\path\to\CosyVoice\pretrained_models\CosyVoice-300M-Instruct"
+```🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/engines/cosyvoice.md` around lines 7 - 21, The CosyVoice install doc
only covers the in-app installer but must also include the manual source-setup
steps required by issue `#55`; update docs/engines/cosyvoice.md to add
instructions to clone the CosyVoice repo with submodules (git clone
--recursive), install Python dependencies (pip install -r requirements.txt),
install SoX on the host OS, and document setting the OMNIVOICE_COSYVOICE_MODEL
environment variable (showing both POSIX export and Windows PowerShell forms)
pointing to the pretrained_models/CosyVoice-300M-Instruct directory so OmniVoice
can find the model.
| **Fix:** see [linux.md#restricted-networks-china--russia](linux.md#restricted-networks-china--russia) | ||
| (same env vars work on macOS and Windows — `UV_PYTHON_INSTALL_MIRROR`, | ||
| `UV_HTTP_TIMEOUT=120`, `UV_HTTP_RETRIES=5`, `UV_PYTHON_PREFERENCE=only-system`). |
There was a problem hiding this comment.
Add explicit Russia VPN guidance per coding guidelines.
The guideline for installation documentation requires: "Document UV_PYTHON_INSTALL_MIRROR and region-specific PyPI mirrors (Tsinghua for China, Aliyun fallback) with explicit guidance that Russia has no blessed PyPI mirror and users should tunnel via VPN".
While you reference linux.md for details, this troubleshooting entry should include inline mention that Russia has no blessed mirror and requires VPN tunneling, since users hitting this error need immediate actionable guidance.
As per coding guidelines: Installation documentation must include explicit guidance that Russia has no blessed PyPI mirror and users should tunnel via VPN.
📝 Suggested addition
**Fix:** see [linux.md#restricted-networks-china--russia](linux.md#restricted-networks-china--russia)
(same env vars work on macOS and Windows — `UV_PYTHON_INSTALL_MIRROR`,
-`UV_HTTP_TIMEOUT=120`, `UV_HTTP_RETRIES=5`, `UV_PYTHON_PREFERENCE=only-system`).
+`UV_HTTP_TIMEOUT=120`, `UV_HTTP_RETRIES=5`, `UV_PYTHON_PREFERENCE=only-system`).
+**Note:** China can use Tsinghua/Aliyun mirrors; Russia has no blessed PyPI mirror — users should tunnel via VPN.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/install/troubleshooting.md` around lines 82 - 84, The troubleshooting
entry currently points to linux.md but lacks the explicit Russia guidance
required by the docs guideline; update the text around the existing env var note
(UV_PYTHON_INSTALL_MIRROR, UV_HTTP_TIMEOUT, UV_HTTP_RETRIES,
UV_PYTHON_PREFERENCE) to add a short inline sentence stating that Russia has no
officially blessed PyPI mirror and users must tunnel via a VPN to reach mirrors
(e.g., use the same env vars as shown) so readers get immediate, actionable
guidance without following the linux.md link.
| URLs, which is wrong when the UI is reached from a different LAN host. | ||
|
|
||
| **Fix:** Plan 01-03 ships a fix that derives the media-preview base from | ||
| `window.location.host`. See [docker.md#lan-access](docker.md#lan-access) for the |
There was a problem hiding this comment.
Remove internal planning reference.
"Plan 01-03" is an internal planning reference that will confuse end users reading troubleshooting docs. Either replace with the version number (e.g., "v0.3.1") or simply remove the reference.
📝 Suggested fix
-**Fix:** Plan 01-03 ships a fix that derives the media-preview base from
+**Fix:** v0.3.1 ships a fix that derives the media-preview base from
`window.location.host`. See [docker.md#lan-access](docker.md#lan-access) for the
override env var (`VITE_OMNIVOICE_API`) when running behind a reverse proxy.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/install/troubleshooting.md` at line 107, The documentation line
references an internal planning tag "Plan 01-03" which should be removed or
replaced; edit the sentence containing `window.location.host` and remove "Plan
01-03" (or replace it with the appropriate public release version such as
"v0.3.1") so the troubleshooting text contains only user-facing information
without internal planning references.
| for mod in list(sys.modules): | ||
| if mod == "core.links": | ||
| del sys.modules[mod] | ||
| import core.links as links # noqa: WPS433 — needed for re-import |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if wemake-python-styleguide is actually in use
rg -l 'wemake-python-styleguide' pyproject.toml setup.cfg setup.py tox.ini .flake8 || echo "Not found in config files"
# Check Ruff external rules config
rg 'lint\.external|external\s*=' pyproject.toml || echo "No external rules configured"Repository: debpalash/OmniVoice-Studio
Length of output: 338
🏁 Script executed:
# Check the pyproject.toml for linter configuration
cat pyproject.toml | head -100Repository: debpalash/OmniVoice-Studio
Length of output: 4410
🏁 Script executed:
# Search for all WPS noqa comments in the codebase
rg 'noqa.*WPS' --no-headingRepository: debpalash/OmniVoice-Studio
Length of output: 297
🏁 Script executed:
# Verify the exact content at the specified file and line
head -30 tests/backend/core/test_links.py | tail -15Repository: debpalash/OmniVoice-Studio
Length of output: 574
🏁 Script executed:
# Check for Ruff configuration in pyproject.toml
rg '\[tool\.ruff\]|tool\.ruff' pyproject.toml -A 20Repository: debpalash/OmniVoice-Studio
Length of output: 52
🏁 Script executed:
# Check if there are any ignore/select rules in pyproject.toml that mention this pattern
rg 'ignore|select|lint' pyproject.toml -B 2 -A 2Repository: debpalash/OmniVoice-Studio
Length of output: 410
🏁 Script executed:
# Check if there's a .ruff.toml or ruff.toml file
fd -name '*ruff*' --type f
# Also check for flake8, pylint, or other linter configs
fd -name '.flake8|.pylintrc|pylintrc|pyproject.toml|setup.cfg' --type fRepository: debpalash/OmniVoice-Studio
Length of output: 532
🏁 Script executed:
# Check if Ruff or any linter is listed in dependencies
rg 'ruff|flake8|pylint|wemake' pyproject.tomlRepository: debpalash/OmniVoice-Studio
Length of output: 52
🏁 Script executed:
# Check for linter config files
fd '(ruff|flake8|pylint)' --type f
# And double-check dependencies for linters
grep -i 'ruff\|flake8\|pylint\|wemake\|linter' pyproject.toml || echo "No linters found"Repository: debpalash/OmniVoice-Studio
Length of output: 97
🏁 Script executed:
# Look at the complete test file to understand the intent of the noqa comment
cat tests/backend/core/test_links.pyRepository: debpalash/OmniVoice-Studio
Length of output: 2876
Remove the outdated noqa comment.
The # noqa: WPS433 references wemake-python-styleguide, which is not a dependency or active linter in this project. Ruff is the active linter (confirmed by ruff.toml), and it does not enforce WPS codes. The re-import pattern itself is intentional and valid for testing module state after cache clearing, so the comment can be safely removed.
Note: A similar WPS433 comment exists in backend/tests/test_tts_backend_lifecycle.py and should also be removed.
🧰 Tools
🪛 Ruff (0.15.13)
[warning] 23-23: Invalid rule code in # noqa: WPS433
Add non-Ruff rule codes to the lint.external configuration option
(RUF102)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tests/backend/core/test_links.py` at line 23, Remove the obsolete noqa
comment on the re-import line `import core.links as links # noqa: WPS433 —
needed for re-import` so it becomes a plain re-import and similarly remove the
identical `# noqa: WPS433` comment found in
`backend/tests/test_tts_backend_lifecycle.py`; the re-import is intentional for
cache-clearing tests and Ruff does not use WPS codes, so simply delete the
trailing `# noqa: WPS433` comments.
…modules (#95) The smoke test used `os.environ.setdefault()` to point at the frozen fixture, which silently skipped when a prior test in the suite had already set the env var. Combined with `core.config` caching `DB_PATH` at module import time, this left smoke tests pointed at the wrong DB once Wave 1's services tests pre-imported `main` with their own temp state. Exposed by Wave 2's additional tests (PR #94) pushing collection order past the tipping point, but the underlying pollution existed since Wave 1 merged — Wave 3 CI passed only by collection-order luck. Fix mirrors the `sys.modules` purge pattern that `tests/backend/services/conftest.py` already uses. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Splits the 600-line README install section into self-contained per-OS docs
under docs/install/{macos,windows,linux,docker}.md plus a Top-10
troubleshooting index. Each OS doc is end-to-end: a user opens it and
reaches a working app following only commands inside that file.
Adds:
- docs/install/{macos,windows,linux,docker}.md (OS-specific install paths)
- docs/install/troubleshooting.md (top 10 install errors)
- docs/engines/cosyvoice.md (closes #55 docs half)
- docs/features/diarization.md (pyannote license flow)
- docs/setup/huggingface-token.md (3-source cascade guide)
- scripts/validate-install-docs.py (INST-06 docs-drift gate)
- tests/scripts/test_validate_install_docs.py (B-5: validator self-tests)
- .github/workflows/ci.yml step running the validator on every PR
Implements INST-02 (README routing), INST-03 (macOS Gatekeeper anchor),
INST-12 docs half (Windows torch-compile-oom anchor), DOCS-01..05.
The validator is a one-way diff: every `<!-- validate -->`-tagged line
in docs must appear in scripts/desktop-prod.sh after normalisation
(prompt-prefix strip, CRLF, trailing whitespace, blank-and-comment skip).
A `<!-- validate: skip -->` marker opts out for human-readability blocks.
Its own 10 unit tests catch regressions in the gate itself.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the single source of truth for the project repo URL and the 4-class
error → docs taxonomy that both the in-app ErrorBoundary deeplink button
(Wave 2 Task 3) and the Phase 5 bug reporter will consume.
New:
- backend/core/links.py — PROJECT_REPO_URL + BLOB_MAIN resolver
(Tauri config first, pyproject fallback)
- backend/core/error_docs_map.py — lookup(error_class) → docs URL
- frontend/src/utils/errorDocsMap.ts (TS mirror with classifyError helper)
- tests/backend/core/test_links.py + test_error_docs_map.py
- frontend/src/utils/errorDocsMap.test.ts
Resolves checker B-6 (links.py ownership) and Open Question #3 (which fork
the deeplinks resolve to — the Tauri updater endpoint wins, which points
at the desktop app fork debpalash/OmniVoice-Studio).
The TS BASE constant is documented as the second hardcoded URL drift site;
the keys-sync test (`test_keys_match_python_map` equivalent) guards the
4-class taxonomy contract between Python + TS halves.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wave 2 AUTH-03 UI half + ErrorBoundary deeplink wiring.
ErrorBoundary fallback now renders an "Open docs for this error" button
that classifies the thrown Error message (heuristic: pkg_resources → 401 /
HfHubHTTP → WebKit / white screen → quarantine / Gatekeeper) and opens the
matching docs anchor via Tauri shell.open (with a window.open fallback
in browser dev mode).
ApiKeysPanel consumes the Wave 1 resolver state endpoint:
- 3 source rows (App / Env var / HF CLI) with set/unset indicator,
masked token preview, whoami username + green check
- "Active" badge on whichever source is currently serving the cascade
- App-row only: Save (POST /api/settings/hf-token) +
Clear (DELETE with optional "also clear HF CLI" confirm dialog)
- "Test now" button refetches state (invalidates the resolver's
validation cache via the same endpoint hit)
Panel mounted in the existing Settings → Credentials tab; the legacy
HF_TOKEN row from CREDENTIAL_FIELDS is filtered out so the two paths
don't fight over the same key.
Threat T-02-02: the panel never displays the full token. The masked
value comes from the resolver state endpoint; the full token only
crosses the IPC boundary on Save (POST) and is cleared from local
state on success.
Closes AUTH-03 fully (Wave 1 backend + this Wave 2 UI).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… UI)
Wave 2 Task 4 — full INST-12 delivery per checker B-2/B-7 v0.3.0 fat-release
decision. Both the docs half (windows.md anchor, shipped in earlier commit)
and the runtime toggle are now in Phase 1.
Backend:
- backend/services/settings_store.py: adds get_text/set_text helpers for
non-secret config (refuses to write to the encrypted hf_token key).
- backend/api/routers/settings.py: GET + PUT
/api/settings/perf/torch-compile-disabled, both under the existing
loopback guard (threat T-02-04).
- backend/services/engine_env.py: new `build_engine_env()` helper that
centralises HF_TOKEN/YOUR_HF_TOKEN injection from the 3-source resolver
AND injects TORCH_COMPILE_DISABLE=1 when the flag is set on win32.
Phase 2 SubprocessBackend launchers should adopt the same helper.
- backend/services/sonitranslate.py: migrated to engine_env.build_engine_env()
while preserving the source-level `env["HF_TOKEN"]` sentinel that
test_sonitranslate_module_uses_resolver checks.
Frontend:
- frontend/src/components/settings/PerformancePanel.{jsx,css,test.jsx}:
toggle UI with the explainer for #65; renders disabled with a "not
applicable" badge on macOS/Linux.
- frontend/src/pages/Settings.jsx: mounts the panel into the Credentials
tab alongside the API Keys panel.
Tests:
- tests/backend/test_perf_settings.py: 7 backend tests (default state,
PUT persistence, T-02-04 non-loopback rejection, settings_store round-
trip, env injection on win32, NO injection on macOS/Linux, NO injection
when disabled).
- frontend PerformancePanel.test.jsx: 5 tests (renders from GET state,
PUT on toggle, disabled on non-Windows platforms, pre-enabled state).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- .planning/phases/01.../01-02-SUMMARY.md: full implementation report
per template (truths, commits, tests, deviations, drift-site
acknowledgments per W-3, launcher seam name for Phase 2,
taxonomy keys for Phase 5).
- .planning/REQUIREMENTS.md: flips Wave 2 closures to Done:
AUTH-03, INST-02, INST-03 (docs half), INST-06, INST-12,
DOCS-01..05.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
06b32d7 to
c949c44
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (5)
docs/engines/cosyvoice.md (1)
7-20:⚠️ Potential issue | 🟠 Major | ⚡ Quick winAdd the manual/source setup path required by issue
#55.Line 7 onward only covers in-app installation. The required source path is still missing:
git clone --recursive,pip install -r requirements.txt, SoX install, andOMNIVOICE_COSYVOICE_MODELexamples for both POSIX and Windows PowerShell.Suggested doc patch
## Install CosyVoice is installed *per-engine* from the in-app **Settings → Engines** tab: @@ 4. Once installed, the engine appears in the **Voice Cloning** and **Voice Design** engine picker dropdowns. + +### Manual/source setup (Issue `#55` compatibility path) + +If you're running OmniVoice from source and need a manual CosyVoice setup: + +```bash +git clone --recursive https://github.com/FunAudioLLM/CosyVoice.git +cd CosyVoice +pip install -r requirements.txt +``` + +Install SoX on your OS, then point OmniVoice to the model directory: + +```bash +export OMNIVOICE_COSYVOICE_MODEL=/path/to/CosyVoice/pretrained_models/CosyVoice-300M-Instruct +``` + +Windows (PowerShell): + +```powershell +$env:OMNIVOICE_COSYVOICE_MODEL="C:\path\to\CosyVoice\pretrained_models\CosyVoice-300M-Instruct" +```🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/engines/cosyvoice.md` around lines 7 - 20, Add the missing manual/source install steps to the "Install" section of docs/engines/cosyvoice.md: include git clone --recursive and cd instructions, pip install -r requirements.txt, a note to install SoX, and examples showing how to set OMNIVOICE_COSYVOICE_MODEL for both POSIX (export OMNIVOICE_COSYVOICE_MODEL=/path/to/CosyVoice/pretrained_models/CosyVoice-300M-Instruct) and Windows PowerShell ($env:OMNIVOICE_COSYVOICE_MODEL="C:\path\to\CosyVoice\pretrained_models\CosyVoice-300M-Instruct"), and place these under the existing "Install" heading alongside the in-app installation steps for clarity..planning/phases/01-install-token-persistence-docs-scaffolding-error-ux/01-02-SUMMARY.md (1)
17-17:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winCorrect the DOCS-02 closure note to match the implemented scope.
Line 17 still describes per-OS install pages, but DOCS-02 in this wave is the error→docs mapping/deeplink work.
Suggested wording
-| DOCS-02 | Done | Per-OS install pages live and end-to-end. | +| DOCS-02 | Done | Error→docs mapping shipped (`backend/core/error_docs_map.py` + `frontend/src/utils/errorDocsMap.ts`) and wired into UI deeplinks. |🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.planning/phases/01-install-token-persistence-docs-scaffolding-error-ux/01-02-SUMMARY.md at line 17, Update the DOCS-02 summary row so its closure note reflects the implemented scope (error→docs mapping/deeplink) instead of "Per-OS install pages live and end-to-end"; locate the table row containing the text "| DOCS-02 | Done | Per-OS install pages live and end-to-end |" and replace the third column with a concise description like "Error-to-docs mapping and deeplink implementation completed" (or similar wording that explicitly mentions error→docs mapping/deeplink).scripts/validate-install-docs.py (1)
100-108:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winFix drift line reporting to use the first code line, not the marker line.
Line 100 currently anchors
block_startto the marker, so Line 167 reports shifted locations. Capture the first fenced body line number and use it directly in the error formatter.Suggested patch
- block_start = pending_marker[0] skip = pending_marker[1] pending_marker = None i += 1 + block_start = i + 1 # first code line inside the fenced block (1-indexed) while i < len(lines) and not _FENCE_CLOSE_RE.match(lines[i]): block_lines.append(lines[i]) i += 1 @@ - f"{md_path.relative_to(args.root)}:{start_line + 1 + offset}: " + f"{md_path.relative_to(args.root)}:{start_line + offset}: " f"docs line not present in scripts/desktop-prod.sh: {norm!r}" )Also applies to: 167-168
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/validate-install-docs.py` around lines 100 - 108, The code currently sets block_start = pending_marker[0] (the marker line) but should record the first fenced body line number so reported drift lines point to the actual code, not the marker; while building the fenced block in the loop inside the parser that uses pending_marker, compute and store first_body_line = i (or i+0 after incrementing) before appending lines, and replace block_start with that first_body_line when appending to blocks (blocks.append((first_body_line, "\n".join(block_lines), skip))); update any error formatter usage that reads the tuple to expect the first code line number instead of the marker line.docs/install/troubleshooting.md (2)
82-84:⚠️ Potential issue | 🟠 Major | ⚡ Quick winAdd explicit Russia VPN guidance in the restricted-network fix.
Line 82 links the detailed section, but Line 83-84 should also state directly that Russia has no blessed PyPI mirror and users should tunnel via VPN.
As per coding guidelines: Installation documentation: Document `UV_PYTHON_INSTALL_MIRROR` and region-specific PyPI mirrors (Tsinghua for China, Aliyun fallback) with explicit guidance that Russia has no blessed PyPI mirror and users should tunnel via VPN.Suggested addition
**Fix:** see [linux.md#restricted-networks-china--russia](linux.md#restricted-networks-china--russia) (same env vars work on macOS and Windows — `UV_PYTHON_INSTALL_MIRROR`, `UV_HTTP_TIMEOUT=120`, `UV_HTTP_RETRIES=5`, `UV_PYTHON_PREFERENCE=only-system`). +In Russia, there is no blessed PyPI mirror; use a VPN tunnel to reach the configured mirrors.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/install/troubleshooting.md` around lines 82 - 84, Update the troubleshooting note to explicitly state that Russia does not have an endorsed PyPI mirror and users must tunnel via VPN to access PyPI; mention the environment variables UV_PYTHON_INSTALL_MIRROR, UV_HTTP_TIMEOUT, UV_HTTP_RETRIES, and UV_PYTHON_PREFERENCE and document recommended mirrors for China (Tsinghua, with Aliyun as fallback) while clarifying that for Russia the only supported workaround is using a VPN or tunnel to reach a public PyPI mirror; add a short sentence after the existing mirror examples to convey this region-specific guidance and include the exact env var names shown (UV_PYTHON_INSTALL_MIRROR etc.) for copy-paste.
106-108:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winReplace internal planning reference with user-facing release wording.
Line 106 mentions “Plan 01-03,” which is internal and unclear in end-user troubleshooting docs.
Suggested wording
-**Fix:** Plan 01-03 ships a fix that derives the media-preview base from +**Fix:** v0.3 ships a fix that derives the media-preview base from `window.location.host`. See [docker.md#lan-access](docker.md#lan-access) for the override env var (`VITE_OMNIVOICE_API`) when running behind a reverse proxy.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/install/troubleshooting.md` around lines 106 - 108, Replace the internal phrasing "Plan 01-03" with user-facing release wording: update the sentence that currently reads "Plan 01-03 ships a fix..." to something like "A recent release fixes..." (or "Version X.Y.Z fixes..." if a version is known) so end users understand it's a release-level change; keep the rest of the guidance intact (retain the reference to deriving media-preview base from `window.location.host` and the override env var `VITE_OMNIVOICE_API` and the link to docker.md#lan-access) and ensure the term "media-preview" remains unchanged for clarity.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/setup/huggingface-token.md`:
- Around line 110-113: Update the wording in the "Settings → API Keys" guidance
so it clarifies that seeing "Env" or "HF CLI" as the active source while the App
row is populated is not always expected — it only happens when the App token
cannot be used (e.g., fails validation or decryption) and the cascade falls back
to Env or HF CLI; otherwise the App source remains highest priority.
Specifically revise the sentence referencing the App row and the active source
("If it's set but the active source is 'Env' or 'HF CLI', that's the cascade
working as intended (App is highest priority).") to explicitly state the
fallback condition (App token invalid/unusable) and that App remains active when
its token is valid.
---
Duplicate comments:
In
@.planning/phases/01-install-token-persistence-docs-scaffolding-error-ux/01-02-SUMMARY.md:
- Line 17: Update the DOCS-02 summary row so its closure note reflects the
implemented scope (error→docs mapping/deeplink) instead of "Per-OS install pages
live and end-to-end"; locate the table row containing the text "| DOCS-02 | Done
| Per-OS install pages live and end-to-end |" and replace the third column with
a concise description like "Error-to-docs mapping and deeplink implementation
completed" (or similar wording that explicitly mentions error→docs
mapping/deeplink).
In `@docs/engines/cosyvoice.md`:
- Around line 7-20: Add the missing manual/source install steps to the "Install"
section of docs/engines/cosyvoice.md: include git clone --recursive and cd
instructions, pip install -r requirements.txt, a note to install SoX, and
examples showing how to set OMNIVOICE_COSYVOICE_MODEL for both POSIX (export
OMNIVOICE_COSYVOICE_MODEL=/path/to/CosyVoice/pretrained_models/CosyVoice-300M-Instruct)
and Windows PowerShell
($env:OMNIVOICE_COSYVOICE_MODEL="C:\path\to\CosyVoice\pretrained_models\CosyVoice-300M-Instruct"),
and place these under the existing "Install" heading alongside the in-app
installation steps for clarity.
In `@docs/install/troubleshooting.md`:
- Around line 82-84: Update the troubleshooting note to explicitly state that
Russia does not have an endorsed PyPI mirror and users must tunnel via VPN to
access PyPI; mention the environment variables UV_PYTHON_INSTALL_MIRROR,
UV_HTTP_TIMEOUT, UV_HTTP_RETRIES, and UV_PYTHON_PREFERENCE and document
recommended mirrors for China (Tsinghua, with Aliyun as fallback) while
clarifying that for Russia the only supported workaround is using a VPN or
tunnel to reach a public PyPI mirror; add a short sentence after the existing
mirror examples to convey this region-specific guidance and include the exact
env var names shown (UV_PYTHON_INSTALL_MIRROR etc.) for copy-paste.
- Around line 106-108: Replace the internal phrasing "Plan 01-03" with
user-facing release wording: update the sentence that currently reads "Plan
01-03 ships a fix..." to something like "A recent release fixes..." (or "Version
X.Y.Z fixes..." if a version is known) so end users understand it's a
release-level change; keep the rest of the guidance intact (retain the reference
to deriving media-preview base from `window.location.host` and the override env
var `VITE_OMNIVOICE_API` and the link to docker.md#lan-access) and ensure the
term "media-preview" remains unchanged for clarity.
In `@scripts/validate-install-docs.py`:
- Around line 100-108: The code currently sets block_start = pending_marker[0]
(the marker line) but should record the first fenced body line number so
reported drift lines point to the actual code, not the marker; while building
the fenced block in the loop inside the parser that uses pending_marker, compute
and store first_body_line = i (or i+0 after incrementing) before appending
lines, and replace block_start with that first_body_line when appending to
blocks (blocks.append((first_body_line, "\n".join(block_lines), skip))); update
any error formatter usage that reads the tuple to expect the first code line
number instead of the marker line.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 44ee38b8-b97f-4c99-87fe-852713584a09
📒 Files selected for processing (37)
.github/workflows/ci.yml.gitignore.planning/REQUIREMENTS.md.planning/phases/01-install-token-persistence-docs-scaffolding-error-ux/01-02-SUMMARY.mdREADME.mdbackend/api/routers/settings.pybackend/core/error_docs_map.pybackend/core/links.pybackend/services/engine_env.pybackend/services/settings_store.pybackend/services/sonitranslate.pydocs/engines/cosyvoice.mddocs/features/diarization.mddocs/install/docker.mddocs/install/linux.mddocs/install/macos.mddocs/install/troubleshooting.mddocs/install/windows.mddocs/setup/huggingface-token.mdfrontend/src/components/ErrorBoundary.jsxfrontend/src/components/ErrorBoundary.test.jsxfrontend/src/components/WaveformErrorBoundary.cssfrontend/src/components/settings/ApiKeysPanel.cssfrontend/src/components/settings/ApiKeysPanel.jsxfrontend/src/components/settings/ApiKeysPanel.test.jsxfrontend/src/components/settings/PerformancePanel.cssfrontend/src/components/settings/PerformancePanel.jsxfrontend/src/components/settings/PerformancePanel.test.jsxfrontend/src/pages/Settings.jsxfrontend/src/utils/errorDocsMap.test.tsfrontend/src/utils/errorDocsMap.tsscripts/validate-install-docs.pytests/backend/core/test_error_docs_map.pytests/backend/core/test_links.pytests/backend/test_perf_settings.pytests/scripts/__init__.pytests/scripts/test_validate_install_docs.py
✅ Files skipped from review due to trivial changes (5)
- docs/features/diarization.md
- docs/install/windows.md
- .gitignore
- docs/install/macos.md
- docs/install/linux.md
| - **Token didn't survive a reboot** — open **Settings → API Keys** and check | ||
| the App row. If it's empty, the SQLite store may have been wiped — re-save. | ||
| If it's set but the active source is "Env" or "HF CLI", that's the cascade | ||
| working as intended (App is highest priority). |
There was a problem hiding this comment.
Clarify when Env/HF CLI can be active despite App being set.
Line 112–113 currently reads like this is always expected. It’s only expected when the App token fails validation/decryption; otherwise App should stay active as highest priority.
Suggested wording tweak
- If it's set but the active source is "Env" or "HF CLI", that's the cascade
- working as intended (App is highest priority).
+ If it's set but the active source is "Env" or "HF CLI", the App source likely
+ failed `whoami` or decrypt and the cascade fell back (App remains highest
+ priority when valid).📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - **Token didn't survive a reboot** — open **Settings → API Keys** and check | |
| the App row. If it's empty, the SQLite store may have been wiped — re-save. | |
| If it's set but the active source is "Env" or "HF CLI", that's the cascade | |
| working as intended (App is highest priority). | |
| - **Token didn't survive a reboot** — open **Settings → API Keys** and check | |
| the App row. If it's empty, the SQLite store may have been wiped — re-save. | |
| If it's set but the active source is "Env" or "HF CLI", the App source likely | |
| failed `whoami` or decrypt and the cascade fell back (App remains highest | |
| priority when valid). |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/setup/huggingface-token.md` around lines 110 - 113, Update the wording
in the "Settings → API Keys" guidance so it clarifies that seeing "Env" or "HF
CLI" as the active source while the App row is populated is not always expected
— it only happens when the App token cannot be used (e.g., fails validation or
decryption) and the cascade falls back to Env or HF CLI; otherwise the App
source remains highest priority. Specifically revise the sentence referencing
the App row and the active source ("If it's set but the active source is 'Env'
or 'HF CLI', that's the cascade working as intended (App is highest priority).")
to explicitly state the fallback condition (App token invalid/unusable) and that
App remains active when its token is valid.
…ink (closes #78) (#110) * fix: speaker detection — gated pyannote license surfaces a docs deeplink (closes #78) Issue #78 ("Speaker detection fails — speakers blend together or aren't detected correctly") was the user-visible symptom of the dub pipeline silently falling back to the silence-gap heuristic in `backend/api/routers/dub_core.py::_diarize`. The heuristic alternates Speaker 1 ↔ Speaker 2 on >1.2s gaps only, so two real speakers with similar pacing get merged or swapped — and once the auto-clone step extracts a reference voice for the wrong label, downstream dubs make "person A speak like person B" (the reporter's exact phrasing). The structural cause is that pyannote-3.1 is gated on HuggingFace: a valid HF_TOKEN by itself isn't enough — the user must also click "Agree and access repository" on both pyannote/speaker-diarization-3.1 AND pyannote/segmentation-3.0. We can't fix that for the user, but we CAN make the failure actionable instead of silent. Changes: - `backend/services/model_manager.py`: `get_diarization_pipeline()` gains an opt-in `return_error=True` shape that returns `(pipeline | None, error_sentinel)`. Sentinels distinguish NO_TOKEN / PYANNOTE_LICENSE_REQUIRED / LOAD_FAILED. A new `_classify_diarization_error()` sniffs the exception's class name + message for 401/403/gated/"accept license" signals — kept as a string heuristic so it survives huggingface_hub major-version churn. Bare-`None` default return preserved for the legacy `_transcribe` call site at dub_core.py:781. - `backend/api/routers/dub_core.py::_diarize`: now emits a structured SSE warning `{detail, source, error_class, docs_url}` instead of plain `{detail, source}`. The new fields let the front-end render a "See docs" button that deeplinks directly to the `License acceptance flow` section of `docs/features/diarization.md` (landed in PR #94) — the page with the click-by-click instructions for fixing this exact failure mode. - `backend/core/error_docs_map.py` + `frontend/src/utils/errorDocsMap.ts`: add a 5th taxonomy class `PYANNOTE_LICENSE_REQUIRED` pointing at the diarization docs section. Distinct from `HF_AUTH_FAILED` (which is the more general "token missing or invalid" case). The TS `classifyError` heuristic also picks up pyannote / gated / "speaker diarization" keywords so a thrown error in the boundary routes to the right deeplink too. - `tests/backend/core/test_error_docs_map.py`: bump locked-keys set to 5 classes; add an explicit assertion that the new class points at the `license-acceptance-flow` anchor. - `frontend/src/utils/errorDocsMap.test.ts`: bump locked-keys set to 5 classes; add classifier tests for pyannote / gated / accept-license keyword routing. - `tests/test_diarization_error_class.py`: regression test (20 cases) covering `_classify_diarization_error`, the new `get_diarization_pipeline(return_error=True)` shape, backward- compatible bare-`None` return for the legacy call site, and the error_docs_map deeplink target. Uses sys.modules patching so pyannote / torch are never actually imported. HF token plumbing: unchanged. The new code continues to route through `token_resolver.resolve()` per the AUTH-01 contract — no new bare `os.environ.get("HF_TOKEN")` reads. Cross-platform: identical behaviour on macOS / Windows / Linux — the only platform-touching change is a docs URL string, which is opened via the existing `openExternal()` helper that already abstracts Tauri's `shell.open` on all three platforms. Verification: .venv/bin/python -m pytest tests/test_diarization_error_class.py \ tests/backend/core/test_error_docs_map.py -v # 20 passed in 0.03s bun run test src/utils/errorDocsMap.test.ts # 13 passed (1 test file) .venv/bin/python -m pytest tests/test_segmentation.py \ tests/test_dub_transcribe.py \ tests/backend/services/test_token_resolver.py \ tests/test_model_manager_preload.py # 40 passed, 10 xfailed (pre-existing), 1 xpassed Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test: add regression test for diarization error classification (issue #78) Companion to the fix in d6e6586. 20 test cases covering: - `_classify_diarization_error` — the string heuristic that buckets pyannote/HF exceptions into NO_TOKEN / LICENSE / LOAD sentinels. Pinned for 401/403/gated/accept-license/accept-user-conditions signals so it survives huggingface_hub major-version churn. - `get_diarization_pipeline(return_error=True)` — the new 2-tuple return shape that lets the dub pipeline's SSE warning carry an error_class. - Backward compatibility — the bare-`None` return on the default signature is preserved so dub_core.py:781's legacy `_transcribe` call site doesn't break. - The error_docs_map deeplink — the new PYANNOTE_LICENSE_REQUIRED class points at `docs/features/diarization.md#license-acceptance-flow`. Uses sys.modules patching for pyannote.audio.Pipeline + token_resolver so the real torch + pyannote + HF API are never imported. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(diarization): dotted-path monkeypatch to survive Wave 1 sys.modules purge The new `test_diarization_error_class.py` tests pass in isolation but fail in the full suite — Wave 1's `fresh_resolver` fixture aggressively purges all `services.*` and `core.*` modules from `sys.modules` mid-suite. When this file's tests later did `from services import token_resolver` then `monkeypatch.setattr(token_resolver, "resolve", ...)`, the local `token_resolver` reference bound to a stale module identity. The function under test does `from services import token_resolver` at call time, which re-resolves through the (post-purge) `sys.modules['services.token_resolver']` — a different object — so the monkeypatch was applied to one ID and the function read from another. Two fixes in this commit: 1. Don't pop `services.token_resolver` in this file's `model_manager` fixture — the test body's import and the function's import must agree on identity. Popping forces re-import that can create two distinct modules. 2. Use the dotted-path form `monkeypatch.setattr("services.token_resolver.resolve", ...)` instead of the object-attribute form. Pytest's dotted form re-resolves the path through `sys.modules` at setattr time, so the binding is always on the live module object regardless of which identity the test imported earlier. Verified: `pytest tests/ -q` → 442 passed, 0 failures (was 1 failed before this commit on PR #110). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Phase 1 Wave 2 of the v0.3.x stabilisation milestone. Closes 11 requirements in one PR:
docs/install/{macos,windows,linux,docker}.md+troubleshooting.md+engines/cosyvoice.md+features/diarization.md+setup/huggingface-token.md), plus the docs-drift CI gate (scripts/validate-install-docs.py) and its B-5 self-test suite (10 tests).windows.md#torch-compile-oom+ Settings → Performance toggle (backend/api/settings/perf/torch-compile-disabled+ frontendPerformancePanel). Honoured by newbackend/services/engine_env.build_engine_env()helper on win32.REQUIREMENTS.mdrow flipped to Done.backend/core/links.py(single source of truth for the repo URL; resolves Tauri config → pyproject fallback per checker B-6), newbackend/core/error_docs_map.py+ TS mirror atfrontend/src/utils/errorDocsMap.ts, ErrorBoundary wired to render an "Open docs for this error" button that classifies the error message and opens the right docs anchor via the existing Tauri opener path.Deeplink-map symbol:
backend/core/error_docs_map.lookup()/frontend/src/utils/errorDocsMap.openDocsFor().Docs files added (8)
docs/install/macos.md(Gatekeeper anchor)docs/install/windows.md(torch-compile-oom anchor, setx warning)docs/install/linux.md(AppImage white-screen anchor, .deb ffprobe anchor, restricted-networks section)docs/install/docker.md(LAN access anchor)docs/install/troubleshooting.md(top 10 install errors with cause/fix/issue links)docs/engines/cosyvoice.md(closes Help with installation off (CosyVoice 3) #55 docs half)docs/features/diarization.md(pyannote license + fallback behaviour)docs/setup/huggingface-token.md(3-source cascade end-to-end)README dropped from 585 → 405 lines.
Test results
tests/backend/services/test_token_resolver.py tests/backend/services/test_settings_store.py tests/backend/core/test_logging_filter.py tests/backend/test_engine_spawn_token.py→ 35 passed.tests/smoke/→ 4 passed.bunx vitest run→ 51 passed across 7 files.python scripts/validate-install-docs.py→ exit 0.CI changes
.github/workflows/ci.ymlgains a new "Validate install docs against desktop-prod.sh" step in the existingtestjob (Linux-only — docs are platform-agnostic). The validator's own B-5 self-tests run as part of the existingpytest tests/step.Test plan
python scripts/validate-install-docs.pyruns cleanErrorBoundary, confirm the "Open docs for this error" button opens the right docs anchor in the browserSee
.planning/phases/01-install-token-persistence-docs-scaffolding-error-ux/01-02-SUMMARY.mdfor the full implementation report, the 4-class taxonomy lock, drift-site acknowledgments (per checker W-3), and the Phase 2 SubprocessBackend integration note forengine_env.build_engine_env.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation
Chores