Commit Graph

6 Commits

Author SHA1 Message Date
alf adc0904009 feat(voice): migration CosyVoice → OmniVoice (.cvps → .ovsp)
Suit docs/OMNIVOICE_VOICE_MIGRATION.md (app patiente migrée vc17+, 22/06).
- enroll.py : réécriture encodeur OmniVoice (create_voice_clone_prompt → format binaire
  OVSP : magic|T_ref|text_len|tokens[8*T_ref]|ref_text). Cap réf 16s. prepare_wav 24kHz.
- transcribe.py : ASR interne OmniVoice (plus d'openai-whisper, absent de ov_venv).
- transfer.py : omnivoice_dir_for (<MODELS_DIR>/omnivoice/voices), deployed_ovsp,
  push_ovsp, suffixe .ovsp.
- bridge.py : OV_PYTHON (/opt/Kazeia/ov_venv). worker dispatch inchangé.
- orchestrator.py : .ovsp, ovsp_bytes ; verrou d'exclusivité + archive WAV INCHANGÉS.
- store : colonne cvps_bytes → ovsp_bytes (+ migration ALTER RENAME idempotente).
- tests adaptés. 39/39.
- validé live sous ov_venv : enroll → .ovsp format byte-identique à damien.ovsp (réf
  engine) ; auto-ASR FR correcte ; bridge ping/transcribe/enroll chaud OK.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 10:15:11 +02:00
Kazeia 46343c9ad5 docs(voice): texte d'enrôlement = phrase de consentement connue + exclusivité dure
- VOICE_ENROLLMENT_SPEC : le texte de référence est CONNU (phrase de consentement
  admin), pas à transcrire → Whisper sort du chemin critique (fallback legacy).
  Fenêtre CV_TARGET_S 15→22s pour que consentement + fin riche entrent dans le .cvps.
- VOICE_DEPLOYMENT_SPEC §4 : exclusivité DURE (consentement/RGPD), capturée
  record-time (scope+owner au manifeste). Gap acté : ingérer depuis le stockage
  ADMIN (pas le provider /voices). Phase 2 = garde-fou on-device. Récap des états.
- enroll.py : CV_TARGET_S=22.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 08:52:37 +02:00
alf 23033384c7 feat(voice): verrou voix↔profil + sync verrou-conscient + déclencheur auto
- store : colonne locked_profile_id (+ migration ALTER idempotente), lock_voice/
  unlock_voice. Verrou = assignation exclusive à un profil ; NULL = voix généraliste.
- orchestrator : list_voices expose locked_profile_id + used_by_profiles (croise
  profile.voice_id) ; sync_device enrôle+déploie les voix en attente, REFUSE de
  déployer une voix verrouillée sur une tablette sans le profil propriétaire.
- autosync : VoiceAutoSync — watcher de connexions armable depuis l'UI (désarmé par
  défaut), statut par tablette, ne fait rien si store verrouillé (PII), delete opt-in.
- API : lock/unlock, POST /{serial}/sync, GET/POST /voices/autosync (déclarées AVANT
  /{serial} pour éviter la capture "autosync" comme serial).
- tests : +8 (verrou, sync verrou-conscient, autosync). 39/39.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 16:20:55 +02:00
alf 4ad513afda feat(voice): orchestration enrôlement — pull/archive/transcribe/enroll/deploy
- store : table voices + WAV chiffré sur disque (archive_voice_wav, voice_wav_bytes,
  transcription chiffrée, marques archived/enrolled/deployed/wav_deleted).
- voice/transfer.py : dérivation du dossier cosyvoice depuis wav_path (device-dépendant),
  pull WAV / push .cvps / delete WAV device (retour vérifié §9).
- voice/orchestrator.py : list_voices (statut par voix), prepare (pull+archive+whisper),
  enroll_deploy (enroll+push + suppression WAV device optionnelle, opt-in).
- API : GET /api/voices/{serial}, /voices/health, POST .../prepare, .../enroll.
- tests : +10 (chemins, archive chiffrée, orchestration via faux adb/bridge). 33/33.
- validé live : jerome (muet) → transcrit FR → .cvps déployé sur tablette + WAV
  archivé chiffré ; WAV device conservé (delete_source=false).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 14:39:29 +02:00
alf 92505a4cac feat(voice): moteur d'enrôlement — worker cv_venv chaud + IPC + transcription
- worker.py : process persistant sous cv_venv (teacher + Whisper chauds), protocole
  JSON-lines. Canal stdout propre (fd1→stderr) pour ne pas corrompre l'IPC avec le
  bruit torch/librosa.
- bridge.py : pont côté API py3.14 (sans torch) — lance/pilote le worker en
  subprocess, jobs sérialisés, démarrage paresseux.
- transcribe.py : Whisper sur le segment PRÉPARÉ (texte == segment enrôlé), défaut
  "small" ("base" transcrit mal le FR, validé).
- Validé live : 1 worker chaud sert ping+transcribe(fr)+enroll, réutilisé (même PID),
  protocole non corrompu (bruit libs → stderr).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 14:24:24 +02:00
alf 8fa7fe4f47 feat(voice): enroll.py — WAV → .cvps (CosyVoice), cœur prouvé sur device réel
- enroll.py : réimplémentation configurable de cv_make_prompt (env CV_REPO/CV_TEACHER),
  teacher chargé une fois (singleton), + préparation WAV obligatoire (mono/16k/~15s)
  car le tokenizer s3 plante >30s et la similarité chute <8s.
- Sortie GGUF arch cosyvoice-prompt-speech, 4 tenseurs aux dtypes exacts.
- Validé live : richard.wav (111s stéréo) → richard.cvps structurellement identique à
  damien.cvps (feat F32[80,750], embedding F32[192,1], tokens I32[375], text I8).
- Hygiène stdout (museler numba/librosa) en prévision de l'IPC worker.

NB : tourne sous cv_venv (torch), PAS sous l'API py3.14 → worker subprocess à venir.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 10:32:11 +02:00