RenzoQuispe commited on
Commit
7049068
verified
1 Parent(s): d4508e0

Upload 3 files

Browse files
Files changed (3) hide show
  1. Dockerfile +28 -0
  2. app.py +134 -0
  3. requirements.txt +9 -0
Dockerfile ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10-slim
2
+
3
+ WORKDIR /app
4
+
5
+ # Instalar dependencias del sistema para OpenCV
6
+ RUN apt-get update && apt-get install -y \
7
+ libglib2.0-0 \
8
+ libsm6 \
9
+ libxext6 \
10
+ libxrender-dev \
11
+ libgomp1 \
12
+ libgl1-mesa-glx \
13
+ && rm -rf /var/lib/apt/lists/*
14
+
15
+ # Copiar archivos de requerimientos
16
+ COPY requirements.txt .
17
+
18
+ # Instalar dependencias de Python
19
+ RUN pip install --no-cache-dir -r requirements.txt
20
+
21
+ # Copiar el c贸digo de la aplicaci贸n
22
+ COPY app.py .
23
+
24
+ # Exponer el puerto
25
+ EXPOSE 7860
26
+
27
+ # Comando para ejecutar la aplicaci贸n
28
+ CMD ["gunicorn", "--bind", "0.0.0.0:7860", "--timeout", "120", "app:app"]
app.py ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, jsonify
2
+ from flask_cors import CORS
3
+ import cv2
4
+ from deepface import DeepFace
5
+ import numpy as np
6
+ import base64
7
+ from io import BytesIO
8
+ from PIL import Image
9
+ import os
10
+
11
+ app = Flask(__name__)
12
+ CORS(app) # permitir peticiones desde Android
13
+
14
+ # cargar el clasificador de rostros
15
+ face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
16
+
17
+ @app.route('/')
18
+ def home():
19
+ return jsonify({
20
+ 'message': 'API de Detecci贸n de Emociones',
21
+ 'endpoints': {
22
+ '/predict': 'POST - Enviar imagen para detectar emoci贸n',
23
+ '/health': 'GET - Verificar estado del servicio'
24
+ }
25
+ })
26
+
27
+ @app.route('/predict', methods=['POST'])
28
+ def predict_emotion():
29
+ try:
30
+ # verificamos si se recibi贸 una imagen
31
+ if 'file' in request.files:
32
+ # Imagen desde archivo
33
+ file = request.files['file']
34
+ image = Image.open(file.stream)
35
+ frame = np.array(image)
36
+ frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
37
+
38
+ elif request.is_json and 'image' in request.json:
39
+ # imagen en base64
40
+ image_data = request.json['image']
41
+ # remover el prefijo data:image si existe
42
+ if ',' in image_data:
43
+ image_data = image_data.split(',')[1]
44
+
45
+ image_bytes = base64.b64decode(image_data)
46
+ image = Image.open(BytesIO(image_bytes))
47
+ frame = np.array(image)
48
+ frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
49
+
50
+ elif request.data:
51
+ # imagen como datos binarios
52
+ image = Image.open(BytesIO(request.data))
53
+ frame = np.array(image)
54
+ frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
55
+ else:
56
+ return jsonify({'error': 'No se recibi贸 ninguna imagen'}), 400
57
+
58
+ # convertir a escala de grises
59
+ gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
60
+
61
+ # convertir a RGB para DeepFace
62
+ rgb_frame = cv2.cvtColor(gray_frame, cv2.COLOR_GRAY2RGB)
63
+
64
+ # detectar rostros en el frame
65
+ faces = face_cascade.detectMultiScale(
66
+ gray_frame,
67
+ scaleFactor=1.1,
68
+ minNeighbors=5,
69
+ minSize=(30, 30)
70
+ )
71
+
72
+ emocion = "Sin Emocion"
73
+ all_emotions = {}
74
+ faces_detected = len(faces)
75
+
76
+ # si se detectaron rostros
77
+ if len(faces) > 0:
78
+ for (x, y, w, h) in faces:
79
+ # extraer la regi贸n del rostro
80
+ face_roi = rgb_frame[y:y + h, x:x + w]
81
+ # realizar an谩lisis de emoci贸n
82
+ result = DeepFace.analyze(
83
+ face_roi,
84
+ actions=['emotion'],
85
+ enforce_detection=False
86
+ )
87
+ # determinamos la emoci贸n dominante
88
+ emocion = result[0]['dominant_emotion']
89
+ all_emotions = result[0]['emotion']
90
+ break # Usar solo el primer rostro detectado
91
+ else:
92
+ # si no se detecta rostro, intentar an谩lisis directo
93
+ try:
94
+ result = DeepFace.analyze(
95
+ frame,
96
+ actions=['emotion'],
97
+ enforce_detection=False
98
+ )
99
+ emocion = result[0]['dominant_emotion']
100
+ all_emotions = result[0]['emotion']
101
+ faces_detected = 1
102
+ except:
103
+ pass
104
+
105
+ # formatear respuesta similar a Hugging Face API
106
+ response = []
107
+ if all_emotions:
108
+ for emotion, score in all_emotions.items():
109
+ response.append({
110
+ 'label': emotion,
111
+ 'score': score / 100.0
112
+ })
113
+ # ordenar por score
114
+ response.sort(key=lambda x: x['score'], reverse=True)
115
+
116
+ return jsonify({
117
+ 'emotion': emocion,
118
+ 'faces_detected': faces_detected,
119
+ 'all_emotions': response if response else None
120
+ })
121
+
122
+ except Exception as e:
123
+ return jsonify({
124
+ 'error': str(e),
125
+ 'emotion': 'Error al procesar imagen'
126
+ }), 500
127
+
128
+ @app.route('/health', methods=['GET'])
129
+ def health():
130
+ return jsonify({'status': 'healthy', 'service': 'Emotion Detection API'})
131
+
132
+ if __name__ == '__main__':
133
+ port = int(os.environ.get('PORT', 7860))
134
+ app.run(host='0.0.0.0', port=port, debug=False)
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ flask==2.3.3
2
+ flask-cors==4.0.0
3
+ opencv-python-headless==4.8.1.78
4
+ deepface==0.0.79
5
+ pillow==10.1.0
6
+ numpy==1.24.3
7
+ gunicorn==21.2.0
8
+ tensorflow==2.15.0
9
+ protobuf==3.20.3