luulinh90s commited on
Commit
ff51625
Β·
1 Parent(s): 1498fe3
Files changed (3) hide show
  1. app.py +69 -191
  2. templates/experiment.html +42 -4
  3. templates/index.html +15 -0
app.py CHANGED
@@ -5,17 +5,8 @@ import os
5
  import string
6
  import logging
7
  from datetime import datetime
8
-
9
-
10
- import os
11
- from huggingface_hub import login
12
-
13
- # Use the Hugging Face token from environment variables
14
- hf_token = os.environ.get("HF_TOKEN")
15
- if hf_token:
16
- login(token=hf_token)
17
- else:
18
- logger.error("HF_TOKEN not found in environment variables")
19
 
20
  # Set up logging
21
  logging.basicConfig(level=logging.INFO,
@@ -26,64 +17,37 @@ logging.basicConfig(level=logging.INFO,
26
  ])
27
  logger = logging.getLogger(__name__)
28
 
 
 
 
 
 
 
 
29
  app = Flask(__name__)
30
  app.config['SECRET_KEY'] = 'supersecretkey' # Change this to a random secret key
31
 
32
  # Directories for visualizations
33
- VISUALIZATION_DIRS_PLAN_OF_SQLS = {
34
- "TP": "htmls_POS/TP",
35
- "TN": "htmls_POS/TN",
36
- "FP": "htmls_POS/FP",
37
- "FN": "htmls_POS/FN"
38
  }
39
 
40
- VISUALIZATION_DIRS_CHAIN_OF_TABLE = {
41
- "TP": "htmls_COT/TP",
42
- "TN": "htmls_COT/TN",
43
- "FP": "htmls_COT/FP",
44
- "FN": "htmls_COT/FN"
45
- }
46
 
47
- VISUALIZATION_DIRS_NO_XAI = {
48
- "TP": "htmls_NO_XAI/TP",
49
- "TN": "htmls_NO_XAI/TN",
50
- "FP": "htmls_NO_XAI/FP",
51
- "FN": "htmls_NO_XAI/FN"
52
- }
53
 
54
- VISUALIZATION_DIRS_DATER = {
55
- "TP": "htmls_DATER/TP",
56
- "TN": "htmls_DATER/TN",
57
- "FP": "htmls_DATER/FP",
58
- "FN": "htmls_DATER/FN"
59
- }
60
 
61
- import json
62
- import os
63
- from datetime import datetime
64
-
65
- from huggingface_hub import HfApi
66
- def save_session_data(username, data):
67
  try:
68
- # Extract seed and start_time from the data
69
- seed = data.get('seed', 'unknown')
70
- start_time = data.get('start_time', datetime.now().isoformat())
71
-
72
- # Create a filename with username, seed, and start_time
73
- file_name = f'{username}_seed{seed}_{start_time}_session.json'
74
-
75
- # Remove any characters that might not be safe for filenames
76
- file_name = "".join(c for c in file_name if c.isalnum() or c in ['_', '-', '.'])
77
-
78
- # Convert data to JSON string
79
  json_data = json.dumps(data, indent=4)
80
-
81
- # Create a temporary file
82
  temp_file_path = f"/tmp/{file_name}"
83
  with open(temp_file_path, 'w') as f:
84
  f.write(json_data)
85
 
86
- # Upload the file to the Hugging Face Space, overwriting if it exists
87
  api = HfApi()
88
  api.upload_file(
89
  path_or_fileobj=temp_file_path,
@@ -92,198 +56,140 @@ def save_session_data(username, data):
92
  repo_type="space",
93
  )
94
 
95
- # Remove the temporary file
96
  os.remove(temp_file_path)
97
-
98
- logger.info(f"Session data saved for user {username} with seed {seed} and start time {start_time} in Hugging Face Data Space")
99
  except Exception as e:
100
- logger.exception(f"Error saving session data for user {username}: {e}")
101
 
102
- from huggingface_hub import hf_hub_download, HfApi
103
 
