Abhishek Thakur
commited on
Commit
·
936d8d9
1
Parent(s):
9b8659c
workflow done
Browse files- competitions/app.py +50 -7
- competitions/info.py +8 -0
- competitions/submissions.py +36 -98
- competitions/templates/index.html +131 -22
competitions/app.py
CHANGED
|
@@ -1,12 +1,14 @@
|
|
| 1 |
import os
|
| 2 |
|
| 3 |
-
from fastapi import FastAPI, Request
|
| 4 |
from fastapi.responses import HTMLResponse, JSONResponse
|
| 5 |
from fastapi.staticfiles import StaticFiles
|
| 6 |
from fastapi.templating import Jinja2Templates
|
|
|
|
| 7 |
|
| 8 |
from competitions.info import CompetitionInfo
|
| 9 |
from competitions.leaderboard import Leaderboard
|
|
|
|
| 10 |
|
| 11 |
|
| 12 |
HF_TOKEN = os.environ.get("HF_TOKEN", None)
|
|
@@ -14,6 +16,11 @@ BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
| 14 |
COMPETITION_ID = os.getenv("COMPETITION_ID")
|
| 15 |
COMP_INFO = CompetitionInfo(competition_id=COMPETITION_ID, autotrain_token=HF_TOKEN)
|
| 16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
app = FastAPI()
|
| 18 |
static_path = os.path.join(BASE_DIR, "static")
|
| 19 |
app.mount("/static", StaticFiles(directory=static_path), name="static")
|
|
@@ -30,7 +37,11 @@ async def read_form(request: Request):
|
|
| 30 |
"""
|
| 31 |
if HF_TOKEN is None:
|
| 32 |
return templates.TemplateResponse("error.html", {"request": request})
|
| 33 |
-
context = {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
return templates.TemplateResponse("index.html", context)
|
| 35 |
|
| 36 |
|
|
@@ -64,9 +75,41 @@ async def get_leaderboard(request: Request, lb: str):
|
|
| 64 |
return resp
|
| 65 |
|
| 66 |
|
| 67 |
-
@app.
|
| 68 |
-
async def
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
return resp
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import os
|
| 2 |
|
| 3 |
+
from fastapi import FastAPI, File, Form, Request, UploadFile
|
| 4 |
from fastapi.responses import HTMLResponse, JSONResponse
|
| 5 |
from fastapi.staticfiles import StaticFiles
|
| 6 |
from fastapi.templating import Jinja2Templates
|
| 7 |
+
from pydantic import BaseModel
|
| 8 |
|
| 9 |
from competitions.info import CompetitionInfo
|
| 10 |
from competitions.leaderboard import Leaderboard
|
| 11 |
+
from competitions.submissions import Submissions
|
| 12 |
|
| 13 |
|
| 14 |
HF_TOKEN = os.environ.get("HF_TOKEN", None)
|
|
|
|
| 16 |
COMPETITION_ID = os.getenv("COMPETITION_ID")
|
| 17 |
COMP_INFO = CompetitionInfo(competition_id=COMPETITION_ID, autotrain_token=HF_TOKEN)
|
| 18 |
|
| 19 |
+
|
| 20 |
+
class User(BaseModel):
|
| 21 |
+
user_token: str
|
| 22 |
+
|
| 23 |
+
|
| 24 |
app = FastAPI()
|
| 25 |
static_path = os.path.join(BASE_DIR, "static")
|
| 26 |
app.mount("/static", StaticFiles(directory=static_path), name="static")
|
|
|
|
| 37 |
"""
|
| 38 |
if HF_TOKEN is None:
|
| 39 |
return templates.TemplateResponse("error.html", {"request": request})
|
| 40 |
+
context = {
|
| 41 |
+
"request": request,
|
| 42 |
+
"logo": COMP_INFO.logo_url,
|
| 43 |
+
"competition_type": COMP_INFO.competition_type,
|
| 44 |
+
}
|
| 45 |
return templates.TemplateResponse("index.html", context)
|
| 46 |
|
| 47 |
|
|
|
|
| 75 |
return resp
|
| 76 |
|
| 77 |
|
| 78 |
+
@app.post("/my_submissions", response_class=JSONResponse)
|
| 79 |
+
async def my_submissions(request: Request, user: User):
|
| 80 |
+
sub = Submissions(
|
| 81 |
+
end_date=COMP_INFO.end_date,
|
| 82 |
+
submission_limit=COMP_INFO.submission_limit,
|
| 83 |
+
competition_id=COMPETITION_ID,
|
| 84 |
+
token=HF_TOKEN,
|
| 85 |
+
)
|
| 86 |
+
success_subs, failed_subs = sub.my_submissions(user.user_token)
|
| 87 |
+
success_subs = success_subs.to_markdown(index=False)
|
| 88 |
+
failed_subs = failed_subs.to_markdown(index=False)
|
| 89 |
+
if len(success_subs.strip()) == 0 and len(failed_subs.strip()) == 0:
|
| 90 |
+
success_subs = "You have not made any submissions yet."
|
| 91 |
+
failed_subs = ""
|
| 92 |
+
resp = {"response": {"success": success_subs, "failed": failed_subs}}
|
| 93 |
return resp
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
@app.post("/new_submission", response_class=JSONResponse)
|
| 97 |
+
async def new_submission(
|
| 98 |
+
submission_file: UploadFile = File(...),
|
| 99 |
+
hub_model: str = Form(...),
|
| 100 |
+
token: str = Form(...),
|
| 101 |
+
submission_comment: str = Form(...),
|
| 102 |
+
):
|
| 103 |
+
sub = Submissions(
|
| 104 |
+
end_date=COMP_INFO.end_date,
|
| 105 |
+
submission_limit=COMP_INFO.submission_limit,
|
| 106 |
+
competition_id=COMPETITION_ID,
|
| 107 |
+
token=HF_TOKEN,
|
| 108 |
+
)
|
| 109 |
+
if COMP_INFO.competition_type == "generic":
|
| 110 |
+
resp = sub.new_submission(token, submission_file)
|
| 111 |
+
return {"response": f"Success! You have {resp} submissions remaining today."}
|
| 112 |
+
elif COMP_INFO.competition_type == "code":
|
| 113 |
+
resp = sub.new_submission(token, hub_model)
|
| 114 |
+
return {"response": f"Success! You have {resp} submissions remaining today."}
|
| 115 |
+
return {"response": "Invalid competition type"}
|
competitions/info.py
CHANGED
|
@@ -99,3 +99,11 @@ class CompetitionInfo:
|
|
| 99 |
@property
|
| 100 |
def dataset_description(self):
|
| 101 |
return self.dataset_desc
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 99 |
@property
|
| 100 |
def dataset_description(self):
|
| 101 |
return self.dataset_desc
|
| 102 |
+
|
| 103 |
+
@property
|
| 104 |
+
def logo_url(self):
|
| 105 |
+
return self.config["LOGO"]
|
| 106 |
+
|
| 107 |
+
@property
|
| 108 |
+
def competition_type(self):
|
| 109 |
+
return self.config["COMPETITION_TYPE"].lower().strip()
|
competitions/submissions.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
| 1 |
import io
|
| 2 |
import json
|
| 3 |
-
import time
|
| 4 |
import uuid
|
| 5 |
from dataclasses import dataclass
|
| 6 |
from datetime import datetime
|
|
@@ -10,8 +9,8 @@ from huggingface_hub import HfApi, hf_hub_download
|
|
| 10 |
from huggingface_hub.utils._errors import EntryNotFoundError
|
| 11 |
from loguru import logger
|
| 12 |
|
| 13 |
-
from .errors import AuthenticationError,
|
| 14 |
-
from .utils import
|
| 15 |
|
| 16 |
|
| 17 |
@dataclass
|
|
@@ -19,16 +18,14 @@ class Submissions:
|
|
| 19 |
competition_id: str
|
| 20 |
submission_limit: str
|
| 21 |
end_date: datetime
|
| 22 |
-
|
| 23 |
-
autotrain_token: str
|
| 24 |
-
autotrain_backend_api: str
|
| 25 |
|
| 26 |
def __post_init__(self):
|
| 27 |
self.public_sub_columns = [
|
| 28 |
"date",
|
| 29 |
"submission_id",
|
| 30 |
"public_score",
|
| 31 |
-
|
| 32 |
"selected",
|
| 33 |
"status",
|
| 34 |
]
|
|
@@ -37,7 +34,7 @@ class Submissions:
|
|
| 37 |
"submission_id",
|
| 38 |
"public_score",
|
| 39 |
"private_score",
|
| 40 |
-
|
| 41 |
"selected",
|
| 42 |
"status",
|
| 43 |
]
|
|
@@ -46,13 +43,13 @@ class Submissions:
|
|
| 46 |
return True
|
| 47 |
|
| 48 |
def _add_new_user(self, user_info):
|
| 49 |
-
api = HfApi()
|
| 50 |
user_submission_info = {}
|
| 51 |
user_submission_info["name"] = user_info["name"]
|
| 52 |
user_submission_info["id"] = user_info["id"]
|
| 53 |
user_submission_info["submissions"] = []
|
| 54 |
# convert user_submission_info to BufferedIOBase file object
|
| 55 |
-
user_submission_info_json = json.dumps(user_submission_info)
|
| 56 |
user_submission_info_json_bytes = user_submission_info_json.encode("utf-8")
|
| 57 |
user_submission_info_json_buffer = io.BytesIO(user_submission_info_json_bytes)
|
| 58 |
|
|
@@ -61,7 +58,6 @@ class Submissions:
|
|
| 61 |
path_in_repo=f"submission_info/{user_info['id']}.json",
|
| 62 |
repo_id=self.competition_id,
|
| 63 |
repo_type="dataset",
|
| 64 |
-
token=self.autotrain_token,
|
| 65 |
)
|
| 66 |
|
| 67 |
def _check_user_submission_limit(self, user_info):
|
|
@@ -70,7 +66,7 @@ class Submissions:
|
|
| 70 |
user_fname = hf_hub_download(
|
| 71 |
repo_id=self.competition_id,
|
| 72 |
filename=f"submission_info/{user_id}.json",
|
| 73 |
-
|
| 74 |
repo_type="dataset",
|
| 75 |
)
|
| 76 |
except EntryNotFoundError:
|
|
@@ -78,14 +74,14 @@ class Submissions:
|
|
| 78 |
user_fname = hf_hub_download(
|
| 79 |
repo_id=self.competition_id,
|
| 80 |
filename=f"submission_info/{user_id}.json",
|
| 81 |
-
|
| 82 |
repo_type="dataset",
|
| 83 |
)
|
| 84 |
except Exception as e:
|
| 85 |
logger.error(e)
|
| 86 |
raise Exception("Hugging Face Hub is unreachable, please try again later.")
|
| 87 |
|
| 88 |
-
with open(user_fname, "r") as f:
|
| 89 |
user_submission_info = json.load(f)
|
| 90 |
|
| 91 |
todays_date = datetime.now().strftime("%Y-%m-%d")
|
|
@@ -107,7 +103,7 @@ class Submissions:
|
|
| 107 |
user_fname = hf_hub_download(
|
| 108 |
repo_id=self.competition_id,
|
| 109 |
filename=f"submission_info/{user_id}.json",
|
| 110 |
-
|
| 111 |
repo_type="dataset",
|
| 112 |
)
|
| 113 |
except EntryNotFoundError:
|
|
@@ -115,14 +111,14 @@ class Submissions:
|
|
| 115 |
user_fname = hf_hub_download(
|
| 116 |
repo_id=self.competition_id,
|
| 117 |
filename=f"submission_info/{user_id}.json",
|
| 118 |
-
|
| 119 |
repo_type="dataset",
|
| 120 |
)
|
| 121 |
except Exception as e:
|
| 122 |
logger.error(e)
|
| 123 |
raise Exception("Hugging Face Hub is unreachable, please try again later.")
|
| 124 |
|
| 125 |
-
with open(user_fname, "r") as f:
|
| 126 |
user_submission_info = json.load(f)
|
| 127 |
|
| 128 |
todays_date = datetime.now().strftime("%Y-%m-%d")
|
|
@@ -140,10 +136,10 @@ class Submissions:
|
|
| 140 |
user_fname = hf_hub_download(
|
| 141 |
repo_id=self.competition_id,
|
| 142 |
filename=f"submission_info/{user_id}.json",
|
| 143 |
-
|
| 144 |
repo_type="dataset",
|
| 145 |
)
|
| 146 |
-
with open(user_fname, "r") as f:
|
| 147 |
user_submission_info = json.load(f)
|
| 148 |
todays_date = datetime.now().strftime("%Y-%m-%d")
|
| 149 |
current_time = datetime.now().strftime("%H:%M:%S")
|
|
@@ -168,16 +164,15 @@ class Submissions:
|
|
| 168 |
todays_submissions += 1
|
| 169 |
|
| 170 |
# convert user_submission_info to BufferedIOBase file object
|
| 171 |
-
user_submission_info_json = json.dumps(user_submission_info)
|
| 172 |
user_submission_info_json_bytes = user_submission_info_json.encode("utf-8")
|
| 173 |
user_submission_info_json_buffer = io.BytesIO(user_submission_info_json_bytes)
|
| 174 |
-
api = HfApi()
|
| 175 |
api.upload_file(
|
| 176 |
path_or_fileobj=user_submission_info_json_buffer,
|
| 177 |
path_in_repo=f"submission_info/{user_id}.json",
|
| 178 |
repo_id=self.competition_id,
|
| 179 |
repo_type="dataset",
|
| 180 |
-
token=self.autotrain_token,
|
| 181 |
)
|
| 182 |
return todays_submissions
|
| 183 |
|
|
@@ -185,10 +180,10 @@ class Submissions:
|
|
| 185 |
user_fname = hf_hub_download(
|
| 186 |
repo_id=self.competition_id,
|
| 187 |
filename=f"submission_info/{user_id}.json",
|
| 188 |
-
|
| 189 |
repo_type="dataset",
|
| 190 |
)
|
| 191 |
-
with open(user_fname, "r") as f:
|
| 192 |
user_submission_info = json.load(f)
|
| 193 |
return user_submission_info["submissions"]
|
| 194 |
|
|
@@ -203,10 +198,10 @@ class Submissions:
|
|
| 203 |
user_fname = hf_hub_download(
|
| 204 |
repo_id=self.competition_id,
|
| 205 |
filename=f"submission_info/{user_id}.json",
|
| 206 |
-
|
| 207 |
repo_type="dataset",
|
| 208 |
)
|
| 209 |
-
with open(user_fname, "r") as f:
|
| 210 |
user_submission_info = json.load(f)
|
| 211 |
|
| 212 |
for sub in user_submission_info["submissions"]:
|
|
@@ -216,16 +211,15 @@ class Submissions:
|
|
| 216 |
sub["selected"] = False
|
| 217 |
|
| 218 |
# convert user_submission_info to BufferedIOBase file object
|
| 219 |
-
user_submission_info_json = json.dumps(user_submission_info)
|
| 220 |
user_submission_info_json_bytes = user_submission_info_json.encode("utf-8")
|
| 221 |
user_submission_info_json_buffer = io.BytesIO(user_submission_info_json_bytes)
|
| 222 |
-
api = HfApi()
|
| 223 |
api.upload_file(
|
| 224 |
path_or_fileobj=user_submission_info_json_buffer,
|
| 225 |
path_in_repo=f"submission_info/{user_id}.json",
|
| 226 |
repo_id=self.competition_id,
|
| 227 |
repo_type="dataset",
|
| 228 |
-
token=self.autotrain_token,
|
| 229 |
)
|
| 230 |
|
| 231 |
def _get_user_subs(self, user_info, private=False):
|
|
@@ -234,7 +228,8 @@ class Submissions:
|
|
| 234 |
try:
|
| 235 |
user_submissions = self._download_user_subs(user_id)
|
| 236 |
except EntryNotFoundError:
|
| 237 |
-
|
|
|
|
| 238 |
|
| 239 |
submissions_df = pd.DataFrame(user_submissions)
|
| 240 |
|
|
@@ -313,64 +308,6 @@ class Submissions:
|
|
| 313 |
raise AuthenticationError("Please verify your email on Hugging Face Hub")
|
| 314 |
return user_info
|
| 315 |
|
| 316 |
-
def _create_autotrain_project(self, submission_id, competition_id, user_id, competition_type):
|
| 317 |
-
payload = {
|
| 318 |
-
"username": self.autotrain_username,
|
| 319 |
-
"proj_name": submission_id,
|
| 320 |
-
"task": 26,
|
| 321 |
-
"config": {
|
| 322 |
-
"advanced": True,
|
| 323 |
-
"language": "unk",
|
| 324 |
-
"max_models": 1,
|
| 325 |
-
"params": [
|
| 326 |
-
{
|
| 327 |
-
"task": "competition",
|
| 328 |
-
"competition_id": competition_id,
|
| 329 |
-
"competition_type": "generic",
|
| 330 |
-
"user_id": user_id,
|
| 331 |
-
"submission_id": submission_id,
|
| 332 |
-
}
|
| 333 |
-
],
|
| 334 |
-
},
|
| 335 |
-
}
|
| 336 |
-
|
| 337 |
-
project_json_resp = http_post(
|
| 338 |
-
path="/projects/create",
|
| 339 |
-
payload=payload,
|
| 340 |
-
token=self.autotrain_token,
|
| 341 |
-
domain=self.autotrain_backend_api,
|
| 342 |
-
).json()
|
| 343 |
-
|
| 344 |
-
time.sleep(5)
|
| 345 |
-
|
| 346 |
-
# Process data
|
| 347 |
-
_ = http_post(
|
| 348 |
-
path=f"/projects/{project_json_resp['id']}/data/start_processing",
|
| 349 |
-
token=self.autotrain_token,
|
| 350 |
-
domain=self.autotrain_backend_api,
|
| 351 |
-
).json()
|
| 352 |
-
|
| 353 |
-
logger.info("⏳ Waiting for data processing to complete ...")
|
| 354 |
-
is_data_processing_success = False
|
| 355 |
-
while is_data_processing_success is not True:
|
| 356 |
-
project_status = http_get(
|
| 357 |
-
path=f"/projects/{project_json_resp['id']}",
|
| 358 |
-
token=self.autotrain_token,
|
| 359 |
-
domain=self.autotrain_backend_api,
|
| 360 |
-
).json()
|
| 361 |
-
# See database.database.enums.ProjectStatus for definitions of `status`
|
| 362 |
-
if project_status["status"] == 3:
|
| 363 |
-
is_data_processing_success = True
|
| 364 |
-
logger.info("✅ Data processing complete!")
|
| 365 |
-
time.sleep(3)
|
| 366 |
-
|
| 367 |
-
# Approve training job
|
| 368 |
-
_ = http_post(
|
| 369 |
-
path=f"/projects/{project_json_resp['id']}/start_training",
|
| 370 |
-
token=self.autotrain_token,
|
| 371 |
-
domain=self.autotrain_backend_api,
|
| 372 |
-
).json()
|
| 373 |
-
|
| 374 |
def my_submissions(self, user_token):
|
| 375 |
user_info = self._get_user_info(user_token)
|
| 376 |
current_date_time = datetime.now()
|
|
@@ -380,7 +317,7 @@ class Submissions:
|
|
| 380 |
success_subs, failed_subs = self._get_user_subs(user_info, private=private)
|
| 381 |
return success_subs, failed_subs
|
| 382 |
|
| 383 |
-
def new_submission(self, user_token, uploaded_file):
|
| 384 |
# verify token
|
| 385 |
user_info = self._get_user_info(user_token)
|
| 386 |
|
|
@@ -388,6 +325,8 @@ class Submissions:
|
|
| 388 |
if self._check_user_submission_limit(user_info) is False:
|
| 389 |
raise SubmissionLimitError("Submission limit reached")
|
| 390 |
|
|
|
|
|
|
|
| 391 |
with open(uploaded_file.name, "rb") as f:
|
| 392 |
bytes_data = f.read()
|
| 393 |
# verify file is valid
|
|
@@ -398,13 +337,12 @@ class Submissions:
|
|
| 398 |
submission_id = str(uuid.uuid4())
|
| 399 |
file_extension = uploaded_file.orig_name.split(".")[-1]
|
| 400 |
# upload file to hf hub
|
| 401 |
-
api = HfApi()
|
| 402 |
api.upload_file(
|
| 403 |
path_or_fileobj=bytes_data,
|
| 404 |
path_in_repo=f"submissions/{user_id}-{submission_id}.{file_extension}",
|
| 405 |
repo_id=self.competition_id,
|
| 406 |
repo_type="dataset",
|
| 407 |
-
token=self.autotrain_token,
|
| 408 |
)
|
| 409 |
# update submission limit
|
| 410 |
submissions_made = self._increment_submissions(
|
|
@@ -412,12 +350,12 @@ class Submissions:
|
|
| 412 |
submission_id=submission_id,
|
| 413 |
submission_comment="",
|
| 414 |
)
|
| 415 |
-
# schedule submission for evaluation
|
| 416 |
-
self._create_autotrain_project(
|
| 417 |
-
|
| 418 |
-
|
| 419 |
-
|
| 420 |
-
|
| 421 |
-
)
|
| 422 |
remaining_submissions = self.submission_limit - submissions_made
|
| 423 |
return remaining_submissions
|
|
|
|
| 1 |
import io
|
| 2 |
import json
|
|
|
|
| 3 |
import uuid
|
| 4 |
from dataclasses import dataclass
|
| 5 |
from datetime import datetime
|
|
|
|
| 9 |
from huggingface_hub.utils._errors import EntryNotFoundError
|
| 10 |
from loguru import logger
|
| 11 |
|
| 12 |
+
from .errors import AuthenticationError, PastDeadlineError, SubmissionError, SubmissionLimitError
|
| 13 |
+
from .utils import user_authentication
|
| 14 |
|
| 15 |
|
| 16 |
@dataclass
|
|
|
|
| 18 |
competition_id: str
|
| 19 |
submission_limit: str
|
| 20 |
end_date: datetime
|
| 21 |
+
token: str
|
|
|
|
|
|
|
| 22 |
|
| 23 |
def __post_init__(self):
|
| 24 |
self.public_sub_columns = [
|
| 25 |
"date",
|
| 26 |
"submission_id",
|
| 27 |
"public_score",
|
| 28 |
+
"submission_comment",
|
| 29 |
"selected",
|
| 30 |
"status",
|
| 31 |
]
|
|
|
|
| 34 |
"submission_id",
|
| 35 |
"public_score",
|
| 36 |
"private_score",
|
| 37 |
+
"submission_comment",
|
| 38 |
"selected",
|
| 39 |
"status",
|
| 40 |
]
|
|
|
|
| 43 |
return True
|
| 44 |
|
| 45 |
def _add_new_user(self, user_info):
|
| 46 |
+
api = HfApi(token=self.token)
|
| 47 |
user_submission_info = {}
|
| 48 |
user_submission_info["name"] = user_info["name"]
|
| 49 |
user_submission_info["id"] = user_info["id"]
|
| 50 |
user_submission_info["submissions"] = []
|
| 51 |
# convert user_submission_info to BufferedIOBase file object
|
| 52 |
+
user_submission_info_json = json.dumps(user_submission_info, indent=4)
|
| 53 |
user_submission_info_json_bytes = user_submission_info_json.encode("utf-8")
|
| 54 |
user_submission_info_json_buffer = io.BytesIO(user_submission_info_json_bytes)
|
| 55 |
|
|
|
|
| 58 |
path_in_repo=f"submission_info/{user_info['id']}.json",
|
| 59 |
repo_id=self.competition_id,
|
| 60 |
repo_type="dataset",
|
|
|
|
| 61 |
)
|
| 62 |
|
| 63 |
def _check_user_submission_limit(self, user_info):
|
|
|
|
| 66 |
user_fname = hf_hub_download(
|
| 67 |
repo_id=self.competition_id,
|
| 68 |
filename=f"submission_info/{user_id}.json",
|
| 69 |
+
token=self.token,
|
| 70 |
repo_type="dataset",
|
| 71 |
)
|
| 72 |
except EntryNotFoundError:
|
|
|
|
| 74 |
user_fname = hf_hub_download(
|
| 75 |
repo_id=self.competition_id,
|
| 76 |
filename=f"submission_info/{user_id}.json",
|
| 77 |
+
token=self.token,
|
| 78 |
repo_type="dataset",
|
| 79 |
)
|
| 80 |
except Exception as e:
|
| 81 |
logger.error(e)
|
| 82 |
raise Exception("Hugging Face Hub is unreachable, please try again later.")
|
| 83 |
|
| 84 |
+
with open(user_fname, "r", encoding="utf-8") as f:
|
| 85 |
user_submission_info = json.load(f)
|
| 86 |
|
| 87 |
todays_date = datetime.now().strftime("%Y-%m-%d")
|
|
|
|
| 103 |
user_fname = hf_hub_download(
|
| 104 |
repo_id=self.competition_id,
|
| 105 |
filename=f"submission_info/{user_id}.json",
|
| 106 |
+
token=self.token,
|
| 107 |
repo_type="dataset",
|
| 108 |
)
|
| 109 |
except EntryNotFoundError:
|
|
|
|
| 111 |
user_fname = hf_hub_download(
|
| 112 |
repo_id=self.competition_id,
|
| 113 |
filename=f"submission_info/{user_id}.json",
|
| 114 |
+
token=self.token,
|
| 115 |
repo_type="dataset",
|
| 116 |
)
|
| 117 |
except Exception as e:
|
| 118 |
logger.error(e)
|
| 119 |
raise Exception("Hugging Face Hub is unreachable, please try again later.")
|
| 120 |
|
| 121 |
+
with open(user_fname, "r", encoding="utf-8") as f:
|
| 122 |
user_submission_info = json.load(f)
|
| 123 |
|
| 124 |
todays_date = datetime.now().strftime("%Y-%m-%d")
|
|
|
|
| 136 |
user_fname = hf_hub_download(
|
| 137 |
repo_id=self.competition_id,
|
| 138 |
filename=f"submission_info/{user_id}.json",
|
| 139 |
+
token=self.token,
|
| 140 |
repo_type="dataset",
|
| 141 |
)
|
| 142 |
+
with open(user_fname, "r", encoding="utf-8") as f:
|
| 143 |
user_submission_info = json.load(f)
|
| 144 |
todays_date = datetime.now().strftime("%Y-%m-%d")
|
| 145 |
current_time = datetime.now().strftime("%H:%M:%S")
|
|
|
|
| 164 |
todays_submissions += 1
|
| 165 |
|
| 166 |
# convert user_submission_info to BufferedIOBase file object
|
| 167 |
+
user_submission_info_json = json.dumps(user_submission_info, indent=4)
|
| 168 |
user_submission_info_json_bytes = user_submission_info_json.encode("utf-8")
|
| 169 |
user_submission_info_json_buffer = io.BytesIO(user_submission_info_json_bytes)
|
| 170 |
+
api = HfApi(token=self.token)
|
| 171 |
api.upload_file(
|
| 172 |
path_or_fileobj=user_submission_info_json_buffer,
|
| 173 |
path_in_repo=f"submission_info/{user_id}.json",
|
| 174 |
repo_id=self.competition_id,
|
| 175 |
repo_type="dataset",
|
|
|
|
| 176 |
)
|
| 177 |
return todays_submissions
|
| 178 |
|
|
|
|
| 180 |
user_fname = hf_hub_download(
|
| 181 |
repo_id=self.competition_id,
|
| 182 |
filename=f"submission_info/{user_id}.json",
|
| 183 |
+
token=self.token,
|
| 184 |
repo_type="dataset",
|
| 185 |
)
|
| 186 |
+
with open(user_fname, "r", encoding="utf-8") as f:
|
| 187 |
user_submission_info = json.load(f)
|
| 188 |
return user_submission_info["submissions"]
|
| 189 |
|
|
|
|
| 198 |
user_fname = hf_hub_download(
|
| 199 |
repo_id=self.competition_id,
|
| 200 |
filename=f"submission_info/{user_id}.json",
|
| 201 |
+
token=self.token,
|
| 202 |
repo_type="dataset",
|
| 203 |
)
|
| 204 |
+
with open(user_fname, "r", encoding="utf-8") as f:
|
| 205 |
user_submission_info = json.load(f)
|
| 206 |
|
| 207 |
for sub in user_submission_info["submissions"]:
|
|
|
|
| 211 |
sub["selected"] = False
|
| 212 |
|
| 213 |
# convert user_submission_info to BufferedIOBase file object
|
| 214 |
+
user_submission_info_json = json.dumps(user_submission_info, indent=4)
|
| 215 |
user_submission_info_json_bytes = user_submission_info_json.encode("utf-8")
|
| 216 |
user_submission_info_json_buffer = io.BytesIO(user_submission_info_json_bytes)
|
| 217 |
+
api = HfApi(token=self.token)
|
| 218 |
api.upload_file(
|
| 219 |
path_or_fileobj=user_submission_info_json_buffer,
|
| 220 |
path_in_repo=f"submission_info/{user_id}.json",
|
| 221 |
repo_id=self.competition_id,
|
| 222 |
repo_type="dataset",
|
|
|
|
| 223 |
)
|
| 224 |
|
| 225 |
def _get_user_subs(self, user_info, private=False):
|
|
|
|
| 228 |
try:
|
| 229 |
user_submissions = self._download_user_subs(user_id)
|
| 230 |
except EntryNotFoundError:
|
| 231 |
+
logger.warning("No submissions found for user")
|
| 232 |
+
return pd.DataFrame(), pd.DataFrame()
|
| 233 |
|
| 234 |
submissions_df = pd.DataFrame(user_submissions)
|
| 235 |
|
|
|
|
| 308 |
raise AuthenticationError("Please verify your email on Hugging Face Hub")
|
| 309 |
return user_info
|
| 310 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 311 |
def my_submissions(self, user_token):
|
| 312 |
user_info = self._get_user_info(user_token)
|
| 313 |
current_date_time = datetime.now()
|
|
|
|
| 317 |
success_subs, failed_subs = self._get_user_subs(user_info, private=private)
|
| 318 |
return success_subs, failed_subs
|
| 319 |
|
| 320 |
+
def new_submission(self, user_token, uploaded_file, submission_comment):
|
| 321 |
# verify token
|
| 322 |
user_info = self._get_user_info(user_token)
|
| 323 |
|
|
|
|
| 325 |
if self._check_user_submission_limit(user_info) is False:
|
| 326 |
raise SubmissionLimitError("Submission limit reached")
|
| 327 |
|
| 328 |
+
logger.info(type(uploaded_file))
|
| 329 |
+
|
| 330 |
with open(uploaded_file.name, "rb") as f:
|
| 331 |
bytes_data = f.read()
|
| 332 |
# verify file is valid
|
|
|
|
| 337 |
submission_id = str(uuid.uuid4())
|
| 338 |
file_extension = uploaded_file.orig_name.split(".")[-1]
|
| 339 |
# upload file to hf hub
|
| 340 |
+
api = HfApi(token=self.token)
|
| 341 |
api.upload_file(
|
| 342 |
path_or_fileobj=bytes_data,
|
| 343 |
path_in_repo=f"submissions/{user_id}-{submission_id}.{file_extension}",
|
| 344 |
repo_id=self.competition_id,
|
| 345 |
repo_type="dataset",
|
|
|
|
| 346 |
)
|
| 347 |
# update submission limit
|
| 348 |
submissions_made = self._increment_submissions(
|
|
|
|
| 350 |
submission_id=submission_id,
|
| 351 |
submission_comment="",
|
| 352 |
)
|
| 353 |
+
# TODO: schedule submission for evaluation
|
| 354 |
+
# self._create_autotrain_project(
|
| 355 |
+
# submission_id=f"{submission_id}",
|
| 356 |
+
# competition_id=f"{self.competition_id}",
|
| 357 |
+
# user_id=user_id,
|
| 358 |
+
# competition_type="generic",
|
| 359 |
+
# )
|
| 360 |
remaining_submissions = self.submission_limit - submissions_made
|
| 361 |
return remaining_submissions
|
competitions/templates/index.html
CHANGED
|
@@ -94,13 +94,41 @@
|
|
| 94 |
console.error('There has been a problem with your fetch operation:', error);
|
| 95 |
});
|
| 96 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 97 |
|
| 98 |
// Find the 'Home' link in the sidebar
|
| 99 |
const homeLink = document.getElementById('home');
|
| 100 |
const datasetLink = document.getElementById('dataset');
|
| 101 |
const publicLBLink = document.getElementById('public_lb');
|
| 102 |
const privateLBLink = document.getElementById('private_lb');
|
| 103 |
-
const
|
|
|
|
| 104 |
|
| 105 |
// Add a click event listener to the 'Home' link
|
| 106 |
homeLink.addEventListener('click', function (event) {
|
|
@@ -123,10 +151,14 @@
|
|
| 123 |
fetchAndDisplayPrivateLeaderboard(); // Fetch and display info on click
|
| 124 |
});
|
| 125 |
|
| 126 |
-
|
| 127 |
event.preventDefault(); // Prevent the default link behavior
|
| 128 |
showSubmissionModal(); // Fetch and display info on click
|
| 129 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
| 130 |
|
| 131 |
// Fetch and display info when the page loads
|
| 132 |
fetchAndDisplayCompetitionInfo();
|
|
@@ -173,7 +205,7 @@
|
|
| 173 |
<li>
|
| 174 |
<button type="button"
|
| 175 |
class="flex items-center w-full p-2 text-base text-gray-900 transition duration-75 rounded-lg group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700"
|
| 176 |
-
aria-controls="dropdown
|
| 177 |
<svg class="flex-shrink-0 w-5 h-5 text-gray-500 transition duration-75 group-hover:text-gray-900 dark:text-gray-400 dark:group-hover:text-white"
|
| 178 |
aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor"
|
| 179 |
viewBox="0 0 18 21">
|
|
@@ -187,7 +219,7 @@
|
|
| 187 |
d="m1 1 4 4 4-4" />
|
| 188 |
</svg>
|
| 189 |
</button>
|
| 190 |
-
<ul id="dropdown
|
| 191 |
<li>
|
| 192 |
<a href="#" id="public_lb"
|
| 193 |
class="flex items-center w-full p-2 text-gray-900 transition duration-75 rounded-lg pl-11 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700">Public</a>
|
|
@@ -199,34 +231,52 @@
|
|
| 199 |
</ul>
|
| 200 |
</li>
|
| 201 |
<li>
|
| 202 |
-
<
|
| 203 |
-
class="flex items-center p-2 text-gray-900 rounded-lg
|
|
|
|
| 204 |
<svg class="flex-shrink-0 w-5 h-5 text-gray-500 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white"
|
| 205 |
aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor"
|
| 206 |
-
viewBox="0 0 20
|
|
|
|
| 207 |
<path
|
| 208 |
-
d="
|
|
|
|
|
|
|
| 209 |
</svg>
|
| 210 |
-
<span class="flex-1 ms-3 whitespace-nowrap">
|
| 211 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 212 |
</li>
|
| 213 |
<li>
|
| 214 |
-
<a href="#"
|
| 215 |
class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group">
|
| 216 |
<svg class="flex-shrink-0 w-5 h-5 text-gray-500 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white"
|
| 217 |
aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor"
|
| 218 |
-
viewBox="0 0 20
|
| 219 |
-
<path d="M5 5V.13a2.96 2.96 0 0 0-1.293.749L.879 3.707A2.96 2.96 0 0 0 .13 5H5Z" />
|
| 220 |
-
<path
|
| 221 |
-
d="M6.737 11.061a2.961 2.961 0 0 1 .81-1.515l6.117-6.116A4.839 4.839 0 0 1 16 2.141V2a1.97 1.97 0 0 0-1.933-2H7v5a2 2 0 0 1-2 2H0v11a1.969 1.969 0 0 0 1.933 2h12.134A1.97 1.97 0 0 0 16 18v-3.093l-1.546 1.546c-.413.413-.94.695-1.513.81l-3.4.679a2.947 2.947 0 0 1-1.85-.227 2.96 2.96 0 0 1-1.635-3.257l.681-3.397Z" />
|
| 222 |
<path
|
| 223 |
-
d="
|
| 224 |
</svg>
|
| 225 |
-
<span class="flex-1 ms-3 whitespace-nowrap">
|
| 226 |
</a>
|
| 227 |
</li>
|
| 228 |
<li>
|
| 229 |
-
<label for="
|
| 230 |
</label>
|
| 231 |
<input type="password" name="user_token" id="user_token"
|
| 232 |
class="mt-1 block w-full border border-gray-300 px-3 py-1.5 bg-white rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
|
|
@@ -234,19 +284,34 @@
|
|
| 234 |
</ul>
|
| 235 |
</div>
|
| 236 |
</aside>
|
| 237 |
-
<
|
| 238 |
-
|
|
|
|
|
|
|
|
|
|
| 239 |
<div id="submission-modal" tabindex="-1"
|
| 240 |
class="hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full">
|
| 241 |
<div class="form-container max-w-5xl mx-auto mt-3 p-6 shadow-2xl bg-white">
|
| 242 |
<form action="#" method="post" class="gap-2" enctype="multipart/form-data">
|
|
|
|
| 243 |
<div class="form-group">
|
| 244 |
-
<label class="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
|
|
|
|
| 245 |
file</label>
|
| 246 |
<input
|
| 247 |
class="block w-full text-sm text-gray-900 border border-gray-300 rounded-lg cursor-pointer bg-gray-50 focus:outline-none "
|
| 248 |
-
id="
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 249 |
</div>
|
|
|
|
| 250 |
<div class="form-group mt-2">
|
| 251 |
<label for="params" class="text-sm font-medium text-gray-700">Submission description (optional)
|
| 252 |
</label>
|
|
@@ -267,4 +332,48 @@
|
|
| 267 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/flowbite/2.2.1/flowbite.min.js"></script>
|
| 268 |
</body>
|
| 269 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 270 |
</html>
|
|
|
|
| 94 |
console.error('There has been a problem with your fetch operation:', error);
|
| 95 |
});
|
| 96 |
}
|
| 97 |
+
function fetchAndDisplaySubmissions() {
|
| 98 |
+
const userToken = document.getElementById('user_token').value;
|
| 99 |
+
const apiEndpoint = '/my_submissions';
|
| 100 |
+
|
| 101 |
+
const requestOptions = {
|
| 102 |
+
method: 'POST',
|
| 103 |
+
headers: {
|
| 104 |
+
'Content-Type': 'application/json',
|
| 105 |
+
},
|
| 106 |
+
body: JSON.stringify({ "user_token": userToken })
|
| 107 |
+
};
|
| 108 |
+
|
| 109 |
+
fetch(apiEndpoint, requestOptions)
|
| 110 |
+
.then(response => {
|
| 111 |
+
if (!response.ok) {
|
| 112 |
+
throw new Error('Network response was not ok');
|
| 113 |
+
}
|
| 114 |
+
return response.json();
|
| 115 |
+
})
|
| 116 |
+
.then(data => {
|
| 117 |
+
const contentDiv = document.getElementById('content');
|
| 118 |
+
contentDiv.innerHTML = marked.parse(data.response.success);
|
| 119 |
+
})
|
| 120 |
+
.catch(error => {
|
| 121 |
+
console.error('There was a problem with the fetch operation:', error);
|
| 122 |
+
});
|
| 123 |
+
}
|
| 124 |
|
| 125 |
// Find the 'Home' link in the sidebar
|
| 126 |
const homeLink = document.getElementById('home');
|
| 127 |
const datasetLink = document.getElementById('dataset');
|
| 128 |
const publicLBLink = document.getElementById('public_lb');
|
| 129 |
const privateLBLink = document.getElementById('private_lb');
|
| 130 |
+
const newSubmission = document.getElementById('new_submission');
|
| 131 |
+
const mySubmissions = document.getElementById('my_submissions');
|
| 132 |
|
| 133 |
// Add a click event listener to the 'Home' link
|
| 134 |
homeLink.addEventListener('click', function (event) {
|
|
|
|
| 151 |
fetchAndDisplayPrivateLeaderboard(); // Fetch and display info on click
|
| 152 |
});
|
| 153 |
|
| 154 |
+
newSubmission.addEventListener('click', function (event) {
|
| 155 |
event.preventDefault(); // Prevent the default link behavior
|
| 156 |
showSubmissionModal(); // Fetch and display info on click
|
| 157 |
});
|
| 158 |
+
mySubmissions.addEventListener('click', function (event) {
|
| 159 |
+
event.preventDefault(); // Prevent the default link behavior
|
| 160 |
+
fetchAndDisplaySubmissions(); // Fetch and display info on click
|
| 161 |
+
});
|
| 162 |
|
| 163 |
// Fetch and display info when the page loads
|
| 164 |
fetchAndDisplayCompetitionInfo();
|
|
|
|
| 205 |
<li>
|
| 206 |
<button type="button"
|
| 207 |
class="flex items-center w-full p-2 text-base text-gray-900 transition duration-75 rounded-lg group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700"
|
| 208 |
+
aria-controls="lb-dropdown" data-collapse-toggle="lb-dropdown">
|
| 209 |
<svg class="flex-shrink-0 w-5 h-5 text-gray-500 transition duration-75 group-hover:text-gray-900 dark:text-gray-400 dark:group-hover:text-white"
|
| 210 |
aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor"
|
| 211 |
viewBox="0 0 18 21">
|
|
|
|
| 219 |
d="m1 1 4 4 4-4" />
|
| 220 |
</svg>
|
| 221 |
</button>
|
| 222 |
+
<ul id="lb-dropdown" class="hidden py-2 space-y-2">
|
| 223 |
<li>
|
| 224 |
<a href="#" id="public_lb"
|
| 225 |
class="flex items-center w-full p-2 text-gray-900 transition duration-75 rounded-lg pl-11 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700">Public</a>
|
|
|
|
| 231 |
</ul>
|
| 232 |
</li>
|
| 233 |
<li>
|
| 234 |
+
<button type="button"
|
| 235 |
+
class="flex items-center w-full p-2 text-base text-gray-900 transition duration-75 rounded-lg group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700"
|
| 236 |
+
aria-controls="submissions-dropdown" data-collapse-toggle="submissions-dropdown">
|
| 237 |
<svg class="flex-shrink-0 w-5 h-5 text-gray-500 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white"
|
| 238 |
aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor"
|
| 239 |
+
viewBox="0 0 20 20">
|
| 240 |
+
<path d="M5 5V.13a2.96 2.96 0 0 0-1.293.749L.879 3.707A2.96 2.96 0 0 0 .13 5H5Z" />
|
| 241 |
<path
|
| 242 |
+
d="M6.737 11.061a2.961 2.961 0 0 1 .81-1.515l6.117-6.116A4.839 4.839 0 0 1 16 2.141V2a1.97 1.97 0 0 0-1.933-2H7v5a2 2 0 0 1-2 2H0v11a1.969 1.969 0 0 0 1.933 2h12.134A1.97 1.97 0 0 0 16 18v-3.093l-1.546 1.546c-.413.413-.94.695-1.513.81l-3.4.679a2.947 2.947 0 0 1-1.85-.227 2.96 2.96 0 0 1-1.635-3.257l.681-3.397Z" />
|
| 243 |
+
<path
|
| 244 |
+
d="M8.961 16a.93.93 0 0 0 .189-.019l3.4-.679a.961.961 0 0 0 .49-.263l6.118-6.117a2.884 2.884 0 0 0-4.079-4.078l-6.117 6.117a.96.96 0 0 0-.263.491l-.679 3.4A.961.961 0 0 0 8.961 16Zm7.477-9.8a.958.958 0 0 1 .68-.281.961.961 0 0 1 .682 1.644l-.315.315-1.36-1.36.313-.318Zm-5.911 5.911 4.236-4.236 1.359 1.359-4.236 4.237-1.7.339.341-1.699Z" />
|
| 245 |
</svg>
|
| 246 |
+
<span class="flex-1 ms-3 text-left rtl:text-right whitespace-nowrap">Submissions</span>
|
| 247 |
+
<svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
|
| 248 |
+
viewBox="0 0 10 6">
|
| 249 |
+
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
| 250 |
+
d="m1 1 4 4 4-4" />
|
| 251 |
+
</svg>
|
| 252 |
+
</button>
|
| 253 |
+
<ul id="submissions-dropdown" class="hidden py-2 space-y-2">
|
| 254 |
+
<li>
|
| 255 |
+
<a href="#" id="my_submissions"
|
| 256 |
+
class="flex items-center w-full p-2 text-gray-900 transition duration-75 rounded-lg pl-11 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700">My
|
| 257 |
+
submissions</a>
|
| 258 |
+
</li>
|
| 259 |
+
<li>
|
| 260 |
+
<a href="#" id="new_submission"
|
| 261 |
+
class="flex items-center w-full p-2 text-gray-900 transition duration-75 rounded-lg pl-11 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700">New
|
| 262 |
+
submission</a>
|
| 263 |
+
</li>
|
| 264 |
+
</ul>
|
| 265 |
</li>
|
| 266 |
<li>
|
| 267 |
+
<a href="#"
|
| 268 |
class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group">
|
| 269 |
<svg class="flex-shrink-0 w-5 h-5 text-gray-500 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white"
|
| 270 |
aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor"
|
| 271 |
+
viewBox="0 0 20 18">
|
|
|
|
|
|
|
|
|
|
| 272 |
<path
|
| 273 |
+
d="M14 2a3.963 3.963 0 0 0-1.4.267 6.439 6.439 0 0 1-1.331 6.638A4 4 0 1 0 14 2Zm1 9h-1.264A6.957 6.957 0 0 1 15 15v2a2.97 2.97 0 0 1-.184 1H19a1 1 0 0 0 1-1v-1a5.006 5.006 0 0 0-5-5ZM6.5 9a4.5 4.5 0 1 0 0-9 4.5 4.5 0 0 0 0 9ZM8 10H5a5.006 5.006 0 0 0-5 5v2a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-2a5.006 5.006 0 0 0-5-5Z" />
|
| 274 |
</svg>
|
| 275 |
+
<span class="flex-1 ms-3 whitespace-nowrap">Team</span>
|
| 276 |
</a>
|
| 277 |
</li>
|
| 278 |
<li>
|
| 279 |
+
<label for="user_token" class="text-xs font-medium text-white">Hugging Face Token (read-only)
|
| 280 |
</label>
|
| 281 |
<input type="password" name="user_token" id="user_token"
|
| 282 |
class="mt-1 block w-full border border-gray-300 px-3 py-1.5 bg-white rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
|
|
|
|
| 284 |
</ul>
|
| 285 |
</div>
|
| 286 |
</aside>
|
| 287 |
+
<div class="p-4 sm:ml-64">
|
| 288 |
+
<img src={{logo}} alt="Competition logo" class="mx-auto mb-4">
|
| 289 |
+
<article class="prose max-w-5xl" id="content">
|
| 290 |
+
</article>
|
| 291 |
+
</div>
|
| 292 |
<div id="submission-modal" tabindex="-1"
|
| 293 |
class="hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full">
|
| 294 |
<div class="form-container max-w-5xl mx-auto mt-3 p-6 shadow-2xl bg-white">
|
| 295 |
<form action="#" method="post" class="gap-2" enctype="multipart/form-data">
|
| 296 |
+
{% if competition_type == 'generic' %}
|
| 297 |
<div class="form-group">
|
| 298 |
+
<label class="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
|
| 299 |
+
for="submission_file">Upload
|
| 300 |
file</label>
|
| 301 |
<input
|
| 302 |
class="block w-full text-sm text-gray-900 border border-gray-300 rounded-lg cursor-pointer bg-gray-50 focus:outline-none "
|
| 303 |
+
id="submission_file" type="file" name="submission_file">
|
| 304 |
+
</div>
|
| 305 |
+
{% endif %}
|
| 306 |
+
{% if competition_type == 'code' %}
|
| 307 |
+
<div class="form-group">
|
| 308 |
+
<label for="hub_model" class="text-sm font-medium text-gray-700">Hub model
|
| 309 |
+
</label>
|
| 310 |
+
<input type="text" name="hub_model" id="hub_model"
|
| 311 |
+
class="mt-1 block w-full border border-gray-300 px-3 py-1.5 bg-white rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500"
|
| 312 |
+
placeholder="username/my-model">
|
| 313 |
</div>
|
| 314 |
+
{% endif %}
|
| 315 |
<div class="form-group mt-2">
|
| 316 |
<label for="params" class="text-sm font-medium text-gray-700">Submission description (optional)
|
| 317 |
</label>
|
|
|
|
| 332 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/flowbite/2.2.1/flowbite.min.js"></script>
|
| 333 |
</body>
|
| 334 |
|
| 335 |
+
<script>
|
| 336 |
+
document.addEventListener('DOMContentLoaded', function () {
|
| 337 |
+
document.querySelector('.confirm').addEventListener('click', function (event) {
|
| 338 |
+
event.preventDefault();
|
| 339 |
+
|
| 340 |
+
var formData = new FormData();
|
| 341 |
+
var competitionType = '{{ competition_type }}';
|
| 342 |
+
|
| 343 |
+
if (competitionType === 'generic') {
|
| 344 |
+
var submissionFile = document.getElementById('submission_file').files[0];
|
| 345 |
+
formData.append('submission_file', submissionFile);
|
| 346 |
+
formData.append('hub_model', 'None');
|
| 347 |
+
} else if (competitionType === 'code') {
|
| 348 |
+
var hubModel = document.getElementById('hub_model').value;
|
| 349 |
+
if (!hubModel) {
|
| 350 |
+
alert('Hub model is required.');
|
| 351 |
+
return;
|
| 352 |
+
}
|
| 353 |
+
formData.append('hub_model', hubModel);
|
| 354 |
+
} else {
|
| 355 |
+
alert('Invalid competition type.');
|
| 356 |
+
return;
|
| 357 |
+
}
|
| 358 |
+
|
| 359 |
+
// Token should be added here if available
|
| 360 |
+
var token = document.getElementById('user_token').value;
|
| 361 |
+
formData.append('token', token);
|
| 362 |
+
|
| 363 |
+
fetch('/new_submission', {
|
| 364 |
+
method: 'POST',
|
| 365 |
+
body: formData
|
| 366 |
+
})
|
| 367 |
+
.then(response => response.json())
|
| 368 |
+
.then(data => {
|
| 369 |
+
alert(data.response);
|
| 370 |
+
// Close the modal here if needed
|
| 371 |
+
})
|
| 372 |
+
.catch((error) => {
|
| 373 |
+
console.error('Error:', error);
|
| 374 |
+
});
|
| 375 |
+
});
|
| 376 |
+
});
|
| 377 |
+
</script>
|
| 378 |
+
|
| 379 |
</html>
|