-
Notifications
You must be signed in to change notification settings - Fork 2
/
app.py
259 lines (192 loc) · 9.14 KB
/
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
### General imports ###
from __future__ import division
import numpy as np
import pandas as pd
import time
import re
import os
from collections import Counter
import altair as alt
### Flask imports
import requests
from flask import Flask, render_template, session, request, redirect, flash, Response
### Audio imports ###
from library.speech_emotion_recognition import *
### Video imports ###
from library.video_emotion_recognition import *
# Flask config
app = Flask(__name__)
app.secret_key = b'(\xee\x00\xd4\xce"\xcf\xe8@\r\xde\xfc\xbdJ\x08W'
app.config['UPLOAD_FOLDER'] = '/Upload'
################################################################################
################################## INDEX #######################################
################################################################################
# Home page
@app.route('/', methods=['GET'])
def index():
return render_template('index.html')
################################################################################
################################## RULES #######################################
################################################################################
# Rules of the game
@app.route('/rules')
def rules():
return render_template('rules.html')
################################################################################
############################### VIDEO INTERVIEW ################################
################################################################################
# Read the overall dataframe before the user starts to add his own data
df = pd.read_csv('static/js/db/histo.txt', sep=",")
# Video interview template
@app.route('/video', methods=['POST'])
def video() :
# Display a warning message
flash('You will have 45 seconds to discuss the topic mentioned above. Due to restrictions, we are not able to redirect you once the video is over. Please move your URL to /video_dash instead of /video_1 once over. You will be able to see your results then.')
return render_template('video.html')
# Display the video flow (face, landmarks, emotion)
@app.route('/video_1', methods=['POST'])
def video_1() :
try :
# Response is used to display a flow of information
return Response(gen(),mimetype='multipart/x-mixed-replace; boundary=frame')
#return Response(stream_template('video.html', gen()))
except :
return None
# Dashboard
@app.route('/video_dash', methods=("POST", "GET"))
def video_dash():
# Load personal history
df_2 = pd.read_csv('static/js/db/histo_perso.txt')
def emo_prop(df_2) :
return [int(100*len(df_2[df_2.density==0])/len(df_2)),
int(100*len(df_2[df_2.density==1])/len(df_2)),
int(100*len(df_2[df_2.density==2])/len(df_2)),
int(100*len(df_2[df_2.density==3])/len(df_2)),
int(100*len(df_2[df_2.density==4])/len(df_2)),
int(100*len(df_2[df_2.density==5])/len(df_2)),
int(100*len(df_2[df_2.density==6])/len(df_2))]
emotions = ["Angry", "Disgust", "Fear", "Happy", "Sad", "Surprise", "Neutral"]
emo_perso = {}
emo_glob = {}
for i in range(len(emotions)) :
emo_perso[emotions[i]] = len(df_2[df_2.density==i])
emo_glob[emotions[i]] = len(df[df.density==i])
df_perso = pd.DataFrame.from_dict(emo_perso, orient='index')
df_perso = df_perso.reset_index()
df_perso.columns = ['EMOTION', 'VALUE']
df_perso.to_csv('static/js/db/hist_vid_perso.txt', sep=",", index=False)
df_glob = pd.DataFrame.from_dict(emo_glob, orient='index')
df_glob = df_glob.reset_index()
df_glob.columns = ['EMOTION', 'VALUE']
df_glob.to_csv('static/js/db/hist_vid_glob.txt', sep=",", index=False)
emotion = df_2.density.mode()[0]
emotion_other = df.density.mode()[0]
def emotion_label(emotion) :
if emotion == 0 :
return "Angry"
elif emotion == 1 :
return "Disgust"
elif emotion == 2 :
return "Fear"
elif emotion == 3 :
return "Happy"
elif emotion == 4 :
return "Sad"
elif emotion == 5 :
return "Surprise"
else :
return "Neutral"
### Altair Plot
df_altair = pd.read_csv('static/js/db/prob.csv', header=None, index_col=None).reset_index()
df_altair.columns = ['Time', 'Angry', 'Disgust', 'Fear', 'Happy', 'Sad', 'Surprise', 'Neutral']
angry = alt.Chart(df_altair).mark_line(color='orange', strokeWidth=2).encode(
x='Time:Q',
y='Angry:Q',
tooltip=["Angry"]
)
disgust = alt.Chart(df_altair).mark_line(color='red', strokeWidth=2).encode(
x='Time:Q',
y='Disgust:Q',
tooltip=["Disgust"])
fear = alt.Chart(df_altair).mark_line(color='green', strokeWidth=2).encode(
x='Time:Q',
y='Fear:Q',
tooltip=["Fear"])
happy = alt.Chart(df_altair).mark_line(color='blue', strokeWidth=2).encode(
x='Time:Q',
y='Happy:Q',
tooltip=["Happy"])
sad = alt.Chart(df_altair).mark_line(color='black', strokeWidth=2).encode(
x='Time:Q',
y='Sad:Q',
tooltip=["Sad"])
surprise = alt.Chart(df_altair).mark_line(color='pink', strokeWidth=2).encode(
x='Time:Q',
y='Surprise:Q',
tooltip=["Surprise"])
neutral = alt.Chart(df_altair).mark_line(color='brown', strokeWidth=2).encode(
x='Time:Q',
y='Neutral:Q',
tooltip=["Neutral"])
chart = (angry + disgust + fear + happy + sad + surprise + neutral).properties(
width=1000, height=400, title='Probability of each emotion over time')
chart.save('static/CSS/chart.html')
return render_template('video_dash.html', emo=emotion_label(emotion), emo_other = emotion_label(emotion_other), prob = emo_prop(df_2), prob_other = emo_prop(df))
################################################################################
############################### AUDIO INTERVIEW ################################
################################################################################
# Audio Index
@app.route('/audio_index', methods=['POST'])
def audio_index():
# Flash message
flash("After pressing the button above, you will have 15sec to answer the question.")
return render_template('audio.html', display_button=False)
# Audio Recording
@app.route('/audio_recording', methods=("POST", "GET"))
def audio_recording():
# Instanciate new SpeechEmotionRecognition object
SER = speechEmotionRecognition()
# Voice Recording
rec_duration = 16 # in sec
rec_sub_dir = os.path.join('tmp','voice_recording.wav')
SER.voice_recording(rec_sub_dir, duration=rec_duration)
# Send Flash message
flash("The recording is over! You now have the opportunity to do an analysis of your emotions. If you wish, you can also choose to record yourself again.")
return render_template('audio.html', display_button=True)
# Audio Emotion Analysis
@app.route('/audio_dash', methods=("POST", "GET"))
def audio_dash():
# Sub dir to speech emotion recognition model
model_sub_dir = os.path.join('Models', 'audio.hdf5')
# Instanciate new SpeechEmotionRecognition object
SER = speechEmotionRecognition(model_sub_dir)
# Voice Record sub dir
rec_sub_dir = os.path.join('tmp','voice_recording.wav')
# Predict emotion in voice at each time step
step = 1 # in sec
sample_rate = 16000 # in kHz
emotions, timestamp = SER.predict_emotion_from_file(rec_sub_dir, chunk_step=step*sample_rate)
# Export predicted emotions to .txt format
SER.prediction_to_csv(emotions, os.path.join("static/js/db", "audio_emotions.txt"), mode='w')
SER.prediction_to_csv(emotions, os.path.join("static/js/db", "audio_emotions_other.txt"), mode='a')
# Get most common emotion during the interview
major_emotion = max(set(emotions), key=emotions.count)
# Calculate emotion distribution
emotion_dist = [int(100 * emotions.count(emotion) / len(emotions)) for emotion in SER._emotion.values()]
# Export emotion distribution to .csv format for D3JS
df = pd.DataFrame(emotion_dist, index=SER._emotion.values(), columns=['VALUE']).rename_axis('EMOTION')
df.to_csv(os.path.join('static/js/db','audio_emotions_dist.txt'), sep=',')
# Get most common emotion of other candidates
df_other = pd.read_csv(os.path.join("static/js/db", "audio_emotions_other.txt"), sep=",")
# Get most common emotion during the interview for other candidates
major_emotion_other = df_other.EMOTION.mode()[0]
# Calculate emotion distribution for other candidates
emotion_dist_other = [int(100 * len(df_other[df_other.EMOTION==emotion]) / len(df_other)) for emotion in SER._emotion.values()]
# Export emotion distribution to .csv format for D3JS
df_other = pd.DataFrame(emotion_dist_other, index=SER._emotion.values(), columns=['VALUE']).rename_axis('EMOTION')
df_other.to_csv(os.path.join('static/js/db','audio_emotions_dist_other.txt'), sep=',')
# Sleep
time.sleep(0.5)
return render_template('audio_dash.html', emo=major_emotion, emo_other=major_emotion_other, prob=emotion_dist, prob_other=emotion_dist_other)
if __name__ == '__main__':
app.run(debug=True)