ShantiView / backend /app /facial_analysis.py
Shouvik599
convert to React-LangGraph integration
7df2966
"""
Facial Emotion Analysis API for ShantiView
Wraps the DeepFace-based facial emotion detection model
"""
import cv2
import logging
import numpy as np
from deepface import DeepFace
logger = logging.getLogger(__name__)
# Confidence threshold for emotion detection
CONFIDENCE_THRESHOLD = 30.0
def _convert_to_native_types(data):
"""Convert numpy types to Python native types for JSON serialization."""
if isinstance(data, dict):
return {k: _convert_to_native_types(v) for k, v in data.items()}
elif isinstance(data, list):
return [_convert_to_native_types(item) for item in data]
elif isinstance(data, (np.float32, np.float64)):
return float(data)
elif isinstance(data, (np.int32, np.int64)):
return int(data)
elif isinstance(data, np.ndarray):
return data.tolist()
else:
return data
def analyze_frame_api(image_path: str) -> dict:
"""
Analyze an image file for facial emotion detection.
Args:
image_path: Path to the image file
Returns:
Dictionary with detection results (JSON serializable)
"""
try:
# Read the image
frame = cv2.imread(image_path)
if frame is None:
return {
"detected": False,
"emotion": "No image",
"score": 0.0,
"message": "Could not read image file"
}
# Analyze using DeepFace
results = DeepFace.analyze(
frame,
actions=['emotion'],
enforce_detection=False,
silent=True
)
# Process results
if results and isinstance(results, list) and len(results) > 0:
result = results[0]
dominant_emotion = str(result.get('dominant_emotion', 'unknown'))
emotion_scores = result.get('emotion', {})
emotion_score = float(emotion_scores.get(dominant_emotion, 0.0))
# Check confidence threshold
detected = emotion_score >= CONFIDENCE_THRESHOLD
emotion = dominant_emotion if detected else "Uncertain"
# Convert all_emotions to native Python types
all_emotions = {}
for k, v in emotion_scores.items():
all_emotions[str(k)] = float(v) / 100.0
return {
"detected": True,
"emotion": emotion.capitalize(),
"score": float(emotion_score) / 100.0, # Convert to 0-1 scale
"all_emotions": _convert_to_native_types(all_emotions)
}
else:
return {
"detected": False,
"emotion": "No face",
"score": 0.0,
"message": "No face detected in image"
}
except Exception as e:
logger.error(f"Error in facial analysis: {e}")
return {
"detected": False,
"emotion": "Error",
"score": 0.0,
"message": str(e)
}