Kamalaskar Disha Vinay (EXT) commited on
Commit Β·
db17692
1
Parent(s): c99a178
change input format
Browse files- app.py +57 -35
- requirements.txt +2 -0
app.py
CHANGED
|
@@ -10,6 +10,9 @@ from torchvision import models
|
|
| 10 |
import tempfile
|
| 11 |
import os
|
| 12 |
from huggingface_hub import hf_hub_download
|
|
|
|
|
|
|
|
|
|
| 13 |
|
| 14 |
# Configuration
|
| 15 |
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
|
@@ -151,6 +154,27 @@ def extract_video_frames(video_path, max_frames=8, resize=(224, 224)):
|
|
| 151 |
frames = np.array(frames[:max_frames], dtype=np.uint8)
|
| 152 |
return frames
|
| 153 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 154 |
def preprocess_inputs(audio_path, text, video_path):
|
| 155 |
"""Preprocess all three modalities"""
|
| 156 |
|
|
@@ -182,16 +206,22 @@ def preprocess_inputs(audio_path, text, video_path):
|
|
| 182 |
|
| 183 |
return audio_values, audio_mask, text_ids, text_mask, frames_tensor
|
| 184 |
|
| 185 |
-
def predict_emotion(
|
| 186 |
-
"""Main prediction function"""
|
| 187 |
|
| 188 |
-
if
|
| 189 |
-
return "Please provide
|
| 190 |
|
| 191 |
try:
|
| 192 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 193 |
audio, audio_mask, text_ids, text_mask, video = preprocess_inputs(
|
| 194 |
-
|
| 195 |
)
|
| 196 |
|
| 197 |
# Inference
|
|
@@ -202,25 +232,23 @@ def predict_emotion(audio_file, text_input, video_file):
|
|
| 202 |
|
| 203 |
# Get probabilities
|
| 204 |
fused_probs = torch.softmax(fused_logits, dim=1)[0].cpu().numpy()
|
| 205 |
-
audio_probs = torch.softmax(a_logits, dim=1)[0].cpu().numpy()
|
| 206 |
-
text_probs = torch.softmax(t_logits, dim=1)[0].cpu().numpy()
|
| 207 |
-
video_probs = torch.softmax(v_logits, dim=1)[0].cpu().numpy()
|
| 208 |
|
| 209 |
# Format results
|
| 210 |
-
|
| 211 |
-
audio_result = {LABELS[i]: float(audio_probs[i]) for i in range(len(LABELS))}
|
| 212 |
-
text_result = {LABELS[i]: float(text_probs[i]) for i in range(len(LABELS))}
|
| 213 |
-
video_result = {LABELS[i]: float(video_probs[i]) for i in range(len(LABELS))}
|
| 214 |
|
| 215 |
predicted_emotion = LABELS[fused_probs.argmax()]
|
| 216 |
confidence = float(fused_probs.max())
|
| 217 |
|
| 218 |
result_text = f"π― **Predicted Emotion: {predicted_emotion.upper()}**\n\n**Confidence: {confidence:.2%}**"
|
| 219 |
|
| 220 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 221 |
|
| 222 |
except Exception as e:
|
| 223 |
-
return f"Error: {str(e)}", None,
|
| 224 |
|
| 225 |
# Gradio Interface
|
| 226 |
with gr.Blocks(title="Multimodal Emotion Recognition", theme=gr.themes.Soft()) as demo:
|
|
@@ -228,43 +256,37 @@ with gr.Blocks(title="Multimodal Emotion Recognition", theme=gr.themes.Soft()) a
|
|
| 228 |
"""
|
| 229 |
# π Multimodal Emotion Recognition
|
| 230 |
|
| 231 |
-
This system predicts emotions
|
|
|
|
|
|
|
|
|
|
| 232 |
|
| 233 |
### How to use:
|
| 234 |
-
1. Upload
|
| 235 |
-
2.
|
| 236 |
-
3.
|
| 237 |
-
4. Click "Predict Emotion"
|
| 238 |
|
| 239 |
-
The model will
|
| 240 |
"""
|
| 241 |
)
|
|
|
|
| 242 |
|
| 243 |
with gr.Row():
|
| 244 |
with gr.Column():
|
| 245 |
-
audio_input = gr.Audio(type="filepath", label="π€ Audio Input")
|
| 246 |
-
text_input = gr.Textbox(
|
| 247 |
-
label="π Text Transcript",
|
| 248 |
-
placeholder="Enter what was said in the audio/video...",
|
| 249 |
-
lines=3
|
| 250 |
-
)
|
| 251 |
video_input = gr.Video(label="π₯ Video Input")
|
| 252 |
predict_btn = gr.Button("π Predict Emotion", variant="primary", size="lg")
|
| 253 |
|
| 254 |
with gr.Column():
|
| 255 |
result_text = gr.Markdown(label="Result")
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
fused_output = gr.Label(label="π Fused Prediction", num_top_classes=4)
|
| 259 |
-
audio_output = gr.Label(label="π€ Audio-only Prediction", num_top_classes=4)
|
| 260 |
-
text_output = gr.Label(label="π Text-only Prediction", num_top_classes=4)
|
| 261 |
-
video_output = gr.Label(label="π₯ Video-only Prediction", num_top_classes=4)
|
| 262 |
|
| 263 |
predict_btn.click(
|
| 264 |
fn=predict_emotion,
|
| 265 |
-
inputs=[
|
| 266 |
-
outputs=[result_text,
|
| 267 |
)
|
|
|
|
| 268 |
|
| 269 |
gr.Markdown(
|
| 270 |
"""
|
|
|
|
| 10 |
import tempfile
|
| 11 |
import os
|
| 12 |
from huggingface_hub import hf_hub_download
|
| 13 |
+
import whisper
|
| 14 |
+
from moviepy.editor import VideoFileClip
|
| 15 |
+
|
| 16 |
|
| 17 |
# Configuration
|
| 18 |
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
|
|
|
| 154 |
frames = np.array(frames[:max_frames], dtype=np.uint8)
|
| 155 |
return frames
|
| 156 |
|
| 157 |
+
def extract_audio_from_video(video_path):
|
| 158 |
+
"""Extract audio from video file"""
|
| 159 |
+
try:
|
| 160 |
+
video = VideoFileClip(video_path)
|
| 161 |
+
audio_path = tempfile.NamedTemporaryFile(delete=False, suffix=".wav").name
|
| 162 |
+
video.audio.write_audiofile(audio_path, fps=SAMPLE_RATE, verbose=False, logger=None)
|
| 163 |
+
video.close()
|
| 164 |
+
return audio_path
|
| 165 |
+
except Exception as e:
|
| 166 |
+
raise ValueError(f"Could not extract audio from video: {str(e)}")
|
| 167 |
+
|
| 168 |
+
def transcribe_audio(audio_path):
|
| 169 |
+
"""Transcribe audio using Whisper"""
|
| 170 |
+
try:
|
| 171 |
+
whisper_model = whisper.load_model("base")
|
| 172 |
+
result = whisper_model.transcribe(audio_path)
|
| 173 |
+
return result["text"].strip()
|
| 174 |
+
except Exception as e:
|
| 175 |
+
raise ValueError(f"Could not transcribe audio: {str(e)}")
|
| 176 |
+
|
| 177 |
+
|
| 178 |
def preprocess_inputs(audio_path, text, video_path):
|
| 179 |
"""Preprocess all three modalities"""
|
| 180 |
|
|
|
|
| 206 |
|
| 207 |
return audio_values, audio_mask, text_ids, text_mask, frames_tensor
|
| 208 |
|
| 209 |
+
def predict_emotion(video_file):
|
| 210 |
+
"""Main prediction function - takes only video input"""
|
| 211 |
|
| 212 |
+
if video_file is None:
|
| 213 |
+
return "Please provide a video file", None, ""
|
| 214 |
|
| 215 |
try:
|
| 216 |
+
# Extract audio from video
|
| 217 |
+
audio_path = extract_audio_from_video(video_file)
|
| 218 |
+
|
| 219 |
+
# Transcribe audio
|
| 220 |
+
transcribed_text = transcribe_audio(audio_path)
|
| 221 |
+
|
| 222 |
+
# Preprocess all modalities
|
| 223 |
audio, audio_mask, text_ids, text_mask, video = preprocess_inputs(
|
| 224 |
+
audio_path, transcribed_text, video_file
|
| 225 |
)
|
| 226 |
|
| 227 |
# Inference
|
|
|
|
| 232 |
|
| 233 |
# Get probabilities
|
| 234 |
fused_probs = torch.softmax(fused_logits, dim=1)[0].cpu().numpy()
|
|
|
|
|
|
|
|
|
|
| 235 |
|
| 236 |
# Format results
|
| 237 |
+
result = {LABELS[i]: float(fused_probs[i]) for i in range(len(LABELS))}
|
|
|
|
|
|
|
|
|
|
| 238 |
|
| 239 |
predicted_emotion = LABELS[fused_probs.argmax()]
|
| 240 |
confidence = float(fused_probs.max())
|
| 241 |
|
| 242 |
result_text = f"π― **Predicted Emotion: {predicted_emotion.upper()}**\n\n**Confidence: {confidence:.2%}**"
|
| 243 |
|
| 244 |
+
# Clean up temporary audio file
|
| 245 |
+
if os.path.exists(audio_path):
|
| 246 |
+
os.remove(audio_path)
|
| 247 |
+
|
| 248 |
+
return result_text, result, transcribed_text
|
| 249 |
|
| 250 |
except Exception as e:
|
| 251 |
+
return f"Error: {str(e)}", None, ""
|
| 252 |
|
| 253 |
# Gradio Interface
|
| 254 |
with gr.Blocks(title="Multimodal Emotion Recognition", theme=gr.themes.Soft()) as demo:
|
|
|
|
| 256 |
"""
|
| 257 |
# π Multimodal Emotion Recognition
|
| 258 |
|
| 259 |
+
This system predicts emotions from video by automatically extracting and analyzing:
|
| 260 |
+
- π€ **Audio** (extracted from video)
|
| 261 |
+
- π **Text** (transcribed from audio using Whisper)
|
| 262 |
+
- π₯ **Video** (visual frames)
|
| 263 |
|
| 264 |
### How to use:
|
| 265 |
+
1. Upload a video file (MP4, AVI, MOV, etc.)
|
| 266 |
+
2. Click "Predict Emotion"
|
| 267 |
+
3. The system will automatically extract audio, transcribe speech, and analyze all modalities
|
|
|
|
| 268 |
|
| 269 |
+
The model will provide emotion predictions based on all three inputs.
|
| 270 |
"""
|
| 271 |
)
|
| 272 |
+
|
| 273 |
|
| 274 |
with gr.Row():
|
| 275 |
with gr.Column():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 276 |
video_input = gr.Video(label="π₯ Video Input")
|
| 277 |
predict_btn = gr.Button("π Predict Emotion", variant="primary", size="lg")
|
| 278 |
|
| 279 |
with gr.Column():
|
| 280 |
result_text = gr.Markdown(label="Result")
|
| 281 |
+
result_output = gr.Label(label="π Prediction Results", num_top_classes=4)
|
| 282 |
+
transcription_output = gr.Textbox(label="π Transcribed Text", lines=3, interactive=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 283 |
|
| 284 |
predict_btn.click(
|
| 285 |
fn=predict_emotion,
|
| 286 |
+
inputs=[video_input],
|
| 287 |
+
outputs=[result_text, result_output, transcription_output]
|
| 288 |
)
|
| 289 |
+
|
| 290 |
|
| 291 |
gr.Markdown(
|
| 292 |
"""
|
requirements.txt
CHANGED
|
@@ -7,3 +7,5 @@ numpy
|
|
| 7 |
soundfile
|
| 8 |
accelerate
|
| 9 |
huggingface_hub
|
|
|
|
|
|
|
|
|
| 7 |
soundfile
|
| 8 |
accelerate
|
| 9 |
huggingface_hub
|
| 10 |
+
openai-whisper
|
| 11 |
+
moviepy
|