Brandýs-Boleslav
Začni psát pro vyhledávání...

Plán: chatbot nad programem a obsahem webu

Plán: chatbot nad programem a obsahem webu

Stav: návrh k odsouhlasení · Založeno 1. 8. 2026

Cíl

Chatbot na brandysboleslav.cz, který s návštěvníkem diskutuje náš politický program a informace z webu. Odpovídá výhradně z našeho publikovaného obsahu a u každého tvrzení odkáže na stránku, ze které čerpá. Když odpověď v podkladech není, řekne to a nabídne kontakt — nedomýšlí politické pozice.

Rozhodnutí (1. 8. 2026)

  • Základ: fork konextu (v2.8.0) a jeho osekání. Získáme hotový hybridní retrieval, chat widget, admin, evidenci nákladů a Quality Loop.
  • Korpus: dlouhodobý program + aktuální články + odborné podklady (doprava, strategie, MHD) + lidé a kontakty. Materiály se budou průběžně doplňovat → ingestace musí být konfigurační, ne hardcodovaná.

Architektura cílového stavu

brandys-pirati (Jekyll, GitHub Pages)
  ├─ obsah: _program/, _posts/, doprava/, _people/ …
  ├─ scripts/export-korpus.mjs ──► korpus.json
  │                                   │
  │                                   ▼  convex run knowledgePages:importBulk
  └─ _includes/footer-md3.html ──► <script src="…/embed.js">
                                        │
                                        ▼
brandys-chatbot (fork konextu)
  ├─ Next.js 16 · /widget (veřejné) + /admin (Kinde)
  └─ Convex: knowledgePages + knowledgeChunks + embeddings
             vector + fulltext + RRF + parent-child retrieval
             → OpenRouter (LLM)

Fáze 0 — Založení repa a osekání

Nový repozitář brandys-chatbot z konextu. Mazat, ne nabalovat.

Pryč:

Oblast Soubory
Produkty a feed convex/products.ts, sync.ts, productClicks.ts, tabulky products, productEmbeddings, productStats
Měny a domény convex/currency.ts (cz/sk/hu/hr/eu), cenová logika v chatFormatting.ts
Zákazníci convex/customerAuth.ts (JWT z CubeCartu), customer* pole v conversations
E-mailový kanál convex/email*.ts (~2 800 ř.), src/components/email/, /admin/emails
Re-ranking produktů rerankProducts v chatSearch.ts (accessory trap)
R2 / PII export corpus*.ts, r2Storage.ts — dokud nebude důvod

Zůstává: chat.ts, chatSearch.ts (RRF), chatAI.ts, chatPrompts.ts, embeddings.ts, knowledgePages.ts, responseCache.ts, rateLimit.ts, apiUsage.ts, answerJudge.ts + Quality Loop, widget a public/embed.js.

Kontrola hotovosti fáze: npm run test:ci prochází, npx convex dev nasadí schéma bez produktových tabulek.

Fáze 1 — Korpus a ingestace

Rozšíření schématu knowledgePages

Ke stávajícím polím (url, title, content, categoryMappings) přidat:

  • sourceType: program clanek podklad osoba kontakt
  • publishedAt (timestamp) a validity: aktualni historicky
  • sourceFile — cesta v repu, aby šlo dohledat, odkud věta pochází

Exportní skript — HOTOVO (2. 8. 2026)

scripts/export-korpus.mjs, zdroje v scripts/korpus-zdroje.json, aby šlo doplňovat bez zásahu do kódu. Čte markdown, ne HTML — je čistší než scrapovaný web a nese frontmatter (datum, kategorii, tagy).

URL se ověřuje proti _site, neodvozuje se jen z názvu souboru: Jekyll slug umí koncovou pomlčku uříznout (…-cez-.md/…-cez/) a odkaz do prázdna je u citací horší než chybějící dokument. Dokument bez dohledatelné URL skript vynechá a nahlásí. Vyžaduje tedy sestavený web.

Výstup: korpus/davka-NN.json ve tvaru argumentu pro knowledgePages.importBulk, plus souhrn.json se statistikou a seznamem problémů. Adresář je v .gitignore.

Stav korpusu: 118 dokumentů, 765 tis. znaků, 6 dávek

Zdroj Počet Druh Platnost
_program/dlouhodoby/ 13 program aktuální
_posts/strategie/ 7 program aktuální
_posts/ (od 2025) 10 článek podle data
_posts/mistostarosti/ 63 článek historický
_posts/proposals/ 18 podklad aktuální
doprava-metodika.md 1 podklad aktuální
_people/ 6 osoba aktuální
_podklady/ 0 podklad nepublikované

Místostarosti (12/2022–7/2025) jsou dobové sloupky z funkce, ne programové dokumenty — proto natvrdo validity: historicky. Bot je bude citovat jako minulost („v Místostarostech z 4. 6. 2023 jsme psali…”), ne jako dnešní pozici.

Články mají hranici odData: 2025-01-01, což vynechává 70 starších (kampaně 2018 a 2022). Odpovídá to výběru korpusu ze 1. 8. — archiv nebyl zvolen. Zapnout jde posunutím nebo smazáním jednoho pole v konfiguraci.

Import

brandys-chatbot/scripts/import-korpus.mjs projde dávky a pošle je do knowledgePages.importBulk (idempotentní přes URL — opakovaný běh aktualizuje, nezdvojuje). S --embeddings rovnou spustí regeneraci.

# 1. v brandys-pirati (vyžaduje sestavený _site)
node scripts/export-korpus.mjs

# 2. v brandys-chatbot (vyžaduje běžící convex dev / nastavený deployment)
node scripts/import-korpus.mjs --embeddings

