Spaces:
Sleeping
Sleeping
Commit ·
fa02816
1
Parent(s): 1f17a48
- backend/api/main.py +7 -0
- frontend/src/hooks/useSensing.ts +1 -1
- frontend/src/lib/sensing.ts +2 -4
backend/api/main.py
CHANGED
|
@@ -10,6 +10,7 @@ from pathlib import Path
|
|
| 10 |
from fastapi import BackgroundTasks, FastAPI, HTTPException
|
| 11 |
from fastapi.middleware.cors import CORSMiddleware
|
| 12 |
from fastapi.responses import StreamingResponse
|
|
|
|
| 13 |
from pydantic import BaseModel, Field
|
| 14 |
|
| 15 |
from backend.config.settings import settings
|
|
@@ -976,3 +977,9 @@ def submit_rating(req: RatingRequest):
|
|
| 976 |
with open(logs_dir / "ratings.jsonl", "a", encoding="utf-8") as f:
|
| 977 |
f.write(json.dumps(entry, ensure_ascii=False) + "\n")
|
| 978 |
return {"status": "ok"}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
from fastapi import BackgroundTasks, FastAPI, HTTPException
|
| 11 |
from fastapi.middleware.cors import CORSMiddleware
|
| 12 |
from fastapi.responses import StreamingResponse
|
| 13 |
+
from fastapi.staticfiles import StaticFiles
|
| 14 |
from pydantic import BaseModel, Field
|
| 15 |
|
| 16 |
from backend.config.settings import settings
|
|
|
|
| 977 |
with open(logs_dir / "ratings.jsonl", "a", encoding="utf-8") as f:
|
| 978 |
f.write(json.dumps(entry, ensure_ascii=False) + "\n")
|
| 979 |
return {"status": "ok"}
|
| 980 |
+
|
| 981 |
+
|
| 982 |
+
# Serve React frontend — must be last so API routes take priority
|
| 983 |
+
_frontend_dist = Path(__file__).parent.parent.parent / "frontend" / "dist"
|
| 984 |
+
if _frontend_dist.exists():
|
| 985 |
+
app.mount("/", StaticFiles(directory=str(_frontend_dist), html=True), name="static")
|
frontend/src/hooks/useSensing.ts
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
| 16 |
import { DEFAULT_AIR_TEMPLATES } from "../lib/airTemplates";
|
| 17 |
|
| 18 |
const EMA_ALPHA = 0.2;
|
| 19 |
-
const GESTURE_DEBOUNCE_FRAMES =
|
| 20 |
const AFFECT_DEBOUNCE_FRAMES = 8;
|
| 21 |
|
| 22 |
export function useSensing() {
|
|
|
|
| 16 |
import { DEFAULT_AIR_TEMPLATES } from "../lib/airTemplates";
|
| 17 |
|
| 18 |
const EMA_ALPHA = 0.2;
|
| 19 |
+
const GESTURE_DEBOUNCE_FRAMES = 3;
|
| 20 |
const AFFECT_DEBOUNCE_FRAMES = 8;
|
| 21 |
|
| 22 |
export function useSensing() {
|
frontend/src/lib/sensing.ts
CHANGED
|
@@ -104,19 +104,17 @@ export function classifyGesture(landmarks: Point3D[]): GestureName | null {
|
|
| 104 |
const pinkyTip = p[20];
|
| 105 |
const indexMcp = p[5];
|
| 106 |
|
| 107 |
-
// Require tip to be meaningfully closer to wrist than MCP (0.85×), not just barely under —
|
| 108 |
-
// prevents borderline pointing poses from satisfying the curl check.
|
| 109 |
const fingersCurled = [
|
| 110 |
[indexTip, p[5]],
|
| 111 |
[middleTip, p[9]],
|
| 112 |
[ringTip, p[13]],
|
| 113 |
-
].every(([tip, mcp]) => norm3(tip) < norm3(mcp)
|
| 114 |
|
| 115 |
// Check POINTING before THUMBS_UP — pointing with a raised thumb would otherwise
|
| 116 |
// satisfy fingersCurled on a noisy frame and fire the wrong label first.
|
| 117 |
const indexExtended = norm3(indexTip) > norm3(indexMcp) * 1.3;
|
| 118 |
const othersCurled = [middleTip, ringTip, pinkyTip].every(
|
| 119 |
-
(tip) => norm3(tip) < 0.
|
| 120 |
);
|
| 121 |
if (indexExtended && othersCurled) return "POINTING";
|
| 122 |
|
|
|
|
| 104 |
const pinkyTip = p[20];
|
| 105 |
const indexMcp = p[5];
|
| 106 |
|
|
|
|
|
|
|
| 107 |
const fingersCurled = [
|
| 108 |
[indexTip, p[5]],
|
| 109 |
[middleTip, p[9]],
|
| 110 |
[ringTip, p[13]],
|
| 111 |
+
].every(([tip, mcp]) => norm3(tip) < norm3(mcp));
|
| 112 |
|
| 113 |
// Check POINTING before THUMBS_UP — pointing with a raised thumb would otherwise
|
| 114 |
// satisfy fingersCurled on a noisy frame and fire the wrong label first.
|
| 115 |
const indexExtended = norm3(indexTip) > norm3(indexMcp) * 1.3;
|
| 116 |
const othersCurled = [middleTip, ringTip, pinkyTip].every(
|
| 117 |
+
(tip) => norm3(tip) < 0.7
|
| 118 |
);
|
| 119 |
if (indexExtended && othersCurled) return "POINTING";
|
| 120 |
|