Vlastní AI rozhraní (custom)
Přepínač KB_AI_PROVIDER má polohu custom — vlastní služba, která mluví stejným jazykem jako killBottleneck. Do téhle chvíle byl ten „jazyk" popsaný jen v našem zdrojovém kódu, což je málo: kdo si chtěl připojit něco vlastního, musel se v něm hrabat. Tady je sepsaný celý.
Většina lidí tuhle stránku nepotřebuje
Když máte klíč od OpenAI, OpenRouteru, Groqu a spol., zvolte openai — ten mluví běžným tvarem a nic programovat nemusíte. custom je pro případ, kdy si chcete mezi killBottleneck a model postavit vlastní mezikus (vlastní prompty, směrování na víc modelů, záznam dotazů, filtr obsahu).
Jak to funguje
killBottleneck pošle na KB_AI_URL POST s JSON tělem. V těle je vždy mode (o jakou úlohu jde) a lang (cs nebo en — jazyk, ve kterém má služba odpovědět; jazyk určuje server podle přihlášeného uživatele, klient ho podvrhnout nemůže).
| Metoda | POST |
| Hlavičky | Content-Type: application/json, X-KB-Token: <KB_AI_TOKEN> |
| Časový limit | 120 s (u transcribe 600 s) |
| Odpověď | JSON, HTTP 2xx |
Volitelně můžete v odpovědi poslat "schema_version": 1. Když pošlete jiné číslo, killBottleneck odpověď odmítne srozumitelnou chybou místo tichého rozbití. Bez toho pole se nic nekontroluje.
Úlohy (mode)
questions — doplňující otázky k cíli
// požadavek
{ "mode": "questions", "goal": "Uspořádat firemní večírek", "scope": "detailní", "lang": "cs" }
// odpověď
{ "questions": ["Kolik lidí?", "Do kdy?", "Jaký rozpočet?"] }Vrací se 1–5 otázek; killBottleneck si vezme prvních pět.
generate — strom plánu z cíle
// požadavek
{ "mode": "generate", "goal": "Uspořádat firemní večírek", "scope": "detailní",
"answers": ["40 lidí", "do Vánoc", "80 tisíc"], "lang": "cs" }
// odpověď
{ "nodes": [
{ "id": "root", "title": "Uspořádat firemní večírek", "description": "", "parentId": null },
{ "id": "n1", "title": "Zamluvit sál", "description": "Do konce října.", "parentId": "root" }
] }Pravidla, která killBottleneck po odpovědi vynucuje:
- právě jeden kořen — uzel s
parentId: null; parentIdmusí ukazovat naid, které je ve stejném seznamu (jinak se uzel pověsí na kořen);titlese ořezává na 120 znaků;answersje pole odpovědí na otázky z předchozího kroku — může chybět.
scope je jedna ze tří hodnot: "stručná", "detailní", "hloubková" (jsou to hodnoty, ne texty pro uživatele — nepřekládají se ani nemění).
from_text — strom plánu z volného textu
{ "mode": "from_text", "text": "Zápis z porady…", "scope": "detailní", "lang": "cs" }Odpověď má stejný tvar jako u generate. Text posílá killBottleneck ořezaný na 8 000 znaků.
expand — rozvinout jeden uzel
// požadavek
{ "mode": "expand", "goal": "Uspořádat firemní večírek",
"path": ["Uspořádat firemní večírek", "Zamluvit sál"],
"node": { "id": "n1", "title": "Zamluvit sál", "description": "Do konce října." },
"action": "subgoals", "count": 3, "lang": "cs" }
// odpověď
{ "nodes": [ { "title": "Obejít tři místa", "description": "Porovnat cenu a kapacitu." } ] }Tady uzly nemají id ani parentId — věší se pod uzel z požadavku.
action | Co se čeká |
|---|---|
subgoals | konkrétní podkroky, jak uzel splnit |
milestones | měřitelné milníky na cestě |
kpi | metriky, kterými se měří úspěch |
risks | rizika (v title) a jak je zmírnit (v description) |
rewrite | jeden uzel — lepší formulace téhož (count je 1) |
chat — rozhovor nad mapou
// požadavek
{ "mode": "chat", "message": "Co mi v plánu chybí?",
"map": { "title": "Večírek", "nodes": [
{ "id": "root", "title": "Večírek", "description": "", "status": "todo", "parentId": null } ] },
"lang": "cs" }
// odpověď
{ "reply": "Chybí ti rozpočet a termín.", "operations": [] }Když má rozhovor mapu i změnit, vrací se operace. Jiné než tyhle čtyři killBottleneck zahodí:
{ "op": "add", "parentId": "root", "title": "…", "description": "…" }
{ "op": "update", "id": "n1", "title": "…", "description": "…", "status": "todo|in_progress|done" }
{ "op": "delete", "id": "n1" }
{ "op": "move", "id": "n1", "newParentId": "root" }transcribe — přepis nahrávky
Jde na KB_AI_TRANSCRIBE_URL. Když ta není vyplněná, odvodí se z KB_AI_URL (koncové kb-advisor se nahradí za kb-transcribe).
// požadavek
{ "mode": "transcribe", "audio_base64": "…", "filename": "nahravka.webm", "lang": "cs" }
// odpověď
{ "text": "přepsaný text" }Pozor: tohle není tvar OpenAI (ten chce multipart se souborem). Kdo má OpenAI-kompatibilní přepis, ať zvolí provider openai — ten si multipart složí sám.
Chyby
| Co vrátíte | Co uvidí uživatel |
|---|---|
| HTTP 2xx s očekávaným tvarem | výsledek |
HTTP 403 nebo 429 s { "error": "…", "code": "…" } | vaši hlášku (tarifní odmítnutí se propouští beze změny) |
| jiný chybový stav | „AI služba odpověděla chybou (HTTP …)" |
| nedostupnost, časový limit | „Nepodařilo se spojit s AI službou" |
schema_version ≠ 1 | „Nekompatibilní verze AI kontraktu" |
Na co si dát pozor
- Odpovídejte ve zvoleném jazyce.
langnení dekorace — uživatel dostane text tak, jak ho pošlete. - Vracejte platný JSON, ne text s JSONem uvnitř. killBottleneck sice umí strhnout obal
```json, ale spoléhat se na to nemá smysl. - Prázdná odpověď je chyba, ne prázdný výsledek — raději pošlete chybový stav s vysvětlením, ať uživatel neví jen to, že „se nic nestalo".
- Na hostované instanci nesmí adresa mířit do privátní sítě (jinak by šla instance použít jako skener sítě poskytovatele). Na vlastním serveru je privátní adresa v pořádku.

