cli: fix event loop never executing by run loop in background thread

ugh...

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I7ddb7aa8d97ea9bb04fdb2ca06aa72eb6a6a6964
This commit is contained in:
raf 2026-04-07 16:04:23 +03:00
commit 9461d346a8
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF

View file

@ -1,12 +1,16 @@
import argparse import argparse
import asyncio import asyncio
from collections.abc import Callable
import os import os
import threading
import time import time
import cv2 import cv2
from mediapipe.tasks.python.components.containers.landmark import NormalizedLandmark
from flipoff.detector import Camera from flipoff.detector import Camera
from flipoff.detector import HandDetector from flipoff.detector import HandDetector
from flipoff.events import Event
from flipoff.events import EventRegistry from flipoff.events import EventRegistry
from flipoff.gesture import Gesture from flipoff.gesture import Gesture
from flipoff.gesture import GestureRegistry from flipoff.gesture import GestureRegistry
@ -15,17 +19,17 @@ from flipoff.gesture import GestureRegistry
def _get_callback( def _get_callback(
loop: asyncio.AbstractEventLoop, loop: asyncio.AbstractEventLoop,
gesture_instance: Gesture, gesture_instance: Gesture,
event_instance: object, event_instance: Event,
cooldown: float, cooldown: float,
last_trigger: list[float], last_trigger: list[float],
) -> callable: ) -> Callable[[list[NormalizedLandmark]], bool]:
def callback(hand: object) -> bool: def callback(hand: list[NormalizedLandmark]) -> bool:
gesture_detected = gesture_instance.detect(hand) gesture_detected = gesture_instance.detect(hand)
if gesture_detected: if gesture_detected:
now = time.time() now = time.time()
if now - last_trigger[0] > cooldown: if now - last_trigger[0] > cooldown:
last_trigger[0] = now last_trigger[0] = now
loop.create_task(event_instance.trigger()) # type: ignore[attr-defined] asyncio.run_coroutine_threadsafe(event_instance.trigger(), loop)
return gesture_detected return gesture_detected
return callback return callback
@ -51,7 +55,8 @@ def run(
raise ValueError(f"Unknown event: {event_name}") raise ValueError(f"Unknown event: {event_name}")
loop = asyncio.new_event_loop() loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop) loop_thread = threading.Thread(target=loop.run_forever, daemon=True)
loop_thread.start()
detector = HandDetector(model_path) detector = HandDetector(model_path)
camera = Camera(camera_index) camera = Camera(camera_index)
@ -69,7 +74,7 @@ def run(
hands = detector.detect(frame) hands = detector.detect(frame)
if hands: if hands:
callback(hands[0]) gesture_detected = callback(hands[0])
if debug: if debug:
for landmark in hands[0]: for landmark in hands[0]:
@ -77,9 +82,12 @@ def run(
y = int(landmark.y * frame.shape[0]) y = int(landmark.y * frame.shape[0])
cv2.circle(frame, (x, y), 5, (0, 255, 0), -1) cv2.circle(frame, (x, y), 5, (0, 255, 0), -1)
flipping = gesture_instance.detect(hands[0]) text = (
text = f"{gesture_name.upper()} DETECTED" if flipping else "Waiting for gesture..." f"{gesture_name.upper()} DETECTED"
color = (0, 0, 255) if flipping else (0, 255, 0) if gesture_detected
else "Waiting for gesture..."
)
color = (0, 0, 255) if gesture_detected else (0, 255, 0)
cv2.putText(frame, text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, color, 2) cv2.putText(frame, text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, color, 2)
if not headless: if not headless:
@ -92,11 +100,8 @@ def run(
cv2.destroyAllWindows() cv2.destroyAllWindows()
detector.close() detector.close()
pending = asyncio.all_tasks(loop) loop.call_soon_threadsafe(loop.stop)
for task in pending: loop_thread.join()
task.cancel()
loop.run_until_complete(asyncio.gather(*pending, return_exceptions=True))
loop.close() loop.close()