Kompletni prehled vsech biometrickych dat, vypoctu a vizualizaci v reportu. Verze 3 / brezen 2026.
Zaklad
Architektura sběru dat
Jak data tečou od kamery přes výpočty do reportu.
Pipeline
Webkamera 1280x720→MediaPipe Face Landmarker→478 landmarks + 52 blendshapes→detect*() funkce→cur objekt (každý frame)→collectSnapshot() 1x/s→KV Store (Cloudflare)→Report
Detekce obličejeGoogle MediaPipe Face Landmarker (GPU)Detekce rukouGoogle MediaPipe Hand Landmarker (GPU)Hlasove komentareWeb Speech API (SpeechRecognition)Hlas systemuWeb Speech API (SpeechSynthesis)Bezí kde100% lokalne v prohlizeci, žádná data neopousti zarizeni bez souhlasu
Frekvence
Jak často se co měří a ukládá
Detekce (výpočet hodnot)
requestAnimationFrame — běží tak rychle, jak to prohlizec stihne. Typicky 30–60 FPS (závisí na GPU/CPU). Každý frame aktualizuje vsechny metriky v objektu cur.
Ukládání
collectSnapshot()každých 1000 ms (1x/s) — kompletni snapshot vsech metrikcollectBlendshapes()každých 2000 ms (1x za 2s) — surovych 52 blendshapescheckMultipleFaces()každých 5000 ms (1x za 5s) — druha instance MP, az 3 obličejefacePhotosevent-triggered — pri session_start, každé otázce, každém revealu, session_end
Kam se uživatel dívá. 100% = pohled přímo dopředu (na obrazovku), 0% = pohled vyrazne stranou nebo nahoru. Měří odchylku smeru pohledu od primeho smeru.
Zdroj dat
Blendshapes (svalové hodnoty) z MediaPipe: eyeLookOutLeft, eyeLookOutRight, eyeLookUpLeft, eyeLookUpRight, eyeLookDownLeft, eyeLookDownRight. Tyto hodnoty jsou přímo z ML modelu — žádná ruční geometrie.
Výpočet: každý frame (30–60 FPS). Ulozeni: 1x/s do collected.gazeAttention[] a do každého snapshotu.
Rozsah
0–100%. Mirne divani se dolu (cteni, obrazovka nize) = stále vysoka hodnota. Penalizace az pri extremnim pohledu dolu (>0.7).
V reportu
Summary karta"Pozornost (pohled)" / "Attention (gaze)" — průměrná hodnotaBio summaryŘádek s průměrem a rozsahem min–maxGrafPlna zelena křivka v grafu "Pozornost & Unava"Question/Video timeline🎯 pohled X% u každé otázky/krokuFoto thumbnails🎯X% pod každou fotkouCharts summary tabulkaŘádek s avg/min/max
Proc blendshapes? ML model MediaPipe extrahuje svalové hodnoty přímo z obrazu. Na rozdil od iris tracking (geometricky výpočet z landmarku) není zavislý na presnych souradnicich a funguje spolehlivé i s běžnou webkamerou.
Experimentální
👁 Iris Tracking
👁Iris TrackingExperimentální
Co měří
Pozici duhovek v ocnich sterbinach. Teoreticky presnejsi nez blendshapes, ale vyzaduje kvalitni kameru nebo dedickovany eye-tracking hardware.
// Pomer pozice duhovky vuci sirce oka
leW = abs(eyeOuter.x - eyeInner.x) // šířka leveho oka
lPos = (irisLeft.x - eyeOuter.x) / leW // ocekavano 0.0–1.0
rPos = (irisRight.x - eyeOuter.x) / reW
dev = abs(((lPos + rPos) / 2) - 0.5) × 2 // odchylka od stredu
attention = round(max(0, min(100, (1 - dev) × 100)))
Znamy problem: S běžnou webkamerou hodnoty lPos/rPos vychazi 2.5–3.7 (místo 0.0–1.0). Důvod: souradnice iris landmarku (473/468) jsou v jinem rozsahu nez eye corner landmarky, pravdepodobne vlivem mirror modu kamery nebo normalizace souradnic. Vysledek: 54–94% měření = 0% pozornost. Proto je metrika oznacena jako experimentalni.
V reportu
Summary karta"Iris tracking (exp.)" — snizena opacity 0.6GrafCarkovana zelena křivka s opacity 0.3Timeline👁 iris (exp.) X% za gaze hodnotou
Ukladana surova data
irisLeft a irisRight v každém snapshotu — pro budouci analyzu s lepsim HW.
😊 Emoce (Emotion Detection)
😊Emotion DetectionFunkcni / bias
Co měří
Dominantni emoce z vyrazu obličeje. 5 kategorii: Happy, Surprised, Focused, Relaxed, Neutral. Kazda s confidence skóre 0–100%.
Znamy bias:browDown > 0.2 zachyti "Focused" u 53–73% uzivatelu, protože někteří lidé mají přirozeně nízké oboci. Prioritni razeni znamena, ze Focused "vyhrava" nad Relaxed/Neutral. Pro presnejsi detekci by byla potreba kalibrace baseline obličeje na zacatku session.
Frekvence
Každý frame → ulozeni 1x/s do collected.emotions[] jako { timestamp, emotion, confidence }.
V reportu
Summary karta"Emoci" — počet různých detekovaných emociEmotion timeline grafBarevne pruhy po sekundach (Happy=zelena, Surprised=zluta, Focused=modra, Relaxed=fialova, Neutral=seda)Červená křivka v emocnim grafuIntenzita usmеvu (smile)Question/Video timeline😊 Emotion + jistota/conf X% u každé otázkyFoto thumbnailsEmoce pod každou fotkou
😴 Únava (Fatigue)
😴Fatigue ScoreFunkcni / kaskada
Co měří
Mira unavy uživatele, 0–100%. Bodovy system z 5 nezavislych faktoru.
Kaskadovy efekt: Faktor attention < 50 závisí na iris tracking, ktery je experimentalni. S běžnou webkamerou je iris attention často 0%, takže tento faktor pridava +15 u 87% měření. Po nasazeni Gaze Attention se muzе prepojit na tu.
Neadaptivni prahy:eyeSquint > 0.3 a browDown > 0.2 jsou fixní — někteří lidé mají přirozeně primhourene oci nebo nízké oboci, coz nafoukne fatigue skóre.
V reportu
Summary karta"Unava" / "Fatigue" — průměrBio summaryŘádek s průměrem a rozsahemGrafČervená křivka v grafu "Pozornost & Unava"Charts summary tabulkaŘádek s avg/min/max
👀 Frekvence mrkání (Blink Rate)
👀Blink RateNeadaptivni prah
Co měří
Počet mrkní za minutu. Normální rozsah: 15–20/min. Vyšší hodnoty mohou signalizovat unavu.
Funkce
detectBlink(blendshapes) v camera.js
Algoritmus
avg = (eyeBlinkLeft + eyeBlinkRight) / 2
eyeOpen = avg < 0.5// prah: < 0.5 = otevrene, >= 0.5 = zavrene// Detekce mrknutí: přechod open → closed → open do 15 framůif přechod z open do closed → start počítání framů
if zpet na open && framy < 15 → zaznamenej mrknutí
blinkHistory = mrkání za posledních 60 sekund (kumulativni)
blinkRate = blinkHistory.length // počet za minutu
Znamy problem: Fixní prah 0.5 není adaptivní. Někteří lidé mají přirozeně vyšší baseline eyeBlink (tezsi vicka) a jejich mrknutí nikdy nedosahne 0.5. Priklad: uživatel mel max eyeBlink 0.489 — cela session 0 mrkní.
V reportu
Bio summary"Mrkání" — poslední zaznamenaná hodnota (rate/min)GrafZluta křivka v grafu "Mrkání (/min)", osa Y: 0–60
📏 Vzdálenost (Face Distance)
📏Face DistanceFunkcni
Co měří
Odhad vzdalenosti obličeje od kamery v centimetrech.
Funkce
detectDistance(landmarks) v camera.js
Algoritmus
d = sqrt((rightEye.x - leftEye.x)² + (rightEye.y - leftEye.y)²)
// d = rozestup oci v normalizovanych souradnicich (0–1)// konstanta 0.095 ≈ průměrná šířka mezi ocima
distance = max(20, min(150, round((0.095 / (d + 0.001)) × 100)))
// Omezeno na 20–150 cm
Presnost: Zalezi na rozlišení kamery a individualni anatomii (šířka mezi ocima se lisi). Jde o odhad, ne presne měření. Konstanta 0.095 není kalibrovana na konkretniho uživatele.
V reportu
Bio summary"Vzdalenost" — průměr a rozsah v cmGrafModra křivka "Vzdalenost obličeje od kamery", osa Y: 0–150 cmFoto modal📏Xcm u každé fotky
🔄 Pohyb hlavy (Head Pose)
🔄Head PoseFunkcni
Co měří
Úhly natoceni hlavy ve stupnich: Pitch (nahoru/dolu), Yaw (vlevo/vpravo), Roll (nakloneni do stran).
Funkce
detectHeadPose(landmarks, transformMatrix) v camera.js
Červená křivka v Emotion timeline grafu. Zobrazuje se i v photo modálu: 😊X%.
✋ Gesta rukou (Hand Gestures)
✋Hand Gesture DetectionFunkcni
Co měří
Gesta rukou v zaberu kamery. 8 rozpoznavanych gest: 👍 Thumbs Up, 👎 Thumbs Down, ✌️ Peace, ☝️ Point, ✋ Open Palm, ✊ Fist, 👌 OK, 🤟 Rock.
Zdroj
MediaPipe Hand Landmarker — 21 bodu ruky. Funkce detectGesture(handLandmarks) porovnava pozice konecku prstu vuci kloubum (tip.y vs joint.y).
Ukládání
Každý snímek (1x/s) se loguje — včetně "None" (ruka není vidět). To umožňuje měřit jak dlouho byla ruka viditelna. Pro report se "None" zaznamy filtruji.
False positives: občas se detekuje "Point" když ruka není přítomná (nos, čelo nebo objekt v pozadí). Jeden uživatel mel 176× Point během 286s session. Shluky 3+ sekund stejneho gesta jsou spolehlivejsi nez izolované detekce.
V reportu
Summary karta"Gest" — počet (filtrovano, bez "None")Sekce gestaSeskupeno podle typu s poctem, mini casovou osou (tecky) a casovym rozsahem
📷 Detekce obličeje (Face Detection Rate)
📷Face DetectionFunkcni
Co měří
Procento snímků, kde byl obličej úspěšně detekován. Nízké hodnoty = obličej mimo zaber, zakryty, nebo spatne osvětlení.
Bio summary: "Detekce" X% (počet/celkem). Zobrazuje se jako prvni řádek.
👥 Detekce dalších osob (Multi-face Presence)
👥Multi-face CheckFunkcni
Co měří
Pritomnost dalších osob v zaberu. Druha instance MediaPipe (bez blendshapes, numFaces: 3) kontroluje každých 5 sekund.
V reportu
Bio summary"další osoby" — počet detekci nebo "Ne"Emotion grafCervene vertikalni zony kde byl detekován vic nez 1 obličejeBiometric grafyCervene vertikalni cary + zony
🎤 Hlasové komentáře (Voice Comments)
🎤Voice CommentsEcho problem
Co měří
Hlasove komentare uživatele prepisane v realnem case pomoci Web Speech API (SpeechRecognition). Každý komentar ma text, timestamp a confidence (0–100%).
Konfigurace
continuous: true, interimResults: false, jazyk dle nastaveni session (cs-CZ / en-US). Auto-restart pri ukonceni.
Znamy problem: Mikrofon běží nepřetržitě a zachytává i zvuk z videa (avatar) nebo TTS. Pauza během prehravani zvuku není implementovana — v planu.
V reportu
Summary karta"Komentaru" — početSekce hlasove komentareSeznam s casem, textem a confidenceTimelineKomentare prirazene k otazkam/krokum podle casu
🔊 Hlasitost mikrofonu (Mic Volume)
🔊Mic VolumeNulova data
Co měří
Peak hlasitost z mikrofonu každou sekundu (AnalyserNode z Web Audio API).
Problem: Vsechny zaznamenane hodnoty jsou 0. AnalyserNode pravdepodobne není správně napojeny na mic stream, nebo peak detekce ma bug. Vyzaduje investigaci.
V reportu
Casova osa hlasitosti (pokud jsou data nenulova). Aktualne se nezobrazuje.
📸 Fotografie a Photo Quality
📸Face Photos + Quality ScoreKaskada z iris
Kdy se poridi fotka
Event-triggered: session_start, video_* (každý video krok), question_*, reveal_*, session_end. Dve verze: clean (cisty obraz) + overlay (s face mesh).
Kaskada: S broken iris attention (vzdy ~0) chybi az 30 bodu. Max dosazitelne skóre je ~70 místo 100. Nejlepsi fotka se vybira pres selectBestPhoto() — porovnava quality a bere nejvyšší.
V reportu
Face Photos sekceCarousel s thumbnaily — klik otevira modal s overlayKazda fotka ukazujeCas, emoce, gaze/attention %, vzdalenost, usmevHlavni fotka uživateleNejlepsi fotka (highest quality) v hlavicce reportu
🧬 Surové blendshapes (Raw Blendshape Log)
🧬Blendshape LogSbira se
Co to je
Kompletni log vsech 52 blendshapes (svalových hodnot) z MediaPipe. Každých 2 sekundy se ulozi surovy snímek. Slouzi pro budouci detailni analyzu a ladeni.
Nezobrazuje se přímo — export JSON obsahuje kompletni log. Pouziva se pro JSON export a budouci AI analyzu.
⚖️ Symetrie obličeje (Face Symmetry)
⚖️Face SymmetrySbira se, nezobrazuje
Výpočet
// 4 pary blendshapes
pary = [mouthSmileL/R, eyeBlinkL/R, browDownL/R, cheekSquintL/R]
symScore = průměr(1 - abs(left - right)) pro každý par
faceSym = round(symScore × 100) // 0–100%, 100 = dokonale symetricky
V reportu
Aktualne se nezobrazuje. Data jsou v každém snapshotu (faceSym). Zajimava metrika pro budouci rozsireni reportu.
— Report sekce —
🔌 Stav senzorů v reportu
Zobrazene senzory
📷 KameraAktivni/Neaktivni + počet snímků🧠 MediaPipeAktivni/Selhalo + počet bodu + počet fotek + "82 dat/s"🎙 MikrofonAktivni/Neaktivni + počet komentaru🔊 ReproduktorHlasitost v %
Zdroj
Ze sessionLog eventu session_started (pole sensors) a dopocitano z dat (fallback).
📊 Grafy v reportu
Vsechny grafy
Emoce v caseBarevne pruhy (1 pruh = 1s), červená křivka usmev, question markery, multi-face zonyPozornost & UnavaGaze (plna zelena), Iris (carkovana zelena 0.3), Fatigue (červená), question markeryVzdalenost (cm)Modra křivka, osa Y: 0–150Mrkání (/min)Zluta křivka, osa Y: 0–60Pohyb hlavyPitch (fialova) + Yaw (ruzova), osa Y: -45° az +45°, stredova linkaHlasitost mikrofonuZelena area chart (pokud data existuji a nejsou nulova)
Technicke detaily grafu
Vsechny grafy jsou SVG s viewBox="0 0 100 100" a preserveAspectRatio="none". Data se mapuji na 0–100% osy. Krivky pouzivaji vector-effect="non-scaling-stroke" pro konzistentni sirku cary. Question markery jsou carkovane vertikalni cary. Multi-face detekce jsou cervene zony.
Funkce pro krivky
buildPath(arr, key, maxVal) {
arr.map((v, i) => {
x = (i / (arr.length - 1)) × 100
y = 100 - ((v[key] ?? v.score ?? 0) / maxVal) × 100
return (i===0 ? 'M' : 'L') + x + ',' + y
}).join(' ')
}
Otázekpočet otázekSprávněcorrect/totalØ Reakceprůměrný reakční cas v sekundach+ spolecne kartyEmoce, Komentare, Gaze, Iris (exp.), Unava, Gesta
Hlavicka reportu
Dynamicky text: "Během školení jsme zachytili X biometrickych snímků (Y datovych bodu), Z fotografii, N gest rukou a M hlasovych komentaru. Vse v realnem case." Počet datovych bodu = snapshots × 82.
Kapitola 2
Analýza session
🧠 Metodologie kontextuální analýzy
Tato kapitola dokumentuje každý odvozený ukazatel použitý v sekci „Analýza session" v reportu. Pro každou metriku je uveden přesný vzorec, zdroj dat, vědecký základ a implementační poznámky pro replikovatelnost na jakýkoliv scénář.
📋Princip analyzyZaklad
Filosofie
Analýza je deterministická — žádné AI generování, žádné náhodné prvky. Každý závěr plyne přímo z číselných dat. Interpretace jsou formulovány jako pozorování, nikoli hodnocení. Cil: poskytnout kontextuální rámec pro surová data, který je replikovatelný a verifikovatelný.
Data jsou segmentována podle videoSteps[] (u video scénáře) nebo answers[] (u classic scénáře). Každý segment je definován časovým rozsahem [startedAt, endedAt] a všechna biometrická data jsou filtrována podle timestampu do příslušného segmentu.
📊 Skóre zapojení (Engagement Score)
🎯Engagement ScoreOdvozena
Účel
Souhrnné číslo 0–100 vyjadřující celkovou míru zapojení účastníka během session. Zobrazeno jako kruhový indikátor v reportu.
gazeNorm (w=0.30)avg(gazeAttention.score) / 100faceNorm (w=0.15)count(faceDetected=true) / totalemotionNorm (w=0.20)count(emotion=Focused|Happy) / totalinteractionNorm (w=0.20)(hasVoiceTips + hasGestures + hasVoiceChoice) / 3completionNorm (w=0.15)1.0 pokud session_completed, 0.5 pokud tab_switch end, 0.0 jinak
Příklad z demo session
0.30×0.694 + 0.15×1.0 + 0.20×0.992 + 0.20×1.0 + 0.15×1.0 = 0.208 + 0.15 + 0.198 + 0.20 + 0.15 = 0.906 → zaokrouhleno na 80 Poznamka: v aktuální implementaci je skóre nastaveno manuálně na základě expertního odhadu. Výše uvedený vzorec je navržená automatizace.
Poznámky k implementaci
Váhy jsou nastavitelné per scénář. Pro classic scénáře přidat složku correctAnswersNorm. Pro platformu bez hlasových vstupů upravit interactionNorm na použití gest a kliknutí.
Report insight #1
🎯 Pozornost podle segmentu (Attention per Segment)
🎯Gaze Attention per Video StepOdvozena
Co se zobrazuje v reportu
Horizontalni mini-bary ukazujici průměr gaze attention pro každý video krok. Barva: zelena (>70), oranzova (60-70), zluta (<60). Umožňuje identifikovat ktery segment účastníka zaujal nejvic a ktery nejmene.
Vzorec
segmentAvg = avg(gazeAttention.score WHERE timestamp BETWEEN step.startedAt AND step.endedAt)
Pro každý prvek videoSteps[] se filtuji vsechny zaznamy z gazeAttention[] jejichz timestamp pada do casoveho rozsahu daneho kroku.
1. Najdi segment s max(avg) → „Nejvyšší pozornost u [název segmentu]"
2. Najdi segment s min(avg) → „Nejnižší pozornost u [název segmentu]"
3. Pokud max - min > 10 → „To naznacuje, ze tema [max segmentu] zaujalo vice nez [min segmentu]"
4. Pokud max - min < 5 → „Pozornost byla rovnomerne rozlozena pres vsechny segmenty"
Sloupcovy mini-graf (bary) ukazujici průměr unavy per segment. Barva: zelena (<45%), oranzova (45–54%), zluta (≥55%). Pod grafem jsou popisy segmentu. Textove: identifikace trendu (rostouci/klesajici) a vyjimek.
Vzorec
segmentFatigueAvg = avg(fatigue.score WHERE timestamp BETWEEN step.startedAt AND step.endedAt)
Identicky filtr jako u pozornosti, pouze z pole fatigue[].
Interpretacni logika v reportu
1. Spocitat firstHalfAvg (průměrná unava prvni poloviny segmentu) a secondHalfAvg
2. Pokud secondHalfAvg - firstHalfAvg > 10 → „Unava postupne rostla"
3. Pro každý segment: pokud segAvg[i] < segAvg[i-1] AND segAvg[i] < segAvg[i+1] → „[Segment] účastníka znovu probudil" (lokalni minimum)
4. Najdi min(segAvg) a max(segAvg) a reportovat oba s casem
5. Globalni minimum z celeho fatigue[] pole → klidkovy peak (Math.min(...fatigue.map(f => f.score)))
1. Pro každý ne-Focused emoci najdi segmenty kde se vyskytuje → „Emoce [X] se objevila vyhradne během [segment]"
2. Pokud gesto (napr. Thumbs Up) ma timestamp v rozsahu stejneho segmentu → „To presne koreluje s gestem [Y]"
3. Pokud vsechny segmenty = 100% Focused → „Cela session probehla v rezimu Focused — stabilni soustredi bez emocnich vykyvu"
4. Dominantni emoce = ta s nejvyšším celkovym poctem
5. „Pozitivni emoce" = Happy, Surprised; „Neutralni" = Focused, Neutral, Relaxed; „Negativni" = None (zatim nepodporovano)
Korelace s gesty
Pro každé gesto z gestures[] (filtr gesture != 'None') najit casove prekryti se segmenty: gestureSegment = videoSteps.find(s => gesture.timestamp >= s.startedAt && gesture.timestamp <= s.endedAt)
Pokud segment s gestem = segment s ne-Focused emoci → silna korelace, uvest v reportu.
Report insight #4
🎙 Interakce a reakce (Interaction Analysis)
🎙Reaction Times & Voice Interaction QualityOdvozena
Co se zobrazuje v reportu
Rozpis hlasovych odpovědi (tip), jejich reakční casy, a analyza konzistence odpovědi. U closing choice analyza formulace.
Zdrojova data
reactionTimes[]{questionId, time_ms} — cas od zobrazení vstupu do odpovědivoiceComments[]{timestamp, text, confidence} — rozpoznany hlasclosingChoice{detectedKeyword, attempts, detailViewed}
1. reactionTimeVariance < 1000 → „Velmi podobne reakční casy ukazuji na konzistentni a aktivni premysleni"
2. avgReactionTime < 2000 → „Rychle odpovědi — mozna nahodile hadani nebo jistota"
3. avgReactionTime 3000–7000 → „Aktivni premysleni pred odpovědi"
4. avgReactionTime > 10000 → „Dlouhe premysleni — slozita otazka nebo nerozhodnost"
5. closingChoice.detectedKeyword != standardni slova (biometrics/hardware/adaptivity/no) → prirozena formulace (napr. „chci do reportu" místo „ne") → poznamka o porozumeni kontextu
6. closingChoice.attempts > 0 → „[N]x upozorneni pred spravnou detekci"
Report insight #5
📏 Fyzicke chovani (Physical Behavior Summary)
📏Distance + Head + Blink Combined InterpretationOdvozena
Co se zobrazuje v reportu
Souhrn fyzickych metrik: vzdalenost (rozsah, drift), pohyb hlavy (průměr pitch/yaw), blink rate vs norma. Kombinovana interpretace.
Zdrojova data a výpočty
Vzdalenost rozsahmin(distance.cm) – max(distance.cm)Vzdalenost driftavg(posledních 10) - avg(prvních 10)Průměrný pitchavg(|headPose.pitch|) ve stupnichPrůměrný yawavg(|headPose.yaw|) ve stupnichFinalni blink rateblinkRate[last].rateBlink norma15–20/min (Bentivoglio et al., 1997)
Interpretacni logika v reportu
1. Vzdalenost:
drift > 0 → „Mirny trend oddalovani — prirozeny projev postupne relaxace" drift < -5 → „Priblizovani k obrazovce — mozna unava oci nebo snaha lepe vidět" |drift| < 2 → „Stabilni pozice po celou dobu"
2. Pohyb hlavy:
avg_pitch < 3 AND avg_yaw < 5 → „Minimalni pohyb hlavy — vysoka vizualni fixace" avg_pitch > 5 OR avg_yaw > 8 → „Zvyseny pohyb — mozna nepohodli nebo rozptyleni"
3. Blink rate:
rate < 10 → „Nižší nez norma — v kombinaci se stabilni hlavou ukazuje na vysokou vizualni fixaci" rate < 10 AND avg_pitch < 3 → „Kombinace nizkeho mrkání a stabilni hlavy = silny signal soustredi"
Poznamka: „Nízké mrkání může byt castecne artefakt detekce"
Report insight #6
📊 Celkový profil a doporučení (Overall Profile & Content Recommendations)
📊Participant Type + Content Effectiveness ScoreOdvozena
Co se zobrazuje v reportu
Tri odstavce: (1) Typ účastníka, (2) Zajimavost — nejzajimavejsi vs nejmene poutavy segment, (3) Doporučení pro obsah.
1. Spocitat per-segment: gazeAvg, emotionVariety (počet unikatnich emoci != Focused), gestureCount, fatigueAvg
2. Segment s max(gazeAvg) AND max(emotionVariety) AND max(gestureCount) → „nejzajimavejsi"
3. Segment s min(gazeAvg) AND max(fatigueAvg) → „nejmene poutavy"
4. Textova sablona: „[Název max segmentu] vyvolal nejsilnejsi reakci — nejvyšší pozornost, [specifika]. [Název min segmentu] byl naopak nejméně poutavy."
Doporučení pro obsah — content effectiveness
segmentScore = gazeAvg × (1 - fatigueAvg / 100)
Logika:
• Segment s min(segmentScore) → „Zvazit zkraceni nebo oziveni [segmentu]"
• Segment s max(segmentScore) → „[Segment] funguje jako hlavni hook scénáře"
• Pokud max(segmentScore) / min(segmentScore) > 1.5 → „Vyrazny rozdil v efektivite mezi segmenty"
• Pokud max(segmentScore) / min(segmentScore) < 1.2 → „Segmenty jsou vyrovnane"
Tabulka sablon pro textovy vystup
Typ„Typ: [classifyParticipant result]. [Popis]"Zajimavost„[max segment] = nejzajimavejsi. [min segment] = nejmene poutavy."Doporučení„Zvazit [akci] u [min segment]. [max segment] funguje jako hook."
Poznámka
Vsechny textove vystupy v reportu jsou generovany z techto sablon a ciselnych prahu. Nejde o volny text — kazda veta ma jasny datovy podklad. Pokud data nedosahnou prahu, prislusna veta se v reportu nezobrazí.
👁 Kognitivní zátěž z mrkání (Blink Suppression)
🧠Blink Suppression IndexOdvozena
Účel
Odhalit míru kognitivní zátěže na základě potlačení spontánního mrkání. Nižší blink rate než norma = vyšší vizuální zapojení.
Vědecký základ
Magliacano et al. (2020) — „Eye blink rate increases as a function of cognitive load during an auditory oddball paradigm." Neuroscience Letters, Vol. 736, doi:10.1016/j.neulet.2020.135293. Zjištění: EBR roste při aktivních ne-vizuálních úlohách vs. klid.
Holland & Tarlow (1972) — „Blinking and mental load." Psychological Reports, 31, 119–127. Zjištění: blink rate a kognitivní zátěž jsou nepřímo úměrné při vizuálních úlohách.
Frontiers in Human Neuroscience (2017) — „What Does Eye-Blink Rate Variability Dynamics Tell Us About Cognitive Performance?" doi:10.3389/fnhum.2017.00620. Zjištění: BRV dynamika predikuje kognitivní výkon.
Nakano et al. (2019) — „Rapid serial blinks: An index of temporally increased cognitive load." PLOS ONE, doi:10.1371/journal.pone.0225897. Zjištění: shlukování mrkání (RSB) indikuje lokální nárůst kognitivní zátěže.
Norma: spontánní EBR u dospělých = ~15–20 blinku/min (Bentivoglio et al., 1997; Ponder & Kennedy, 1927).
Metrika 1: Suppression ratio
suppression = 1 - (measured_blink_rate / baseline_norm)
Kde baseline_norm = 17.5 (střed rozsahu 15–20).
Priklad: 1 - (5 / 17.5) = 0.71 → 71% suppression = vysoká kognitivní zátěž.
Metrika 2: Blink clustering per segment
Pro každý video segment spočítat počet blink events (= momenty kdy blinkRate[i].rate > blinkRate[i-1].rate). segment_blink_events = count(rate_increases) within [stepStart, stepEnd]
Segmenty s 0 blink events = maximální vizuální fixace.
Implementace
function blinkEvents(blinkRate, startTs, endTs) {
const seg = blinkRate.filter(b => b.timestamp >= startTs && b.timestamp <= endTs);
let events = 0;
for (let i = 1; i < seg.length; i++) {
if (seg[i].rate > seg[i-1].rate) events++;
}
return events;
}
function blinkSuppression(finalRate, norm = 17.5) {
return Math.max(0, 1 - (finalRate / norm));
}
Z 52 ARKit blendshapes extrahovat vzory odpovídající známým výrazům obličeje podle FACS (Ekman & Friesen, 1978). ARKit blendshapes mapuji na FACS Action Units (AU).
Vědecký základ
Ekman & Friesen (1978) — Facial Action Coding System (FACS). Standardní systém pro popis pohybů obličejových svalů.
Blendshape values jsou 0.0–1.0. Průměrování přes segment dává „bazální tonus" svalu. Maximum ukazuje peak intenzitu. Pro identifikaci krátkých úsměvů stačí max(mouthSmile) > 0.5 i když avg < 0.05.
Rozlišovat nízkou std ze soustředění (= vysoká avg + nízká std) vs. nizkou std z nezájmu (= nízká avg + nízká std). Vždy reportovat std společně s průměrem.
🔄 Analýza pohybů hlavy (Head Movement Events)
🔄Head Movement per Segment + Spike DetectionOdvozena
Metrika 1: Průměrný pohyb per segment
avg_movement = Σ(|pitch[i]-pitch[i-1]| + |yaw[i]-yaw[i-1]|) / (2 × (n-1))
Měří frame-to-frame „jitter" — kolik se hlava pohne průměrně každý snímek.
Metrika 2: Spike detection
spike = |value[i] - value[i-1]| > threshold
Prah pro yaw: 10°, prah pro pitch: 5°. Spiky indikují prudké otočení hlavy — reakce na externí podnět, změna pozice, nebo překvapení.
Interpretace
avg_movement < 0.3°Velmi stabilní — fixovaný pohled na obsahavg_movement 0.3–1.0°Normální — mírne pohyby pri zpracovaniavg_movement > 1.0°Zvýšená aktivita — fyzická reakce na obsah nebo rozptýleníYaw spike > 10°Prudké otočení — externí podnět nebo změna pozice
Implementace
function headMovementPerSegment(headPose, startTs, endTs) {
const seg = headPose.filter(h => h.timestamp >= startTs && h.timestamp <= endTs);
if (seg.length < 2) return { avgMovement: 0, spikes: [] };
let totalDiff = 0, spikes = [];
for (let i = 1; i < seg.length; i++) {
const dP = Math.abs(seg[i].pitch - seg[i-1].pitch);
const dY = Math.abs(seg[i].yaw - seg[i-1].yaw);
totalDiff += dP + dY;
if (dY > 10 || dP > 5) spikes.push({ ts: seg[i].timestamp, dP, dY });
}
return { avgMovement: totalDiff / (2 * (seg.length - 1)), spikes };
}
📊 Korelace: únava ↔ pozornost
📉Pearson Correlation: Fatigue vs GazeOdvozena
Účel
Ověřit, zda únava a pozornost měří konzistentní jev. Očekávaná negativní korelace (vyšší únava → nižší pozornost) validuje obě metriky.
Vzorec (Pearson r)
r = Σ((xi - x̄)(yi - ȳ)) / sqrt(Σ(xi - x̄)² × Σ(yi - ȳ)²)
Kde xi = gaze score, yi = fatigue score, párováno podle nejbližšího timestampu (tolerance 2s).
Interpretace
r = -0.7 az -1.0Silná negativní — únava dominantně ovlivňuje pozornostr = -0.3 az -0.7Střední negativní — únava je jeden z faktorůr = 0 az -0.3Slabá — pozornost řídí především obsah, ne únavar > 0Neočekávaná — možná chyba v datech nebo netypický účastník
⚡ Detekce rozptýlení a návratu (Attention Drops & Spikes)
⚡Gaze Attention Drops & RecoveryOdvozena
Účel
Identifikovat přesné momenty kde účastník ztratil pozornost (drop) a kde se vrátil (spike). Umožňuje korelaci s externími událostmi (přechod segmentu, zvuk, pohyb).
drop_countCelkový počet poklesů > thresholdspike_countCelkový počet návratů > thresholdmax_dropNejvětší jednorázový poklesrecovery_ratiospike_count / drop_count — blize k 1.0 = dobrá samoregulaceavg_recovery_timePrůměrný čas (s) mezi drop a následným spike
Implementace
function detectDropsAndSpikes(gazeAttention, threshold = 15) {
const drops = [], spikes = [];
for (let i = 1; i < gazeAttention.length; i++) {
const diff = gazeAttention[i].score - gazeAttention[i-1].score;
if (diff < -threshold) drops.push({ ts: gazeAttention[i].timestamp, from: gazeAttention[i-1].score, to: gazeAttention[i].score });
if (diff > threshold) spikes.push({ ts: gazeAttention[i].timestamp, from: gazeAttention[i-1].score, to: gazeAttention[i].score });
}
const recoveryRatio = drops.length > 0 ? spikes.length / drops.length : 1;
return { drops, spikes, recoveryRatio };
}
📐 Ergonomie a vzdálenost (Distance Ergonomics)
📐Distance Drift & Ergonomic ZoneOdvozena
Účel
Vyhodnotit, zda účastník sedí v ergonomické zóně a jak se jeho vzdálenost mění v čase (drift = relaxace vs. naklonění vpřed = snaha lépe vidět).
Vědecký základ
CCOHS (Canadian Centre for Occupational Health and Safety) — Resting Point of Accommodation (RPA) ≈ 80 cm. Při této vzdálenosti oční svaly nepotřebují úsilí na zaostření.
OSHA eTools Computer Workstations — doporučený rozsah 50–100 cm (20–40 palcu) od očí k monitoru.
Ergonomická interpretace driftu: postupné oddalování = relaxace, přibližování = snaha lépe vidět (možná únava očí nebo malý text).
Odlišit aktivní řeč od okolního šumu. Identifikovat hlasový profil účastníka.
Metriky z micVolume[]
speaking_ratiocount(isSpeaking=true) / totalambient_volumeavg(rms) where isSpeaking=falsespeech_volumeavg(rms) where isSpeaking=truesnr (signal-to-noise)speech_volume / ambient_volumedominant_freq_speechavg(dominantFreq) where isSpeaking=true
Automaticky generovaný textový profil účastníka na základě kombinace všech metrik. Určen pro trenéry a manažery školení.
Rozhodovací logika
Typ: Soustředěný, klidnýgazeAvg > 60 AND fatigueAvg < 60 AND headMovement < 1.0°Typ: Aktivní, zapojenýgazeAvg > 60 AND gestureCount > 0 AND voiceComments > 0Typ: Unavený, klesajícífatigueAvg > 60 AND gazeTrend < 0 (klesající trend)Typ: RozptylovanýdropCount > 5 AND recoveryRatio < 0.5Typ: PasivnígazeAvg < 50 AND gestureCount = 0 AND voiceComments = 0
Doporučení pro obsah (per segment)
Pro každý video segment spočítat segmentScore = gazeAvg × (1 - fatigueAvg/100). Segmenty s nejnižším skóre → kandidáti na zkrácení nebo přepracování. Segmenty s nejvyšším skóre → potvrdit jako efektivní.