104
- def load_session_data(username):
105
  try:
106
- # List all files in the repo
107
- api = HfApi()
108
- files = api.list_repo_files(repo_id="luulinh90s/Tabular-LLM-Study-Data", repo_type="space")
109
-
110
- # Filter files for the user
111
- user_files = [f for f in files if f.startswith(f'session_data_pref/{username}_')]
112
-
113
- if not user_files:
114
- logger.warning(f"No session data found for user {username}")
115
- return None
116
-
117
- # Get the most recent file
118
- latest_file = sorted(user_files, reverse=True)[0]
119
-
120
- # Download the file from the data storage Space
121
- file_path = hf_hub_download(repo_id="luulinh90s/Tabular-LLM-Study-Data", repo_type="space",
122
- filename=latest_file)
123
 
124
  with open(file_path, 'r') as f:
125
  data = json.load(f)
126
 
127
- logger.info(f"Session data loaded for user {username} from Hugging Face Data Space")
128
  return data
129
  except Exception as e:
130
- logger.exception(f"Error loading session data for user {username}: {e}")
131
  return None
132
 
 
133
  def load_samples(methods):
134
  logger.info(f"Loading samples for methods: {methods}")
135
- samples = set() # Use a set to avoid duplicates
136
  categories = ["TP", "TN", "FP", "FN"]
137
 
138
- method_dirs = [get_method_dir(method) for method in methods]
139
-
140
  for category in categories:
141
- dir_a = f'htmls_{method_dirs[0].upper()}/{category}'
142
- dir_b = f'htmls_{method_dirs[1].upper()}/{category}'
143
-
144
- files_a = set(os.listdir(dir_a))
145
- files_b = set(os.listdir(dir_b))
146
-
147
  matching_files = files_a & files_b
148
-
149
  for file in matching_files:
150
  samples.add((category, file))
151
 
152
- # Convert set of tuples back to list of dictionaries
153
  samples = [{'category': category, 'file': file} for category, file in samples]
154
-
155
  logger.info(f"Loaded {len(samples)} unique samples across all categories")
156
  return samples
157
 
 
158
  def select_balanced_samples(samples):
159
  try:
160
- # Ensure we have at least 10 unique samples
161
  unique_samples = list({(s['category'], s['file']) for s in samples})
162
-
163
  if len(unique_samples) < 10:
164
  logger.warning(f"Not enough unique samples. Only {len(unique_samples)} available.")
165
  selected_samples = unique_samples
166
  else:
167
  selected_samples = random.sample(unique_samples, 10)
168
 
169
- logger.info(f"Unique sampled samples:\n{selected_samples}")
170
-
171
- # Convert back to dictionary format
172
  selected_samples = [{'category': category, 'file': file} for category, file in selected_samples]
173
-
174
  logger.info(f"Selected {len(selected_samples)} unique samples")
175
  return selected_samples
176
  except Exception as e:
177
  logger.exception("Error selecting balanced samples")
178
  return []
179
 
180
- def generate_random_string(length=8):
181
- return ''.join(random.choices(string.ascii_letters + string.digits, k=length))
182
 
183
  @app.route('/', methods=['GET', 'POST'])
184
  def index():
185
- logger.info("Rendering index page.")
186
  if request.method == 'POST':
187
  username = request.form.get('username')
188
  seed = request.form.get('seed')
189
  methods = request.form.get('method').split(',')
190
 
191
  if not username or not seed or len(methods) != 2:
192
- logger.error("Missing username, seed, or incorrect number of methods.")
193
  return "Please fill in all fields and select exactly two methods.", 400
194
 
195
  try:
196
- seed_int = int(seed) # Convert to int for random.seed()
197
  random.seed(seed_int)
198
  all_samples = load_samples(methods)
199
  selected_samples = select_balanced_samples(all_samples)
200
- logger.info(f"Number of selected samples: {len(selected_samples)}")
201
 
202
  if len(selected_samples) == 0:
203
- logger.error("No samples were selected.")
204
  return "No samples were selected", 500
