From bc0947fac18de7220dd3a738c8e8f1db8a8fdb2e Mon Sep 17 00:00:00 2001 From: Pim Hutting Date: Mon, 19 Jan 2026 18:26:15 +0100 Subject: [PATCH] chore: added a dot --- .../visual_emotion_recognition_agent.py | 53 ++++++++++--------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/src/control_backend/agents/perception/visual_emotion_recognition_agent/visual_emotion_recognition_agent.py b/src/control_backend/agents/perception/visual_emotion_recognition_agent/visual_emotion_recognition_agent.py index 647ddac..465903b 100644 --- a/src/control_backend/agents/perception/visual_emotion_recognition_agent/visual_emotion_recognition_agent.py +++ b/src/control_backend/agents/perception/visual_emotion_recognition_agent/visual_emotion_recognition_agent.py @@ -6,23 +6,27 @@ import cv2 import numpy as np import zmq import zmq.asyncio as azmq -from control_backend.agents.perception.visual_emotion_recognition_agentvisual_emotion_recognizer import ( # noqa - DeepFaceEmotionRecognizer, -) from pydantic_core import ValidationError from control_backend.agents import BaseAgent +from control_backend.agents.perception.visual_emotion_recognition_agent.visual_emotion_recognizer import ( # noqa + DeepFaceEmotionRecognizer, +) from control_backend.core.agent_system import InternalMessage from control_backend.core.config import settings from control_backend.schemas.belief_message import Belief class VisualEmotionRecognitionAgent(BaseAgent): - def __init__(self, name: str, socket_address: str, bind: bool = False, timeout_ms: int = 1000, - window_duration: - int = settings.behaviour_settings.visual_emotion_recognition_window_duration_s - , min_frames_required: int = - settings.behaviour_settings.visual_emotion_recognition_min_frames_per_face): + def __init__( + self, + name: str, + socket_address: str, + bind: bool = False, + timeout_ms: int = 1000, + window_duration: int = settings.behaviour_settings.visual_emotion_recognition_window_duration_s, # noqa + min_frames_required: int = settings.behaviour_settings.visual_emotion_recognition_min_frames_per_face, # noqa + ): """ Initialize the Visual Emotion Recognition Agent. @@ -31,7 +35,7 @@ class VisualEmotionRecognitionAgent(BaseAgent): :param bind: Whether to bind to the socket address (True) or connect (False) :param timeout_ms: Timeout for socket receive operations in milliseconds :param window_duration: Duration in seconds over which to aggregate emotions - :param min_frames_required: Minimum number of frames per face required to consider a face + :param min_frames_required: Minimum number of frames per face required to consider a face valid """ super().__init__(name) @@ -78,29 +82,29 @@ class VisualEmotionRecognitionAgent(BaseAgent): # Tracks counts of detected emotions per face index face_stats = defaultdict(Counter) - + prev_dominant_emotions = set() while self._running: try: frame_bytes = await self.video_in_socket.recv() - + # Convert bytes to a numpy buffer nparr = np.frombuffer(frame_bytes, np.uint8) - + # Decode image into the generic Numpy Array DeepFace expects frame_image = cv2.imdecode(nparr, cv2.IMREAD_COLOR) if frame_image is None: # Could not decode image, skip this frame continue - + # Get the dominant emotion from each face current_emotions = self.emotion_recognizer.sorted_dominant_emotions(frame_image) # Update emotion counts for each detected face for i, emotion in enumerate(current_emotions): face_stats[i][emotion] += 1 - + # If window duration has passed, process the collected stats if time.time() >= next_window_time: window_dominant_emotions = set() @@ -111,35 +115,36 @@ class VisualEmotionRecognitionAgent(BaseAgent): if total_detections >= self.min_frames_required: dominant_emotion = counter.most_common(1)[0][0] window_dominant_emotions.add(dominant_emotion) - + await self.update_emotions(prev_dominant_emotions, window_dominant_emotions) prev_dominant_emotions = window_dominant_emotions face_stats.clear() next_window_time = time.time() + self.window_duration - + except zmq.Again: self.logger.warning("No video frame received within timeout.") async def update_emotions(self, prev_emotions: set[str], emotions: set[str]): """ - Compare emotions from previous window and current emotions, + Compare emotions from previous window and current emotions, send updates to BDI Core Agent. """ emotions_to_remove = prev_emotions - emotions emotions_to_add = emotions - prev_emotions if not emotions_to_add and not emotions_to_remove: - return - + return + emotion_beliefs_remove = [] for emotion in emotions_to_remove: self.logger.info(f"Emotion '{emotion}' has disappeared.") try: - emotion_beliefs_remove.append(Belief(name="emotion_detected", arguments=[emotion], - remove=True)) + emotion_beliefs_remove.append( + Belief(name="emotion_detected", arguments=[emotion], remove=True) + ) except ValidationError: self.logger.warning("Invalid belief for emotion removal: %s", emotion) - + emotion_beliefs_add = [] for emotion in emotions_to_add: self.logger.info(f"New emotion detected: '{emotion}'") @@ -147,7 +152,7 @@ class VisualEmotionRecognitionAgent(BaseAgent): emotion_beliefs_add.append(Belief(name="emotion_detected", arguments=[emotion])) except ValidationError: self.logger.warning("Invalid belief for new emotion: %s", emotion) - + beliefs_list_add = [b.model_dump() for b in emotion_beliefs_add] beliefs_list_remove = [b.model_dump() for b in emotion_beliefs_remove] payload = {"create": beliefs_list_add, "delete": beliefs_list_remove} @@ -158,4 +163,4 @@ class VisualEmotionRecognitionAgent(BaseAgent): body=json.dumps(payload), thread="beliefs", ) - await self.send(message) \ No newline at end of file + await self.send(message)