BEAM X1 Sense
Tenký doplněk, který si vložíte do vlastní školící stránky jedním skriptem. Po souhlasu účastníka sleduje přes kameru a mikrofon, jestli je ve školení přítomen a pozorný, a po skončení vám předá výsledek na společné časové ose v milisekundách.
Princip
Měříme to, co umíme
Doplněk předává naměřenou realitu bez výkladu. Co z ní uděláte, je na vás.
U každého měření uvádíme spolehlivost
Naměřeno, nebo odvozeno pravidly. Procenta přesnosti neuvádíme, protože je nemáme změřená, a nechceme je vymýšlet.
Žádný obraz ani zvuk
Doplněk neukládá a neodesílá obraz ani zvuk. Výsledkem jsou body obličeje, metriky, události a přepis řeči.
Všechno běží v prohlížeči účastníka
Zpracování probíhá u účastníka. Výsledek dostane hostitel až po jeho schválení.
Co se měří
Každé pole výsledku má záznamy s časem t (ms od startu měření). Spolehlivost je i přímo ve výsledku, v timeline.measurements.<pole>.reliability, spolu s krátkým zdůvodněním a příznakem validated: false.
| Pole | Co obsahuje | Zápis | Spolehlivost |
|---|---|---|---|
faceDetected | Je obličej v záběru | 1 s | naměřeno |
presenceChecks | Počet obličejů v záběru (druhá kontrola, až 3) | 5 s | naměřeno |
landmarkLog | 478 bodů obličeje z modelu MediaPipe | 2 s | naměřeno |
blendshapeLog | 52 svalových hodnot z modelu MediaPipe | 2 s | naměřeno |
micVolume | Hlasitost, rms, dominantní frekvence, příznak mluvení | 1 s | naměřeno |
voiceComments | Přepis řeči po větách s jistotou rozpoznávače | každá věta | naměřeno |
sessionLog | Události: start, stav kamery, okno ztratilo fokus, změna viditelnosti karty, myš v okně nebo mimo něj, celá obrazovka | při události | naměřeno |
attention | Poloha duhovky mezi koutky oka, 100 = uprostřed (nezahrnuje otočení hlavy) | 1 s | odvozeno |
gazeAttention | Pozornost podle pohledu: odklon do stran, nahoru a extrémně dolů | 1 s | odvozeno |
headPose | Natočení hlavy ve stupních: pitch, yaw, roll | 1 s | odvozeno |
distance | Odhad vzdálenosti od kamery v cm, přesný jen po kalibraci měřítka | 1 s | odvozeno |
blinkRate | Počet mrknutí za posledních 60 s (mrknutí je zavření očí do 500 ms) | 1 s | odvozeno |
fatigueIndicators | PERCLOS (podíl času se zavřenýma očima za 60 s), průměrná doba mrknutí, zívnutí za 5 min | 1 s | odvozeno |
fatigue | Heuristické skóre únavy, prahy jsou předpoklady a nebyly ověřeny | 1 s | odvozeno |
emotions | Výraz obličeje (Happy, Surprised, Focused, Relaxed, Neutral) pravidly nad blendshapy, není to natrénovaný model emocí | 1 s | odvozeno |
gestures | Gesta rukou a poloha ruky | 1 s | odvozeno |
cameraSnapshots | Všechny metriky jednoho okamžiku pohromadě (a volitelně všech 52 blendshapů) | 1 s | odvozeno |
Naměřeno je přímý výstup senzoru nebo modelu. Odvozeno je spočítáno jednoduchými pravidly z naměřeného a je třeba s tím tak zacházet. Úroveň unreliable je ve formátu pro měření se známým problémem ve výpočtu, aktuálně ji žádné měření nemá.
Kvalita konkrétní relace
Blok quality ve výsledku říká, jak dopadlo toto měření: od kdy kamera měřila (MediaPipe se načítá několik sekund), v kolika snímcích byl nalezen obličej, kolik bylo mezer bez obličeje a jak dlouhá byla nejdelší, nejvíce osob v záběru, podíl mluvení a počet přepsaných vět a chyb rozpoznávání řeči. Podle něj poznáte, jestli měření stojí za zpracování, třeba když účastník kameru zakryl.
Vypínače kategorií
Každou kategorii dat lze v init vypnout (categories: { landmarks: false }). Vypnutá kategorie se nesbírá a její pole ve výsledku chybí. Výchozí je vše zapnuto, kromě photos.
| Kategorie | Pole výsledku |
|---|---|
face | faceDetected, emotions, attention, gazeAttention, headPose, distance, blinkRate, fatigue, fatigueIndicators, cameraSnapshots, presenceChecks |
blendshapes | blendshapeLog |
landmarks | landmarkLog |
gestures | gestures |
voice | voiceComments |
audio | micVolume |
activity | sessionLog |
device | device |
photos (výchozí vypnuto) | faceSnapshot, facePhotos, periodicPhotos, jen pro ladění |
Vložení do vaší stránky
1. Skript a inicializace
Stáhnout beamsense-0.1.0.js (verze 0.1.0, formát výsledku 0.1, 110 kB). Soubor se nikdy nemění, nové verze přibývají jako nové soubory. Poslední sestavení je vždy na dist/beamsense.js, to se ale mění a pro nasazení ho nepoužívejte.
Otisk SHA-256: d825cf51b92a4e89ffd67e6b6a2cc543c6a8d0c97b3c3e62515a2736f7cc13f3
<script src="https://sense.beamx1.cz/releases/beamsense-0.1.0.js"
integrity="sha256-2CXPUbkqTon/1n5raizFQ8ao0Ml7PD5iUVonNvfME/M="
crossorigin="anonymous"></script>
Atribut integrity zajistí, že prohlížeč soubor spustí jen tehdy, když odpovídá otisku. Doporučujeme si soubor stáhnout a dát na vlastní hosting, pak integrity nepotřebujete.
Skript do globálního prostoru stránky přidá jen window.BeamSense.
<script src="beamsense.js"></script>
<script>
BeamSense.init({
lang: 'cs',
host: { sessionId: 'id-relace-na-vasi-strane', participantRef: 'odkaz-na-ucastnika' },
onResult: function (result) {
// výsledek po schválení účastníkem, pošlete ho na svůj server
}
});
</script>
Po init se vpravo nahoře zobrazí ikona s oknem pro souhlas. Po souhlasu se spustí kamera a mikrofon. Na konci školení zavolejte BeamSense.stop(): účastník uvidí volbu Odeslat, Stáhnout kopii nebo Zahodit. Po Odeslat dostane vaše onResult výsledek. Chcete-li výsledek odesílat sami, použijte volbu endpoint (POST).
2. Volby a volání
Volba init | Význam |
|---|---|
categories | Vypínače kategorií dat |
lang | cs nebo en |
host | sessionId, participantRef a další vaše pole, předají se do výsledku |
onResult | Funkce, která dostane výsledek po schválení účastníkem |
endpoint | Volitelně adresa pro odeslání výsledku metodou POST |
cameraPreset | demo-max, demo-high, standard nebo lite |
widget | false = bez vlastního rozhraní, souhlas pak řešíte vy |
| Volání | Co dělá |
|---|---|
BeamSense.stop() | Ukončí relaci a zobrazí Odeslat, Stáhnout kopii nebo Zahodit |
BeamSense.now() | Čas společné osy v ms od startu měření (před startem null) |
BeamSense.getStatus() | Stav a počty záznamů |
BeamSense.on('state', fn) | Změny stavu |
Časová osa v milisekundách
Hostitel nemusí doplňku nic hlásit, žádné značky ani začátky a konce kapitol. Každý záznam výsledku má t (ms od startu měření) a původní absolutní timestamp. Výsledek má startedAt (ms, epoch). Události svého školení si zaznamenejte s Date.now() a jejich místo na ose spočítejte takto:
var udalosti = [];
function zaznamenej(nazev) { udalosti.push({ nazev: nazev, cas: Date.now() }); }
// po obdržení výsledku:
udalosti.forEach(function (u) {
u.t = u.cas - result.startedAt; // ms na společné ose
});
Četnost zápisu zůstává (metriky obličeje jednou za sekundu, body obličeje jednou za 2 sekundy). Milisekundy určují přesnost časové značky, ne hustotu vzorků.
Tvar výsledku (zkráceně)
{
"formatVersion": "0.1",
"sessionId": "id-relace-na-vasi-strane",
"host": { "participantRef": "odkaz-na-ucastnika" },
"startedAt": 1760000000000, "completedAt": 1760000060000, "duration": 60,
"timeline": { "unit": "ms", "origin": "startedAt",
"measurements": { "attention": { "category": "face", "everyMs": 1000,
"values": "score: ...", "reliability": { "level": "derived", "basis": "...", "validated": false } } } },
"quality": { "camera": { "faceFoundPercent": 89, "gapCount": 1, "longestGapMs": 6000 } },
"faceDetected": [ { "t": 3000, "timestamp": 1760000003000, "detected": true } ],
"headPose": [ { "t": 3000, "pitch": -3, "yaw": 2, "roll": 0 } ],
"voiceComments": [ { "t": 14000, "text": "...", "confidence": 0.9 } ],
"sessionLog": [ { "t": 20000, "event": "window_blur", "toIframe": true } ]
}
Definice úhlů: yaw je kladný, když se obličej otáčí doprava v obraze kamery (člověk se otáčí doleva), pitch je kladný při pohledu nahoru a roll je kladný při náklonu proti směru hodinových ručiček v obraze.
Požadavky na stránku, která doplněk vkládá
- HTTPS (nebo localhost), jinak prohlížeč kameru nepovolí.
- Prohlížeč Chrome nebo Edge. Přepis řeči zajišťuje prohlížeč.
- Iframe: pokud doplněk běží uvnitř iframe, musí mít rámeček atribut
allow="camera; microphone". Bez něj prohlížeč kameru a mikrofon zablokuje. - Content Security Policy: při startu se stahuje knihovna MediaPipe a modely. Ověřená politika, která prošla:
default-src 'none';
script-src 'self' https://cdn.jsdelivr.net 'wasm-unsafe-eval';
style-src 'self' 'unsafe-inline';
connect-src 'self' https://cdn.jsdelivr.net https://storage.googleapis.com;
img-src 'self' data: blob:;
media-src 'self' blob: mediastream:;
worker-src 'self' blob:;
Widget si styl vkládá sám, proto je potřeba style-src 'unsafe-inline'. Nutnost jednotlivých položek jsme zvlášť netestovali, politika je ověřená jako celek.
Přítomnost v okně. Událost window_blur má příznak toIframe: je true, když fokus přešel do vloženého iframe na stránce. Účastník pak zůstal ve školení, jen klikl do jeho obsahu, a ztrátu fokusu proto nemusíte brát jako odchod. Sleduje se jen okno, ve kterém doplněk běží. Souřadnice myši se nesbírají, jen přechody (myš opustila okno, vrátila se).
Soukromí a souhlas
- Před startem účastník sám odsouhlasí sběr a povolí kameru a mikrofon.
- Obraz a zvuk se nenahrávají ani neukládají, výsledek obsahuje jen body, metriky, události a přepis řeči.
- Na konci účastník rozhoduje: Odeslat, Stáhnout kopii, nebo Zahodit.
- Přepis řeči zpracovává prohlížeč Chrome, který zvuk posílá ke zpracování službě Google. To je třeba uvést účastníkovi.
- Body obličeje a metriky jsou biometrické údaje. Právní posouzení (GDPR, EU AI Act) je na straně provozovatele školení.
Omezení ukázkové verze
- Jedna relace na načtení stránky. Pro novou relaci načtěte stránku znovu.
- Při startu se stahují knihovna MediaPipe a modely z
cdn.jsdelivr.netastorage.googleapis.com. Bez nich se nic z obličeje neměří a výsledek to pravdivě uvede (biometricStatus). - Data z kamery začínají až po načtení MediaPipe, obvykle 2 až 8 sekund po startu. Okamžik uvádí
quality.camera.measuringFromMs. - Žádné měření zatím nebylo ověřeno proti referenčním datům. Výpočty ověřují testy se syntetickou geometrií a vedený test na kameře, ale prahy únavy a zívnutí jsou předpoklady.
Vyzkoušet
Na testovacích stránkách si doplněk vyzkoušíte v několika způsobech vložení: čisté HTML, stránka generovaná JavaScriptem, přísná CSP, školení v iframe s doplňkem nad ním nebo uvnitř. Je tam také vedený test výpočtů na skutečné kameře. Nejjednodušší ukázka je demo-host.html.