# Web-API ↔ didi-brain integration Web-api folosește didi-brain ca **layer de cache cu 2 fețe**: 1. **Cache read** (ambele tiers — free și premium) — înainte să cheme SearXNG sau paid providers, web-api întreabă brain. Dacă brain are evidence relevante cached, le servește direct; clientul primește răspuns în ~1-2s în loc de 10-30s. 2. **Cache write** (doar tier premium, quality-gated) — după o cerere premium care a trecut pragurile de calitate, web-api pompează evidence în brain fire-and-forget. Brain face extraction async. Viitoarele cereri pe claim-uri similare vor hit-ui cache-ul. Ideea de bază: **free users primesc quality-ul plătit de premium users**, dar doar premium plătește pentru popularea cache-ului. --- ## Flow-ul per request ``` POST /v1/gather { claim, tier } │ ▼ ┌─────────────────────────────────────────┐ │ 1. Cache READ (brain /v1/gather) │ │ (ambele tiers, dacă brain configured│ │ și brain_cache_read_enabled=true) │ └────────┬────────────────────────────────┘ │ ├─ brain HIT cu quality OK │ → returnează direct răspunsul (skip orchestrator) │ └─ brain MISS sau quality slab │ ▼ ┌────────────────────────────────┐ │ 2. Orchestrator normal │ │ free → SearXNG + Qwen │ │ premium → Paid + OpenRouter│ └────────┬───────────────────────┘ │ ▼ ┌────────────────────────────────┐ │ 3. Cache WRITE (doar premium) │ │ dacă quality_ok_for_cache │ │ fire-and-forget ingest │ │ (nu blochează response) │ └────────────────────────────────┘ │ ▼ Return to client ``` --- ## Componente ### `src/web/brain/client.py` — `BrainClient` Client HTTP minimal pentru brain: - `gather(claim, max_evidence, run_nli, ...)` — cache read, returnează JSON sau None pe eroare - `ingest(payload)` — cache write, fire-and-forget via sink de obicei Timeout-uri separate (gather e rapid, ingest poate fi mai lent). ### `src/web/brain/sink.py` — `BrainIngestSink` Queue bounded (1000 items max) processat de un single worker task. Overflow → drop oldest. Eșecuri → log DEBUG, swallowed. Zero impact pe latența web-api. ### `src/web/brain/quality.py` — Quality gates - `quality_ok_for_cache(response)` — decide dacă un gather result e worth-caching (3+ evidence, cel puțin 1 sursă credibilă dacă sunt scored, toate stages OK, execution > 2s) - `brain_hit_acceptable(brain_raw)` — decide dacă un brain HIT e suficient de bun (HIT = da; PARTIAL = da doar dacă 3+ items cu relevance ≥ 0.7) ### `src/web/brain/adapter.py` — Schema conversion - `brain_response_to_web(brain_raw, request_id)` — convertește response-ul brain în `GatherResponse` web (datetime → ISO string, provenance dict, `brain_meta` flatten în provenance per evidence item) - `web_response_to_ingest_payload(response, claim)` — convertește `GatherResponse` în `IngestRequest` pentru brain (ISO dates, safe defaults pentru field-urile required brain-side: title/retrieved_at/score defaults) --- ## Configurare În `deploy/.env`: ```bash WEB_BRAIN_URL=http://didibrain-api:8090 # Feature toggles (default true dacă brain_url setat) WEB_BRAIN_CACHE_READ_ENABLED=true WEB_BRAIN_INGEST_ENABLED=true # Quality thresholds pentru ingest WEB_BRAIN_INGEST_MIN_EVIDENCE=3 WEB_BRAIN_INGEST_MIN_CREDIBILITY=0.7 WEB_BRAIN_INGEST_MIN_EXECUTION_MS=2000 # Acceptance thresholds pentru PARTIAL cache hit WEB_BRAIN_HIT_MIN_EVIDENCE=3 WEB_BRAIN_HIT_MIN_RELEVANCE=0.7 # Timeouts WEB_BRAIN_GATHER_TIMEOUT=8.0 WEB_BRAIN_INGEST_TIMEOUT=15.0 ``` Toate sunt optional. Dacă `WEB_BRAIN_URL` e gol, integrarea e dezactivată complet (fallback la orchestrator normal pentru tot). --- ## Networking Docker Web-api trăiește pe rețeaua `deploy_default` (cu dashboard, video, audio, searxng). Brain trăiește pe rețeaua proprie `didibrain`. Web-api e atașat la **ambele** rețele în `deploy/docker-compose.yml`: ```yaml networks: deploy_default: external: true didibrain: external: true services: web-api: networks: - deploy_default - didibrain ``` Asta îi permite să rezolve `didibrain-api` prin DNS-ul Docker. --- ## Fail-open Brain down ≠ web-api down. Toate apelurile spre brain sunt wrapped cu try/except generos: - Gather cache read eșuează → continuă la orchestrator normal - Ingest eșuează → log și drop event (queue-ul va reumple) Clientul nu vede niciodată o eroare datorită brain. --- ## Cum monitorizezi HIT rate Log-urile web-api emit `Brain cache HIT [tier=X, N items]: ` pe fiecare hit. Pentru producție, integrarea cu dashboard face count-uri în tabela `request_history` (câmp `raw_response.stages` conține `retrieval`/`rerank` când e din brain vs `search`/`fetch` când e direct). Query exemplu (post-deploy): ```sql -- HIT rate per tier pe ultimele 24h SELECT tier, COUNT(*) FILTER ( WHERE raw_response::jsonb -> 'stages' @> '[{"stage":"retrieval"}]' ) AS brain_hits, COUNT(*) AS total_gathers, ROUND(100.0 * COUNT(*) FILTER ( WHERE raw_response::jsonb -> 'stages' @> '[{"stage":"retrieval"}]' ) / NULLIF(COUNT(*), 0), 1) AS hit_rate_pct FROM request_history WHERE endpoint = '/v1/gather' AND created_at > now() - interval '24 hours' GROUP BY tier; ``` --- ## Ce NU face integrarea - Nu scrie la brain pe tier `free` (doar citește) — tip premium gold standard - Nu face fallback la premium când brain MISS pe free (menține tier isolation) - Nu retry — un singur request la brain, orice eșec → fallback silent Pentru detaliile contractului verification_cache (backend ↔ brain), vezi `modules/didi_brain/CONTRACT_VERIFICATION_CACHE.md`.