Tianyi (Alex) Qiu commited on
Commit
87d617d
·
1 Parent(s): 5a15668

implement submission

Browse files
app.py CHANGED
@@ -144,7 +144,7 @@ with demo:
144
  gr.Markdown(EVALUATION_QUEUE_TEXT, elem_classes="markdown-text")
145
 
146
  with gr.Row():
147
- gr.Markdown("# Submission Form", elem_classes="markdown-text")
148
 
149
  with gr.Row():
150
  with gr.Column():
 
144
  gr.Markdown(EVALUATION_QUEUE_TEXT, elem_classes="markdown-text")
145
 
146
  with gr.Row():
147
+ gr.Markdown("# Submission Form\nSubmitted files will be stored and made public.", elem_classes="markdown-text")
148
 
149
  with gr.Row():
150
  with gr.Column():
src/challenges/result_parsers.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+
3
+
4
+ def parse_challenge_result_dict(challenge_name: str, challenge_result_dict: dict) -> float:
5
+ """
6
+ Parse the challenge result dictionary and return the score.
7
+ Currently only reads the score stored in the dict. Will be updated to include score verification.
8
+ """
9
+ score_fields = ['score', 'accuracy']
10
+
11
+ for field in score_fields:
12
+ if field in challenge_result_dict:
13
+ return challenge_result_dict[field]
14
+
15
+ raise ValueError(f"Could not parse the score for {challenge_name}.")
src/envs.py CHANGED
@@ -6,12 +6,11 @@ from huggingface_hub import HfApi
6
  # ----------------------------------
7
  TOKEN = os.environ.get("TOKEN") # A read/write token for your org
8
 
9
- OWNER = "demo-leaderboard-backend" # Change to your org - don't forget to create a results and request dataset, with the correct format!
10
  # ----------------------------------
11
 
12
- REPO_ID = f"{OWNER}/leaderboard"
13
- QUEUE_REPO = f"{OWNER}/requests"
14
- RESULTS_REPO = f"{OWNER}/results"
15
 
16
  # If you setup a cache later, just change HF_HOME
17
  CACHE_PATH=os.getenv("HF_HOME", ".")
 
6
  # ----------------------------------
7
  TOKEN = os.environ.get("TOKEN") # A read/write token for your org
8
 
9
+ OWNER = "PKU-Alignment" # Change to your org - don't forget to create a results and request dataset, with the correct format!
10
  # ----------------------------------
11
 
12
+ REPO_ID = f"{OWNER}/ProgressGym-LeaderBoard"
13
+ DATA_REPO = f"{OWNER}/ProgressGym-LeaderBoardData"
 
14
 
15
  # If you setup a cache later, just change HF_HOME
16
  CACHE_PATH=os.getenv("HF_HOME", ".")
