devangoyal commited on
Commit
292c924
Β·
1 Parent(s): 86e9890

final deploy

Browse files
Files changed (1) hide show
  1. app.py +109 -77
app.py CHANGED
@@ -2,98 +2,130 @@ import gradio as gr
2
  from inference import model_fn, predict_fn
3
  import os
4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  # Load model once
6
  model_dict = model_fn('.')
7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  def predict(video):
9
  temp_path = "temp.mp4"
10
  try:
11
- # Save upload to temp
12
  if isinstance(video, str) and os.path.exists(video):
13
  os.rename(video, temp_path)
14
  else:
15
- with open(temp_path, "wb") as f:
16
  f.write(video.read())
17
- input_data = {"video_path": temp_path}
18
- result = predict_fn(input_data, model_dict)
19
- # Build HTML output
20
- output_md = ""
21
- for i, utt in enumerate(result["utterances"], 1):
22
- output_md += f"<div class='utt-card'>"
23
- output_md += f"<h4>Utterance {i}</h4>"
24
- output_md += f"<p><strong>Time:</strong> {utt['start_time']}s – {utt['end_time']}s</p>"
25
- output_md += f"<p><strong>Text:</strong> {utt['text']}</p>"
26
- # Emotions
27
- output_md += "<div class='tag-group'><span class='tag-header'>Emotions:</span>"
28
- for emo in utt['emotions']:
29
- output_md += f"<span class='tag emo'>{emo['label'].capitalize()} ({emo['confidence']:.2f})</span>"
30
- output_md += "</div>"
31
- # Sentiments
32
- output_md += "<div class='tag-group'><span class='tag-header'>Sentiments:</span>"
33
- for sent in utt['sentiments']:
34
- output_md += f"<span class='tag senti'>{sent['label'].capitalize()} ({sent['confidence']:.2f})</span>"
35
- output_md += "</div>"
36
- output_md += "</div>"
37
- return output_md
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  finally:
39
  if os.path.exists(temp_path):
40
  os.remove(temp_path)
41
 
42
- with gr.Blocks(css="""
43
- .utt-card {
44
- background: #fff;
45
- padding: 16px;
46
- margin-bottom: 12px;
47
- border-radius: 12px;
48
- box-shadow: 0 2px 6px rgba(0,0,0,0.1);
49
- }
50
- .tag-group {
51
- margin: 8px 0;
52
- display: flex;
53
- flex-wrap: wrap;
54
- gap: 6px;
55
- align-items: center;
56
- }
57
- .tag-header {
58
- font-weight: 600;
59
- margin-right: 6px;
60
- }
61
- .tag {
62
- padding: 4px 8px;
63
- border-radius: 8px;
64
- font-size: 0.9em;
65
- }
66
- .tag.emo {
67
- background: #fdecef;
68
- color: #e74c3c;
69
- }
70
- .tag.senti {
71
- background: #eafaf1;
72
- color: #27ae60;
73
- }
74
- .gradio-container {
75
- background-color: #f0f2f5;
76
- }
77
- #title {
78
- font-size: 2rem;
79
- font-weight: bold;
80
- margin-bottom: 0.5em;
81
- }
82
- #description {
83
- font-size: 1.1rem;
84
- color: #555;
85
- }
86
- """) as demo:
87
- gr.Markdown("# 🎬 Video Sentiment & Emotion Analyzer", elem_id="title")
88
- gr.Markdown("Upload an .mp4 video to analyze emotions and sentiments per utterance.", elem_id="description")
89
  with gr.Row():
90
  with gr.Column(scale=1):
91
- vid_input = gr.Video(label="Input Video")
92
- run_btn = gr.Button("Analyze", variant="primary")
93
- with gr.Column(scale=1):
94
- output_html = gr.HTML(label="Results")
95
-
96
- run_btn.click(fn=predict, inputs=vid_input, outputs=output_html)
97
 
98
- if __name__ == "__main__":
99
  demo.launch()
 
2
  from inference import model_fn, predict_fn
3
  import os
4
 
5
+ # Emoji mappings
6
+ EMOTION_EMOJI = {
7
+ 'anger': '😑',
8
+ 'disgust': '🀒',
9
+ 'fear': '😨',
10
+ 'joy': 'πŸ˜„',
11
+ 'neutral': '😐',
12
+ 'sadness': '😒',
13
+ 'surprise': '😲'
14
+ }
15
+ SENTIMENT_EMOJI = {
16
+ 'negative': '😑',
17
+ 'neutral': '😐',
18
+ 'positive': 'πŸ˜„'
19
+ }
20
+
21
  # Load model once
22
  model_dict = model_fn('.')
23
 