205
 
 
206
  start_time = datetime.now().isoformat()
207
  session_data = {
 
208
  'username': username,
209
- 'seed': seed, # Store as string
210
  'methods': methods,
211
  'selected_samples': selected_samples,
212
  'current_index': 0,
213
  'responses': [],
214
  'start_time': start_time
215
  }
216
- save_session_data(username, session_data)
217
- logger.info(f"Session data initialized for user: {username}")
218
 
219
- return redirect(url_for('experiment', username=username))
220
  except Exception as e:
221
  logger.exception(f"Error in index route: {e}")
222
  return "An error occurred", 500
223
  return render_template('index.html')
224
 
225
- @app.route('/experiment/<username>', methods=['GET', 'POST'])
226
- def experiment(username):
 
227
  try:
228
- session_data = load_session_data(username)
229
  if not session_data:
230
- logger.error(f"No session data found for user: {username}")
231
  return redirect(url_for('index'))
232
 
233
-
234
- logger.info(f"Session data:\n{session_data}")
235
-
236
  selected_samples = session_data['selected_samples']
237
  methods = session_data['methods']
238
  current_index = session_data['current_index']
239
 
240
- logger.info(f"current_index:\n{current_index}")
241
-
242
  if current_index >= len(selected_samples):
243
- return redirect(url_for('completed', username=username))
244
 
245
  sample = selected_samples[current_index]
246
- logger.info(f"sample:\n{sample}")
247
-
248
  method_a, method_b = methods
249
 
250
- # Find matching files for both methods
251
-
252
- method_a_dir = get_method_dir(method_a)
253
- method_b_dir = get_method_dir(method_b)
254
 
255
- # for category in ['TP', 'TN', 'FP', 'FN']:
256
- category = sample['category']
257
- dir_a = f'htmls_{method_a_dir.upper()}/{category}'
258
- dir_b = f'htmls_{method_b_dir.upper()}/{category}'
259
-
260
- file_a = os.path.join(dir_a, sample['file'])
261
- file_b = os.path.join(dir_b, sample['file'])
262
- logger.info(f"file_a:\n{file_a}")
263
- logger.info(f"file_b:\n{file_a}")
264
-
265
- # files_a = os.listdir(dir_a)
266
- # files_b = os.listdir(dir_b)
267
- #
268
- # matching_files = set(files_a) & set(files_b)
269
- # if matching_files:
270
- # file_a = os.path.join(dir_a, next(iter(matching_files)))
271
- # file_b = os.path.join(dir_b, next(iter(matching_files)))
272
- # break
273
-
274
- if not file_a or not file_b:
275
  logger.error(f"Missing files for comparison at index {current_index}")
276
  session_data['current_index'] += 1
277
- save_session_data(username, session_data)
278
- return redirect(url_for('experiment', username=username))
279
 
280
  visualization_a = url_for('send_visualization', filename=file_a)
281
  visualization_b = url_for('send_visualization', filename=file_b)
282
 
283
  statement = """
284
- Please note that in select row function, starting index is 0 for Chain-of-Table 1 for Dater and Index * represents the selection of the whole Table.
285
- You are now given two explanations that describe the reasoning process of the Table QA model.
286
- Please analyze the explanations and determine which one provides a clearer and more accurate reasoning process.
287
  """
288
 
289
  return render_template('experiment.html',
@@ -293,76 +199,51 @@ Please analyze the explanations and determine which one provides a clearer and m
293
  visualization_b=visualization_b,
294
  method_a=method_a,
295
  method_b=method_b,
296
- username=username)
297
  except Exception as e:
298
  logger.exception(f"An error occurred in the experiment route: {e}")
299
  return "An error occurred", 500
300
 
