* feat(engines): one-click IndexTTS-2 sidecar install from Settings → Engines
IndexTTS-2 required four manual terminal steps (git clone, uv venv,
uv pip install -e ., export OMNIVOICE_INDEXTTS_DIR). This turns that into
a guided in-app install:
- backend/services/sidecar_install.py — parametrized sidecar provisioner
(SidecarSpec/SPECS so future sidecar engines are one entry, not another
installer). Resumable background job with step-by-step status: disk-space
preflight (needs-X/have-Y message), source fetch (git clone --depth 1
primary, GitHub tarball fallback when git is absent/fails), dedicated
venv via uv (OMNIVOICE_BUNDLED_UV → PATH resolution; transformers<5
isolation preserved — the parent env is never touched), import-probe
verification, IndexTeam/IndexTTS-2 weights into <checkout>/checkpoints
(where the sidecar actually loads from) via snapshot_download with the
auto-selected/configured HF endpoint + token — no hardcoded
huggingface.co — and persistence of OMNIVOICE_INDEXTTS_DIR (os.environ
for immediate use, prefs.json env.* for the next launch). Idempotent:
partial installs repair, downloads resume, healthy installs (incl. a
user's own clone) report already_installed and are never touched.
- API: POST /engines/{id}/install starts the job, GET
/engines/{id}/install/status polls it, DELETE /engines/{id}/install
removes an app-managed install (loopback-gated; refuses user-managed
clones). list_backends() gains one_click_install.
- Frontend: Settings → Engines shows an Install button on the IndexTTS2
row with per-step progress, live log tail, weight-download %, and
error+remediation; the manual setup snippet is demoted to a collapsed
"Manual install" fallback. All strings via i18n (en.json).
- OMNIVOICE_INDEXTTS_DIR joins the Settings env-var allowlist
(single-sourced from the installer SPECS).
- Docs: docs/engines/indextts.md leads with the one-click flow; manual
steps become the fallback section. CHANGELOG Unreleased entry added.
- Tests: tests/test_sidecar_install.py (24 cases — happy path, disk-space
fail, git-absent/git-failing tarball fallback, partial-install repair,
already-installed/running gating, uninstall safety, spec↔bootstrap
contract, router wiring) + 6 new EngineCompatibilityMatrix RTL cases.
API route snapshot regenerated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(engines): harden the sidecar installer — review findings
- Route namespace: /engines/sidecar/{id}/install — a dynamic
/engines/{id}/install would shadow the literal
POST /engines/sonitranslate/install (engines router registers first);
regression-guarded by test_sidecar_routes_never_shadow_literal_engine_routes.
- Weights completion marker: a killed-mid-download multi-shard weights dir
(config.yaml + plausible shards) no longer passes for healthy; the marker
is written only after snapshot_download returns, so re-runs resume.
- _run_logged: drain thread + proc.wait(timeout) + POSIX process-group kill
— a grandchild holding the stdout pipe can no longer hang the step past
its timeout.
- Job log lock: the status poll's list(deque) copy no longer races the
worker's appends (RuntimeError under active logging).
- Self-heal: a healthy managed install whose env var was lost (prefs wiped)
is re-pointed by start_install instead of reported already_installed
while the engine stays unavailable; legacy bootstrap installs (Probe-2
venv) are trusted via the engine's own probe.
- Single-sourced uv/venv-layout resolution: engines.indextts.bootstrap now
delegates _locate_uv/_venv_python_path to services.sidecar_install.
- Frontend: stable poll interval (keyed on the running-id set, not the
status map), reload on a job that finishes before the first poll,
re-attach to an in-flight job on remount, i18n'd Install aria-label,
manual-install <details> auto-opens on failure, snippet block hoisted
out of the JSX IIFE.
- list_backends: sidecar-installable set hoisted out of the per-engine
loop; exhaustive-shape registry test updated for one_click_install.
- Tests rebind the live services.sidecar_install module per test (other
suites purge sys.modules["services"], which made router tests
order-dependent).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(changelog): fill in the PR ref (#1083)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(security): validated tarball fallback + scanner-clean installer
- The pre-filter= extractall fallback (Python < 3.11.4) now extracts
member-by-member behind the same guards extractall(filter="data")
enforces — regular files/dirs only, no absolute paths, no ../ escapes,
resolved-path containment. Kills the new CodeQL py/tarslip (high) and
Bandit B202 (error) alerts; regression-tested with a malicious tarball
(test_safe_extract_members_blocks_tar_slip).
- snapshot_download tracks the weights repo's default branch on purpose
(same policy as every other model download; artifacts are
checksum-verified by hf_hub) — documented + B615 waived at the call.
- Explanatory comments on the intentional empty-except blocks
(CodeQL py/empty-except notes).
Verified locally: bandit -ll -ii on the module reports 0 MEDIUM+ findings.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(engines): address Greptile review — Windows tree kill, prefs write race, poll robustness
- _kill_tree: Windows now uses taskkill /F /T so a git/uv helper spawned by
the timed-out child can't keep writing into the checkout (POSIX already
killed the process group). Unit-tested with os.name patched to nt.
- core/prefs: mutations (set_/delete) are serialized behind a module lock —
the installer worker persisting its env.* key concurrently with a Settings
write could previously drop whichever key saved first (whole-class fix:
every threaded prefs writer, not just the installer). Fail-before/
pass-after: tests/test_prefs_thread_safety.py.
- Matrix polling: at most one in-flight status request per engine (an old
'running' response can no longer land after a newer 'succeeded' and
restart the poller), and four consecutive poll failures drop the stale
snapshot instead of showing "Installing…" and hammering a dead backend
forever.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
250 lines
6.8 KiB
Plaintext
250 lines
6.8 KiB
Plaintext
# OmniVoice backend API route snapshot — regenerate with scripts/dump_api_routes.py
|
|
# Guards against accidental endpoint removal/rename (tests/test_api_route_inventory.py).
|
|
DELETE /api/mcp/bindings/{client_id}
|
|
DELETE /api/settings/hf-token
|
|
DELETE /batch/jobs/{job_id}
|
|
DELETE /dub/history
|
|
DELETE /dub/history/{history_id}
|
|
DELETE /engines/sidecar/{engine_id}/install
|
|
DELETE /engines/translation/{engine_id}
|
|
DELETE /gallery/voices/{voice_id}
|
|
DELETE /glossary/{project_id}
|
|
DELETE /glossary/{project_id}/{term_id}
|
|
DELETE /history
|
|
DELETE /history/{history_id}
|
|
DELETE /marketplace/{filename}
|
|
DELETE /models/{repo_id:path}
|
|
DELETE /profiles/{profile_id}
|
|
DELETE /profiles/{profile_id}/consent
|
|
DELETE /projects/{project_id}
|
|
DELETE /pronunciation/{entry_id}
|
|
GET /api/mcp/bindings
|
|
GET /api/settings/asr-openai-compat
|
|
GET /api/settings/changelog
|
|
GET /api/settings/db-backup
|
|
GET /api/settings/dictation-refinement
|
|
GET /api/settings/hf-mirror
|
|
GET /api/settings/hf-token/state
|
|
GET /api/settings/history-retention
|
|
GET /api/settings/license/{engine_id}
|
|
GET /api/settings/llm-endpoint
|
|
GET /api/settings/llm-providers
|
|
GET /api/settings/llm-providers/{provider_id}/models
|
|
GET /api/settings/llm-skills
|
|
GET /api/settings/perf/torch-compile-disabled
|
|
GET /api/settings/storage
|
|
GET /api/settings/storage/models-dir
|
|
GET /archetypes
|
|
GET /archetypes/categories
|
|
GET /archetypes/{archetype_id}
|
|
GET /archetypes/{archetype_id}/preview
|
|
GET /audiobook/jobs
|
|
GET /batch/download/{job_id}/{lang}
|
|
GET /batch/jobs
|
|
GET /batch/jobs/{job_id}
|
|
GET /community/items
|
|
GET /community/manifest
|
|
GET /community/sources
|
|
GET /community/submit-url
|
|
GET /dictation/models
|
|
GET /dictation/prefs
|
|
GET /docs
|
|
GET /dub/audio/{job_id}
|
|
GET /dub/download-audio/{job_id}
|
|
GET /dub/download-audio/{job_id}/{filename}
|
|
GET /dub/download-mp3/{job_id}
|
|
GET /dub/download-mp3/{job_id}/{filename}
|
|
GET /dub/download/{job_id}
|
|
GET /dub/download/{job_id}/{filename}
|
|
GET /dub/export-segments/{job_id}
|
|
GET /dub/export-stems/{job_id}
|
|
GET /dub/history
|
|
GET /dub/media/{job_id}
|
|
GET /dub/onsets/{job_id}
|
|
GET /dub/preview-video/{job_id}
|
|
GET /dub/preview/{job_id}/{segment_index}
|
|
GET /dub/srt/{job_id}
|
|
GET /dub/srt/{job_id}/{filename}
|
|
GET /dub/thumb/{job_id}
|
|
GET /dub/tracks/{job_id}
|
|
GET /dub/transcribe-stream/{job_id}
|
|
GET /dub/vtt/{job_id}
|
|
GET /dub/vtt/{job_id}/{filename}
|
|
GET /engines
|
|
GET /engines/asr
|
|
GET /engines/effects/presets
|
|
GET /engines/llm
|
|
GET /engines/sidecar/{engine_id}/install/status
|
|
GET /engines/sonitranslate/status
|
|
GET /engines/translation
|
|
GET /engines/tts
|
|
GET /engines/{engine_id}/health
|
|
GET /export/history
|
|
GET /gallery/categories
|
|
GET /gallery/voices
|
|
GET /gallery/voices/{voice_id}
|
|
GET /gallery/voices/{voice_id}/preview
|
|
GET /glossary/{project_id}
|
|
GET /health
|
|
GET /history
|
|
GET /jobs
|
|
GET /jobs/{job_id}
|
|
GET /jobs/{job_id}/events
|
|
GET /longform/jobs
|
|
GET /marketplace/browse
|
|
GET /media-tools/status
|
|
GET /model/loaded
|
|
GET /model/status
|
|
GET /models
|
|
GET /openapi.json
|
|
GET /personalities
|
|
GET /preview/{filename}
|
|
GET /profiles
|
|
GET /profiles/{profile_id}
|
|
GET /profiles/{profile_id}/audio
|
|
GET /profiles/{profile_id}/usage
|
|
GET /projects
|
|
GET /projects/{project_id}
|
|
GET /pronunciation
|
|
GET /pronunciation/export
|
|
GET /setup/download-stream
|
|
GET /setup/preflight
|
|
GET /setup/recommendations
|
|
GET /setup/status
|
|
GET /sysinfo
|
|
GET /system/asr-backends
|
|
GET /system/diagnose
|
|
GET /system/errors/recent
|
|
GET /system/hf-token/state
|
|
GET /system/info
|
|
GET /system/logs
|
|
GET /system/logs/stream
|
|
GET /system/logs/tauri
|
|
GET /system/network/state
|
|
GET /system/notifications
|
|
GET /system/quarantine-status
|
|
GET /system/tailscale/status
|
|
GET /tasks/stream/{task_id}
|
|
GET /tools/effects
|
|
GET /tools/plugins
|
|
GET /v1/audio/voices
|
|
GET /watermark/status
|
|
PATCH /gallery/voices/{voice_id}
|
|
PATCH /projects/{project_id}
|
|
POST /api/settings/hf-mirror/test
|
|
POST /api/settings/hf-token
|
|
POST /api/settings/license
|
|
POST /api/settings/llm-providers/active
|
|
POST /api/settings/llm-providers/{provider_id}/test
|
|
POST /api/settings/storage/temp/clear
|
|
POST /archetypes/{archetype_id}/use
|
|
POST /audiobook
|
|
POST /audiobook/cover
|
|
POST /audiobook/import
|
|
POST /audiobook/plan
|
|
POST /audiobook/preview
|
|
POST /audiobook/resume/{job_id}
|
|
POST /batch/enqueue
|
|
POST /batch/jobs/{job_id}/cancel
|
|
POST /clean-audio
|
|
POST /community/items/{item_id}/use
|
|
POST /design/describe
|
|
POST /dictation/prefs
|
|
POST /dub/abort/{job_id}
|
|
POST /dub/cleanup-segments/{job_id}
|
|
POST /dub/generate/{job_id}
|
|
POST /dub/import-srt/{job_id}
|
|
POST /dub/ingest-url
|
|
POST /dub/preview-segment/{job_id}
|
|
POST /dub/qc/{job_id}
|
|
POST /dub/transcribe/{job_id}
|
|
POST /dub/translate
|
|
POST /dub/upload
|
|
POST /engines/select
|
|
POST /engines/sidecar/{engine_id}/install
|
|
POST /engines/sonitranslate/dub
|
|
POST /engines/sonitranslate/install
|
|
POST /engines/sonitranslate/start
|
|
POST /engines/sonitranslate/stop
|
|
POST /engines/translation/{engine_id}/install
|
|
POST /engines/{engine_id}/selftest
|
|
POST /export
|
|
POST /export/record
|
|
POST /export/reveal
|
|
POST /gallery/download
|
|
POST /gallery/search/youtube
|
|
POST /gallery/upload
|
|
POST /gallery/voices/batch-delete
|
|
POST /gallery/voices/{voice_id}/save-as-profile
|
|
POST /gallery/voices/{voice_id}/to-profile
|
|
POST /generate
|
|
POST /glossary/{project_id}
|
|
POST /glossary/{project_id}/auto-extract
|
|
POST /longform/render
|
|
POST /marketplace/export/{profile_id}
|
|
POST /marketplace/import
|
|
POST /marketplace/install/{filename}
|
|
POST /marketplace/publish/{profile_id}
|
|
POST /media-tools/acquire
|
|
POST /media-tools/ytdlp/restore
|
|
POST /media-tools/ytdlp/update
|
|
POST /media-tools/{tool}/custom-path
|
|
POST /media-tools/{tool}/restore
|
|
POST /media-tools/{tool}/use-system
|
|
POST /model/unload/{model_id}
|
|
POST /models/install
|
|
POST /models/install/cancel
|
|
POST /personas/export/{profile_id}
|
|
POST /personas/import
|
|
POST /personas/inspect
|
|
POST /preview/upload
|
|
POST /profiles
|
|
POST /profiles/{profile_id}/consent
|
|
POST /profiles/{profile_id}/lock
|
|
POST /profiles/{profile_id}/unlock
|
|
POST /projects
|
|
POST /pronunciation
|
|
POST /pronunciation/import
|
|
POST /pronunciation/test
|
|
POST /setup/warmup
|
|
POST /stories/encode
|
|
POST /system/crash/ack
|
|
POST /system/diagnostic-bundle
|
|
POST /system/flush-memory
|
|
POST /system/logs/clear
|
|
POST /system/logs/tauri/clear
|
|
POST /system/network/disable
|
|
POST /system/network/enable
|
|
POST /system/set-env
|
|
POST /system/tailscale/disable
|
|
POST /system/tailscale/enable
|
|
POST /tasks/cancel/{task_id}
|
|
POST /tools/direction
|
|
POST /tools/incremental
|
|
POST /tools/probe
|
|
POST /tools/rate-fit
|
|
POST /tools/video-context/{job_id}
|
|
POST /transcribe
|
|
POST /v1/audio/speech
|
|
POST /v1/audio/transcriptions
|
|
POST /watermark/detect
|
|
POST /watermark/settings
|
|
PUT /api/mcp/bindings
|
|
PUT /api/settings/asr-openai-compat
|
|
PUT /api/settings/dictation-refinement
|
|
PUT /api/settings/hf-mirror
|
|
PUT /api/settings/history-retention
|
|
PUT /api/settings/llm-endpoint
|
|
PUT /api/settings/llm-providers/{provider_id}
|
|
PUT /api/settings/llm-skills/{skill_id}
|
|
PUT /api/settings/perf/torch-compile-disabled
|
|
PUT /api/settings/storage/models-dir
|
|
PUT /glossary/{project_id}/{term_id}
|
|
PUT /history/{history_id}/starred
|
|
PUT /profiles/{profile_id}
|
|
PUT /projects/{project_id}
|
|
PUT /pronunciation/{entry_id}
|
|
WS /ws/events
|
|
WS /ws/transcribe
|
|
WS /ws/tts
|