Popisujeme tu tři způsoby napojení: okno Nory přímo ve vašem systému, webhooky, kterými vám Nora předá dotazy, a automatické nahrávání podkladů ze schránek a složek. Každá firma má vlastní instanci Nory, takže adresy níže začínají adresou té vaší.
Přehled
Klíče, tajné hodnoty a povolené adresy nastavuje na vaší instanci tým Nory. Neposílejte je e-mailem v otevřeném textu, bezpečný způsob předání domluvíme.
Okno Nory ve vašem systému
Váš systém zobrazí stránku Nory v rámu iframe, typicky v postranním panelu. Lidé se v něm ptají na postupy firmy a odpovědi dostávají se zdrojem, aniž by systém opustili. Všechno v okně je stránka Nory: úpravy nasazujeme na naší straně, do vašeho systému není potřeba sahat.
- Bez přihlašování. Okno se ověří klíčem v adrese a adresou sítě, ze které pobočka přistupuje. Na pokladně se nikdo nepřihlašuje.
- Bez jmen. Zaměstnance pozná jen podle neprůhledného ID z vašeho systému. Jméno Nora nikdy nedostane.
- Každý vidí jen své dotazy. Historie patří pobočce a zaměstnanci, jiný zaměstnanec ji neuvidí.
- Odpovídá z podkladů, které určíte. Co okno smí číst, nastavíme štítky spojení. Odpovědi umí text i obrázky.
- Když neví, předá dotaz. Pod odpovědí je tlačítko pro předání člověku. Odpověď se pak ukáže přímo v okně.
Adresa a parametry
Pro váš systém připravíme spojení s vlastním klíčem. Adresu okna si uložíte do nastavení systému a parametry k ní doplní systém sám:
<iframe
src="https://<vaše-instance>/embed/<systém>/<klíč>?lang=cs&store=PRAHA01&station=PRAHA01-POKLADNA2&user=u_8f3a2c&theme=light&accent=%231e6bd8&header=1"
width="380" height="560" title="Nora">
</iframe>
| Parametr | Význam | Příklad |
|---|---|---|
lang | Jazyk okna: cs, sk, pl, hu, ro, hr, en. Jiná hodnota znamená en. Nora odpovídá v jazyce otázky. | cs |
store | Kód pobočky. Pobočka musí mít povolené IP adresy. | PRAHA01 |
station | Pokladna nebo zařízení. Při prvním načtení se zaregistruje samo. | PRAHA01-POKLADNA2 |
user | Neprůhledné ID zaměstnance z vašeho systému, nikdy jméno. | u_8f3a2c |
theme | Světlý nebo tmavý vzhled: light, dark. | light |
accent | Barva vašeho systému pro bubliny zaměstnance (hex, zakódovaná v URL). | %231e6bd8 |
header | 1 záhlaví s tlačítky Nový chat a Chaty, 0 jen řádek odkazů. | 1 |
app | Verze vašeho systému, ukáže se v přehledu zařízení. | 4.2.0 |
Neznámé parametry Nora ignoruje. Okno počítá s velikostí 320–480 × 400–720 px a funguje i v izolovaném rámu (sandbox): nepoužívá dialogová okna a odkazy z odpovědí otevírá v novém okně prohlížeče. Zdroje, obrázky, starší chaty i předání člověku se otevírají přímo v okně.
Zprávy s vaším systémem
Okno a váš systém si posílají zprávy přes postMessage. Každá zpráva má stejný tvar, typ a data. Okno přijímá zprávy jen od rodičovského okna, neznámé typy ignoruje a do zpráv nikdy nedává klíč, dotaz ani odpověď.
// Zprávy z okna Nory
window.addEventListener("message", (event) => {
if (event.source !== noraFrame.contentWindow) return;
const message = event.data; // { protocol, version: 1, type, payload }
if (message.type === "unread") showBadge(message.payload.count);
if (message.type === "error") showUnavailable(message.payload.message);
});
// Panel se ukázal: Nora označí odpovědi jako přečtené a zkontroluje stav
noraFrame.contentWindow.postMessage(
{ protocol: "<protokol>", version: 1, type: "visibility", payload: { visible: true } },
"https://<vaše-instance>"
);
| Typ | Směr | Kdy |
|---|---|---|
ready | Nora → systém | Okno je připravené, s verzí Nory (version). |
error | Nora → systém | Okno se nemohlo otevřít, například neznámá pobočka nebo vyměněný klíč (code, message). Systém ukáže vlastní hlášku a tlačítko Zkusit znovu. |
close | Nora → systém | Uživatel okno zavřel klávesou Esc. |
unread | Nora → systém | Přišla odpověď, zatímco je okno skryté (count). |
activity | Nora → systém | Uživatel s oknem pracuje, nejvýš jednou za 10 sekund. |
scan | Nora → systém | Do okna se načetl čárový kód ze čtečky (raw). Z pole pro dotaz ho Nora odstraní. |
visibility | systém → Nora | Okno se ukázalo nebo skrylo (visible). |
context | systém → Nora | Na jaké obrazovce systému uživatel právě je (screen). |
Přesný název protokolu i sadu zpráv dostanete s klíčem. Pro každý systém připravujeme vlastní adaptér, takže se přizpůsobíme tomu, co váš systém umí.
Bezpečnost okna
- Klíč a adresy poboček dohromady. Uniklá adresa okna mimo síť vašich poboček nefunguje. Každé odmítnuté načtení vidíme v přehledu a jedním krokem ho povolíme.
- Žádné cookies. Okno drží podepsaný token s platností 12 hodin jen v paměti stránky. IP adresa se kontroluje u každého požadavku.
- Klíč neodchází dál. Okno posílá hlavičku
Referrer-Policy: no-referrera má přísnou politiku obsahu (CSP): skripty, styly i spojení jen z Nory. - Výměna klíče platí hned. Ukončí starou adresu i všechna otevřená okna. Spojení jde kdykoli vypnout.
- Limity a mazání. Výchozí limit je 60 dotazů za hodinu na zaměstnance a 400 dotazů denně na spojení. Historie se maže 4 měsíce po poslední zprávě. Obojí jde upravit.
Webhooky
Když Nora odpověď nezná, nebo ji člověk chce ověřit, předá dotaz správnému člověku. Místo e-mailu ho může poslat do vašeho systému: helpdesku, systému úkolů nebo vlastní služby. Cesty nastavíte ve Správa → Eskalační směrování. Jedna cesta může obsluhovat jen vybraná oddělení.
| Hlavička | Hodnota |
|---|---|
Content-Type | application/json; charset=utf-8 |
User-Agent | Nora-Outbox/1 |
X-Nora-Event | escalation.raised |
X-Nora-Delivery | ID doručení. Při opakování zůstává stejné, hodí se proti zpracování dvakrát. |
X-Nora-Signature | sha256= a HMAC-SHA256 těla zprávy v hexadecimálním tvaru. Posílá se, když má cesta tajnou hodnotu. |
Tělo zprávy
Nora pošle požadavek POST s tělem v JSON: tazatel, oddělení, otázka, odpověď Nory s jejími zdroji a posledních několik zpráv rozhovoru.
{
"event": "escalation.raised",
"severity": "normal",
"company": "Vaše firma s.r.o.",
"asker": { "id": 42, "name": "Jana Nováková", "email": "jana.novakova@vasefirma.cz" },
"department": { "id": 3, "name": "Prodejna" },
"question": "Můžu dát slevu na zboží s poškozeným obalem?",
"note": "Zákazník čeká u pokladny.",
"answer": {
"outcome": "not_found",
"text": "To v podkladech nemám, tak si nic nevymýšlím.",
"sources": []
},
"conversation": [
{ "role": "user", "text": "Můžu dát slevu na zboží s poškozeným obalem?" },
{ "role": "assistant", "text": "To v podkladech nemám, tak si nic nevymýšlím." }
],
"reply": "Respond with JSON {\"answer\": \"...\"} to answer the asker right away, or with anything else to answer later in Nora.",
"escalation_id": 1287
}
| Pole | Význam |
|---|---|
severity | high, když tazatel označil dotaz jako naléhavý, jinak normal. |
department | Oddělení, za které se tazatel ptal, nebo null. |
note | Poznámka tazatele k předání, nejvýš 1000 znaků. |
answer.outcome | Jak dopadla odpověď Nory: answered, partial, not_found, unverified, no_access, off_topic, chat, clarify, error. |
answer.sources | Zdroje odpovědi: type (record nebo customer_solution), id, title, category, topic a doslovné citace v quotes. |
conversation | Až šest posledních zpráv rozhovoru (role je user nebo assistant). |
escalation_id | Číslo předání v Noře. |
Ověření podpisu
Když má cesta tajnou hodnotu, ověřte před zpracováním, že zpráva přišla od vaší Nory. Podpis se počítá z těla zprávy přesně tak, jak dorazilo, proto ho ověřte dřív, než JSON přečtete.
<?php
$body = file_get_contents('php://input');
$expected = 'sha256=' . hash_hmac('sha256', $body, getenv('NORA_WEBHOOK_SECRET'));
if (!hash_equals($expected, $_SERVER['HTTP_X_NORA_SIGNATURE'] ?? '')) {
http_response_code(401);
exit;
}
$event = json_decode($body, true);
// Hned odpovědět tazateli:
header('Content-Type: application/json');
echo json_encode(['answer' => 'Ano, do 5 % z ceny. Důvod zapište do pokladny.']);import crypto from "node:crypto";
import express from "express";
const app = express();
app.post("/nora", express.raw({ type: "application/json" }), (req, res) => {
const expected = "sha256=" + crypto.createHmac("sha256", process.env.NORA_WEBHOOK_SECRET).update(req.body).digest("hex");
const received = req.get("X-Nora-Signature") || "";
if (received.length !== expected.length || !crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected))) {
return res.sendStatus(401);
}
const event = JSON.parse(req.body);
res.sendStatus(202); // přijato, odpovíte později v Noře
});import hashlib, hmac, os
from flask import Flask, abort, request
app = Flask(__name__)
@app.post("/nora")
def nora():
body = request.get_data()
expected = "sha256=" + hmac.new(os.environ["NORA_WEBHOOK_SECRET"].encode(), body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, request.headers.get("X-Nora-Signature", "")):
abort(401)
event = request.get_json()
return "", 202 # přijato, odpovíte později v NořeOdpověď a opakování
- Odpovězte hned, nebo později. Když vrátíte JSON
{"answer": "…"}, tazatel dostane odpověď hned (nejvýš 20 000 znaků). Jakákoli jiná odpověď s kódem 2xx znamená „přijato“ a odpovědět můžete později v Noře. - Opakování. Nora čeká na odpověď 15 sekund. Když doručení selže, zkusí to znovu po 1, 5, 15 a 60 minutách. Po pátém neúspěšném pokusu předání označí jako nedoručené a v Noře je to vidět.
- Bez dvojího zpracování. Hlavička
X-Nora-Deliveryje při opakování stejná. Podle ní poznáte zprávu, kterou už máte. - Tajná hodnota. Ukládá se na serveru vaší instance, ne v administraci. Nastaví ji a vymění tým Nory.
Podklady ze schránek a složek
Nové podklady si Nora umí brát sama. Zdroje nastavíte ve Správa → Kontrola schránek, přihlašovací údaje uloží na server tým Nory.
| Zdroj | Co Nora vezme |
|---|---|
| E-mailová schránka (IMAP) | Nepřečtené zprávy ve složce, výchozí je INBOX. Každou jako e-mail včetně textu a příloh. |
| Sdílená složka (SMB) | Nové soubory ve složce nebo na síťovém disku, například \\server\sdilene. |
| FTP a FTPS | Nové soubory ve složce. Pro šifrované spojení použijte ftps://. |
- Kontrola běží v časech, které u zdroje nastavíte, a kdykoli ručně.
- Každá položka se nahraje jen jednou. Po nahrání ji Nora může přesunout do jiné složky, zprávy bez nastavené složky označí jako přečtené.
- Co Nora v podkladech najde, čeká na schválení stejně jako u každého jiného nahrání.
Formáty a limity
| Druh | Formáty |
|---|---|
| Dokumenty | PDF, DOCX, PPTX |
| Tabulky | XLSX, CSV, TSV |
| Text | TXT, MD, HTML, XML, JSON, titulky SRT a VTT |
| Obrázky a skeny | JPG, PNG, WEBP, GIF, BMP, TIFF, HEIC |
| Zvuk | MP3, M4A, WAV, OGG, OPUS, AAC, FLAC, AMR, WMA |
| Video | MP4, MOV, WEBM, MKV, AVI, M4V, 3GP |
| E-maily | EML, MSG |
| Archivy | ZIP |
- Starší formáty (DOC, XLS, PPT, RTF a OpenDocument) Nora převede, když je převod na vaší instanci zapnutý. Jinak poradí, jak soubor uložit.
- Jeden soubor může mít až 2 GB. Do 20 MB a 10 souborů najednou Nora zpracuje hned, větší soubory a dávky si nejdřív uloží a zpracuje postupně.
Bezpečnost a data
- Oddělená instance pro každou firmu. Vlastní databáze, úložiště i nastavení. Žádná sdílená databáze mezi zákazníky.
- Provoz v EU. Aplikace běží v datovém centru v Amsterdamu a je dostupná jen přes HTTPS.
- Netrénujeme na vašich datech. Podklady ani dotazy nepoužíváme k trénování modelů.
- Každé napojení má vlastní klíč. Výměna klíče nebo tajné hodnoty platí hned a staré přístupy končí.
Podpora
Napojení připravujeme s vámi. Napište nám na info@nora-labs.cz, jaký systém používáte, a domluvíme postup, klíče i testování.