Spaces:
Sleeping
Sleeping
Gesture simplification
Browse files- Dockerfile +7 -7
- src/gesturedetection/__pycache__/api.cpython-312.pyc +0 -0
- src/gesturedetection/__pycache__/models.cpython-312.pyc +0 -0
- src/gesturedetection/api.py +3 -3
- src/gesturedetection/models.py +37 -1
- src/validate/__pycache__/__init__.cpython-312.pyc +0 -0
- src/validate/__pycache__/gesture_validator.cpython-312.pyc +0 -0
- src/validate/__pycache__/models.cpython-312.pyc +0 -0
- src/validate/gesture_validator.py +18 -13
Dockerfile
CHANGED
|
@@ -29,18 +29,18 @@ WORKDIR $HOME/app
|
|
| 29 |
RUN pip install --no-cache-dir --upgrade pip
|
| 30 |
|
| 31 |
# Copy requirements first for better Docker layer caching
|
| 32 |
-
COPY --chown=user requirements.txt $HOME/app/
|
| 33 |
|
| 34 |
# Install Python dependencies
|
| 35 |
RUN pip install --no-cache-dir --user -r requirements.txt
|
| 36 |
|
| 37 |
-
# Copy the source code
|
| 38 |
-
COPY --chown=user src/ $HOME/app/src/
|
| 39 |
-
COPY --chown=user models/ $HOME/app/models/
|
| 40 |
|
| 41 |
-
# Copy the main entry point
|
| 42 |
-
COPY --chown=user main.py $HOME/app/
|
| 43 |
-
COPY --chown=user README.md $HOME/app/
|
| 44 |
|
| 45 |
# Expose the port that the app runs on (HF Spaces default is 7860)
|
| 46 |
EXPOSE 7860
|
|
|
|
| 29 |
RUN pip install --no-cache-dir --upgrade pip
|
| 30 |
|
| 31 |
# Copy requirements first for better Docker layer caching
|
| 32 |
+
COPY --chown=user docker/requirements.txt $HOME/app/
|
| 33 |
|
| 34 |
# Install Python dependencies
|
| 35 |
RUN pip install --no-cache-dir --user -r requirements.txt
|
| 36 |
|
| 37 |
+
# Copy the source code from parent directory
|
| 38 |
+
COPY --chown=user ../src/ $HOME/app/src/
|
| 39 |
+
COPY --chown=user ../models/ $HOME/app/models/
|
| 40 |
|
| 41 |
+
# Copy the main entry point from parent directory
|
| 42 |
+
COPY --chown=user ../main.py $HOME/app/
|
| 43 |
+
COPY --chown=user ../README.md $HOME/app/
|
| 44 |
|
| 45 |
# Expose the port that the app runs on (HF Spaces default is 7860)
|
| 46 |
EXPOSE 7860
|
src/gesturedetection/__pycache__/api.cpython-312.pyc
CHANGED
|
Binary files a/src/gesturedetection/__pycache__/api.cpython-312.pyc and b/src/gesturedetection/__pycache__/api.cpython-312.pyc differ
|
|
|
src/gesturedetection/__pycache__/models.cpython-312.pyc
CHANGED
|
Binary files a/src/gesturedetection/__pycache__/models.cpython-312.pyc and b/src/gesturedetection/__pycache__/models.cpython-312.pyc differ
|
|
|
src/gesturedetection/api.py
CHANGED
|
@@ -8,7 +8,7 @@ from fastapi import FastAPI, UploadFile, File, HTTPException, Form
|
|
| 8 |
from fastapi.responses import ORJSONResponse
|
| 9 |
from fastapi.encoders import jsonable_encoder
|
| 10 |
|
| 11 |
-
from .models import Gesture, GestureResponse, GESTURE_MAPPING, FULL_GESTURE_MAPPING
|
| 12 |
from .config import get_logfire_token, is_monitoring_enabled
|
| 13 |
|
| 14 |
# Import the gesture detection components
|
|
@@ -178,7 +178,7 @@ def process_video_for_gestures(video_path: str, detector_path: str = "models/han
|
|
| 178 |
# Adjust minimum duration based on frame skip
|
| 179 |
min_duration = max(5, frame_skip * 2) # At least 2 processed frames
|
| 180 |
if current_gesture is not None and current_duration >= min_duration:
|
| 181 |
-
gesture_name =
|
| 182 |
avg_confidence = current_confidence / current_duration if current_duration > 0 else 0.0
|
| 183 |
# Scale duration back to original frame count
|
| 184 |
scaled_duration = current_duration * frame_skip
|
|
@@ -208,7 +208,7 @@ def process_video_for_gestures(video_path: str, detector_path: str = "models/han
|
|
| 208 |
# Don't forget the last gesture
|
| 209 |
min_duration = max(5, frame_skip * 2) # At least 2 processed frames
|
| 210 |
if current_gesture is not None and current_duration >= min_duration:
|
| 211 |
-
gesture_name =
|
| 212 |
avg_confidence = current_confidence / current_duration if current_duration > 0 else 0.0
|
| 213 |
# Scale duration back to original frame count
|
| 214 |
scaled_duration = current_duration * frame_skip
|
|
|
|
| 8 |
from fastapi.responses import ORJSONResponse
|
| 9 |
from fastapi.encoders import jsonable_encoder
|
| 10 |
|
| 11 |
+
from .models import Gesture, GestureResponse, GESTURE_MAPPING, FULL_GESTURE_MAPPING, PRODUCTION_GESTURE_MAPPING
|
| 12 |
from .config import get_logfire_token, is_monitoring_enabled
|
| 13 |
|
| 14 |
# Import the gesture detection components
|
|
|
|
| 178 |
# Adjust minimum duration based on frame skip
|
| 179 |
min_duration = max(5, frame_skip * 2) # At least 2 processed frames
|
| 180 |
if current_gesture is not None and current_duration >= min_duration:
|
| 181 |
+
gesture_name = PRODUCTION_GESTURE_MAPPING.get(current_gesture, f"unknown_{current_gesture}")
|
| 182 |
avg_confidence = current_confidence / current_duration if current_duration > 0 else 0.0
|
| 183 |
# Scale duration back to original frame count
|
| 184 |
scaled_duration = current_duration * frame_skip
|
|
|
|
| 208 |
# Don't forget the last gesture
|
| 209 |
min_duration = max(5, frame_skip * 2) # At least 2 processed frames
|
| 210 |
if current_gesture is not None and current_duration >= min_duration:
|
| 211 |
+
gesture_name = PRODUCTION_GESTURE_MAPPING.get(current_gesture, f"unknown_{current_gesture}")
|
| 212 |
avg_confidence = current_confidence / current_duration if current_duration > 0 else 0.0
|
| 213 |
# Scale duration back to original frame count
|
| 214 |
scaled_duration = current_duration * frame_skip
|
src/gesturedetection/models.py
CHANGED
|
@@ -39,7 +39,43 @@ GESTURE_MAPPING = {
|
|
| 39 |
35: "stop", # stop gesture
|
| 40 |
}
|
| 41 |
|
| 42 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
FULL_GESTURE_MAPPING = {
|
| 44 |
0: "hand_down",
|
| 45 |
1: "hand_right",
|
|
|
|
| 39 |
35: "stop", # stop gesture
|
| 40 |
}
|
| 41 |
|
| 42 |
+
# Production gesture mapping with clean, consistent names
|
| 43 |
+
# Hand-agnostic counting (left/right variations map to same gesture)
|
| 44 |
+
PRODUCTION_GESTURE_MAPPING = {
|
| 45 |
+
# Counting gestures (1-5) - hand agnostic
|
| 46 |
+
30: "one", # 1 finger (any direction)
|
| 47 |
+
42: "one", # 1 finger left (maps to "one")
|
| 48 |
+
43: "one", # 1 finger right (maps to "one")
|
| 49 |
+
44: "one", # 1 finger down (maps to "one")
|
| 50 |
+
|
| 51 |
+
32: "two", # 2 fingers (peace sign)
|
| 52 |
+
39: "two", # 2 fingers up (maps to "two")
|
| 53 |
+
14: "two", # 2 fingers left (maps to "two")
|
| 54 |
+
15: "two", # 2 fingers right (maps to "two")
|
| 55 |
+
16: "two", # 2 fingers down (maps to "two")
|
| 56 |
+
|
| 57 |
+
37: "three", # 3 fingers (any direction)
|
| 58 |
+
21: "three", # 3 fingers variant (maps to "three")
|
| 59 |
+
38: "three", # 3 fingers variant 2 (maps to "three")
|
| 60 |
+
|
| 61 |
+
26: "four", # 4 fingers
|
| 62 |
+
|
| 63 |
+
31: "five", # 5 fingers (open palm)
|
| 64 |
+
|
| 65 |
+
# Extra gestures for production
|
| 66 |
+
27: "thumbs_up", # thumbs up gesture
|
| 67 |
+
23: "middle_finger", # middle finger
|
| 68 |
+
33: "peace_inverted", # peace sign inverted
|
| 69 |
+
|
| 70 |
+
# Additional useful gestures
|
| 71 |
+
29: "ok", # OK sign
|
| 72 |
+
20: "call", # call me gesture
|
| 73 |
+
25: "fist", # closed fist
|
| 74 |
+
19: "point", # pointing
|
| 75 |
+
35: "stop", # stop gesture
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
# Additional gesture mappings for completeness (all raw model outputs)
|
| 79 |
FULL_GESTURE_MAPPING = {
|
| 80 |
0: "hand_down",
|
| 81 |
1: "hand_right",
|
src/validate/__pycache__/__init__.cpython-312.pyc
CHANGED
|
Binary files a/src/validate/__pycache__/__init__.cpython-312.pyc and b/src/validate/__pycache__/__init__.cpython-312.pyc differ
|
|
|
src/validate/__pycache__/gesture_validator.cpython-312.pyc
CHANGED
|
Binary files a/src/validate/__pycache__/gesture_validator.cpython-312.pyc and b/src/validate/__pycache__/gesture_validator.cpython-312.pyc differ
|
|
|
src/validate/__pycache__/models.cpython-312.pyc
CHANGED
|
Binary files a/src/validate/__pycache__/models.cpython-312.pyc and b/src/validate/__pycache__/models.cpython-312.pyc differ
|
|
|
src/validate/gesture_validator.py
CHANGED
|
@@ -60,11 +60,11 @@ class GestureValidator:
|
|
| 60 |
# Import here to avoid circular imports and handle missing dependencies gracefully
|
| 61 |
try:
|
| 62 |
from ..gesturedetection.main_controller import MainController
|
| 63 |
-
from ..gesturedetection.models import
|
| 64 |
self._main_controller_class = MainController
|
| 65 |
-
self._gesture_mapping =
|
| 66 |
self._initialized = True
|
| 67 |
-
logger.info("GestureValidator initialized successfully")
|
| 68 |
except ImportError as e:
|
| 69 |
logger.warning(f"Could not import gesture detection components: {e}")
|
| 70 |
self._initialized = False
|
|
@@ -458,7 +458,11 @@ class GestureValidator:
|
|
| 458 |
|
| 459 |
def _normalize_gesture_name(self, gesture_name: str) -> str:
|
| 460 |
"""
|
| 461 |
-
Normalize gesture names to standard format.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 462 |
|
| 463 |
Parameters
|
| 464 |
----------
|
|
@@ -468,25 +472,26 @@ class GestureValidator:
|
|
| 468 |
Returns
|
| 469 |
-------
|
| 470 |
str
|
| 471 |
-
Normalized gesture name
|
| 472 |
"""
|
| 473 |
# Convert to lowercase and remove common variations
|
| 474 |
normalized = gesture_name.lower().strip()
|
| 475 |
|
| 476 |
-
# Handle common variations
|
| 477 |
variations = {
|
| 478 |
-
"thumbs_up": ["thumbsup", "thumb_up", "like"],
|
| 479 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 480 |
"ok": ["okay", "ok_sign"],
|
| 481 |
"call": ["call_me", "phone"],
|
| 482 |
-
"palm": ["open_palm", "five_fingers"],
|
| 483 |
"fist": ["closed_fist"],
|
| 484 |
"point": ["pointing"],
|
| 485 |
"stop": ["stop_sign"],
|
| 486 |
-
"
|
| 487 |
-
"two_up": ["two_fingers_up"],
|
| 488 |
-
"three": ["three_fingers"],
|
| 489 |
-
"four": ["four_fingers"]
|
| 490 |
}
|
| 491 |
|
| 492 |
for standard_name, variant_list in variations.items():
|
|
|
|
| 60 |
# Import here to avoid circular imports and handle missing dependencies gracefully
|
| 61 |
try:
|
| 62 |
from ..gesturedetection.main_controller import MainController
|
| 63 |
+
from ..gesturedetection.models import PRODUCTION_GESTURE_MAPPING
|
| 64 |
self._main_controller_class = MainController
|
| 65 |
+
self._gesture_mapping = PRODUCTION_GESTURE_MAPPING
|
| 66 |
self._initialized = True
|
| 67 |
+
logger.info("GestureValidator initialized successfully with PRODUCTION_GESTURE_MAPPING")
|
| 68 |
except ImportError as e:
|
| 69 |
logger.warning(f"Could not import gesture detection components: {e}")
|
| 70 |
self._initialized = False
|
|
|
|
| 458 |
|
| 459 |
def _normalize_gesture_name(self, gesture_name: str) -> str:
|
| 460 |
"""
|
| 461 |
+
Normalize gesture names to production-standard format.
|
| 462 |
+
|
| 463 |
+
Handles legacy naming and variations to ensure consistent gesture names
|
| 464 |
+
across different parts of the system. Maps old names like "like" to
|
| 465 |
+
"thumbs_up", and handles hand-agnostic counting variations.
|
| 466 |
|
| 467 |
Parameters
|
| 468 |
----------
|
|
|
|
| 472 |
Returns
|
| 473 |
-------
|
| 474 |
str
|
| 475 |
+
Normalized gesture name matching PRODUCTION_GESTURE_MAPPING
|
| 476 |
"""
|
| 477 |
# Convert to lowercase and remove common variations
|
| 478 |
normalized = gesture_name.lower().strip()
|
| 479 |
|
| 480 |
+
# Handle common variations and legacy names
|
| 481 |
variations = {
|
| 482 |
+
"thumbs_up": ["thumbsup", "thumb_up", "like"], # "like" is legacy name
|
| 483 |
+
"one": ["one_finger", "one_left", "one_right", "one_down"], # Hand-agnostic
|
| 484 |
+
"two": ["peace_sign", "victory", "two_fingers", "two_up", "two_left", "two_right", "two_down"], # Hand-agnostic
|
| 485 |
+
"three": ["three_fingers", "three2", "three3"], # Hand-agnostic
|
| 486 |
+
"four": ["four_fingers"],
|
| 487 |
+
"five": ["palm", "open_palm", "five_fingers"], # "palm" is alias for "five"
|
| 488 |
+
"peace_inverted": ["peace_inverted_sign"],
|
| 489 |
"ok": ["okay", "ok_sign"],
|
| 490 |
"call": ["call_me", "phone"],
|
|
|
|
| 491 |
"fist": ["closed_fist"],
|
| 492 |
"point": ["pointing"],
|
| 493 |
"stop": ["stop_sign"],
|
| 494 |
+
"middle_finger": ["middle"],
|
|
|
|
|
|
|
|
|
|
| 495 |
}
|
| 496 |
|
| 497 |
for standard_name, variant_list in variations.items():
|