24
+ # Utility to compute top emotion/sentiment across utterances
25
+ def compute_overall(utterances):
26
+ # aggregate confidences
27
+ emo_scores = {}
28
+ senti_scores = {}
29
+ for utt in utterances:
30
+ for emo in utt.get('emotions', []):
31
+ emo_scores.setdefault(emo['label'], []).append(emo['confidence'])
32
+ for sent in utt.get('sentiments', []):
33
+ senti_scores.setdefault(sent['label'], []).append(sent['confidence'])
34
+ # compute average
35
+ def avg(scores): return sum(scores)/len(scores) if scores else 0
36
+ emo_avg = [(label, avg(scores)) for label, scores in emo_scores.items()]
37
+ senti_avg = [(label, avg(scores)) for label, scores in senti_scores.items()]
38
+ if not emo_avg or not senti_avg:
39
+ return None
40
+ # pick top
41
+ top_emo_label, top_emo_score = max(emo_avg, key=lambda x: x[1])
42
+ top_sent_label, top_sent_score = max(senti_avg, key=lambda x: x[1])
43
+ return {
44
+ 'emotion_label': top_emo_label,
45
+ 'emotion_score': top_emo_score,
46
+ 'emotion_emoji': EMOTION_EMOJI.get(top_emo_label, ''),
47
+ 'sentiment_label': top_sent_label,
48
+ 'sentiment_score': top_sent_score,
49
+ 'sentiment_emoji': SENTIMENT_EMOJI.get(top_sent_label, '')
50
+ }
51
+
52
+
53
  def predict(video):
54
  temp_path = "temp.mp4"
55
  try:
56
+ # save upload
57
  if isinstance(video, str) and os.path.exists(video):
58
  os.rename(video, temp_path)
59
  else:
60
+ with open(temp_path, 'wb') as f:
61
  f.write(video.read())
62
+ # run inference
63
+ result = predict_fn({'video_path': temp_path}, model_dict)
64
+ utterances = result.get('utterances', [])
65
+ # overall analysis
66
+ overall = compute_overall(utterances) or {}
67
+ overall_html = f"""
68
+ <div class='overall-card'>
69
+ <div>
70
+ <strong>Primary Emotion</strong><br>
71
+ <span class='emoji'>{overall.get('emotion_emoji')}</span> {overall.get('emotion_label', '')}<br>
72
+ <small>{overall.get('emotion_score', 0)*100:.1f}%</small>
73
+ </div>
74
+ <div>
75
+ <strong>Primary Sentiment</strong><br>
76
+ <span class='emoji'>{overall.get('sentiment_emoji')}</span> {overall.get('sentiment_label', '')}<br>
77
+ <small>{overall.get('sentiment_score', 0)*100:.1f}%</small>
78
+ </div>
79
+ </div>
80
+ """
81
+ # utterance cards
82
+ utt_html = ''
83
+ for utt in utterances:
84
+ utt_html += f"""
85
+ <div class='utt-card'>
86
+ <div class='time'>{utt['start_time']:.1f}s - {utt['end_time']:.1f}s</div>
87
+ <div class='text'>{utt['text']}</div>
88
+ <div class='bar-group'><span>Emotions</span>"""
89
+ for emo in utt.get('emotions', []):
90
+ pct = emo['confidence'] * 100
91
+ utt_html += f"<div class='bar'><div class='fill emo' style='width:{pct:.0f}%'></div><span>{emo['label']}: {pct:.0f}%</span></div>"
92
+ utt_html += "</div><div class='bar-group'><span>Sentiments</span>"
93
+ for sent in utt.get('sentiments', []):
94
+ pct = sent['confidence'] * 100
95
+ utt_html += f"<div class='bar'><div class='fill senti' style='width:{pct:.0f}%'></div><span>{sent['label']}: {pct:.0f}%</span></div>"
96
+ utt_html += "</div></div>"
97
+ return overall_html + utt_html
98
  finally:
99
  if os.path.exists(temp_path):
100
  os.remove(temp_path)
101
 
102
+ # Dark-mode CSS
103
+ gr_css = """
104
+ body { background: #121212; color: #e0e0e0; }
105
+ .overall-card { display: flex; justify-content: space-around; background: #1f1f1f; padding: 16px; border-radius: 10px; margin-bottom: 16px; }
106
+ .overall-card .emoji { font-size: 2rem; display: block; margin: 4px 0; }
107
+ .utt-card { background: #1f1f1f; padding: 12px; margin-bottom: 12px; border-radius: 10px; }
108
+ .time { font-size: 0.85rem; color: #888; margin-bottom: 4px; }
109
+ .text { font-size: 0.95rem; margin-bottom: 8px; }
110
+ .bar-group { margin-bottom: 8px; }
111
+ .bar-group span { font-weight: 600; display: block; margin-bottom: 4px; }
112
+ .bar { position: relative; background: #2a2a2a; height: 14px; border-radius: 7px; margin-bottom: 4px; overflow: hidden; }
113
+ .fill { height: 100%; }
114
+ .fill.emo { background: #e67e22; }
115
+ .fill.senti { background: #27ae60; }
116
+ .bar span { position: absolute; top: 0; left: 6px; font-size: 0.75rem; line-height: 14px; }
117
+ """
118
+
119
+ # Build Gradio App
120
+ with gr.Blocks(css=gr_css) as demo:
121
+ gr.Markdown('# 🎬 Video Sentiment & Emotion Analyzer')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  with gr.Row():
123
  with gr.Column(scale=1):
124
+ vid_in = gr.Video(label='Upload a video')
125
+ btn = gr.Button('Analyze', variant='primary')
126
+ with gr.Column(scale=2):
127
+ out = gr.HTML()
128
+ btn.click(predict, inputs=vid_in, outputs=out)
 
129
 
130
+ if __name__ == '__main__':
131
  demo.launch()