Phase D + E — Plánované¶
Phase D — Chat s RAG injection¶
Stav: ⏳ Plánováno
Cíl: Přepsat /chat endpoint aby používal /retrieve interně místo full report textu
Aktuální stav (Phase B/C)¶
/chat endpoint (app/routers/chat.py):
- Načte report row →
parsed_markdown(v2) neboclean_text(v1-import legacy) - Volá Pydantic AI Agent s plným textem reportu v system promptu (~10-40K tokens)
- Streamovaný SSE response
Problém: full text = drahý kontext + vendor model může mít problém s "needle in haystack" pro velké reporty.
Co Phase D změní¶
/chatinterně volá/retrievepro každý turn- top_k = 8 chunks
- scope = folder (current report context)
- Inject chunks do system promptu místo full textu
- 8 chunks × ~500 tokens = ~4K vs 40K full text
- 10× tokens saving
- AI cituje per chunk (
source_label+attachment_filenamedenormalized v chunks) - "Z přílohy 'Vyjádření ČEZ' vyplývá..."
- "V sekci 'Riziko povodní' najdete..."
- Streaming odpověď zachovat (SSE)
- Multi-turn conversation history —
rewrite_standalonev Phase C MVP no-op, Phase D dostane real history → použije LLM rewrite
Plánovaný flow¶
User → ChatWindow → POST /chat {message, conversation_id}
→ Backend retrieve interně /retrieve {query, scope=folder, top_k=8}
→ top-K chunks
→ Build system prompt:
"Jsi asistent pro hodnocení nemovitostí. Odpovídej z následujícího kontextu:
[1] Sekce 'Riziko povodní': Pozemek je v zóně Q100...
[2] Příloha 'Vyjádření ČEZ': Nad parcelou nejsou nadzemní vedení...
[3] Figura 'map_zoning' (sekce Územní plán): Mapa ukazuje...
..."
→ Pydantic AI Agent stream response
→ SSE chunks → Frontend
Změny per komponenta¶
Backend:
- app/routers/chat.py — rewrite use /retrieve interně
- app/retrieval/rewrite.py — implement rewrite_standalone s history (currently no-op)
- Možná nový chat_context_formatter.py — assemble system prompt z chunks
Frontend:
- ChatWindow.tsx — nezbytně malé změny (response shape stejný)
- Možná zobrazit cited chunks v UI ("Z těchto pasáží:" + linky na sekce)
Schema:
- messages table možná přidat cited_chunk_ids uuid[] pro UI render
Open questions Phase D¶
- Jak handle-ovat reporty bez chunks? (D7 soft-fail) → fallback na full-report dump, ale zminit user "bez RAG, basic fallback"
- Multi-report chat support? Aktuálně 1 conversation = 1 report. Phase D může umožnit cross-report queries.
- Streaming + chunks injection — Pydantic AI patterns pro streamovaný response
Časový odhad¶
~1-2 dny implementace + 1 den testing + golden eval (Phase C.12 deferred → mohlo by se hodit zde).
Phase E — Nette integration¶
Stav: ⏳ Plánováno (gate: Nette tým ready) Cíl: Embed chat do Nette aplikace, JWT bridge, HMAC webhooks, DNS cutover
Co bylo připraveno v Phase A/B¶
verify_nette_jwt()ready hook vapp/auth.py— RS256 + iss/aud/exp enforcement, neaktivní v APOST /reports/{id}/attachments/system— HMAC-authed endpoint pro Nette automatické attachment uploady (Phase B B.11)- Embed-first frontend — chat je vždy iframe, jen parent origin se změní
Plánovaný flow¶
Nette user logged in
→ Nette signs RS256 JWT { sub: nette_user_id, email, aud: "nemoreport-ai", iss: "nemoreport.cz", exp: now+15min }
→ postMessage { type: "nemoreport-ai:init", authToken: "<JWT>" }
↓
Chat iframe (https://review.algaweb.cz/chat?id=...)
→ POST /auth/nette-exchange { jwt }
↓
Backend
→ verify_nette_jwt(token) — RS256 přes NETTE_JWT_PUBLIC_KEY
→ lookup or create Supabase user via auth.identities(provider='nette')
→ generate Supabase session → return { access_token, refresh_token }
↓
Frontend uses Supabase session, chatuje bez druhého loginu
Komponenty¶
Backend:
- POST /auth/nette-exchange — verify Nette JWT → mint Supabase session
- ENV NETTE_JWT_PUBLIC_KEY (PEM) — pro RS256 verify
- ENV NETTE_AUDIENCE = "nemoreport-ai", NETTE_ISSUER = "nemoreport.cz"
Frontend:
- iframe child listener pro postMessage event nemoreport-ai:init
- apiFetch exchange Nette JWT → Supabase session
- Adjust CORS / origins pro Nette domain
Infra:
- DNS cutover: NemoReport AI app on review.algaweb.cz (currently on nemoreport-ai-frontend-v2.algaweb.workers.dev)
- CF Workers route bind
Časový odhad¶
~1 týden implementace + integration testing s Nette tým + DNS cutover.
Další plánované funkce (mimo phase plan)¶
Token credit system (přeprodej)¶
Per project memory project_nemoreport_admin_section:
Až přijde, bude další admin sekce — token mint/refund, user balances, transaction log. Cost tracking se přepíše z raw halíře na "tokens spent". Pro Phase C zatím držet raw cost v
ingestion_cost_cents.
User explicit decision 30.4: bude "přeprodej tokenů jako platební systém — uživatelé kupují kredity, utrácejí na platformě". Frontend cost zobrazení teď interní, pro produkci se přepíše.
Admin analytics dashboard¶
/admin/retrieval/* endpointy nad retrieval_log:
- Top queries / scope distribution
- A/B variant comparison
- Per-tenant retrieval stats
- Latency p50/p95/p99 trends
/admin/cost/* UI v admin frontu (zatím jen JSON endpointy).
Multi-report scope retrieval¶
Phase C MVP supports jen scope.type='folder' (single report). Multi-report scope:
scope.type='multi_report', report_ids=[...]- HNSW with WHERE report_id IN (...) — pgvector iterative_scan='relaxed_order'
- Use case: cross-report comparison ("porovnej tyto 3 nemovitosti")
Resend production domain¶
Pro reálné testery (mimo owner email). Verifikace auth.algaweb.cz nebo auth.nemoreport.cz.
Cohere production key¶
Trial limit ~1000 calls/měsíc. Pilot OK, scale potřebuje upgrade.