301
- def get_method_dir(method):
302
- if method == 'No-XAI':
303
- return 'NO_XAI'
304
- elif method == 'Dater':
305
- return 'DATER'
306
- elif method == 'Chain-of-Table':
307
- return 'COT'
308
- elif method == 'Plan-of-SQLs':
309
- return 'POS'
310
-
311
- def get_visualization_dir(method):
312
- if method == "No-XAI":
313
- return 'htmls_NO_XAI'
314
- elif method == "Dater":
315
- return 'htmls_DATER'
316
- elif method == "Chain-of-Table":
317
- return 'htmls_COT'
318
- else: # Plan-of-SQLs
319
- return 'htmls_POS'
320
-
321
 
322
  @app.route('/feedback', methods=['POST'])
323
  def feedback():
324
  try:
325
- username = request.form['username']
326
  feedback = request.form['feedback']
327
 
328
- session_data = load_session_data(username)
329
  if not session_data:
330
- logger.error(f"No session data found for user: {username}")
331
  return redirect(url_for('index'))
332
 
333
- # Store the feedback
334
  session_data['responses'].append({
335
  'sample_id': session_data['current_index'],
336
  'preferred_method': feedback,
337
  'timestamp': datetime.now().isoformat()
338
  })
339
 
340
- # Move to the next sample
341
  session_data['current_index'] += 1
342
-
343
- # Save updated session data
344
- save_session_data(username, session_data)
345
- logger.info(f"Feedback saved for user {username}, sample {session_data['current_index'] - 1}")
346
 
347
  if session_data['current_index'] >= len(session_data['selected_samples']):
348
- return redirect(url_for('completed', username=username))
349
 
350
- return redirect(url_for('experiment', username=username))
351
  except Exception as e:
352
  logger.exception(f"Error in feedback route: {e}")
353
  return "An error occurred", 500
354
 
355
 
356
- @app.route('/completed/<username>')
357
- def completed(username):
358
  try:
359
- session_data = load_session_data(username)
360
  if not session_data:
361
- logger.error(f"No session data found for user: {username}")
362
  return redirect(url_for('index'))
363
 
364
  session_data['end_time'] = datetime.now().isoformat()
365
-
366
  methods = session_data['methods']
367
  responses = session_data['responses']
368
 
@@ -377,9 +258,7 @@ def completed(username):
377
  preferences[method] = round((preferences[method] / total_responses) * 100, 2)
378
 
379
  session_data['preferences'] = preferences
380
-
381
- # Save the final updated session data
382
- save_session_data(username, session_data)
383
 
384
  return render_template('completed.html', preferences=preferences)
385
  except Exception as e:
@@ -390,7 +269,6 @@ def completed(username):
390
  @app.route('/visualizations/<path:filename>')
391
  def send_visualization(filename):
392
  logger.info(f"Attempting to serve file: {filename}")
393
- # Ensure the path is safe and doesn't allow access to files outside the intended directory
394
  base_dir = os.getcwd()
395
  file_path = os.path.normpath(os.path.join(base_dir, filename))
396
  if not file_path.startswith(base_dir):
@@ -406,5 +284,5 @@ def send_visualization(filename):
406
 
407
 
408
  if __name__ == "__main__":
409
- os.makedirs('session_data', exist_ok=True) # Ensure the directory for session files exists
410
  app.run(host="0.0.0.0", port=7860, debug=True)
 
5
  import string
6
  import logging
7
  from datetime import datetime
8
+ import uuid
9
+ from huggingface_hub import login, HfApi, hf_hub_download
 
 
 
 
 
 
 
 
 
10
 
11
  # Set up logging
12
  logging.basicConfig(level=logging.INFO,
 
17
  ])
18
  logger = logging.getLogger(__name__)
19
 
20
+ # Use the Hugging Face token from environment variables
21
+ hf_token = os.environ.get("HF_TOKEN")
22
+ if hf_token:
23
+ login(token=hf_token)
24
+ else:
25
+ logger.error("HF_TOKEN not found in environment variables")
26
+
27
  app = Flask(__name__)
28
  app.config['SECRET_KEY'] = 'supersecretkey' # Change this to a random secret key
29
 
30
  # Directories for visualizations
