File size: 12,902 Bytes
2ba821f
 
 
 
 
 
 
 
 
4638e06
74020c7
2ba821f
 
 
e4e90a2
249560c
 
2ba821f
 
 
 
 
4638e06
2ba821f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8869bc8
920e3a0
2ba821f
 
 
 
 
 
e4e90a2
74020c7
e4e90a2
2ba821f
 
 
74020c7
2ba821f
74020c7
 
 
 
 
 
2ba821f
 
74020c7
 
2ba821f
 
 
 
 
 
 
920e3a0
2ba821f
74020c7
2ba821f
74020c7
2ba821f
74020c7
 
 
 
b5dbf16
 
2ba821f
 
 
 
 
 
 
 
 
74020c7
2ba821f
 
 
 
 
 
 
 
 
74020c7
 
 
2ba821f
 
74020c7
2ba821f
 
 
 
 
 
74020c7
2ba821f
 
 
 
 
 
 
 
74020c7
 
4638e06
 
e4e90a2
2ba821f
 
 
 
 
 
 
 
 
 
 
e4e90a2
2ba821f
 
74020c7
 
4638e06
 
e4e90a2
4638e06
 
 
 
 
2ba821f
 
 
 
b5dbf16
 
2ba821f
 
 
 
 
 
 
 
 
 
 
 
 
e88f4b9
2ba821f
74020c7
 
4638e06
 
e4e90a2
2ba821f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e88f4b9
 
2ba821f
74020c7
 
4638e06
 
e4e90a2
2ba821f
 
 
 
 
 
 
 
e4e90a2
2ba821f
 
e88f4b9
2ba821f
74020c7
 
4638e06
 
e4e90a2
2ba821f
 
 
 
 
 
 
 
 
74020c7
 
e4e90a2
 
 
 
249560c
febbf71
e4e90a2
74020c7
 
 
2ba821f
 
 
 
 
 
e4e90a2
 
 
 
74020c7
e4e90a2
 
 
 
 
 
 
 
2ba821f
 
 
 
 
74020c7
e4e90a2
2ba821f
 
 
74020c7
e4e90a2
2ba821f
 
 
 
 
 
e88f4b9
2ba821f
 
 
b5dbf16
2ba821f
b5dbf16
 
2ba821f
 
 
 
 
b5dbf16
2ba821f
74020c7
 
4638e06
 
e4e90a2
2ba821f
 
 
b5dbf16
2ba821f
 
 
 
 
b5dbf16
 
2ba821f
 
 
b5dbf16
2ba821f
 
 
 
b5dbf16
2ba821f
 
 
 
 
 
 
e88f4b9
 
 
74020c7
 
4638e06
 
e4e90a2
e88f4b9
 
 
2ba821f
 
 
 
 
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
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
import gradio as gr
import random
import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore
import uuid
import json
import os
from dotenv import load_dotenv
import re
import pandas as pd

load_dotenv()

video_pairs = pd.read_csv('file_pairs.csv')[['file_name', 'vista_id', 'gem_id', 'rgb_id']].values.tolist()
random.seed(42)
random.shuffle(video_pairs)

my_credentials = {
    "type": "service_account",
    "project_id": "human-eval-c4f83",
    "private_key_id": os.environ.get("PRIVATE_KEY_ID"),
    "private_key": os.environ.get("PRIVATE_KEY").replace(r'\n', '\n'),
    "client_email": os.environ.get("CLIENT_EMAIL"),
    "client_id": os.environ.get("CLIENT_ID"),
    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
    "token_uri": "https://oauth2.googleapis.com/token",
    "auth_provider_x509_cert_url": os.environ.get("AUTH_PROVIDER_X509_CERT_URL"),
    "client_x509_cert_url": os.environ.get("CLIENT_X509_CERT_URL")
}

# Initialize Firebase
if not firebase_admin._apps:
    cred = credentials.Certificate(my_credentials)
    firebase_admin.initialize_app(cred)
db = firestore.client()


def get_embed_link(file_id):
    link = f"https://player.vimeo.com/video/{file_id}?title=0&byline=0&portrait=0&sidedock=0&badge=0&autopause=0&player_id=0&app_id=58479&quality=540p"
    return link

