shwetangisingh commited on
Commit
34b30e1
·
1 Parent(s): 5a953f7

tighten affect classifier: less twitchy FRUSTRATED, smile beats brow

Browse files

Three changes to classifyAffect after live testing showed FRUSTRATED
firing on neutral expressions:

1. FRUSTRATED's brow check now requires both sides (browDL && browDR)
instead of either side. Asymmetric brow movement from a sideways
glance was triggering it constantly.

2. HAPPY now wins over FRUSTRATED when both fire — smile-while-thinking
is a common pose while reading a reply, and a smiling user
misread as frustrated is worse than the inverse.

3. SIGMA_K bumped 2.0 → 2.8 so the calibrated baseline check requires
a more decisive expression to fire. Blendshape noise above neutral
was easily clearing the old 2σ threshold.

Files changed (1) hide show
  1. frontend/src/lib/sensing.ts +10 -5
frontend/src/lib/sensing.ts CHANGED
@@ -1,7 +1,7 @@
1
  import type { Matrix } from "@mediapipe/tasks-vision";
2
  import type { Affect, GestureName, HeadDebug, HeadSignal, MemoryBucket } from "../types";
3
 
4
- const SIGMA_K = 2.0;
5
  const CALIBRATION_DURATION_MS = 5000;
6
  const CALIBRATION_WARMUP_MS = 1000;
7
  const OUTLIER_TRIM_FRACTION = 0.10;
@@ -161,10 +161,15 @@ export function classifyAffect(
161
  const jawOpen = isAbove(bs, "jawOpen", baseline);
162
  const browIn = isAbove(bs, "browInnerUp", baseline);
163
 
164
- if (jawOpen && browIn) return "SURPRISED";
165
- if (browDL || browDR) return "FRUSTRATED";
166
- if (squintL && squintR) return "FRUSTRATED";
167
- if (smileL && smileR) return "HAPPY";
 
 
 
 
 
168
  return "NEUTRAL";
169
  }
170
 
 
1
  import type { Matrix } from "@mediapipe/tasks-vision";
2
  import type { Affect, GestureName, HeadDebug, HeadSignal, MemoryBucket } from "../types";
3
 
4
+ const SIGMA_K = 2.8;
5
  const CALIBRATION_DURATION_MS = 5000;
6
  const CALIBRATION_WARMUP_MS = 1000;
7
  const OUTLIER_TRIM_FRACTION = 0.10;
 
161
  const jawOpen = isAbove(bs, "jawOpen", baseline);
162
  const browIn = isAbove(bs, "browInnerUp", baseline);
163
 
164
+ // Order matters here — first match wins. HAPPY is checked before FRUSTRATED
165
+ // because smile+concentration (smile + slight brow furrow) is a common
166
+ // pose while reading a reply, and we'd rather miss frustration than
167
+ // mis-read a smiling user as frustrated. Both sides required for every
168
+ // affect to suppress one-sided twitches.
169
+ if (jawOpen && browIn) return "SURPRISED";
170
+ if (smileL && smileR) return "HAPPY";
171
+ if (browDL && browDR) return "FRUSTRATED";
172
+ if (squintL && squintR) return "FRUSTRATED";
173
  return "NEUTRAL";
174
  }
175