31
+ VISUALIZATION_DIRS = {
32
+ "No-XAI": "htmls_NO_XAI",
33
+ "Dater": "htmls_DATER",
34
+ "Chain-of-Table": "htmls_COT",
35
+ "Plan-of-SQLs": "htmls_POS"
36
  }
37
 
 
 
 
 
 
 
38
 
39
+ def generate_session_id():
40
+ return str(uuid.uuid4())
 
 
 
 
41
 
 
 
 
 
 
 
42
 
43
+ def save_session_data(session_id, data):
 
 
 
 
 
44
  try:
45
+ file_name = f'{session_id}_session.json'
 
 
 
 
 
 
 
 
 
 
46
  json_data = json.dumps(data, indent=4)
 
 
47
  temp_file_path = f"/tmp/{file_name}"
48
  with open(temp_file_path, 'w') as f:
49
  f.write(json_data)
50
 
 
51
  api = HfApi()
52
  api.upload_file(
53
  path_or_fileobj=temp_file_path,
 
56
  repo_type="space",
57
  )
58
 
 
59
  os.remove(temp_file_path)
60
+ logger.info(f"Session data saved for session ID {session_id} in Hugging Face Data Space")
 
61
  except Exception as e:
62
+ logger.exception(f"Error saving session data for session ID {session_id}: {e}")
63
 
 
64
 
65
+ def load_session_data(session_id):
66
  try:
67
+ file_name = f'{session_id}_session.json'
68
+ file_path = hf_hub_download(
69
+ repo_id="luulinh90s/Tabular-LLM-Study-Data",
70
+ repo_type="space",
71
+ filename=f"session_data_pref/{file_name}"
72
+ )
 
 
 
 
 
 
 
 
 
 
 
73
 
74
  with open(file_path, 'r') as f:
75
  data = json.load(f)
76
 
77
+ logger.info(f"Session data loaded for session ID {session_id} from Hugging Face Data Space")
78
  return data
79
  except Exception as e:
80
+ logger.exception(f"Error loading session data for session ID {session_id}: {e}")
81
  return None
82
 
83
+
84
  def load_samples(methods):
85
  logger.info(f"Loading samples for methods: {methods}")
86
+ samples = set()
87
  categories = ["TP", "TN", "FP", "FN"]
88
 
 
 
89
  for category in categories:
90
+ files_a = set(os.listdir(f'{VISUALIZATION_DIRS[methods[0]]}/{category}'))
91
+ files_b = set(os.listdir(f'{VISUALIZATION_DIRS[methods[1]]}/{category}'))
 
 
 
 
92
  matching_files = files_a & files_b
 
93
  for file in matching_files:
94
  samples.add((category, file))
95
 
 
96
  samples = [{'category': category, 'file': file} for category, file in samples]
 
97
  logger.info(f"Loaded {len(samples)} unique samples across all categories")
98
  return samples
99
 
100
+
101
  def select_balanced_samples(samples):
102
  try:
 
103
  unique_samples = list({(s['category'], s['file']) for s in samples})
 
104
  if len(unique_samples) < 10:
105
  logger.warning(f"Not enough unique samples. Only {len(unique_samples)} available.")
106
  selected_samples = unique_samples
107
  else:
108
  selected_samples = random.sample(unique_samples, 10)
109
 
 
 
 
110
  selected_samples = [{'category': category, 'file': file} for category, file in selected_samples]
 
111
  logger.info(f"Selected {len(selected_samples)} unique samples")
112
  return selected_samples
113
  except Exception as e:
114
  logger.exception("Error selecting balanced samples")
115
  return []
116
 
 
 
117
 
118
  @app.route('/', methods=['GET', 'POST'])
119
  def index():
 
120
  if request.method == 'POST':
121
  username = request.form.get('username')
122
  seed = request.form.get('seed')
123
  methods = request.form.get('method').split(',')
124
 
125
  if not username or not seed or len(methods) != 2:
 
126
  return "Please fill in all fields and select exactly two methods.", 400
