# Punte WhatsApp + RAG pentru Maria (LXC 171) Bot de suport ROA pe WhatsApp: puntea WhatsApp (Baileys) primeste mesajele, consumer-ul RAG raspunde folosind DOAR informatiile dintr-un depozit de documente indexat cu embeddings (Ollama). Controlul (start/stop/restart, documente, reindexare, sincronizare Google Drive) se face din **dashboard-ul puntii Discord** (`../discord-bridge/dashboard/`), sectiunea "Maria — WhatsApp + RAG" — un singur panou comun pentru ambele punti de pe acest container, nu un dashboard separat per serviciu. Continua prototipul descris in `claude-agent/docs/maria-whatsapp-rag-prototype.md` (construit initial in `/tmp/maria-bridge/`) — aici e mutat in git, ca serviciu persistent. Nu confunda cu: - **Maria pe Flowise** (`vfp_roaauto/COMUN/utile/chatbot/`) — chatbot web separat. - **Echo / `echo-whatsapp-bridge.service`** (LXC 110 moltbot) — alt bot, alta punte. - **Punte Discord -> Claude Code** (`discord-bridge/`, acelasi container) — alt proiect, alt scop (comanda Claude Code de pe Discord, nu suport RAG). ## Arhitectura ``` WhatsApp (self-chat, sau numarul legat) | v whatsapp/index.js (Baileys) -- API HTTP :8099 (/status /send /messages /react /qr) | v rag/consumer.py -- polling la /messages, RAG stateless (FARA memorie intre mesaje) | vezi docs/maria-whatsapp-rag-prototype.md pentru motiv 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 ../discord-bridge/dashboard/api.py -- panou comun; sectiunea Maria controleaza maria-whatsapp.service + maria-rag.service, gestioneaza documentele si declanseaza sincronizare/reindexare ``` Servicii `systemctl --user` (vezi `ops/`): | Unitate | Ce face | |---|---| | `maria-whatsapp.service` | Puntea Baileys (Node), port 8099 | | `maria-rag.service` | Consumer RAG (Python), polling + raspunsuri | | `maria-sync.service` + `.timer` | Sincronizare Drive + reindexare, la 10 min | ## Instalare ```bash cd maria-whatsapp-bridge ./ops/install.sh # creeaza ~/.maria-bridge/, venv, npm install, symlink-uri unit ``` Completeaza manual `~/.maria-bridge/env` (copiat din `ops/env.example` la prima rulare): cel putin `LLM_URL` (backend-ul de chat) si, daca vrei sincronizare automata cu Drive, `DRIVE_REMOTE`. `OLLAMA_URL` (implicit `http://127.0.0.1:11434`, folosit pentru embeddings la indexare) presupune un Ollama instalat local pe container — nu exista alt Ollama documentat in infrastructura. Instalare (facuta deja pe LXC 171, 2026-08-31): ```bash sudo apt-get install -y zstd # dependinta a instalatorului Ollama 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 (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" ``` ## Dashboard (comun cu puntea Discord) Nu exista un dashboard separat pentru Maria. Controlul se face din dashboard-ul puntii Discord — vezi `../discord-bridge/README.md` pentru URL si autentificare (`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) - 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`) ## Depozitul de documente Fisiere `.txt`/`.md`/`.xml` in `~/.maria-bridge/documents/` (lista exacta: `store.DOC_EXTENSIONS`). Se pot administra: 1. **manual din dashboard-ul comun** (adaugare/stergere text, reindexare automata la salvare); 2. **prin sincronizare Google Drive** — vezi mai jos. ## Sincronizare cu Google Drive Sursa: dosarul `document_store` din Drive-ul contului `mmarius28@gmail.com` (pe Windows apare ca `D:\GoogleDrive\romfast\document_store`, prin Google Drive Desktop). ID-ul dosarului: `1C4e75zgH1_7ZK-_oBP5ZZBvUPh3iEo1O`. Containerul e headless (fara browser pentru OAuth), deci autorizarea se face pe o masina cu browser si se muta aici ca token — **fara cont de serviciu si fara consola Google Cloud**. rclone e deja instalat pe LXC 171 (`rclone v1.60.1`). Pasi (o singura data): 1. **Pe Windows**, ia `rclone.exe` de la (arhiva portabila, nu cere instalare) si ruleaza in acel dosar: ``` rclone.exe authorize "drive" --drive-scope=drive.readonly ``` Se deschide browserul; autentifica-te cu `mmarius28@gmail.com` si accepta. In consola apare un token JSON intre `--->` si `<---`. Copiaza-l intreg. 2. **Pe container**, da tokenul scriptului de configurare: ``` ops/setup-drive.sh '' ``` Face restul singur: creeaza remote-ul `gdrive`, verifica accesul la dosar, scrie `DRIVE_REMOTE` in `~/.maria-bridge/env` (cu backup) si ruleaza prima sincronizare cu reindexare. E idempotent — se poate rula din nou oricand. Tinta scrisa in env e `gdrive,root_folder_id=:` — sintaxa „connection string" a rclone, care fixeaza dosarul dupa ID, fara sa depinda de structura de nume din My Drive. 3. Verifica in dashboard: sectiunea Maria trebuie sa arate „Drive: …" in loc de „Sincronizare Drive dezactivata". Tokenul se reimprospateaza singur (refresh token) cat timp aplicatia ramane autorizata in contul Google. Daca expira, dashboard-ul arata sincronizarea ca esuata — reia pasii 1-2. ### Ce se sincronizeaza `rclone sync` aduce doar `*.txt`, `*.md` si `*.xml` (vezi `store.DOC_EXTENSIONS`). Restul din dosar — chatflow-uri Flowise `.json`, scripturi `.ps1`, `.docx` — sunt ignorate deliberat: nu sunt cunostinte de suport. **`sync` sterge local ce nu mai exista in Drive**, deci depozitul e o oglinda a dosarului din Drive, nu o colectie care creste. Documentele adaugate manual din dashboard dispar la prima sincronizare daca nu exista si in Drive. ### Acelasi document in doua formate Cand exista `X.xml` si `X.md`, **in index intra doar `.xml`** (ordinea de preferinta: `.xml` > `.md` > `.txt`, in `rag/store.py`). Sursele `.xml` sunt structurate pe probleme si de regula mai noi decat exporturile `.md` — la `d406_saft_knowledge`, `.xml` era cu trei luni mai nou si cu 50% mai mare. Fisierul umbrit ramane pe disc si apare in dashboard marcat „umbrit de …", ca sa se vada de ce nu e indexat; daca ar fi indexate ambele, acelasi raspuns ar aparea de doua ori in rezultatele RAG. ### Cum se taie XML-ul in chunk-uri Un chunk per element de nivel 1 — adica **o problema = un chunk**, cu mesajul de eroare si rezolvarea impreuna. Taierea pe linii goale (cea folosita la `.md`) le-ar separa, iar cautarea ar gasi eroarea si ar returna un chunk fara raspuns. Etichetele raman ca prefixe lizibile (`mesaj eroare: …`, `rezolvare: …`), fara paranteze unghiulare. Un XML care nu se poate parsa nu opreste indexarea: cade pe taierea obisnuita, cu o linie in log. Vezi `rag/indexer.py` si `tests/test_store_si_chunking.py`. Dupa configurare, `maria-sync.timer` trage la fiecare 10 minute; reindexarea ruleaza DOAR daca s-a schimbat efectiv ceva in depozit (amprenta pe nume + mtime + marime, vezi `rag/sync.py`), ca sa nu reface embeddings degeaba. ## Teste ```bash cd /workspace/romfastsql/proxmox/lxc171-claude-agent/maria-whatsapp-bridge python3 -m pytest # preferinta de format + taierea XML, fara retea si fara Ollama ``` ## Context conversational `rag/consumer.py` nu retine memorie intre mesaje — fiecare intrebare e o interogare RAG independenta (system prompt + top-K chunk-uri + intrebare). Vezi `claude-agent/docs/maria-whatsapp-rag-prototype.md` pentru motiv si comparatie cu celelalte punti (Discord: context nelimitat + `/new`; Maria pe Flowise: fereastra fixa de 5 schimburi).