fix(transcribe): rulare detașată, ca joburile video să nu mai moară la timeout
Două linkuri Facebook trimise pe Discord n-au produs niciun răspuns: scriptul
rula în interiorul turnului de chat, iar yt-dlp + ffmpeg + whisper depășeau
constant DEFAULT_TIMEOUT (300s, src/claude_session.py:37). Procesul era omorât
la mijlocul transcrierii, de cinci ori pe patru încercări.
Efecte în cascadă, toate reparate aici:
- retry-uri oarbe: linkul 1 reprocesat de două ori (notițe duplicate), linkul 2
niciodată atins
- notițe cu TL;DR gol — arată „gata" în index dar nu sunt
- orfani de 33MB în /tmp (trap EXIT nu rulează la SIGKILL)
- userul nu primea nici rezultat, nici eroare acționabilă
Schimbări:
- --bg (setsid nohup) + --notify <channel_id>; turnul confirmă pornirea, nu
terminarea. send_text() nou în tools/discord_send_file.py, pentru că un job
detașat supraviețuiește turnului și nu mai poate raporta prin on_text.
- faster-whisper int8 în locul openai-whisper: 554s audio în 113s (~5x realtime)
vs. peste 300s. Era deja în requirements.txt; openai-whisper nici măcar nu era
declarat. cpu_threads pe core-uri fizice, nu logice.
- limba implicită „auto": rularea forțată cu `ro` pe audio englezesc producea
transcriere halucinată (română inventată amestecată cu CJK)
- .venv/bin/python3 explicit; whisper nu există în python-ul de sistem, scriptul
mergea doar când era chemat cu venv-ul activat
- metadata yt-dlp pe disc, parsată o dată: descrierile Facebook conțin caractere
de control care corup variabila de shell, iar `|| echo Unknown` masca eșecul
- titlul sare segmentele de statistici: Facebook emite „830K views · 15K
reactions | Titlul real | Pagina", iar split('|')[0] producea notițe numite
2026-08-31_807k-views-15k-reactions.md
- curăță workdir-urile orfane mai vechi de 60 min la pornire
.gitignore: bridge/whatsapp/auth.bak-*/ — backup-urile Baileys conțin creds.json
(chei de sesiune vii), la fel ca auth/ care era deja ignorat.
Verificat end-to-end pe ambele linkuri: titlu corect, limbă en auto-detectată,
notiță + reindex + link, trap curăță /tmp, zero orfani.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0188YmDTUAzVvZDVh8JL8xSa
This commit is contained in:
@@ -63,7 +63,7 @@ Lecții capturate din corectările lui Marius. Citește acest fișier la începu
|
||||
**Data:** 2026-04-29
|
||||
**Context:** Salvam o notiță din Facebook reel în memory/kb/. Am adăugat manual o intrare în index.json cu schema greșită (`id` + `path` în loc de `file`), ceea ce a blocat notes.html pe "Se încarcă..." cu un TypeError în renderNoteCard.
|
||||
**Greșeala:** Am editat index.json direct, cu o schemă diferită față de ce produce update_notes_index.py.
|
||||
**Regula:** Niciodată nu scriei manual în `memory/kb/index.json`. Fluxul corect: (1) creezi fișierul `.md` în `memory/kb/<categorie>/`, (2) rulezi `python3 tools/update_notes_index.py`. Dacă ai nevoie să salvezi o notiță din Facebook/video, folosești `scripts/transcribe_video.sh <URL> <lang> --save-kb` care face totul corect.
|
||||
**Regula:** Niciodată nu scriei manual în `memory/kb/index.json`. Fluxul corect: (1) creezi fișierul `.md` în `memory/kb/<categorie>/`, (2) rulezi `python3 tools/update_notes_index.py`. Dacă ai nevoie să salvezi o notiță din Facebook/video, folosești `scripts/transcribe_video.sh <URL> auto --save-kb --bg --notify <channel_id>` care face totul corect (`--bg` e obligatoriu dintr-un turn de chat — vezi lecția despre timeout-ul de 300s).
|
||||
**Când se aplică:** Orice salvare de notiță în KB (Facebook, YouTube, coaching, insights, orice). Dacă ești tentat să `json.dump` în index.json — stop, rulează scriptul.
|
||||
|
||||
## Verifică că modelul/tool-ul numit chiar are capabilitatea ÎNAINTE de a planifica în jurul lui
|
||||
@@ -86,3 +86,20 @@ Lecții capturate din corectările lui Marius. Citește acest fișier la începu
|
||||
**Greșeala:** Am optimizat pentru „să se audă ceva" fără să întreb ce dimensiune e prioritară pentru user. Vocea clonată E produsul; schimbarea ei e regresia maximă percepută.
|
||||
**Regula:** Când un input parțial invalid ajunge la un sistem cu identitate configurată de user (voce, persona, stil), remediază conținutul ca să treacă (transliterare, sanitizare), nu comuta pe altă identitate. Fallback pe alt engine/voce doar la eșec TEHNIC (server picat), nu la eșec de conținut.
|
||||
**Când se aplică:** Orice pipeline TTS/persona cu fallback. Implementare: `fold_ro_diacritics` în tools/tts.py + push_text în src/voice/tts_stream.py.
|
||||
|
||||
## Munca mai lungă de 300s nu are ce căuta într-un turn de chat — rulează detașat și raportează pe canal
|
||||
**Data:** 2026-08-31
|
||||
**Context:** Marius a trimis două linkuri de video Facebook pe Discord. Niciunul n-a produs un răspuns. În jurnal: `Claude CLI timed out after 300s`, de cinci ori, pe patru încercări diferite. `scripts/transcribe_video.sh` rula în interiorul turnului, iar yt-dlp + ffmpeg + openai-whisper pe 9 minute de audio depășeau constant `DEFAULT_TIMEOUT` (`src/claude_session.py:37`). Procesul era omorât la mijlocul Whisper-ului.
|
||||
**Greșeala:** Am tratat o sarcină cu durată nemărginită (descărcare rețea + inferență ML) ca pe un apel sincron într-un turn conversațional. Efectele în cascadă au fost mai rele decât timeout-ul în sine:
|
||||
- **Retry-uri oarbe pe linkul greșit** — la reîncercare am reprocesat linkul 1 de două ori (două notițe duplicate) și n-am procesat niciodată linkul 2. Când mai multe linkuri eșuează, verifică *care* a eșuat înainte să reiei.
|
||||
- **Documente pe jumătate** — scriptul scrie template-ul cu TL;DR gol, iar rezumatul îl completez eu *după* ce scriptul întoarce. Procesul omorât ⇒ notițe cu TL;DR gol, care arată „gata" în index dar nu sunt.
|
||||
- **Orfani pe disc** — `trap ... EXIT` nu rulează la SIGKILL; rămâneau 33MB în `/tmp/transcribe_$$`.
|
||||
- **Eșec tăcut la nivel de user** — Marius n-a primit nici rezultat, nici eroare acționabilă.
|
||||
**Regula:** Dacă un pas poate depăși ~2-3 minute, nu-l rula în turn. Pornește-l detașat (`setsid nohup`), întoarce imediat un confirm cu job id + cale de log, și raportează finalizarea pe canal (`tools/discord_send_file.py --text`). Turnul confirmă *pornirea*, nu *terminarea*.
|
||||
**Corolare descoperite la fix:**
|
||||
- **Nu forța limba.** Rularea cu `ro` pe audio englezesc a produs transcriere halucinată (română inventată amestecată cu CJK). Implicit e acum `auto`; forțează doar dacă ești sigur.
|
||||
- **Alege motorul înainte de a ridica timeout-ul.** faster-whisper int8 face 554s de audio în 113s (~5x realtime); openai-whisper depășea 300s pe același fișier. `faster-whisper` era deja în `requirements.txt`, openai-whisper nici măcar nu era declarat. Un motor de 5x a fost fix mai bun decât un timeout mai mare.
|
||||
- **Folosește `.venv/bin/python3` explicit în scripturi shell.** Scriptul chema `python3` bare, iar `whisper` nu există în python-ul de sistem — mergea doar din noroc, când era chemat cu venv-ul activat.
|
||||
- **Nu trece JSON mare printr-o variabilă de shell.** Descrierile Facebook conțin caractere de control care corup variabila (`character not in range`); scrie-l pe disc și parsează fișierul o singură dată. `|| echo Unknown` masca eșecul.
|
||||
- **Titlurile Facebook încep cu statistici,** nu cu titlul: `830K views · 15K reactions | Titlul real | Pagina`. `split('|')[0]` producea notițe numite `2026-08-31_807k-views-15k-reactions.md`. Sari segmentele de statistici și pe cel egal cu numele paginii.
|
||||
**Când se aplică:** Orice transcriere video/audio, OCR pe fișiere mari, scraping multi-pagină, build sau inferență ML pornită dintr-un mesaj de chat. Implementare: `scripts/transcribe_video.sh` (`--bg`, `--notify`) + `send_text()` în `tools/discord_send_file.py`.
|
||||
|
||||
Reference in New Issue
Block a user