Files
ROMFASTSQL/proxmox/lxc171-claude-agent/maria-whatsapp-bridge/tests/test_ocr.py
Claude Agent 7a1d2a2073 feat(maria): asociere prin cod de telefon si citirea capturilor cu erori
Doua lucruri cerute de utilizator, ambele pe acelasi drum: sa poti lega
puntea fara sa ai un ecran de scanat, si sa poti trimite Mariei o poza cu
eroarea in loc sa transcrii mesajul.

Asociere prin cod de 8 caractere (alternativa la QR):
- endpoint-ul /pair exista, dar nu era folosibil: fara `browser` explicit
  WhatsApp refuza codul, iar dupa introducerea lui corecta serverul cere un
  restart (515) care consuma din bugetul de reincercari si putea opri puntea.
  Acum descriptorul e Browsers.ubuntu('Chrome') si restartRequired reconecteaza
  imediat, fara sa numere.
- codul are TTL de 3 minute, iar /status il da doar cat timp e valabil —
  un cod expirat afisat in dashboard trimite omul sa tasteze degeaba.
- dashboard: camp pentru numar + buton, in acelasi card cu QR-ul.

Imagini cu erori (capturi de ecran):
- puntea descarca imaginile in ~/.maria-bridge/media/ (imageMessage sau
  document cu mimetype image/*, si prin ambalajele efemer/"vezi o data" —
  fara despachetare pareau mesaje fara continut si se aruncau tacut).
- rag/ocr.py: tesseract ron+eng. Modelul de raspuns e strict text, deci OCR
  nu e o optiune de calitate, e singura cale.
- cautarea in index merge DOAR pe liniile care arata a eroare; o fereastra
  intreaga de meniuri si totaluri dilueaza embedding-ul si scoate chunk-uri
  fara legatura. Modelul primeste captura intreaga, marcata ca text OCR.
- capturile se sterg imediat dupa citire (pot contine date de client).
- cand nu se citeste nimic si nu exista legenda, Maria cere textul erorii
  in loc sa raspunda in gol.

16 teste noi (42 in total). install.sh verifica tesseract; README documenteaza
ambele metode de asociere si drumul unei capturi.

Separat, in docs/chatboti-si-punti.md: chatul "Eu" e vazut de AMBELE punti de pe
numar. Puntea lui Echo (LXC 110) e asociata ca dispozitiv :11 al aceluiasi cont,
momentan nelegata dar pornita — daca se reasociaza, raspunde in "Eu" langa Maria.
Notat si ca serviciile lui Echo sunt unitati de UTILIZATOR: `systemctl is-active`
ca root raspunde "inactive" desi botul ruleaza.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4uzvgm7AyJch5WH8QHRhY
2026-08-31 21:22:42 +00:00

63 lines
2.2 KiB
Python

"""Curatarea textului OCR si alegerea interogarii de cautare.
Fara tesseract si fara retea: `ocr.run` e singurul care atinge procese externe si
nu e testat aici — restul sunt functii pure peste text.
"""
from __future__ import annotations
import ocr
def test_clean_scoate_liniile_goale_si_ramele():
raw = "Eroare la salvare\n\n \n|||||\n----\nORA-01722: invalid number\n"
assert ocr.clean(raw) == "Eroare la salvare\nORA-01722: invalid number"
def test_clean_normalizeaza_spatiile_si_taie_duplicatele():
raw = "ORA-00001: unique constraint\nORA-00001: unique constraint\n"
# a doua linie e identica dupa normalizare — tesseract repeta uneori randuri
assert ocr.clean(raw) == "ORA-00001: unique constraint"
def test_clean_plafoneaza_si_marcheaza_trunchierea():
out = ocr.clean("\n".join(f"linia numarul {i}" for i in range(500)), max_chars=100)
assert len(out) < 200
assert out.endswith("[…text trunchiat]")
def test_error_lines_gaseste_codurile_oracle_si_mesajele_romanesti():
text = (
"Fisier Editare Ajutor\n"
"Nr. crt. Denumire Cantitate\n"
"ORA-12154: TNS:could not resolve\n"
"Documentul nu exista in baza de date\n"
"Total general 1.234,00\n"
)
assert ocr.error_lines(text) == [
"ORA-12154: TNS:could not resolve",
"Documentul nu exista in baza de date",
]
def test_error_lines_limiteaza_numarul():
text = "\n".join(f"eroare {i}" for i in range(20))
assert len(ocr.error_lines(text, limit=3)) == 3
def test_retrieval_query_pune_legenda_prima_apoi_erorile():
q = ocr.retrieval_query("nu pot factura", "Meniu principal\nORA-00942: table or view does not exist")
assert q == "nu pot factura\nORA-00942: table or view does not exist"
def test_retrieval_query_fara_linii_de_eroare_cade_pe_primele_linii():
# O captura fara niciun cuvant-cheie tot trebuie cautata cumva; mai bine
# aproximativ decat deloc.
text = "\n".join(f"linia {i}" for i in range(20))
q = ocr.retrieval_query("", text)
assert q.splitlines() == [f"linia {i}" for i in range(8)]
def test_retrieval_query_doar_legenda_cand_ocr_e_gol():
assert ocr.retrieval_query("cum sterg o factura?", "") == "cum sterg o factura?"