yunusajib commited on
Commit
2754fd7
·
verified ·
1 Parent(s): 2a37e94

create App.py

Browse files
Files changed (1) hide show
  1. app.py +219 -0
app.py ADDED
@@ -0,0 +1,219 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import numpy as np
3
+ import cv2
4
+ import torch
5
+ import torchvision.transforms as transforms
6
+ from fer import FER
7
+ import librosa
8
+ from python_speech_features import mfcc
9
+ import pandas as pd
10
+ from datetime import datetime
11
+ import time
12
+ from transformers import pipeline
13
+
14
+ # Initialize models
15
+ emotion_detector = FER(mtcnn=True) # Facial expression recognition
16
+ voice_classifier = pipeline("audio-classification", model="superb/hubert-base-superb-er")
17
+
18
+ # Global variables to store results
19
+ emotion_history = []
20
+ current_emotions = {"face": "Neutral", "voice": "Neutral"}
21
+ last_update_time = time.time()
22
+
23
+ # Preprocessing for face detection
24
+ transform = transforms.Compose([
25
+ transforms.ToPILImage(),
26
+ transforms.Resize((48, 48)),
27
+ transforms.Grayscale(),
28
+ transforms.ToTensor(),
29
+ ])
30
+
31
+ def analyze_face(frame):
32
+ """Analyze facial expressions in the frame"""
33
+ try:
34
+ # Convert frame to RGB (FER expects RGB)
35
+ rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
36
+
37
+ # Detect emotions
38
+ results = emotion_detector.detect_emotions(rgb_frame)
39
+
40
+ if results:
41
+ emotions = results[0]['emotions']
42
+ dominant_emotion = max(emotions, key=emotions.get)
43
+ return dominant_emotion, emotions
44
+ return "Neutral", {"angry": 0, "disgust": 0, "fear": 0, "happy": 0, "sad": 0, "surprise": 0, "neutral": 1}
45
+ except Exception as e:
46
+ print(f"Face analysis error: {e}")
47
+ return "Neutral", {"angry": 0, "disgust": 0, "fear": 0, "happy": 0, "sad": 0, "surprise": 0, "neutral": 1}
48
+
49
+ def analyze_voice(audio):
50
+ """Analyze voice tone from audio"""
51
+ try:
52
+ sr, y = audio
53
+ y = y.astype(np.float32)
54
+
55
+ # Convert to mono if stereo
56
+ if len(y.shape) > 1:
57
+ y = np.mean(y, axis=0)
58
+
59
+ # Resample to 16kHz if needed
60
+ if sr != 16000:
61
+ y = librosa.resample(y, orig_sr=sr, target_sr=16000)
62
+ sr = 16000
63
+
64
+ # Classify emotion
65
+ result = voice_classifier({"sampling_rate": sr, "raw": y})
66
+ dominant_emotion = result[0]['label']
67
+ return dominant_emotion, result
68
+ except Exception as e:
69
+ print(f"Voice analysis error: {e}")
70
+ return "neutral", [{"label": "neutral", "score": 1.0}]
71
+
72
+ def update_emotion_history(face_emotion, voice_emotion):
73
+ """Update the emotion history and current emotions"""
74
+ global current_emotions, emotion_history, last_update_time
75
+
76
+ current_time = datetime.now().strftime("%H:%M:%S")
77
+
78
+ # Update current emotions
79
+ current_emotions = {
80
+ "face": face_emotion,
81
+ "voice": voice_emotion,
82
+ "timestamp": current_time
83
+ }
84
+
85
+ # Add to history (every 5 seconds or when emotion changes significantly)
86
+ if (time.time() - last_update_time) > 5 or not emotion_history:
87
+ emotion_history.append({
88
+ "timestamp": current_time,
89
+ "face": face_emotion,
90
+ "voice": voice_emotion
91
+ })
92
+ last_update_time = time.time()
93
+
94
+ # Keep only last 20 entries
95
+ if len(emotion_history) > 20:
96
+ emotion_history = emotion_history[-20:]
97
+
98
+ def get_emotion_timeline():
99
+ """Create a timeline DataFrame for display"""
100
+ if not emotion_history:
101
+ return pd.DataFrame(columns=["Time", "Facial Emotion", "Voice Emotion"])
102
+
103
+ df = pd.DataFrame(emotion_history)
104
+ df = df.rename(columns={
105
+ "timestamp": "Time",
106
+ "face": "Facial Emotion",
107
+ "voice": "Voice Emotion"
108
+ })
109
+ return df
110
+
111
+ def get_practitioner_advice(face_emotion, voice_emotion):
112
+ """Generate suggestions based on detected emotions"""
113
+ advice = []
114
+
115
+ # Facial emotion advice
116
+ if face_emotion in ["sad", "fear"]:
117
+ advice.append("Patient appears distressed. Consider speaking more slowly and with reassurance.")
118
+ elif face_emotion == "angry":
119
+ advice.append("Patient seems frustrated. Acknowledge their concerns and maintain calm demeanor.")
120
+ elif face_emotion == "confused":
121
+ advice.append("Patient may not understand. Consider rephrasing or providing more explanation.")
122
+ elif face_emotion == "pain":
123
+ advice.append("Patient appears to be in pain. Consider asking about discomfort.")
124
+
125
+ # Voice emotion advice
126
+ if voice_emotion in ["sad", "fear"]:
127
+ advice.append("Patient's tone suggests anxiety. Provide clear explanations and emotional support.")
128
+ elif voice_emotion == "angry":
129
+ advice.append("Patient sounds upset. Practice active listening and validate their feelings.")
130
+ elif voice_emotion == "happy":
131
+ advice.append("Patient seems positive. This may be a good time to discuss treatment options.")
132
+
133
+ return "\n".join(advice) if advice else "Patient appears neutral. Continue with consultation."
134
+
135
+ def process_input(video, audio):
136
+ """Process video and audio inputs to detect emotions"""
137
+ try:
138
+ # Process video frame
139
+ if video is not None:
140
+ frame = cv2.cvtColor(video, cv2.COLOR_RGB2BGR)
141
+ face_emotion, face_details = analyze_face(frame)
142
+ else:
143
+ face_emotion, face_details = "Neutral", {}
144
+
145
+ # Process audio
146
+ if audio is not None:
147
+ voice_emotion, voice_details = analyze_voice(audio)
148
+ else:
149
+ voice_emotion, voice_details = "neutral", {}
150
+
151
+ # Update history and get outputs
152
+ update_emotion_history(face_emotion, voice_emotion)
153
+ timeline_df = get_emotion_timeline()
154
+ advice = get_practitioner_advice(face_emotion, voice_emotion)
155
+
156
+ # Prepare outputs
157
+ outputs = {
158
+ "current_face": face_emotion,
159
+ "current_voice": voice_emotion,
160
+ "timeline": timeline_df,
161
+ "advice": advice,
162
+ "face_details": str(face_details),
163
+ "voice_details": str(voice_details)
164
+ }
165
+
166
+ return outputs
167
+ except Exception as e:
168
+ print(f"Processing error: {e}")
169
+ return {
170
+ "current_face": "Error",
171
+ "current_voice": "Error",
172
+ "timeline": pd.DataFrame(),
173
+ "advice": "System error occurred",
174
+ "face_details": "",
175
+ "voice_details": ""
176
+ }
177
+
178
+ # Gradio interface
179
+ with gr.Blocks(title="Patient Emotion Recognition", theme="soft") as demo:
180
+ gr.Markdown("# Real-Time Patient Emotion Recognition")
181
+ gr.Markdown("Analyze facial expressions and voice tone during medical consultations")
182
+
183
+ with gr.Row():
184
+ with gr.Column():
185
+ video_input = gr.Image(label="Live Camera Feed", source="webcam", streaming=True)
186
+ audio_input = gr.Audio(label="Voice Input", source="microphone", type="numpy")
187
+ submit_btn = gr.Button("Analyze Emotions")
188
+
189
+ with gr.Column():
190
+ current_face = gr.Textbox(label="Current Facial Emotion")
191
+ current_voice = gr.Textbox(label="Current Voice Emotion")
192
+ advice_output = gr.Textbox(label="Practitioner Suggestions", lines=3)
193
+ timeline_output = gr.Dataframe(label="Emotion Timeline", interactive=False)
194
+ face_details = gr.Textbox(label="Face Analysis Details", visible=False)
195
+ voice_details = gr.Textbox(label="Voice Analysis Details", visible=False)
196
+
197
+ # Live processing
198
+ video_input.change(
199
+ process_input,
200
+ inputs=[video_input, audio_input],
201
+ outputs=[current_face, current_voice, timeline_output, advice_output, face_details, voice_details],
202
+ show_progress="hidden"
203
+ )
204
+
205
+ audio_input.change(
206
+ process_input,
207
+ inputs=[video_input, audio_input],
208
+ outputs=[current_face, current_voice, timeline_output, advice_output, face_details, voice_details],
209
+ show_progress="hidden"
210
+ )
211
+
212
+ submit_btn.click(
213
+ process_input,
214
+ inputs=[video_input, audio_input],
215
+ outputs=[current_face, current_voice, timeline_output, advice_output, face_details, voice_details]
216
+ )
217
+
218
+ if __name__ == "__main__":
219
+ demo.launch(debug=True)