kennn14 commited on
Commit
2ff570e
Β·
verified Β·
1 Parent(s): 2816fba

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +57 -45
app.py CHANGED
@@ -414,9 +414,12 @@ class AutoResponse(BaseModel):
414
  async def predict_auto(files: List[UploadFile] = File(...)):
415
  """
416
  Accepts 60 JPEG frames.
417
- 1. Runs CNN on every frame β†’ majority vote
418
- 2. If vote_ratio >= 0.75 β†’ return letter
419
- 3. Else β†’ run LSTM on same frames β†’ return phrase
 
 
 
420
  """
421
  if not files:
422
  raise HTTPException(status_code=400, detail="No frames provided")
@@ -427,27 +430,55 @@ async def predict_auto(files: List[UploadFile] = File(...)):
427
  data = await file.read()
428
  frame_data.append(data)
429
 
430
- # ── Step 2: CNN majority vote on all frames ───────────────
431
- votes = {}
432
-
433
- for data in frame_data:
434
- mp_img = bytes_to_mp_image(data)
435
- result = hand_detector_alpha.detect(mp_img)
436
- hand_lms = result.hand_landmarks[0] if result.hand_landmarks else None
437
-
438
- if hand_lms is None:
439
- continue
440
-
441
- skel = render_hand_skeleton(hand_lms)
442
- tensor = infer_transform(skel).unsqueeze(0).to(device)
443
 
444
- with torch.no_grad():
445
- probs = torch.softmax(alphabet_model(tensor), dim=1)[0]
446
 
447
- conf, idx = probs.max(dim=0)
448
- letter = ALPHA_CLASSES[idx.item()]
449
- votes[letter] = votes.get(letter, 0) + 1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
450
 
 
451
  vote_ratio = 0.0
452
  best_letter = ""
453
 
@@ -455,7 +486,6 @@ async def predict_auto(files: List[UploadFile] = File(...)):
455
  best_letter = max(votes, key=votes.get)
456
  vote_ratio = votes[best_letter] / sum(votes.values())
457
 
458
- # ── Step 3: Letter decision ───────────────────────────────
459
  if vote_ratio >= 0.75 and best_letter:
460
  return AutoResponse(
461
  result=best_letter,
@@ -465,29 +495,7 @@ async def predict_auto(files: List[UploadFile] = File(...)):
465
  detected=True
466
  )
467
 
468
- # ── Step 4: LSTM on same frames ───────────────────────────
469
- coord_buffer = []
470
- last_pose_vec = np.zeros(POSE_SIZE, dtype=np.float32)
471
- last_left_hand_vec = np.zeros(HAND_SIZE, dtype=np.float32)
472
- last_right_hand_vec = np.zeros(HAND_SIZE, dtype=np.float32)
473
-
474
- for data in frame_data:
475
- mp_img = bytes_to_mp_image(data)
476
-
477
- pose_result = pose_detector.detect(mp_img)
478
- pose_lms = pose_result.pose_landmarks[0] \
479
- if pose_result.pose_landmarks else None
480
- if pose_lms:
481
- last_pose_vec = normalize_pose(pose_lms)
482
-
483
- hand_result = hand_detector_phrase.detect(mp_img)
484
- left_lms, right_lms = get_hands_by_side(hand_result)
485
- if left_lms is not None: last_left_hand_vec = normalize_hand(left_lms)
486
- if right_lms is not None: last_right_hand_vec = normalize_hand(right_lms)
487
-
488
- vec = np.concatenate([last_pose_vec, last_left_hand_vec, last_right_hand_vec])
489
- coord_buffer.append(vec)
490
-
491
  if len(coord_buffer) < MIN_COORD_FRAMES:
492
  return AutoResponse(
493
  result="", result_type="phrase",
@@ -512,6 +520,10 @@ async def predict_auto(files: List[UploadFile] = File(...)):
512
  detected=True
513
  )
514
 
 
 
 
 
515
 
516
  async def predict_phrase(files: List[UploadFile] = File(...)):
517
  """
 
414
  async def predict_auto(files: List[UploadFile] = File(...)):
415
  """
416
  Accepts 60 JPEG frames.