def get_video_pair(state):
    pair_index = state['pair_index']
    shuffled_pairs = state['shuffled_pairs']
    user_votes = state['user_votes']
    while pair_index < len(shuffled_pairs):
        video_name, vista_id, gem_id, rgb_id = shuffled_pairs[pair_index]
        pair_key = f"{vista_id}_{gem_id}"
        state['rgb_id'] = rgb_id
        if pair_key not in user_votes:
            # Randomize left-right positions
            if random.choice([True, False]):
                video1_id, video2_id = vista_id, gem_id
            else:
                video1_id, video2_id = gem_id, vista_id
            left_video_url = get_embed_link(video1_id)
            right_video_url = get_embed_link(video2_id)
            state['video_name'] = video_name
            state['left_video_url'] = left_video_url
            state['right_video_url'] = right_video_url
            state['video1_id'] = video1_id
            state['video2_id'] = video2_id
            state['vista_id'] = vista_id
            state['gem_id'] = gem_id
            return left_video_url, right_video_url
        else:
            pair_index += 1
            state['pair_index'] = pair_index
    return None, None  # No more pairs

def generate_video_html(url):
    return f'<div style="padding:56.25% 0 0 0;position:relative;"><iframe src="{url}" frameborder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write" style="position:absolute;top:0;left:0;width:100%;height:100%;" title="GenericTitle"></iframe></div><script src="https://player.vimeo.com/api/player.js"></script>'

def save_vote(video_name, email, vista_id, gem_id, video1_id, video2_id, responses):
    vote_data = {
        'video_name': video_name,
        'email': email,
        'vista_id': vista_id,
        'gem_id': gem_id,
        'video1_id': video1_id,
        'video2_id': video2_id,
        'q1': responses['q1'],
        'q2': responses['q2'],
    }
    db.collection('votes').add(vote_data)
    # Update user's vote history
    user_ref = db.collection('users').document(email)
    user_doc = user_ref.get()
    if user_doc.exists:
        user_votes = set(user_doc.to_dict().get('votes', []))
    else:
        user_votes = set()
    pair_key = f"{vista_id}_{gem_id}"
    user_votes.add(pair_key)
    user_ref.set({'votes': list(user_votes)}, merge=True)

def update_interface(responses, state):
    email = state['email']
    user_votes = state['user_votes']
    pair_index = state['pair_index']
    video1_id = state['video1_id']
    video2_id = state['video2_id']
    vista_id = state['vista_id']
    gem_id = state['gem_id']
    video_name = state['video_name']

    # Save the user's responses
    save_vote(video_name, email, vista_id, gem_id, video1_id, video2_id, responses)

    # Update state
    pair_index += 1
    state['pair_index'] = pair_index

    # Update user_votes in state
    pair_key = f"{vista_id}_{gem_id}"
    user_votes.add(pair_key)
    state['user_votes'] = user_votes

    video1_url, video2_url = get_video_pair(state)
    if video1_url is None:
        # No more pairs
        output_message = "Thank you for participating! No more videos."
        return (
            gr.update(visible=False),  # video_column
            gr.update(visible=False),  # video_column
            gr.update(value=""),       # video1
            gr.update(value=""),       # video2
            gr.update(value=""),       # rgb_video
            gr.update(visible=False),  # question_column
            gr.update(visible=False),  # button_row
            output_message,            # output
            gr.update(value=None),     # q1
            gr.update(value=None),     # q2
            gr.update(interactive=False),  # next_btn
            state
        )
    else:
        video1_html = generate_video_html(video1_url)
        video2_html = generate_video_html(video2_url)
        rgb_html = generate_video_html(get_embed_link(state['rgb_id']))
        # Update videos and reset questions
        return (
            gr.update(visible=True),   # video_column
            gr.update(visible=True),   # video_column
            gr.update(value=video1_html),  # video1
            gr.update(value=video2_html),  # video2
            gr.update(value=rgb_html),       # rgb_video
            gr.update(visible=True),   # question_column
            gr.update(visible=True),   # button_row
            "",                        # output
            gr.update(value=None),     # q1
            gr.update(value=None),     # q2
            gr.update(interactive=False),  # next_btn
            state
        )

def check_all_answers(q1, q2):
    if q1 and q2:
        return gr.update(interactive=True)
    else:
        return gr.update(interactive=False)

def is_valid_email(email):
    regex = r'^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$'
    return re.match(regex, email)

