PedroMartelleto commited on
Commit
2ba821f
·
1 Parent(s): d944844

initial commit

Browse files
Files changed (2) hide show
  1. app.py +375 -0
  2. requirements.txt +2 -0
app.py ADDED
@@ -0,0 +1,375 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import random
3
+ import firebase_admin
4
+ from firebase_admin import credentials
5
+ from firebase_admin import firestore
6
+ import uuid
7
+ import json
8
+ import os
9
+ from dotenv import load_dotenv
10
+
11
+ load_dotenv()
12
+
13
+ video_pairs = [
14
+ ('1XCLpvcAPg8fUAZ7k5hdUbT9avNnf12t3', '1Nve35Qo3I4Oe6ANsdj78Uo-3EZJkf28P'),
15
+ ('1bHfhebrflmGTksFlzTskOjQX28TM-yVb', '1-LwBNDp1mliDGYVnIb_cCERvyNFeC4bC'),
16
+ ('1mlSxLm_9LeTKj-m03pGun-1eefX58aF_', '1x4j79qiBkzl-bgjSRddwWF4yTMm63tKC'),
17
+ ]
18
+
19
+ my_credentials = {
20
+ "type": "service_account",
21
+ "project_id": "human-eval-c4f83",
22
+ "private_key_id": os.environ.get("PRIVATE_KEY_ID"),
23
+ "private_key": os.environ.get("PRIVATE_KEY").replace(r'\n', '\n'), # CHANGE HERE
24
+ "client_email": os.environ.get("CLIENT_EMAIL"),
25
+ "client_id": os.environ.get("CLIENT_ID"),
26
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
27
+ "token_uri": "https://oauth2.googleapis.com/token",
28
+ "auth_provider_x509_cert_url": os.environ.get("AUTH_PROVIDER_X509_CERT_URL"),
29
+ "client_x509_cert_url": os.environ.get("CLIENT_X509_CERT_URL")
30
+ }
31
+
32
+ # Initialize Firebase
33
+ if not firebase_admin._apps:
34
+ cred = credentials.Certificate(my_credentials)
35
+ firebase_admin.initialize_app(cred)
36
+ db = firestore.client()
37
+
38
+ import re
39
+
40
+ def get_embed_link(file_id):
41
+ return f"https://drive.google.com/file/d/{file_id}/preview"
42
+
43
+ def get_video_pair(state):
44
+ pair_index = state['pair_index']
45
+ shuffled_pairs = state['shuffled_pairs']
46
+ user_votes = state['user_votes']
47
+ while pair_index < len(shuffled_pairs):
48
+ video1_id, video2_id = shuffled_pairs[pair_index]
49
+ pair_key = f"{video1_id}_{video2_id}"
50
+ if pair_key not in user_votes:
51
+ # Randomize left-right positions
52
+ if random.choice([True, False]):
53
+ left_video_id, right_video_id = video1_id, video2_id
54
+ else:
55
+ left_video_id, right_video_id = video2_id, video1_id
56
+ left_video_url = get_embed_link(left_video_id)
57
+ right_video_url = get_embed_link(right_video_id)
58
+ print("Links", left_video_url, right_video_url)
59
+ state['left_video_id'] = left_video_id
60
+ state['right_video_id'] = right_video_id
61
+ state['video1_id'] = video1_id
62
+ state['video2_id'] = video2_id
63
+ return left_video_url, right_video_url
64
+ else:
65
+ pair_index += 1
66
+ state['pair_index'] = pair_index
67
+ return None, None # No more pairs
68
+
69
+ def generate_video_html(url):
70
+ return f'<iframe src="{url}" width="480" height="320" allow="autoplay"></iframe>'
71
+
72
+ def save_vote(email, video1_id, video2_id, left_video_id, right_video_id, responses):
73
+ vote_data = {
74
+ 'email': email,
75
+ 'video1': video1_id,
76
+ 'video2': video2_id,
77
+ 'left_video': left_video_id,
78
+ 'right_video': right_video_id,
79
+ 'visual_quality': responses['visual_quality'],
80
+ 'temporal_consistency': responses['temporal_consistency'],
81
+ 'realistic_dynamics': responses['realistic_dynamics'],
82
+ }
83
+ db.collection('votes').add(vote_data)
84
+ # Update user's vote history
85
+ user_ref = db.collection('users').document(email)
86
+ user_doc = user_ref.get()
87
+ if user_doc.exists:
88
+ user_votes = set(user_doc.to_dict().get('votes', []))
89
+ else:
90
+ user_votes = set()
91
+ pair_key = f"{video1_id}_{video2_id}"
92
+ user_votes.add(pair_key)
93
+ user_ref.set({'votes': list(user_votes)}, merge=True)
94
+
95
+ def update_interface(responses, state):
96
+ email = state['email']
97
+ user_votes = state['user_votes']
98
+ pair_index = state['pair_index']
99
+ left_video_id = state['left_video_id']
100
+ right_video_id = state['right_video_id']
101
+ video1_id = state['video1_id']
102
+ video2_id = state['video2_id']
103
+
104
+ # Save the user's responses
105
+ print(left_video_id, right_video_id, responses)
106
+ save_vote(email, video1_id, video2_id, left_video_id, right_video_id, responses)
107
+
108
+ # Update state
109
+ pair_index += 1
110
+ state['pair_index'] = pair_index
111
+
112
+ # Update user_votes in state
113
+ pair_key = f"{video1_id}_{video2_id}"
114
+ user_votes.add(pair_key)
115
+ state['user_votes'] = user_votes
116
+
117
+ video1_url, video2_url = get_video_pair(state)
118
+ if video1_url is None:
119
+ # No more pairs
120
+ output_message = "Thank you for participating! No more videos."
121
+ return (
122
+ gr.update(visible=False), # video_row
123
+ gr.update(visible=False), # question_column
124
+ gr.update(visible=False), # button_row
125
+ output_message, # output
126
+ gr.update(value=None), # q1
127
+ gr.update(value=None), # q2
128
+ gr.update(value=None), # q3
129
+ gr.update(interactive=False), # next_btn
130
+ state
131
+ )
132
+ else:
133
+ video1_html = generate_video_html(video1_url)
134
+ video2_html = generate_video_html(video2_url)
135
+ # Update videos and reset questions
136
+ return (
137
+ gr.update(visible=True, value=[
138
+ gr.update(value=video1_html),
139
+ gr.update(value=video2_html)
140
+ ]), # video_row
141
+ gr.update(visible=True), # question_column
142
+ gr.update(visible=True), # button_row
143
+ "", # output
144
+ gr.update(value=None), # q1
145
+ gr.update(value=None), # q2
146
+ gr.update(value=None), # q3
147
+ gr.update(interactive=False), # next_btn
148
+ state
149
+ )
150
+
151
+ def skip_pair(state):
152
+ pair_index = state['pair_index']
153
+
154
+ # Update state
155
+ pair_index += 1
156
+ state['pair_index'] = pair_index
157
+
158
+ video1_url, video2_url = get_video_pair(state)
159
+ if video1_url is None:
160
+ # No more pairs
161
+ output_message = "Thank you for participating! No more videos."
162
+ return (
163
+ gr.update(visible=False), # video_row
164
+ gr.update(visible=False), # question_column
165
+ gr.update(visible=False), # button_row
166
+ output_message, # output
167
+ gr.update(value=None), # q1
168
+ gr.update(value=None), # q2
169
+ gr.update(value=None), # q3
170
+ gr.update(interactive=False), # next_btn
171
+ state
172
+ )
173
+ else:
174
+ video1_html = generate_video_html(video1_url)
175
+ video2_html = generate_video_html(video2_url)
176
+ # Update videos and reset questions
177
+ return (
178
+ gr.update(visible=True, value=[
179
+ gr.update(value=video1_html),
180
+ gr.update(value=video2_html)
181
+ ]), # video_row
182
+ gr.update(visible=True), # question_column
183
+ gr.update(visible=True), # button_row
184
+ "You chose to skip this pair.", # output
185
+ gr.update(value=None), # q1
186
+ gr.update(value=None), # q2
187
+ gr.update(value=None), # q3
188
+ gr.update(interactive=False), # next_btn
189
+ state
190
+ )
191
+
192
+ def check_all_answers(visual_quality, temporal_consistency, realistic_dynamics):
193
+ if visual_quality and temporal_consistency and realistic_dynamics:
194
+ return gr.update(interactive=True)
195
+ else:
196
+ return gr.update(interactive=False)
197
+
198
+ def is_valid_email(email):
199
+ regex = r'^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$'
200
+ return re.match(regex, email)
201
+
202
+ def authenticate_user(email, state):
203
+ email = email.strip()
204
+ if not email or not is_valid_email(email):
205
+ return (
206
+ gr.update(), # email_input (remains visible)
207
+ "Please enter a valid email.", # email_output
208
+ gr.update(visible=False), # video_row
209
+ gr.update(visible=False), # question_column
210
+ gr.update(visible=False), # button_row
211
+ "", # output
212
+ state
213
+ )
214
+ else:
215
+ # Initialize user state
216
+ user_ref = db.collection('users').document(email)
217
+ user_doc = user_ref.get()
218
+ if user_doc.exists:
219
+ user_votes = set(user_doc.to_dict().get('votes', []))
220
+ else:
221
+ user_votes = set()
222
+
223
+ # Shuffle video pairs for this user
224
+ shuffled_pairs = video_pairs.copy()
225
+ random.shuffle(shuffled_pairs)
226
+
227
+ state.update({
228
+ 'email': email,
229
+ 'user_votes': user_votes,
230
+ 'pair_index': 0,
231
+ 'shuffled_pairs': shuffled_pairs
232
+ })
233
+
234
+ # Load the first pair
235
+ video1_url, video2_url = get_video_pair(state)
236
+ if video1_url is None:
237
+ output_message = "No new videos available for you."
238
+ return (
239
+ gr.update(), # email_input
240
+ "", # email_output
241
+ gr.update(visible=False), # video_row
242
+ gr.update(visible=False), # question_column
243
+ gr.update(visible=False), # button_row
244
+ output_message, # output
245
+ state
246
+ )
247
+ else:
248
+ video1_html = generate_video_html(video1_url)
249
+ video2_html = generate_video_html(video2_url)
250
+ return (
251
+ gr.update(visible=False), # email_input
252
+ "", # email_output
253
+ gr.update(visible=True, value=[
254
+ gr.update(value=video1_html),
255
+ gr.update(value=video2_html)
256
+ ]), # video_row
257
+ gr.update(visible=True), # question_column
258
+ gr.update(visible=True), # button_row
259
+ "", # output
260
+ state
261
+ )
262
+
263
+ with gr.Blocks() as demo:
264
+ state = gr.State(value={})
265
+
266
+ # Email Input
267
+ email_input = gr.Textbox(label="Enter your email to begin:", placeholder="[email protected]", type="text")
268
+ submit_email = gr.Button("Submit")
269
+ email_output = gr.Markdown()
270
+
271
+ # Video components (initially hidden)
272
+ with gr.Row(visible=False) as video_row:
273
+ with gr.Column():
274
+ gr.Markdown("### Left Video")
275
+ video1 = gr.HTML()
276
+ with gr.Column():
277
+ gr.Markdown("### Right Video")
278
+ video2 = gr.HTML()
279
+
280
+ # Questions (initially hidden)
281
+ with gr.Column(visible=False) as question_column:
282
+ gr.Markdown("## Please answer the following questions:")
283
+ q1 = gr.Radio(
284
+ choices=["Video 1", "Video 2"],
285
+ label="1. Which video has higher visual quality?",
286
+ type="value"
287
+ )
288
+ q2 = gr.Radio(
289
+ choices=["Video 1", "Video 2"],
290
+ label="2. Which video has better temporal consistency?",
291
+ type="value"
292
+ )
293
+ q3 = gr.Radio(
294
+ choices=["Video 1", "Video 2"],
295
+ label="3. Which video has more realistic dynamics?",
296
+ type="value"
297
+ )
298
+
299
+ # Buttons (initially hidden)
300
+ with gr.Row(visible=False) as button_row:
301
+ next_btn = gr.Button("Next", interactive=False)
302
+ skip_btn = gr.Button("Skip")
303
+
304
+ output = gr.Markdown()
305
+
306
+ def on_next(visual_quality, temporal_consistency, realistic_dynamics, state):
307
+ responses = {
308
+ 'visual_quality': visual_quality,
309
+ 'temporal_consistency': temporal_consistency,
310
+ 'realistic_dynamics': realistic_dynamics
311
+ }
312
+ return update_interface(responses, state)
313
+
314
+ next_btn.click(
315
+ fn=on_next,
316
+ inputs=[q1, q2, q3, state],
317
+ outputs=[
318
+ video_row, # Update video_row
319
+ question_column, # Update question_column
320
+ button_row, # Update button_row
321
+ output, # Update output message
322
+ q1, q2, q3, # Reset questions
323
+ next_btn, # Update next_btn
324
+ state
325
+ ]
326
+ )
327
+
328
+ skip_btn.click(
329
+ fn=skip_pair,
330
+ inputs=state,
331
+ outputs=[
332
+ video_row, # Update video_row
333
+ question_column, # Update question_column
334
+ button_row, # Update button_row
335
+ output, # Update output message
336
+ q1, q2, q3, # Reset questions
337
+ next_btn, # Update next_btn
338
+ state
339
+ ]
340
+ )
341
+
342
+ def on_change(visual_quality, temporal_consistency, realistic_dynamics):
343
+ return check_all_answers(visual_quality, temporal_consistency, realistic_dynamics)
344
+
345
+ q1.change(
346
+ fn=on_change,
347
+ inputs=[q1, q2, q3],
348
+ outputs=next_btn
349
+ )
350
+ q2.change(
351
+ fn=on_change,
352
+ inputs=[q1, q2, q3],
353
+ outputs=next_btn
354
+ )
355
+ q3.change(
356
+ fn=on_change,
357
+ inputs=[q1, q2, q3],
358
+ outputs=next_btn
359
+ )
360
+
361
+ submit_email.click(
362
+ fn=authenticate_user,
363
+ inputs=[email_input, state],
364
+ outputs=[
365
+ email_input, # Hide email_input after submission
366
+ email_output, # Clear email_output
367
+ video_row, # Show video_row
368
+ question_column, # Show question_column
369
+ button_row, # Show button_row
370
+ output, # Clear output message
371
+ state
372
+ ]
373
+ )
374
+
375
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ gradio
2
+ firebase-admin