gmmcleod commited on
Commit
46d89e3
·
verified ·
1 Parent(s): 59c800c

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +509 -0
app.py ADDED
@@ -0,0 +1,509 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # change the eval ftn to take a list of lists
2
+ import gradio as gr
3
+ import pandas as pd
4
+ import time
5
+ import torch
6
+ import os
7
+ import torchvision.transforms as transforms
8
+ from torchvision import datasets
9
+ import torch.nn.functional as F
10
+ from torch.utils.data import DataLoader
11
+ import subprocess
12
+ # from dummy_eval import foo
13
+ import zipfile
14
+ import shutil
15
+ import numpy as np
16
+ import importlib.util
17
+ import inspect
18
+ from huggingface_hub import HfApi
19
+ from datasets import load_dataset, Dataset
20
+ from huggingface_hub import login, hf_hub_download
21
+ import requests
22
+ import matplotlib
23
+ matplotlib.use("Agg")
24
+
25
+ def fetch_required_files(exp_config):
26
+ # os.makedirs("temp_data", exist_ok=True)
27
+ for key in exp_config:
28
+ file_path = exp_config[key]['file']
29
+ url = f"https://saraht14-server.hf.space/file/{file_path}.txt"
30
+
31
+ filename_only = os.path.basename(file_path) + ".txt"
32
+ local_path = os.path.join("./", filename_only)
33
+
34
+ downloaded = download_file(url, local_path)
35
+ if not downloaded:
36
+ raise Exception(f"Could not download file: {file_path}")
37
+
38
+ exp_config[key]["local_file"] = local_path
39
+
40
+ return exp_config
41
+
42
+
43
+ def call_flask_server(username):
44
+ url = "https://saraht14-server.hf.space/"
45
+
46
+ try:
47
+ response = requests.get(url)
48
+ result = response.json()
49
+ print("Flask response:", result)
50
+ return result.get("result", "No result")
51
+ except Exception as e:
52
+ print("Failed to contact Flask server:", e)
53
+ return f"Error contacting server: {e}"
54
+ call_flask_server("sarah")
55
+ def download_file(url, local_path):
56
+ try:
57
+ r = requests.get(url, headers={"Authorization": f"Bearer {HF_TOKEN}"})
58
+ r.raise_for_status()
59
+ with open(local_path, 'wb') as f:
60
+ f.write(r.content)
61
+ return local_path
62
+ except Exception as e:
63
+ print(f"Error downloading file from {url}: {e}")
64
+ return None
65
+ # def log_submission_request(username, zip_file):
66
+ # try:
67
+ # requests_ds = load_dataset("IndoorOutdoor/requests", split="train")
68
+ # except Exception as e:
69
+ # print("Could not load requests dataset, creating a new one.", e)
70
+ # requests_ds = Dataset.from_dict({"username": [], "timestamp": [], "zip_filename": []})
71
+
72
+ # new_entry = {"username": username,
73
+ # "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
74
+ # "zip_filename": os.path.basename(zip_file.name)}
75
+
76
+ # updated_requests = requests_ds.add_item(new_entry)
77
+
78
+ # updated_requests.push_to_hub("IndoorOutdoor/requests", token=HF_TOKEN)
79
+ # print("Logged submission request to the requests dataset.")
80
+ # def update_results_dataset(leaderboard_df):
81
+ repo_id = "saraht14/responses"
82
+ def update_results_dataset(new_row_df):
83
+ repo_id = "saraht14/responses"
84
+
85
+ try:
86
+ leaderboard_dataset = load_dataset(repo_id, split="train", token=HF_TOKEN)
87
+ leaderboard_df = leaderboard_dataset.to_pandas()
88
+ updated_df = pd.concat([leaderboard_df, new_row_df], ignore_index=True)
89
+ updated_dataset = Dataset.from_pandas(updated_df)
90
+ updated_dataset.push_to_hub(repo_id, token=HF_TOKEN)
91
+ print("New row(s) added to existing leaderboard dataset.")
92
+ return updated_dataset
93
+ except Exception as e:
94
+ print("Dataset not found or failed to load, creating a new one.")
95
+ try:
96
+ new_dataset = Dataset.from_pandas(new_row_df)
97
+ new_dataset.push_to_hub(repo_id, token=HF_TOKEN)
98
+ return new_dataset
99
+ print("New leaderboard dataset created and uploaded.")
100
+ except Exception as inner_e:
101
+ print("Failed to create and push new leaderboard dataset:", inner_e)
102
+
103
+
104
+
105
+ # Info to change for your repository
106
+ # ----------------------------------
107
+ HF_TOKEN = os.environ.get("HF_TOKEN") # A read/write token for your org
108
+ print(f"{HF_TOKEN}")
109
+ OWNER = "IndoorOutdoor" # Change to your org - don't forget to create a results and request dataset, with the correct format!
110
+ # ----------------------------------
111
+ READ_TOKEN = os.environ.get("read_token")
112
+ local_file_path = hf_hub_download(repo_id="IndoorOutdoor/metadata",
113
+ filename="ali/home/office-gain-50-10-25-2023-16-16-03-dump1090.txt",
114
+ repo_type="dataset",
115
+ token=READ_TOKEN)
116
+ REPO_ID = f"{OWNER}/leaderboard"
117
+ QUEUE_REPO = f"{OWNER}/requests"
118
+ RESULTS_REPO = f"{OWNER}/results"
119
+ global_error_message = "Ready for submission!"
120
+ # def set_error_message(message):
121
+ # global global_error_message
122
+ # global_error_message = message
123
+ # print("ERROR UPDATED:", global_error_message) # Debugging
124
+
125
+ def get_error_message():
126
+ return global_error_message
127
+
128
+ def install_requirements(file_path):
129
+ try:
130
+ with open(file_path, "r") as file:
131
+ requirements = file.readlines()
132
+
133
+ for req in requirements:
134
+ package = req.strip()
135
+ if package:
136
+ subprocess.run(["pip", "install", package], check=True)
137
+ print(f"Installed: {package}")
138
+
139
+ print("All requirements installed successfully.")
140
+
141
+ except FileNotFoundError:
142
+ print(f"Error: {file_path} not found.")
143
+ except subprocess.CalledProcessError as e:
144
+ print(f"Installation failed: {e}")
145
+ HEADERS = ["Username", "Execution Time (s)", "Accuracy", "TP", "FP", "FN", "TN", "Status"]
146
+ BASE = {'ottawa':(45.30326753851309,-75.93640391349997),
147
+ 'ali_home':(37.88560412289598,-122.30218612514359),
148
+ 'josh_home':(37.8697406, -122.30218612514359),
149
+ 'cory':(37.8697406,-122.281570)}
150
+
151
+ def get_base(filename):
152
+ if "home" in filename:
153
+ return BASE["ali_home"]
154
+ elif "ottawa" in filename:
155
+ return BASE["ottawa"]
156
+ elif "josh" in filename:
157
+ return BASE["josh_home"]
158
+ else:
159
+ return BASE["cory"]
160
+
161
+ metadata_path = "metadata.csv"
162
+ dir = ""
163
+ df = pd.read_csv(metadata_path)
164
+
165
+ print(df.head())
166
+ def fetch_lb():
167
+ try:
168
+ leaderboard_dataset = load_dataset("saraht14/responses", split="train", token=HF_TOKEN)
169
+ leaderboard_data = leaderboard_dataset.to_pandas()
170
+ leaderboard_data = leaderboard_data[HEADERS] # keep it ordered
171
+ leaderboard_data = leaderboard_data.sort_values(by=["Accuracy", "Execution Time (s)"], ascending=[False, True])
172
+ except Exception as e:
173
+ print(f"Error loading leaderboard:", e)
174
+ leaderboard_data = pd.DataFrame(columns=HEADERS)
175
+
176
+ print(f"THIS IS THE LEADERBOARD:\n{leaderboard_data}")
177
+ return leaderboard_data
178
+
179
+
180
+ leaderboard_data = fetch_lb()
181
+
182
+ def compute_stats_sector(sectors_model, sector_gt):
183
+ TP = FP = FN = TN = 0
184
+ ignored = 0
185
+ for i in range(len(sector_gt)):
186
+ if sector_gt[i] == 1:
187
+ if sectors_model[i] > 0 or sectors_model[(i+1) % 8] > 0 or sectors_model[(i-1) % 8] > 0 :
188
+ TP += 1
189
+ else:
190
+ FN += 1
191
+ else:
192
+ if sectors_model[i] > 0:
193
+ if sector_gt[(i-1) % 8] > 0 or sector_gt[(i+1) % 8] > 0:
194
+ TP += 1
195
+ continue
196
+ FP += 1
197
+ else:
198
+ TN += 1
199
+ NUM_SECTORS = 8 - ignored
200
+ return [TP / NUM_SECTORS, FP / NUM_SECTORS, FN / NUM_SECTORS, TN / NUM_SECTORS]
201
+
202
+ #Compare the model output with ground truth
203
+ #return TP, FP, FN, TN
204
+ #This fuction compute stats when the model is binary i.e., outputs only indoor vs outdoor
205
+ def compute_stats_in_out(sectors_model, indoor_gt):
206
+ if indoor_gt: #if groundtruth is indoor
207
+ for i in range(len(sectors_model)):
208
+ if sectors_model[i]:
209
+ return [0,1,0,0]
210
+ return [0,0,0,1]
211
+ else: #if outdoor
212
+ for i in range(len(sectors_model)):
213
+ if sectors_model[i]:
214
+ return [1,0,0,0]
215
+ return [0,0,1,0]
216
+
217
+ def read_configuration(filename):
218
+ print("read config")
219
+ with open(filename, 'r') as file:
220
+ data = file.read().split('\n')
221
+ data = data[1:] #ignore the header
222
+ print("head", data)
223
+ exp = {}
224
+ for line in data:
225
+ if len(line) == 0:
226
+ continue
227
+ tokens =line.split(',')
228
+ file = tokens[0]
229
+ scenario = tokens[1]
230
+ indoor = True if tokens[2] == "TRUE" else 0
231
+
232
+ exp[scenario] = {'sectors':[1 if x == "TRUE" else 0 for x in tokens[3:]], 'indoor':indoor, "file":file}
233
+ return exp
234
+
235
+
236
+
237
+
238
+ def evaluate_model(username, file):
239
+ print("evaluating...")
240
+ global leaderboard_data
241
+
242
+ username = username.strip()
243
+ if not username:
244
+ return leaderboard_data.values.tolist()
245
+
246
+ script_path = f"submissions/{username}.py"
247
+ os.makedirs("submissions", exist_ok=True)
248
+
249
+ # # Get the file path from the NamedString object
250
+ # file_path = file.name # Get the actual file path
251
+ # print("file_path:", file_path)
252
+ # with open(script_path, "wb") as f:
253
+ # with open(file_path, "rb") as uploaded_file:
254
+ # f.write(uploaded_file.read())
255
+
256
+
257
+
258
+ # script_path = f"submissions/{username}.py"
259
+ # os.makedirs("submissions", exist_ok=True)
260
+ # with open(script_path, "wb") as f:
261
+ # f.write(file.read())
262
+
263
+ try:
264
+
265
+ exp = read_configuration("metadata.csv")
266
+ print(f"FIRST: {len(exp)}")
267
+ # exp = fetch_required_files(exp)
268
+ # print(f"SECOND: {len(exp)}")
269
+
270
+ start_time = time.time()
271
+ stats_model_sectors = []
272
+ stats_model_in_out = []
273
+
274
+ for key in exp:
275
+ filename = exp[key]['file']
276
+ indoor_gt = exp[key]['indoor']
277
+ sectors_gt = exp[key]["sectors"]
278
+
279
+ # file_path = os.path.join(dataset_directory, filename)
280
+ # print(file_path)
281
+ filename = filename + ".txt"
282
+ print("FILE TO PROCESS:", filename)
283
+ # filename_url = f"https://saraht14-server.hf.space/file/{filename}"
284
+ # local_txt_path = f"./{filename}.txt"
285
+ # os.makedirs("temp_data", exist_ok=True)
286
+ # local_file_path = exp[key]["local_file"]
287
+ # downloaded = download_file(filename_url, local_txt_path)
288
+ local_file_path = hf_hub_download(repo_id="IndoorOutdoor/metadata",
289
+ filename=filename,
290
+ repo_type="dataset",
291
+ token=READ_TOKEN)
292
+ # if not downloaded:
293
+ # raise Exception("Failed to fetch remote file.")
294
+ # sectors_model = subprocess.run(["python", script_path,filename], capture_output=True, text=True, timeout=300)
295
+ # hello = foo()
296
+ # print(f"HELLO: {hello}")
297
+ # import
298
+ sectors_model = import_and_run_function(file, "evaluate", local_file_path)
299
+ try:
300
+ os.remove(local_file_path)
301
+ except Exception as e:
302
+ print(f"Warning: Couldn't delete {local_file_path} — {e}")
303
+ # print(status)
304
+ print(f"TYPE: {type(sectors_model), {type(sectors_model[0])}}")
305
+
306
+
307
+ print("SECTORS MODEL: ", sectors_model)
308
+ # sectors_model = eval(filename)
309
+ # print(sectors_model)
310
+ # sectors_model = model_based_clustering(dataset_directory, filename)
311
+
312
+ stats_model_sectors.append(compute_stats_sector(sectors_model, sectors_gt))
313
+ stats_model_in_out.append(compute_stats_in_out(sectors_model, indoor_gt))
314
+
315
+ execution_time = round(time.time() - start_time, 4)
316
+ print("calculating summary stats")
317
+ TP = np.mean([x[0] for x in stats_model_sectors])
318
+ FP = np.mean([x[1] for x in stats_model_sectors])
319
+ FN = np.mean([x[2] for x in stats_model_sectors])
320
+ TN = np.mean([x[3] for x in stats_model_sectors])
321
+ print("calculating exec stats")
322
+
323
+ accuracy = round((TP + TN) / (TP + TN + FP + FN), 2)
324
+
325
+ status = "Success" if accuracy > 0 else "Incorrect Model"
326
+ # ["Username", "Execution Time (s)", "Accuracy", "True Positive", "False Positive", "False Negative", "False Positive", "Status"]
327
+ except Exception as e:
328
+ leaderboard_data = pd.concat([leaderboard_data, pd.DataFrame([[username, float("inf"), 0,-1,-1,-1,-1, f"Model Error: {str(e)}"]],
329
+ columns=HEADERS)], ignore_index=True)
330
+ return leaderboard_data.values.tolist()
331
+ print("calculating new entry")
332
+
333
+ new_entry = pd.DataFrame([[username, execution_time, accuracy, TP, FP, FN, TN, status]],
334
+ columns=HEADERS)
335
+ print("updating new entry")
336
+ leaderboard_data = update_results_dataset(new_entry)
337
+ # leaderboard_data = pd.concat([leaderboard_data, new_entry], ignore_index=True)
338
+ leaderboard_data = leaderboard_data.to_pandas() if leaderboard_data is not None else None
339
+ if leaderboard_data is not None:
340
+ leaderboard_data = leaderboard_data.sort_values(by=["Accuracy", "Execution Time (s)"], ascending=[False, True]).reset_index(drop=True)
341
+ print(f"DATA: {leaderboard_data}")
342
+ return leaderboard_data.values.tolist()
343
+
344
+
345
+ def import_and_run_function(script_path, function_name, filename):
346
+
347
+
348
+ if not os.path.exists(script_path):
349
+ set_error_message(f"Error: {script_path} not found.")
350
+ return None
351
+
352
+
353
+ if not script_path.endswith(".py"):
354
+ set_error_message("Error: Provided file is not a Python script.")
355
+ return None
356
+
357
+ module_name = os.path.splitext(os.path.basename(script_path))[0]
358
+
359
+ try:
360
+ spec = importlib.util.spec_from_file_location(module_name, script_path)
361
+ module = importlib.util.module_from_spec(spec)
362
+ spec.loader.exec_module(module)
363
+ except SyntaxError as e:
364
+ set_error_message(f"Error: Syntax error in the script - {e}")
365
+ return None
366
+ except ImportError as e:
367
+ set_error_message(f"Error: Import issue in the script - {e}")
368
+ return None
369
+ except Exception as e:
370
+ set_error_message(f"Error: Failed to import script - {e}")
371
+ return None
372
+
373
+
374
+ if not hasattr(module, function_name):
375
+ set_error_message(f"Error: Function '{function_name}' not found in '{script_path}'.")
376
+ return None
377
+
378
+ function_to_run = getattr(module, function_name)
379
+
380
+ try:
381
+ sig = inspect.signature(function_to_run)
382
+ params = list(sig.parameters.values())
383
+ if len(params) != 1 or params[0].kind not in [inspect.Parameter.POSITIONAL_OR_KEYWORD]:
384
+ set_error_message(f"Error: Function '{function_name}' must have exactly one parameter (filepath).")
385
+ return None
386
+ except Exception as e:
387
+ set_error_message(f"Error: Unable to inspect function signature - {e}")
388
+ return None
389
+
390
+ try:
391
+ result = function_to_run(filename)
392
+ print(f"TYPE: {type(result), {type(result[0])}}, RESULT: {result}")
393
+ except Exception as e:
394
+ set_error_message(f"Error: Function '{function_name}' raised an error during execution - {e}")
395
+ return None
396
+
397
+ if not isinstance(result, list):
398
+ set_error_message(f"Error: Function '{function_name}' must return a list.")
399
+ return None
400
+
401
+ if len(result) != 8:
402
+ set_error_message(f"Error: Function '{function_name}' must return a list of exactly 8 elements.")
403
+ return None
404
+
405
+ if not all(isinstance(x, int) and x in [0, 1] for x in result):
406
+ return f"Error: Function '{function_name}' must return a list of 8 integers, each 0 or 1.", None
407
+
408
+ print(f"Function '{function_name}' executed successfully. Output: {result}")
409
+ # set_error_message(f"Function '{function_name}' executed successfully.")
410
+ return result
411
+
412
+
413
+
414
+
415
+ def update_leaderboard(username, zip_file):
416
+ if not zip_file:
417
+ set_error_message("No file uploaded.")
418
+ return get_error_message(), None
419
+
420
+ zip_path = zip_file.name
421
+ extract_path = os.path.join("", username)
422
+ # if not os.path.exists(extract_path):
423
+ # os.makedirs(extract_path)
424
+
425
+ try:
426
+ if not os.path.exists(extract_path):
427
+ os.makedirs(extract_path)
428
+
429
+ except OSError:
430
+ set_error_message("Error creating directory for extraction.")
431
+ return get_error_message(), None
432
+
433
+ try:
434
+ with zipfile.ZipFile(zip_path, "r") as zip_ref:
435
+ zip_ref.extractall(extract_path)
436
+ except zipfile.BadZipFile:
437
+ return "Invalid ZIP file.", None
438
+
439
+ except Exception as e:
440
+ return f"Error extracting ZIP file: {str(e)}", None
441
+
442
+
443
+ extracted_files = os.listdir(extract_path)
444
+ print("EXTRACTED FILES:", extracted_files)
445
+
446
+ req_file = os.path.join(extract_path, "user_reqs.txt")
447
+
448
+ if "user_reqs.txt" not in extracted_files:
449
+ return "Missing user_reqs.txt in ZIP file.", None
450
+ try:
451
+ install_requirements(req_file)
452
+ except Exception as e:
453
+ return f"Error installing dependencies: {str(e)}", None
454
+
455
+
456
+
457
+ # for file in os.listdir(extract_path):
458
+ # if file.endswith(".py"):
459
+ # python_script = os.path.join(extract_path, file)
460
+ # break
461
+ python_script = os.path.join(extract_path, "main.py")
462
+
463
+ if "main.py" not in extracted_files:
464
+ return "No Python script (main.py) found in ZIP.", None
465
+
466
+
467
+ # if not python_script:
468
+ # return "No Python script found in ZIP."
469
+
470
+ if "main.py" not in extracted_files:
471
+ return "No Python script (main.py) found in ZIP.", None
472
+
473
+ try:
474
+ updated_leaderboard = evaluate_model(username, python_script)
475
+ except Exception as e:
476
+ print("Error in eval mode:", str(e))
477
+ return f"Error evaluating model: {str(e)}", None
478
+
479
+ # log_submission_request(username, zip_file)
480
+ return "Submission successful!", updated_leaderboard
481
+
482
+
483
+
484
+ with gr.Blocks() as demo:
485
+
486
+ gr.Markdown("# 🚀 Model Submission & Leaderboard (Hugging Face Spaces)")
487
+
488
+ with gr.Row():
489
+ username_input = gr.Textbox(label="Username")
490
+ file_input = gr.File(label="Upload Zip File")
491
+ submit_button = gr.Button("Submit File")
492
+
493
+ status_output = gr.Textbox(label="Status", interactive=False)
494
+
495
+ with gr.Row():
496
+ leaderboard_display = gr.Dataframe(
497
+ headers=HEADERS,
498
+ value=fetch_lb,
499
+ label="Leaderboard"
500
+ )
501
+
502
+
503
+ submit_button.click(fn=update_leaderboard,
504
+ inputs=[username_input, file_input],
505
+ outputs=[status_output, leaderboard_display])
506
+
507
+ status_output.change(fn=get_error_message, inputs=[], outputs=status_output)
508
+
509
+ demo.launch()