Files
echo-core/memory/kb/projects/pocket-tts-integration-handoff-prompt.md
Marius Mutu 155d6cb9c1 Update TOOLS.md, cron jobs, KB index; add discord file sender + pocket-tts plan
Pre-existing work committed before starting Ralph self-improvement run on
ralph/echo-improve branch, so that branch's diff stays isolated to the
pocket-tts integration.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-11 09:54:36 +00:00

6.8 KiB

Vreau să integrezi pocket-tts (Kyutai) ca motor TTS nou în echo-core, alături de Supertonic (motorul actual). Task arhitectural, nu un fix simplu — intră în plan mode înainte să atingi cod, și trece planul prin /plan-eng-review (arhitectură, edge cases, cum ating fișierele existente fără să stric fluxul live) înainte de implementare. Nu implementa nimic până planul nu e aprobat.

Context — ce există deja

  • Motor actual: Supertonic, rulează ca serviciu systemd separat (supertonic-tts.service), HTTP pe 127.0.0.1:7788. Wrapper: tools/tts.py (synthesize(text, voice, lang)).
  • Comandă on-demand: /audio (Discord slash command, src/adapters/discord_bot.py ~L911-995) — parametri voce (M1-M5/F1-F5), text_sau_url, rezumat. Apelează fast_dispatch("audio", ...) din src/fast_commands.py, care întoarce __AUDIO__:<path> — interceptat de discord_bot.py și trimis ca attachment.
  • Mod live: Discord Voice (/voice join), src/voice/pipeline.py + src/voice/tts_stream.py — streaming TTS pe clauze (clause_segments()), buget de latență strict (~5s perceput end-to-end, filler audio după 3s fără răspuns). Folosește tools/tts.py intern.
  • Credențiale: keyring, serviciu "echo-core" (src/credential_store.py). Există deja discord_token și hf_token (HuggingFace, pentru modelul gated pocket-tts cu voice cloning — vezi mai jos).

Research + teste deja făcute (nu le repeta)

Am evaluat deja pocket-tts manual într-o sesiune anterioară (vezi memory: project_pocket_tts_voice_clone_eval.md):

  • Nu suportă română oficial — doar english, french, german, portuguese, italian, spanish. Testele confirmă: text românesc sintetizat cu modelul englez sună cu accent englezesc puternic.
  • Voice cloning funcționează bine din sample-uri scurte (~4-35s testate), via get_state_for_audio_prompt(path_sau_nume_voce_predefinita).
  • Viteză reală măsurată pe acest CPU: ~2.7-2.9x faster-than-real-time (Kyutai raportează 6x pe Apple M4 — CPU-ul ăsta e mai lent per-core, dar tot confortabil peste real-time).
  • Modelul cu voice cloning e gated pe HuggingFace — cere account + accept termeni + token (HF_TOKEN). Tokenul lui Marius e deja în keyring (hf_token).
  • Instalare testată: pip install pocket-tts (venv izolat de test la /tmp/pocket-tts-test/.venv, nu producție). CLI: pocket-tts generate --text "..." --voice <nume_sau_path.wav> --output-path out.wav.
  • Sample-uri de voce ale lui Marius, deja înregistrate (la ~/workspace/pocket-tts-test/, convertite la wav mono 24kHz):
    • marius_real_voice.wav (7.8s) → devine voce "Marius 1"
    • marius_real_voice_2.wav (12.6s) → devine voce "Marius 2"
    • marius_real_voice_3.wav (35s, mai expresiv) → devine voce "Marius 3"
  • Tool nou creat, deja în repo: tools/discord_send_file.py — trimite fișier direct pe un canal Discord via REST API (necesar pentru că __AUDIO__: prefix nu funcționează în afara fast_commands — vezi docstring din script și personality/TOOLS.md § "Discord — trimite fișier direct").

