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
This commit is contained in:
Claude Agent
2026-08-31 21:22:28 +00:00
parent f5c8df7adf
commit 7a1d2a2073
12 changed files with 733 additions and 36 deletions

View File

@@ -60,12 +60,16 @@ embeddings.
WhatsApp (self-chat, sau numarul legat)
|
v
whatsapp/index.js (Baileys) -- API HTTP :8099 (/status /send /messages /react /qr)
whatsapp/index.js (Baileys) -- API HTTP :8099 (/status /send /messages /react /qr /pair)
| descarca imaginile primite in ~/.maria-bridge/media/
|
v
rag/consumer.py -- polling la /messages, RAG stateless (FARA memorie intre mesaje)
| vezi docs/maria-whatsapp-rag-prototype.md pentru motiv
v
rag/ocr.py -- capturile de ecran -> text (tesseract), inainte de RAG
|
v
rag/store.py -- depozit documente (.txt/.md) in ~/.maria-bridge/documents/
rag/indexer.py -- chunking + embeddings Ollama -> rag_index.json
rag/sync.py -- rclone pull din Google Drive + reindexare conditionata
@@ -104,15 +108,77 @@ curl -fsSL https://ollama.com/install.sh | sh
ollama pull nomic-embed-text # ~274 MB, CPU-only pe acest container
```
Bridge-ul WhatsApp NU porneste automat la instalare — cere scanarea unui cod QR
Pentru citirea capturilor de ecran primite (vezi „Imagini cu erori" mai jos):
```bash
sudo apt-get install -y tesseract-ocr tesseract-ocr-ron
```
Bridge-ul WhatsApp NU porneste automat la instalare — cere asocierea cu telefonul
(actiune manuala, o singura data):
```bash
./ops/install.sh --start
# apoi deschide dashboard-ul puntii Discord si scaneaza codul QR din
# sectiunea "Maria — WhatsApp + RAG" -> cardul "Conectare WhatsApp"
# apoi deschide dashboard-ul puntii Discord, sectiunea "Maria — WhatsApp + RAG"
# -> cardul "Conectare WhatsApp", si alege una din cele doua metode (mai jos)
```
## Asocierea cu telefonul: QR sau cod
Ambele duc la acelasi rezultat — puntea devine un *dispozitiv conectat* al contului.
Alegerea e practica, nu tehnica:
| | Cand se foloseste |
|---|---|
| **Cod QR** | Ai dashboard-ul deschis pe un ecran pe care telefonul il poate fotografia. |
| **Cod de asociere** (8 caractere) | Esti pe telefon, sau ecranul cu QR-ul e la distanta: scrii numarul in dashboard, primesti un cod si il tastezi pe telefon. |
Pentru codul de asociere, in dashboard: scrie numarul **in format international,
fara `+` si fara `00`** (ex. `40723197939`), apasa „Cere cod de asociere", apoi pe
telefon: WhatsApp -> Dispozitive conectate -> Conecteaza un dispozitiv ->
**Conecteaza cu numar de telefon** -> tastezi codul.
Codul e valabil **~3 minute**; dupa ce expira, dashboard-ul il marcheaza ca expirat
si trebuie cerut altul. Dupa introducerea corecta, WhatsApp inchide conexiunea cu
codul `restartRequired` (515) — puntea se reconecteaza singura, imediat; nu e o
eroare si nu consuma din bugetul de reincercari.
Din linia de comanda, aceleasi lucruri:
```bash
curl -s -X POST -H 'Content-Type: application/json' \
-d '{"phone":"40723197939"}' http://127.0.0.1:8099/pair
curl -s http://127.0.0.1:8099/status | python3 -m json.tool # cod + secunde ramase
```
Codul se poate cere doar cat timp sesiunea NU e inregistrata. Daca puntea raspunde
„sesiunea e deja inregistrata", opreste-o, sterge `~/.maria-bridge/whatsapp-auth/`
si porneste-o din nou — dar atentie, asta desface asocierea existenta.
## Imagini cu erori
Utilizatorii trimit aproape intotdeauna o captura cu fereastra de eroare, nu textul
ei. Puntea descarca imaginea in `~/.maria-bridge/media/`, iar consumer-ul o trece
prin **tesseract** (`ron+eng`) inainte de RAG. Modelul de raspuns (Qwen3.5-2B pe
LXC 104) e strict text, deci OCR-ul e singura cale — nu e o optiune de calitate.
Doua detalii care nu se vad din cod la prima citire:
- **Cautarea in index nu foloseste toata captura.** Un ecran intreg de meniuri,
coloane si totaluri dilueaza embedding-ul si scoate chunk-uri fara legatura. Se
cauta doar dupa liniile care arata a eroare (`ORA-…`, „eroare", „nu exista", …);
modelul primeste totusi fereastra intreaga, marcata explicit ca text OCR, ca sa nu
trateze greselile de recunoastere ca date exacte. Vezi `rag/ocr.py`.
- **Capturile se sterg imediat dupa citire.** Pot contine date de client si nu exista
niciun motiv sa ramana pe disc. Ce ramane dupa un restart in mijlocul procesarii se
curata la pornirea puntii (dupa 24h).
Legenda imaginii, daca exista, conteaza: intra si in intrebare si in cautare. Daca
OCR-ul nu gaseste nimic lizibil si nu exista legenda, Maria cere textul erorii in
loc sa inventeze un raspuns.
Limite: `MAX_MEDIA_MB` (implicit 8) pentru imaginea bruta, `OCR_MAX_CHARS`
(implicit 1500) pentru textul trimis modelului, `OCR_TIMEOUT_S` (60).
Videoclipurile, audio si documentele non-imagine sunt in continuare ignorate.
## Dashboard (comun cu puntea Discord)
Nu exista un dashboard separat pentru Maria. Controlul se face din dashboard-ul
@@ -120,7 +186,7 @@ puntii Discord — vezi `../discord-bridge/README.md` pentru URL si autentificar
(`DASHBOARD_TOKEN` din `~/.claude-discord/env`, tunel SSH sau Tailscale la
`/claude`). Acolo, sectiunea "Maria — WhatsApp + RAG":
- start/stop/restart pentru puntea WhatsApp si consumer-ul RAG
- starea conexiunii WhatsApp si codul QR de asociere (cand nu e conectat)
- starea conexiunii WhatsApp si asocierea (cod QR sau cod de 8 caractere), cand nu e conectat
- listare, adaugare si stergere documente din depozitul RAG
- reconstruire index manual, sau sincronizare Drive imediata
- ultimele linii din logurile fiecarui serviciu Maria (`whatsapp.log`/`rag.log`)
@@ -207,7 +273,8 @@ mtime + marime, vezi `rag/sync.py`), ca sa nu reface embeddings degeaba.
```bash
cd /workspace/romfastsql/proxmox/lxc171-claude-agent/maria-whatsapp-bridge
python3 -m pytest # preferinta de format + taierea XML, fara retea si fara Ollama
python3 -m pytest # preferinta de format, taierea XML, OCR si mesajele cu imagine
# — fara retea, fara Ollama si fara tesseract
```
## Context conversational