src/legacy/submit.py ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ from datetime import datetime, timezone
4
+
5
+ from src.display.formatting import styled_error, styled_message, styled_warning
6
+ from src.envs import API, EVAL_REQUESTS_PATH, TOKEN, QUEUE_REPO
7
+ from src.submission.check_validity import (
8
+ already_submitted_models,
9
+ check_model_card,
10
+ get_model_size,
11
+ is_model_on_hub,
12
+ )
13
+
14
+ REQUESTED_MODELS = None
15
+ USERS_TO_SUBMISSION_DATES = None
16
+
17
+ def add_new_eval(
18
+ model: str,
19
+ base_model: str,
20
+ revision: str,
21
+ precision: str,
22
+ weight_type: str,
23
+ model_type: str,
24
+ ):
25
+ global REQUESTED_MODELS
26
+ global USERS_TO_SUBMISSION_DATES
27
+ if not REQUESTED_MODELS:
28
+ REQUESTED_MODELS, USERS_TO_SUBMISSION_DATES = already_submitted_models(EVAL_REQUESTS_PATH)
29
+
30
+ user_name = ""
31
+ model_path = model
32
+ if "/" in model:
33
+ user_name = model.split("/")[0]
34
+ model_path = model.split("/")[1]
35
+
36
+ precision = precision.split(" ")[0]
37
+ current_time = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
38
+
39
+ if model_type is None or model_type == "":
40
+ return styled_error("Please select a model type.")
41
+
42
+ # Does the model actually exist?
43
+ if revision == "":
44
+ revision = "main"
45
+
46
+ # Is the model on the hub?
47
+ if weight_type in ["Delta", "Adapter"]:
48
+ base_model_on_hub, error, _ = is_model_on_hub(model_name=base_model, revision=revision, token=TOKEN, test_tokenizer=True)
49
+ if not base_model_on_hub:
50
+ return styled_error(f'Base model "{base_model}" {error}')
51
+
52
+ if not weight_type == "Adapter":
53
+ model_on_hub, error, _ = is_model_on_hub(model_name=model, revision=revision, token=TOKEN, test_tokenizer=True)
54
+ if not model_on_hub:
55
+ return styled_error(f'Model "{model}" {error}')
56
+
57
+ # Is the model info correctly filled?
58
+ try:
59
+ model_info = API.model_info(repo_id=model, revision=revision)
60
+ except Exception:
61
+ return styled_error("Could not get your model information. Please fill it up properly.")
62
+
63
+ model_size = get_model_size(model_info=model_info, precision=precision)
64
+
65
+ # Were the model card and license filled?
66
+ try:
67
+ license = model_info.cardData["license"]
68
+ except Exception:
69
+ return styled_error("Please select a license for your model")
70
+
71
+ modelcard_OK, error_msg = check_model_card(model)
72
+ if not modelcard_OK:
73
+ return styled_error(error_msg)
74
+
75
+ # Seems good, creating the eval
76
+ print("Adding new eval")
77
+
78
+ eval_entry = {
79
+ "model": model,
80
+ "base_model": base_model,
81
+ "revision": revision,
82
+ "precision": precision,
83
+ "weight_type": weight_type,
84
+ "status": "PENDING",
85
+ "submitted_time": current_time,
86
+ "model_type": model_type,
87
+ "likes": model_info.likes,
88
+ "params": model_size,
89
+ "license": license,
90
+ "private": False,
91
+ }
92
+
93
+ # Check for duplicate submission
94
+ if f"{model}_{revision}_{precision}" in REQUESTED_MODELS:
95
+ return styled_warning("This model has been already submitted.")
96
+
97
+ print("Creating eval file")
98
+ OUT_DIR = f"{EVAL_REQUESTS_PATH}/{user_name}"
99
+ os.makedirs(OUT_DIR, exist_ok=True)
100
+ out_path = f"{OUT_DIR}/{model_path}_eval_request_False_{precision}_{weight_type}.json"
101
+
102
+ with open(out_path, "w") as f:
103
+ f.write(json.dumps(eval_entry))
104
+
105
+ print("Uploading eval file")
106
+ API.upload_file(
107
+ path_or_fileobj=out_path,
108
+ path_in_repo=out_path.split("eval-queue/")[1],
109
+ repo_id=QUEUE_REPO,
110
+ repo_type="dataset",
111
+ commit_message=f"Add {model} to eval queue",
112
+ )
113
+
114
+ # Remove the local file
115
+ os.remove(out_path)
116
+
117
+ return styled_message(
118
+ "Your request has been submitted to the evaluation queue!\nPlease wait for up to an hour for the model to show in the PENDING list."
119
+ )
src/submission/submit.py CHANGED
@@ -1,9 +1,21 @@
1
  import json
2
  import os
 
3
  from datetime import datetime, timezone
4
 
 
 
 
 
 
 
 
 
 
 
 
5
  from src.display.formatting import styled_error, styled_message, styled_warning
