Fix: transcribe.py nu mai sterge audio daca transcrierea nu pare completa
Cauza: am rulat `find transcripts -size -1k -delete` cat transcribe.py scria in acelasi director. faster_whisper scrie bufferat, deci o transcriere de o ora sta sub 1KB minute in sir; find a sters fisierul de sub proces, Python a logat "Transcribed" pe un inode disparut, si audio-ul a fost sters. Lectia 11 (25.11.2025) pierduta complet, re-descarcata. - transcribe_file() intoarce bool, verifica nr. cuvinte vs durata audio - pull_moltbot.sh: staging + mutare doar peste 1KB, in loc de find -delete - PROGRESS.md: documentat, ca sa nu se repete Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MtSTyTmt6AbCL9j5ajEDm1
This commit is contained in:
18
PROGRESS.md
18
PROGRESS.md
@@ -169,6 +169,24 @@ exemple long+short, minim 2-3 exemple numerice, secțiune obligatorie
|
||||
referințe web reale). **Citește-l integral înainte de orice lecție nouă.**
|
||||
|
||||
## Probleme întâlnite + fix-uri
|
||||
- **NU rula `find <transcripts> -size -1k -delete` cât rulează
|
||||
`transcribe.py`.** Greșeală făcută pe 2026-09-12: am folosit-o ca să curăț
|
||||
fișierele goale aduse de pe moltbot, în timp ce transcrierea locală scria
|
||||
în același director. `faster_whisper` ține fișierul deschis și scrie
|
||||
bufferat — o transcriere de o oră stă sub 1KB minute în șir. `find` a
|
||||
șters fișierul de sub proces; la final Python a închis un handle către un
|
||||
inode dispărut, a logat "Transcribed" ca și cum ar fi reușit, iar
|
||||
`transcribe.py` a șters și audio-ul. Lecția 11 (25.11.2025) a fost pierdută
|
||||
complet și a trebuit re-descărcată.
|
||||
Fix-uri aplicate:
|
||||
- `pull_moltbot.sh` — aduce în staging, mută doar fișierele peste 1KB.
|
||||
Folosește-l în loc de `scp` + `find -delete`.
|
||||
- `transcribe.py` — `transcribe_file()` întoarce acum bool și **verifică
|
||||
numărul de cuvinte față de durata audio** (prag: 15% din 100 cuvinte/min)
|
||||
înainte ca apelantul să șteargă audio-ul. Un fișier dispărut sau o
|
||||
transcriere suspect de scurtă păstrează audio-ul, deci pierzi doar timp
|
||||
de CPU, nu și descărcarea.
|
||||
|
||||
- **Halucinație whisper** (propoziții repetate în buclă): a apărut la
|
||||
`05_MODUL_4/02_3_STRATEGIA_5_MDSRT.txt`. Fix: re-extrage audio pentru
|
||||
lecția aia (`extract_audio.py` are funcțiile reutilizabile), retranscrie
|
||||
|
||||
27
pull_moltbot.sh
Executable file
27
pull_moltbot.sh
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
# Aduce transcrierile gata de pe moltbot.
|
||||
#
|
||||
# NU folosi `scp ... && find -size -1k -delete` pe directorul de transcrieri:
|
||||
# transcribe.py scrie acolo în paralel, iar un fișier în curs de scriere e
|
||||
# sub 1KB minute în șir. Un `find -delete` l-a șters o dată de sub proces,
|
||||
# iar transcrierea s-a pierdut complet (audio-ul fusese deja șters).
|
||||
#
|
||||
# Aici: aducem într-un director de staging, mutăm doar ce e complet.
|
||||
set -euo pipefail
|
||||
DEST=${1:-transcripts/09_Q_and_A}
|
||||
STAGE=$(mktemp -d)
|
||||
trap 'rm -rf "$STAGE"' EXIT
|
||||
|
||||
scp -q "root@moltbot:/root/atm/transcripts/*.txt" "$STAGE/" 2>/dev/null || true
|
||||
moved=0
|
||||
for f in "$STAGE"/*.txt; do
|
||||
[ -e "$f" ] || continue
|
||||
if [ "$(stat -c%s "$f")" -lt 1024 ]; then
|
||||
echo " sar peste (incomplet, $(stat -c%s "$f") octeți): $(basename "$f")"
|
||||
continue
|
||||
fi
|
||||
mv "$f" "$DEST/"
|
||||
echo " adus: $(basename "$f")"
|
||||
moved=$((moved + 1))
|
||||
done
|
||||
echo "Aduse $moved transcrieri în $DEST"
|
||||
@@ -16,13 +16,32 @@ logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(me
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def transcribe_file(model: WhisperModel, audio_path: Path, txt_path: Path) -> None:
|
||||
# Vorbirea normală dă ~100-150 cuvinte/minut. Sub 15% din asta înseamnă
|
||||
# halucinație, tăcere, sau o scriere care a eșuat — nu o transcriere bună.
|
||||
MIN_WORDS_PER_SECOND = 100 / 60 * 0.15
|
||||
|
||||
|
||||
def transcribe_file(model: WhisperModel, audio_path: Path, txt_path: Path) -> bool:
|
||||
"""Întoarce True doar dacă transcrierea rezultată pare completă.
|
||||
Apelantul șterge audio-ul DOAR pe True — altfel un fișier pierdut
|
||||
înseamnă re-descărcare, nu doar re-transcriere."""
|
||||
segments, info = model.transcribe(str(audio_path), language="ro", beam_size=5, vad_filter=True)
|
||||
txt_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(txt_path, "w", encoding="utf-8") as f:
|
||||
for seg in segments:
|
||||
f.write(seg.text.strip() + "\n")
|
||||
log.info(f" Transcribed: {txt_path.name} (lang={info.language}, duration={info.duration:.0f}s)")
|
||||
|
||||
if not txt_path.exists():
|
||||
log.error(f" {txt_path} a dispărut în timpul scrierii — păstrez audio-ul")
|
||||
return False
|
||||
words = len(txt_path.read_text(encoding="utf-8").split())
|
||||
expected = info.duration * MIN_WORDS_PER_SECOND
|
||||
if words < expected:
|
||||
log.error(f" {txt_path.name}: doar {words} cuvinte pentru {info.duration:.0f}s "
|
||||
f"(minim așteptat {expected:.0f}) — păstrez audio-ul")
|
||||
return False
|
||||
log.info(f" Transcribed: {txt_path.name} (lang={info.language}, duration={info.duration:.0f}s, {words} cuvinte)")
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
@@ -55,8 +74,8 @@ def main():
|
||||
continue
|
||||
|
||||
log.info(f"Transcribing: {audio_path}")
|
||||
transcribe_file(model, audio_path, txt_path)
|
||||
if not args.keep_audio:
|
||||
ok = transcribe_file(model, audio_path, txt_path)
|
||||
if ok and not args.keep_audio:
|
||||
audio_path.unlink()
|
||||
done += 1
|
||||
|
||||
|
||||
0
transcripts/09_Q_and_A/12_18112025.txt
Normal file
0
transcripts/09_Q_and_A/12_18112025.txt
Normal file
Reference in New Issue
Block a user