def authenticate_user(email, state):
    email = email.strip()
    if not email or not is_valid_email(email):
        return (
            gr.update(),            # email_input (remains visible)
            gr.update(),            # submit_email (remains visible)
            "Please enter a valid email.",  # email_output
            gr.update(visible=False),  # video_column
            gr.update(visible=False),  # video_column
            gr.update(value=""),       # video1
            gr.update(value=""),       # video2
            gr.update(value=""),       # rgb_video
            gr.update(visible=False),  # question_column
            gr.update(visible=False),  # button_row
            "",                      # output
            state
        )
    else:
        # Initialize user state
        user_ref = db.collection('users').document(email)
        user_doc = user_ref.get()
        if user_doc.exists:
            user_votes = set(user_doc.to_dict().get('votes', []))
        else:
            user_votes = set()

        # Shuffle video pairs for this user
        shuffled_pairs = video_pairs.copy()

        state.update({
            'email': email,
            'user_votes': user_votes,
            'pair_index': 0,
            'shuffled_pairs': shuffled_pairs
        })

        # Load the first pair
        video1_url, video2_url = get_video_pair(state)
        if video1_url is None:
            output_message = "No new videos available for you."
            return (
                gr.update(visible=False),  # email_input
                gr.update(visible=False),  # submit_email
                "",                     # email_output
                gr.update(visible=False),  # video_column
                gr.update(visible=False),  # video_column
                gr.update(value=""),       # video1
                gr.update(value=""),       # video2
                gr.update(value=""),       # rgb_video
                gr.update(visible=False),  # question_column
                gr.update(visible=False),  # button_row
                output_message,         # output
                state
            )
        else:
            video1_html = generate_video_html(video1_url)
            video2_html = generate_video_html(video2_url)
            rgb_html = generate_video_html(get_embed_link(state['rgb_id']))
            return (
                gr.update(visible=False),  # email_input
                gr.update(visible=False),  # submit_email
                "",                        # email_output
                gr.update(visible=True),   # video_column
                gr.update(visible=True),   # video_column
                gr.update(value=video1_html),  # video1
                gr.update(value=video2_html),  # video2
                gr.update(value=rgb_html),       # rgb_video
                gr.update(visible=True),    # question_column
                gr.update(visible=True),    # button_row
                "",                         # output
                state
            )

with gr.Blocks() as demo:
    state = gr.State(value={})

    gr.Markdown(
        """
        You'll be seeing three videos per question.
        At the top, you'll see a video with the RGB view.
        Below, you'll see two depth videos.
        You'll be asked to select which depth video seems to be better quality with respect to the RGB video.

        **There are 30 videos in total.**
        **Avoid "No preference" answers as much as possible.**
        """
    )

    # Email Input
    email_input = gr.Textbox(label="Enter your email to begin:", placeholder="your.email@example.com", type="text")
    submit_email = gr.Button("Submit")
    email_output = gr.Markdown()

    # Video components (initially hidden)
    with gr.Column():
        with gr.Column() as video1_column:
            gr.Markdown("### RGB Video")
            rgb_video = gr.HTML()

        with gr.Row():
            with gr.Column(visible=False) as video1_column:
                gr.Markdown("### Video 1")
                video1 = gr.HTML()

            with gr.Column(visible=False) as video2_column:
                gr.Markdown("### Video 2")
                video2 = gr.HTML()

    # Questions (initially hidden)
    with gr.Column(visible=False) as question_column:
        gr.Markdown("## Please answer the following questions:")
        q1 = gr.Radio(
            choices=["Video 1", "Video 2", "No preference"],
            label="1. Which depth video is more aligned with RGB?",
            type="value"
        )
        q2 = gr.Radio(
            choices=["Video 1", "Video 2", "No preference"],
            label="2. Which depth video is more consistent and has less flickering?",
            type="value"
        )

    # Buttons (initially hidden)
    with gr.Row(visible=False) as button_row:
        next_btn = gr.Button("Next", interactive=False)
        # skip_btn = gr.Button("Skip")  # Commented out if not used

    output = gr.Markdown()

    def on_next(q1, q2, state):
        responses = {
            'q1': q1,
            'q2': q2,
        }
        return update_interface(responses, state)

    next_btn.click(
        fn=on_next,
        inputs=[q1, q2, state],
        outputs=[
            video1_column,        # Update video_column
            video2_column,        # Update video_column
            video1,           # Update video1
            video2,           # Update video2
            rgb_video,
            question_column,  # Update question_column
            button_row,       # Update button_row
            output,           # Update output message
            q1, q2,       # Reset questions
            next_btn,         # Update next_btn
            state
        ]
    )

    def on_change(q1, q2):
        return check_all_answers(q1, q2)

    q1.change(
        fn=on_change,
        inputs=[q1, q2],
        outputs=next_btn
    )
    q2.change(
        fn=on_change,
        inputs=[q1, q2],
        outputs=next_btn
    )

    submit_email.click(
        fn=authenticate_user,
        inputs=[email_input, state],
        outputs=[
            email_input,      # Update email_input
            submit_email,     # Update submit_email
            email_output,     # Update email_output
            video1_column,    # Update video_column
            video2_column,    # Update video_column
            video1,           # Update video1
            video2,           # Update video2
            rgb_video,
            question_column,  # Update question_column
            button_row,       # Update button_row
            output,           # Update output message
            state
        ]
    )

demo.launch()