127
 
128
  try:
129
+ seed_int = int(seed)
130
  random.seed(seed_int)
131
  all_samples = load_samples(methods)
132
  selected_samples = select_balanced_samples(all_samples)
 
133
 
134
  if len(selected_samples) == 0:
 
135
  return "No samples were selected", 500
136
 
137
+ session_id = generate_session_id()
138
  start_time = datetime.now().isoformat()
139
  session_data = {
140
+ 'session_id': session_id,
141
  'username': username,
142
+ 'seed': seed,
143
  'methods': methods,
144
  'selected_samples': selected_samples,
145
  'current_index': 0,
146
  'responses': [],
147
  'start_time': start_time
148
  }
149
+ save_session_data(session_id, session_data)
150
+ logger.info(f"New session initialized for user: {username}, session ID: {session_id}")
151
 
152
+ return redirect(url_for('experiment', session_id=session_id))
153
  except Exception as e:
154
  logger.exception(f"Error in index route: {e}")
155
  return "An error occurred", 500
156
  return render_template('index.html')
157
 
158
+
159
+ @app.route('/experiment/<session_id>', methods=['GET', 'POST'])
160
+ def experiment(session_id):
161
  try:
162
+ session_data = load_session_data(session_id)
163
  if not session_data:
164
+ logger.error(f"No session data found for session ID: {session_id}")
165
  return redirect(url_for('index'))
166
 
 
 
 
167
  selected_samples = session_data['selected_samples']
168
  methods = session_data['methods']
169
  current_index = session_data['current_index']
170
 
 
 
171
  if current_index >= len(selected_samples):
172
+ return redirect(url_for('completed', session_id=session_id))
173
 
174
  sample = selected_samples[current_index]
 
 
175
  method_a, method_b = methods
176
 
177
+ file_a = os.path.join(VISUALIZATION_DIRS[method_a], sample['category'], sample['file'])
178
+ file_b = os.path.join(VISUALIZATION_DIRS[method_b], sample['category'], sample['file'])
 
 
179
 
180
+ if not os.path.exists(file_a) or not os.path.exists(file_b):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181
  logger.error(f"Missing files for comparison at index {current_index}")
182
  session_data['current_index'] += 1
183
+ save_session_data(session_id, session_data)
184
+ return redirect(url_for('experiment', session_id=session_id))
185
 
186
  visualization_a = url_for('send_visualization', filename=file_a)
187
  visualization_b = url_for('send_visualization', filename=file_b)
188
 
189
  statement = """
190
+ Please note that in select row function, starting index is 0 for Chain-of-Table 1 for Dater and Index * represents the selection of the whole Table.
191
+ You are now given two explanations that describe the reasoning process of the Table QA model.
192
+ Please analyze the explanations and determine which one provides a clearer and more accurate reasoning process.
193
  """
194
 
195
  return render_template('experiment.html',
 
199
  visualization_b=visualization_b,
200
  method_a=method_a,
201
  method_b=method_b,
202
+ session_id=session_id)
203
  except Exception as e:
204
  logger.exception(f"An error occurred in the experiment route: {e}")
205
  return "An error occurred", 500
206
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
 
208
  @app.route('/feedback', methods=['POST'])
209
  def feedback():
210
  try:
211
+ session_id = request.form['session_id']
212
  feedback = request.form['feedback']
213
 
214
+ session_data = load_session_data(session_id)
215
  if not session_data:
216
+ logger.error(f"No session data found for session ID: {session_id}")
217
  return redirect(url_for('index'))
218
 
 
219
  session_data['responses'].append({
220
  'sample_id': session_data['current_index'],
221
  'preferred_method': feedback,
222
  'timestamp': datetime.now().isoformat()
223
  })
224
 
 
225
  session_data['current_index'] += 1
226
+ save_session_data(session_id, session_data)
227
+ logger.info(f"Feedback saved for session {session_id}, sample {session_data['current_index'] - 1}")
 
 
228
 