Vyloučit explicitně:

  • _people/_priklad.md, _posts/_priklad.md — šablony s výplňovým textem
  • _archive/, _site/, export_wayback/

Import: npx convex run knowledgePages:importBulk (mutace v konextu už existuje, je idempotentní přes url), pak embeddings:regenerateAllEmbeddings.

Nepublikované podklady

Materiály, které nemají být na webu jako stránka, ale bot z nich smí čerpat a citovat je. Zadání ze 1. 8. 2026: nejde o utajení obsahu, jen o to, že se nepublikují.

Umístění: adresář _podklady/ v tomto repu. Jekyll adresáře začínající podtržítkem do _site nekopíruje (ověřeno — v _site žádný takový není), takže se na web nedostanou; exportní skript je bere jako běžný zdroj (sourceType: podklad, publikovano: false). Do exclude v _config.yml je přidat jako druhou pojistku.

Co tam smí: protože bot obsah reprodukuje návštěvníkům, je fakticky veřejný, jen bez URL. Navíc repozitář tangero/brandys-pirati je veřejný, takže soubory jsou čitelné i přímo na GitHubu. Nepatří sem interní strategie kampaně, osobní údaje ani nic, co by nemělo zaznít.

Citace bez cíle — u nepublikovaného podkladu odkaz nikam nevede. Dvě cesty, rozhodnutí je na zadavateli:

  • bot cituje jménem dokumentu bez odkazu („podle naší analýzy dopravy z 3/2026”)
  • dokument se v okamžiku, kdy z něj bot veřejně cituje, publikuje — doporučeno, publikovaná verze je lepší než parafráze bez zdroje

Spouštět ručně; automatizaci přes GitHub Action až po ověření. Pozor: npm run build je v tomto repu mrtvý a nebezpečný (přepsal by _config.yml), ingestace se ho nesmí dotknout.

Fáze 2 — Prompt, citace a guardrails

Tři věci, které konext nemá a bez kterých bot nemůže ven:

  1. Citace. chatPrompts.ts:252 dnes URL odkazy zakazuje (e-shop je nahrazuje #ID produktu). Přepsat knowledge sekci promptu tak, aby každá stránka šla do kontextu s title + url, a vynutit odkaz u každého věcného tvrzení.
  2. Datová platnost. Do promptu předat publishedAt a validity s pravidlem, že historické materiály se citují jako historie („v roce 2022 jsme navrhovali”), nikdy jako současná pozice.
  3. Tvrdé „nevím”. Vymyšlený politický závazek je horší než chybějící odpověď. Překlopit escalationDecision.ts na „na tohle nemáme veřejnou pozici, napište nám na …”. Doplnit pravidla pro provokace, dotazy na konkurenci a osobní útoky.

Dále: nový systémový prompt (tón — věcný, nekampaňový), viditelné označení „odpovídá AI, může se mýlit” ve widgetu, GDPR režim logování konverzací.

Fáze 3 — Evaluace

Sada reálných otázek voličů v docs/chatbot-otazky.md (obchvat, kulturní dům, parkování, školy, MHD, „proč jste skončili na radnici”, „co jste reálně dokázali”). Ke každé očekávaný zdroj. Projet přes Quality Loop (answerJudge, /admin/labeling), měřit podíl odpovědí bez opory ve zdroji — to je jediné číslo, které rozhoduje o vypuštění ven.

Fáze 4 — Nasazení

  • Convex + Vercel, subdoména (např. chat.brandysboleslav.cz)
  • <script> do _includes/footer-md3.html (vedle Clicky analytics)
  • Kinde pro /admin, verze v UI a health endpointu podle zvyklosti

Fáze 5 — Hlasové rozhraní (až po textu)

OpenAI vydala 7. 5. 2026 GPT-Realtime-2 (Realtime API přes WebSocket, WebRTC i SIP, 128K kontext) a spolu s ním GPT-Realtime-Whisper pro streamovaný přepis.

Nepoužívat speech-to-speech. Model by mluvil přímo z audia a retrieval by si tahal přes function calling — tím obejde cache, snapshoty Quality Loopu i citace. Právě to je u politického bota jádro obhajitelnosti a nahrávka je zdaleka nejsdílitelnější artefakt.

Místo toho hlas jako vrstva nad textovou pipeline:

mikrofon → GPT-Realtime-Whisper (přepis)
         → stávající retrieval + citace + Quality Loop
         → odpověď s odkazy na obrazovce + TTS

Latence horší, ale u diskuse o obchvatu nerozhoduje. Zachová logování, měření halucinací i viditelné zdroje — a audio-in/audio-out je řádově levnější než speech-to-speech.

K ověření před nasazením: GDPR režim pro hlas návštěvníka (citlivější než textový log, zvlášť v předvolebním období) a výslovnost místních jmen — Houštka, Zápy, Vrábí, Brandýs nad Labem-Stará Boleslav.

Rizika

  • Halucinovaný závazek — hlavní riziko celého projektu. Mitigace: citace, tvrdé „nevím”, evaluační sada, konzervativní temperature.
  • Zastaralý obsah jako aktuální pozice — 70 z 80 článků je starších než 2025.
  • Volební období — dnes 1. 8. 2026, komunální volby na podzim. Zvážit chování bota v době volebního moratoria a připravit vypínač.
  • Zneužití k útoku — screenshot nešťastné odpovědi. Řešení: logovat vše, mít možnost bota okamžitě vypnout.

Otevřené otázky

  • Kde je DNS pro brandysboleslav.cz (subdoména pro Vercel)?
  • Vercel Hobby vs. Pro — politický projekt strany, komerční licence?
  • Kdo bude číst logy konverzací a jak často?