6
- from src.envs import API, EVAL_REQUESTS_PATH, TOKEN, QUEUE_REPO
7
  from src.submission.check_validity import (
8
  already_submitted_models,
9
  check_model_card,
@@ -11,109 +23,113 @@ from src.submission.check_validity import (
11
  is_model_on_hub,
12
  )
13
 
14
- REQUESTED_MODELS = None
15
- USERS_TO_SUBMISSION_DATES = None
16
-
17
  def add_new_eval(
18
- submission_file: str,
19
  algo_name: str,
20
  algo_info: str,
21
  algo_link: str,
22
  submitter_email: str,
23
  ):
24
- return 'Success!'
25
- global REQUESTED_MODELS
26
- global USERS_TO_SUBMISSION_DATES
27
- if not REQUESTED_MODELS:
28
- REQUESTED_MODELS, USERS_TO_SUBMISSION_DATES = already_submitted_models(EVAL_REQUESTS_PATH)
29
-
30
- user_name = ""
31
- model_path = model
32
- if "/" in model:
33
- user_name = model.split("/")[0]
34
- model_path = model.split("/")[1]
35
-
36
- precision = precision.split(" ")[0]
37
- current_time = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
38
-
39
- if model_type is None or model_type == "":
40
- return styled_error("Please select a model type.")
41
-
42
- # Does the model actually exist?
43
- if revision == "":
44
- revision = "main"
45
-
46
- # Is the model on the hub?
47
- if weight_type in ["Delta", "Adapter"]:
48
- base_model_on_hub, error, _ = is_model_on_hub(model_name=base_model, revision=revision, token=TOKEN, test_tokenizer=True)
49
- if not base_model_on_hub:
50
- return styled_error(f'Base model "{base_model}" {error}')
51
-
52
- if not weight_type == "Adapter":
53
- model_on_hub, error, _ = is_model_on_hub(model_name=model, revision=revision, token=TOKEN, test_tokenizer=True)
54
- if not model_on_hub:
55
- return styled_error(f'Model "{model}" {error}')
56
-
57
- # Is the model info correctly filled?
58
  try:
59
- model_info = API.model_info(repo_id=model, revision=revision)
60
- except Exception:
61
- return styled_error("Could not get your model information. Please fill it up properly.")
62
-
63
- model_size = get_model_size(model_info=model_info, precision=precision)
64
-
65
- # Were the model card and license filled?
 
 
66
  try:
67
- license = model_info.cardData["license"]
68
- except Exception:
69
- return styled_error("Please select a license for your model")
70
-
71
- modelcard_OK, error_msg = check_model_card(model)
72
- if not modelcard_OK:
73
- return styled_error(error_msg)
74
-
75
- # Seems good, creating the eval
76
- print("Adding new eval")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
 
 
78
  eval_entry = {
79
- "model": model,
80
- "base_model": base_model,
81
- "revision": revision,
82
- "precision": precision,
83
- "weight_type": weight_type,
84
- "status": "PENDING",
85
- "submitted_time": current_time,
86
- "model_type": model_type,
87
- "likes": model_info.likes,
88
- "params": model_size,
89
- "license": license,
90
- "private": False,
91
  }
92
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  # Check for duplicate submission
94
- if f"{model}_{revision}_{precision}" in REQUESTED_MODELS:
95
- return styled_warning("This model has been already submitted.")
96
-
97
- print("Creating eval file")
98
- OUT_DIR = f"{EVAL_REQUESTS_PATH}/{user_name}"
99
- os.makedirs(OUT_DIR, exist_ok=True)
100
- out_path = f"{OUT_DIR}/{model_path}_eval_request_False_{precision}_{weight_type}.json"
101
-
102
- with open(out_path, "w") as f:
103
- f.write(json.dumps(eval_entry))
104
-
105
- print("Uploading eval file")
106
  API.upload_file(
107
- path_or_fileobj=out_path,
108
- path_in_repo=out_path.split("eval-queue/")[1],
109
- repo_id=QUEUE_REPO,
110
  repo_type="dataset",
111
- commit_message=f"Add {model} to eval queue",
112
  )
113
 
114
- # Remove the local file
115
- os.remove(out_path)
116
-
117
- return styled_message(
118
- "Your request has been submitted to the evaluation queue!\nPlease wait for up to an hour for the model to show in the PENDING list."
119
- )
 
1
  import json
2
  import os
3
+ import re
4
  from datetime import datetime, timezone
5
 
6
+ from src.challenges.result_parsers import parse_challenge_result_dict
7
+
8
+ # email validity checker
9
+ from email.utils import parseaddr
10
+
11
+ # url validity checker
12
+ from urllib.parse import urlparse
13
+
14
+ # json parser
15
+ from json.decoder import JSONDecodeError
16
+
17
  from src.display.formatting import styled_error, styled_message, styled_warning
18
+ from src.envs import API, EVAL_REQUESTS_PATH, TOKEN, DATA_REPO
19
  from src.submission.check_validity import (
20
  already_submitted_models,
21
  check_model_card,
 
23
  is_model_on_hub,
24
  )
25
 
 
 
 
26
  def add_new_eval(
27
+ submission_file,
28
  algo_name: str,
29
  algo_info: str,
30
  algo_link: str,
31
  submitter_email: str,
32
  ):
33
+ return_str = 'Success! Your submission will soon be added to the leaderboard.'
34
+
35
+ # validate email and url
36
+ if not parseaddr(submitter_email):
37
+ return styled_error("Please enter a valid email address.")
38
+
39
+ if algo_link.strip() and not urlparse(algo_link).scheme:
40
+ return styled_error("Please enter a valid URL.")
41
+
42
+ # get file path
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  try:
44
+ file_path: str = submission_file.name,
45
+ assert isinstance(file_path, str)
46
+ except:
47
+ if isinstance(submission_file, str):
48
+ file_path: str = submission_file
49
+ else:
50
+ return styled_error("Invalid submission file: File path not found.")
51
+
52
+ # parse the submission file
53
  try:
54
+ submission_data = json.loads(file_path)
55
+ except JSONDecodeError:
56
+ return styled_error("Invalid submission file: JSON parsing failed.")
57
+
58
+ try:
59
+ assert isinstance(submission_data, dict)
60
+ submission_data_content = list(submission_data.items())
61
+ assert len(submission_data_content) == 1
62
+ results_per_challenge = submission_data_content[0][1]
63
+ assert isinstance(results_per_challenge, dict)
64
+ assert all(isinstance(challenge, str) for challenge in results_per_challenge.keys())
65
+ assert all(isinstance(result, dict) for result in results_per_challenge.values())
66
+ except (AssertionError, KeyError):
67
+ return styled_error("Invalid submission file: Incorrect organization of the JSON file.")
68
+
69
+ # format the algo name
70
+ algo_name = algo_name.strip()
71
+ algo_name_filename = re.sub(r"[^a-zA-Z0-9]+", "-", algo_name).lower()
72
+ timestamp_filename = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H-%M-%S")
73
+
74
+ print("Uploading submission file")
75
+ API.upload_file(
76
+ path_or_fileobj=file_path,
77
+ path_in_repo=f'upload_history/{algo_name_filename}/{timestamp_filename}.json',
78
+ repo_id=DATA_REPO,
79
+ repo_type="dataset",
80
+ commit_message=f"Add {algo_name} to eval queue by {submitter_email} at {timestamp_filename}",
81
+ )
82
 
83
+ # Construct entry in the master table
84
  eval_entry = {
85
+ "name": algo_name,
86
+ "id": algo_name_filename,
87
+ "info": algo_info,
88
+ "link": algo_link,
89
+ "email": submitter_email,
90
+ "update_timestamp": timestamp_filename,
 
 
 
 
 
 
91
  }
92
+
93
+ for challenge, result in results_per_challenge:
94
+ try:
95
+ parsed_result: float = parse_challenge_result_dict(challenge, result)
96
+ assert isinstance(parsed_result, float)
97
+ except:
98
+ return styled_error(f"Could not parse the score for {challenge}.")
99
+
100
+ eval_entry[challenge] = parsed_result
101
+
102
+ # Get content of the master table from DATA_REPO
103
+ try:
104
+ master_table = {}
105
+ if API.file_exists(DATA_REPO, "master_table.json"):
106
+ API.hf_hub_download(DATA_REPO, "master_table.json", EVAL_REQUESTS_PATH, force_download=True)
107
+ with open(f"{EVAL_REQUESTS_PATH}/master_table.json", "r") as f:
108
+ master_table = json.load(f)
109
+ else:
110
+ print("No master table found. Will create a new one.")
111
+ except:
112
+ return styled_error("Could not get the master table from the data repository.")
113
+
114
  # Check for duplicate submission
115
+ if algo_name_filename in master_table:
116
+ return_str += ' An existing submission with the same name has been found. Your submission will be used to update the existing one.'
117
+ master_table[algo_name_filename].update(eval_entry)
118
+ else:
119
+ print("Creating eval entry")
120
+ master_table[algo_name_filename] = eval_entry
121
+
122
+ # Save the updated master table
123
+ with open(f"./master_table.json", "w") as f:
124
+ f.write(json.dumps(master_table))
125
+
126
+ print("Uploading master table")
127
  API.upload_file(
128
+ path_or_fileobj="./master_table.json",
129
+ path_in_repo="master_table.json",
130
+ repo_id=DATA_REPO,
131
  repo_type="dataset",
132
+ commit_message=f"Update master table with {algo_name} by {submitter_email} at {timestamp_filename}",
133
  )
134
 
135
+ return styled_message(return_str)