229
  if session_data['current_index'] >= len(session_data['selected_samples']):
230
+ return redirect(url_for('completed', session_id=session_id))
231
 
232
+ return redirect(url_for('experiment', session_id=session_id))
233
  except Exception as e:
234
  logger.exception(f"Error in feedback route: {e}")
235
  return "An error occurred", 500
236
 
237
 
238
+ @app.route('/completed/<session_id>')
239
+ def completed(session_id):
240
  try:
241
+ session_data = load_session_data(session_id)
242
  if not session_data:
243
+ logger.error(f"No session data found for session ID: {session_id}")
244
  return redirect(url_for('index'))
245
 
246
  session_data['end_time'] = datetime.now().isoformat()
 
247
  methods = session_data['methods']
248
  responses = session_data['responses']
249
 
 
258
  preferences[method] = round((preferences[method] / total_responses) * 100, 2)
259
 
260
  session_data['preferences'] = preferences
261
+ save_session_data(session_id, session_data)
 
 
262
 
263
  return render_template('completed.html', preferences=preferences)
264
  except Exception as e:
 
269
  @app.route('/visualizations/<path:filename>')
270
  def send_visualization(filename):
271
  logger.info(f"Attempting to serve file: {filename}")
 
272
  base_dir = os.getcwd()
273
  file_path = os.path.normpath(os.path.join(base_dir, filename))
274
  if not file_path.startswith(base_dir):
 
284
 
285
 
286
  if __name__ == "__main__":
287
+ os.makedirs('session_data', exist_ok=True)
288
  app.run(host="0.0.0.0", port=7860, debug=True)
templates/experiment.html CHANGED
@@ -95,6 +95,34 @@
95
  height: 100%;
96
  border: none;
97
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  </style>
99
  <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">
100
  </head>
@@ -116,15 +144,25 @@
116
  <p class="question-text">Which explanation provides a clearer and more accurate reasoning process?</p>
117
  </div>
118
  <div class="buttons">
119
- <form action="{{ url_for('feedback') }}" method="post" style="width: 48%;">
120
- <input type="hidden" name="username" value="{{ username }}">
121
  <button type="submit" name="feedback" value="{{ method_a }}">{{ method_a }}</button>
122
  </form>
123
- <form action="{{ url_for('feedback') }}" method="post" style="width: 48%;">
124
- <input type="hidden" name="username" value="{{ username }}">
125
  <button type="submit" name="feedback" value="{{ method_b }}">{{ method_b }}</button>
126
  </form>
127
  </div>
128
  </div>
 
 
 
 
 
 
 
 
 
 
129
  </body>
130
  </html>
 
95
  height: 100%;
96
  border: none;
97
  }
98
+ .loader {
99
+ border: 5px solid #f3f3f3;
100
+ border-top: 5px solid #3498db;
101
+ border-radius: 50%;
102
+ width: 50px;
103
+ height: 50px;
104
+ animation: spin 1s linear infinite;
105
+ position: fixed;
106
+ top: 50%;
107
+ left: 50%;
108
+ transform: translate(-50%, -50%);
109
+ display: none;
110
+ z-index: 1000;
111
+ }
112
+ @keyframes spin {
113
+ 0% { transform: translate(-50%, -50%) rotate(0deg); }
114
+ 100% { transform: translate(-50%, -50%) rotate(360deg); }
115
+ }
116
+ .overlay {
117
+ position: fixed;
118
+ top: 0;
119
+ left: 0;
120
+ width: 100%;
121
+ height: 100%;
122
+ background-color: rgba(0, 0, 0, 0.5);
123
+ display: none;
124
+ z-index: 999;
125
+ }
126
  </style>
127
  <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">
128
  </head>
 
144
  <p class="question-text">Which explanation provides a clearer and more accurate reasoning process?</p>
145
  </div>
146
  <div class="buttons">