417
+ Optimization: runs MediaPipe on every other frame (30 calls instead of 60).
418
+ - CNN: votes on the 30 processed frames
419
+ - LSTM: 60 coord vectors β€” processed frames get real coords,
420
+ in-between frames reuse the previous frame's coords
421
+ 1. If CNN vote_ratio >= 0.75 β†’ return letter
422
+ 2. Else β†’ run LSTM on 60 coords β†’ return phrase
423
  """
424
  if not files:
425
  raise HTTPException(status_code=400, detail="No frames provided")
 
430
  data = await file.read()
431
  frame_data.append(data)
432
 
433
+ # ── Step 2: Run MediaPipe on every other frame ────────────
434
+ # For each frame, store: hand_lms, pose_vec, left_vec, right_vec
435
+ # Odd-indexed frames reuse the previous even frame's results
 
 
 
 
 
 
 
 
 
 
436
 
437
+ votes = {}
 
438
 
439
+ # LSTM coord buffer β€” 60 entries total
440
+ coord_buffer = []
441
+ last_pose_vec = np.zeros(POSE_SIZE, dtype=np.float32)
442
+ last_left_hand_vec = np.zeros(HAND_SIZE, dtype=np.float32)
443
+ last_right_hand_vec = np.zeros(HAND_SIZE, dtype=np.float32)
444
+
445
+ for i, data in enumerate(frame_data):
446
+ if i % 2 == 0:
447
+ # ── Process this frame through MediaPipe ──────────
448
+ mp_img = bytes_to_mp_image(data)
449
+
450
+ # CNN β€” hand landmarks
451
+ cnn_result = hand_detector_alpha.detect(mp_img)
452
+ hand_lms = cnn_result.hand_landmarks[0] \
453
+ if cnn_result.hand_landmarks else None
454
+
455
+ if hand_lms is not None:
456
+ skel = render_hand_skeleton(hand_lms)
457
+ tensor = infer_transform(skel).unsqueeze(0).to(device)
458
+ with torch.no_grad():
459
+ probs = torch.softmax(alphabet_model(tensor), dim=1)[0]
460
+ conf, idx = probs.max(dim=0)
461
+ letter = ALPHA_CLASSES[idx.item()]
462
+ votes[letter] = votes.get(letter, 0) + 1
463
+
464
+ # LSTM β€” pose + hand coords
465
+ pose_result = pose_detector.detect(mp_img)
466
+ pose_lms = pose_result.pose_landmarks[0] \
467
+ if pose_result.pose_landmarks else None
468
+ if pose_lms:
469
+ last_pose_vec = normalize_pose(pose_lms)
470
+
471
+ lstm_result = hand_detector_phrase.detect(mp_img)
472
+ left_lms, right_lms = get_hands_by_side(lstm_result)
473
+ if left_lms is not None: last_left_hand_vec = normalize_hand(left_lms)
474
+ if right_lms is not None: last_right_hand_vec = normalize_hand(right_lms)
475
+
476
+ # Both even and odd frames get a coord entry
477
+ # Odd frames reuse the last updated coords (from the previous even frame)
478
+ vec = np.concatenate([last_pose_vec, last_left_hand_vec, last_right_hand_vec])
479
+ coord_buffer.append(vec)
480
 
481
+ # ── Step 3: CNN vote decision ─────────────────────────────
482
  vote_ratio = 0.0
483
  best_letter = ""
484
 
 
486
  best_letter = max(votes, key=votes.get)
487
  vote_ratio = votes[best_letter] / sum(votes.values())
488
 
 
489
  if vote_ratio >= 0.75 and best_letter:
490
  return AutoResponse(
491
  result=best_letter,
 
495
  detected=True
496
  )
497
 
498
+ # ── Step 4: LSTM on 60 coords ─────────────────────────────
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
499
  if len(coord_buffer) < MIN_COORD_FRAMES:
500
  return AutoResponse(
501
  result="", result_type="phrase",
 
520
  detected=True
521
  )
522
 
523
+ vote_ratio=vote_ratio,
524
+ detected=True
525
+ )
526
+
527
 
528
  async def predict_phrase(files: List[UploadFile] = File(...)):
529
  """