Files
VoiceStudio/tests/fixtures/api_routes.txt
T
ff56865cf7 feat(engines): one-click IndexTTS-2 sidecar install from Settings → Engines (#1083)
* 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>
2026-07-12 01:13:35 +05:30

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