147
+ <form action="{{ url_for('feedback') }}" method="post" style="width: 48%;" onsubmit="showLoader()">
148
+ <input type="hidden" name="session_id" value="{{ session_id }}">
149
  <button type="submit" name="feedback" value="{{ method_a }}">{{ method_a }}</button>
150
  </form>
151
+ <form action="{{ url_for('feedback') }}" method="post" style="width: 48%;" onsubmit="showLoader()">
152
+ <input type="hidden" name="session_id" value="{{ session_id }}">
153
  <button type="submit" name="feedback" value="{{ method_b }}">{{ method_b }}</button>
154
  </form>
155
  </div>
156
  </div>
157
+
158
+ <div class="overlay" id="overlay"></div>
159
+ <div class="loader" id="loader"></div>
160
+
161
+ <script>
162
+ function showLoader() {
163
+ document.getElementById('overlay').style.display = 'block';
164
+ document.getElementById('loader').style.display = 'block';
165
+ }
166
+ </script>
167
  </body>
168
  </html>
templates/index.html CHANGED
@@ -26,6 +26,14 @@
26
  font-size: 48px;
27
  margin-bottom: 30px;
28
  }
 
 
 
 
 
 
 
 
29
  label {
30
  display: block;
31
  margin: 20px 0 10px;
@@ -106,6 +114,7 @@
106
  </style>
107
  <script>
108
  let selectedMethods = [];
 
109
  function selectMethod(method) {
110
  const index = selectedMethods.indexOf(method);
111
  if (index > -1) {
@@ -115,7 +124,9 @@
115
  } else {
116
  return;
117
  }
 
118
  document.getElementById('method').value = selectedMethods.join(',');
 
119
  const buttons = document.getElementsByClassName('method-button');
120
  for (let button of buttons) {
121
  if (selectedMethods.includes(button.getAttribute('data-method'))) {
@@ -125,6 +136,7 @@
125
  }
126
  }
127
  }
 
128
  function validateForm() {
129
  const username = document.getElementById('username').value;
130
  const seed = document.getElementById('seed').value;
@@ -140,6 +152,9 @@
140
  <body>
141
  <div class="container">
142
  <h1>Trustworthy LLMs for Table QA</h1>
 
 
 
143
  <form id="method-form" action="/" method="post" onsubmit="return validateForm();">
144
  <label for="username">Hi there πŸ‘‹πŸ‘‹πŸ‘‹ ! What is your name?</label>
145
  <input type="text" id="username" name="username" required>
 
26
  font-size: 48px;
27
  margin-bottom: 30px;
28
  }
29
+ .instruction {
30
+ font-size: 20px;
31
+ color: #333;
32
+ margin-bottom: 30px;
33
+ padding: 15px;
34
+ background-color: #f0f0f0;
35
+ border-radius: 5px;
36
+ }
37
  label {
38
  display: block;
39
  margin: 20px 0 10px;
 
114
  </style>
115
  <script>
116
  let selectedMethods = [];
117
+
118
  function selectMethod(method) {
119
  const index = selectedMethods.indexOf(method);
120
  if (index > -1) {
 
124
  } else {
125
  return;
126
  }
127
+
128
  document.getElementById('method').value = selectedMethods.join(',');
129
+
130
  const buttons = document.getElementsByClassName('method-button');
131
  for (let button of buttons) {
132
  if (selectedMethods.includes(button.getAttribute('data-method'))) {
 
136
  }
137
  }
138
  }
139
+
140
  function validateForm() {
141
  const username = document.getElementById('username').value;
142
  const seed = document.getElementById('seed').value;
 
152
  <body>
153
  <div class="container">
154
  <h1>Trustworthy LLMs for Table QA</h1>
155
+ <div class="instruction">
156
+ Let's get started! Please input your name, enter a random number as your seed, and select two methods for your experiment.
157
+ </div>
158
  <form id="method-form" action="/" method="post" onsubmit="return validateForm();">
159
  <label for="username">Hi there πŸ‘‹πŸ‘‹πŸ‘‹ ! What is your name?</label>
160
  <input type="text" id="username" name="username" required>