Cerințe confirmate de Marius (decizii arhitecturale — NU le renegocia, doar implementează)

  1. pocket-tts rulează ca proces/serviciu separat, exact ca Supertonic — systemd propriu, port propriu, apelat via HTTP din restul codului. Nu integrat direct în procesul bot (evită să bagi torch ca dependență grea în .venv principal).
  2. pocket-tts = engine default. Supertonic = fallback.
  3. pocket-tts răspunde MEREU în engleză (fonetic), indiferent de limba textului de intrare — inclusiv pe text românesc (va suna cu accent, e acceptat/intenționat). Nu face rutare automată pe limbă.
  4. Fallback pe Supertonic doar la:
    • (a) eșec tehnic pocket-tts (model indisponibil, HF token expirat, server jos, etc.)
    • (b) comandă manuală de schimbare engine de la Marius — trebuie adăugată o comandă nouă pentru switch engine (ex: /engine supertonic / /engine pockettts, sau similar — alege convenția care se potrivește cel mai bine cu comenzile existente).
  5. Scope complet: atât mod live (Discord Voice, streaming pe clauze) cât și on-demand (/audio). Nu doar unul din ele.
  6. Selector de voce unificat: vocile Supertonic existente (M1-M5, F1-F5) plus vocile clonate, ca opțiuni suplimentare în același selector/aceeași comandă.
  7. Voci clonate salvate ca .safetensors (export via export_model_state(), încărcare rapidă — vezi README pocket-tts pentru API exact), cu convenție de nume <Nume> <N> (ex: Marius 1, Marius 2, Marius 3; extensibil la alte persoane, ex: Paula 1, dacă Marius mai trimite sample-uri).
  8. Marius va mai trimite sample-uri de voce în timp — trebuie un flux clar (comandă + atașament) pentru a adăuga o voce clonată nouă la catalog, fără intervenție manuală de cod de fiecare dată.

Ce trebuie să decidă/detalieze planul (edge cases de rezolvat explicit)

  • Cum se comportă fallback-ul din mod live dacă pocket-tts pică la mijlocul unei conversații (schimbare de engine mid-sesiune, fără să rupă turul curent)?
  • Ce se întâmplă cu lang="ro" / --lang parametrul existent din tools/tts.py odată ce pocket-tts (mereu engleză) devine default — rămâne relevant doar pentru calea Supertonic?
  • Cum se integrează streaming-ul propriu al pocket-tts cu clause_segments() din tts_stream.py (format audio, sample rate, chunking) — pocket-tts produce 24kHz, pipeline-ul Discord așteaptă 48kHz stereo s16le (vezi _ffmpeg_resample în tts_stream.py).
  • Unde se stochează fișierele .safetensors ale vocilor clonate (director nou în repo? models/voices/? ~/workspace/?) — și cum se mapează nume → fișier (config nou în config.json, sau fișier JSON dedicat).
  • Cum se gestionează HF_TOKEN pentru serviciul systemd nou (environment file, similar cu cum discord_token e disponibil altor procese).
  • Comanda de switch engine — ephemeral (doar sesiunea curentă) sau persistă în config.json / sessions/active.json?
  • Ce se întâmplă cu comanda /audio existentă când alegi o voce clonată — flow-ul de azi (fast_dispatch__AUDIO__: prefix) rămâne valid pentru pocket-tts, sau outputul trebuie tratat diferit?

Instrucțiuni pentru sesiunea care preia

  1. Citește memory/kb/ relevant + project_pocket_tts_voice_clone_eval.md din memory pentru context complet de research.
  2. Intră în plan mode, scrie un plan concret care acoperă toate punctele de mai sus.
  3. Rulează planul prin /plan-eng-review (arhitectură, edge cases, performance) înainte de orice modificare de cod.
  4. Prezintă planul lui Marius pentru aprobare explicită înainte de implementare.
  5. Respectă principiile din CLAUDE.md: impact minim, fără scope creep, verifică înainte de "done".