| | import io |
| | import json |
| |
|
| | import gradio as gr |
| | from huggingface_hub import HfApi |
| | from loguru import logger |
| |
|
| | from competitions.utils import token_information |
| |
|
| |
|
| | COMPETITION_DESC = """Sample competition description""" |
| | DATASET_DESC = """Sample dataset description""" |
| | SUBMISSION_DESC = """Sample submission description""" |
| | RULES = """Sample rules""" |
| | SOLUTION_CSV = """ |
| | id,pred,split |
| | 0,1,public |
| | 1,0,private |
| | 2,0,private |
| | 3,1,private |
| | 4,0,public |
| | 5,1,private |
| | 6,1,public |
| | 7,1,private |
| | 8,0,public |
| | 9,0,private |
| | 10,0,private |
| | 11,0,private |
| | 12,1,private |
| | 13,0,private |
| | 14,1,public |
| | 15,1,private |
| | 16,1,private |
| | 17,0,private |
| | 18,0,private |
| | 19,0,public |
| | 20,0,private |
| | 21,0,private |
| | 22,1,private |
| | 23,1,public |
| | 24,0,private |
| | 25,0,private |
| | 26,0,public |
| | 27,1,private |
| | 28,1,private |
| | 29,0,private |
| | 30,0,public |
| | """ |
| | SOLUTION_CSV = SOLUTION_CSV.strip() |
| |
|
| | DOCKERFILE = """ |
| | FROM huggingface/competitions:latest |
| | |
| | CMD uvicorn competitions.app:app --host 0.0.0.0 --port 7860 --workers 1 |
| | """ |
| | DOCKERFILE = DOCKERFILE.replace("\n", " ").replace(" ", "\n").strip() |
| |
|
| | HARDWARE_CHOICES = [ |
| | "cpu-basic", |
| | "cpu-upgrade", |
| | "t4-small", |
| | "t4-medium", |
| | "a10g-small", |
| | "a10g-large", |
| | "a10g-largex2", |
| | "a10g-largex4", |
| | "a100-large", |
| | ] |
| | METRIC_CHOICES = [ |
| | "accuracy_score", |
| | "f1_score", |
| | "hamming_loss", |
| | "jaccard_score", |
| | "log_loss", |
| | "roc_auc_score", |
| | "mean_squared_error", |
| | "mean_absolute_error", |
| | "r2_score", |
| | "custom", |
| | ] |
| |
|
| |
|
| | def check_if_user_can_create_competition(user_token): |
| | """ |
| | Check if the user can create a competition |
| | :param user_token: the user's token |
| | :return: True if the user can create a competition, False otherwise |
| | """ |
| | user_info = token_information(user_token) |
| | valid_orgs = user_info["orgs"] |
| |
|
| | return gr.Dropdown( |
| | choices=valid_orgs, |
| | visible=True, |
| | value=valid_orgs[0], |
| | ) |
| |
|
| |
|
| | def _create_readme(competition_name): |
| | _readme = "---\n" |
| | _readme += f"title: {competition_name}\n" |
| | _readme += "emoji: 🚀\n" |
| | _readme += "colorFrom: green\n" |
| | _readme += "colorTo: indigo\n" |
| | _readme += "sdk: docker\n" |
| | _readme += "pinned: false\n" |
| | _readme += "tags:\n" |
| | _readme += " - competition\n" |
| | _readme += "hf_oauth: true\n" |
| | _readme += "hf_oauth_scopes:\n" |
| | _readme += " - read-repos\n" |
| | _readme += "---\n" |
| | _readme = io.BytesIO(_readme.encode()) |
| | return _readme |
| |
|
| |
|
| | def _create( |
| | user_token, |
| | organization, |
| | competition_name, |
| | competition_logo, |
| | hardware, |
| | competition_type, |
| | time_limit, |
| | metric, |
| | metric_higher_is_better, |
| | submission_limit, |
| | selection_limit, |
| | end_date, |
| | submission_id_column, |
| | submission_columns, |
| | submission_rows, |
| | ): |
| | """ |
| | Create a competition |
| | """ |
| |
|
| | |
| | competition_name = "".join([c for c in competition_name if c.isalnum()]) |
| | if len(competition_name) == 0: |
| | raise gr.Error("Please provide a valid alphanumeric competition name") |
| |
|
| | conf_json = { |
| | "COMPETITION_TYPE": competition_type, |
| | "SUBMISSION_LIMIT": int(submission_limit), |
| | "TIME_LIMIT": int(time_limit), |
| | "SELECTION_LIMIT": int(selection_limit), |
| | "HARDWARE": hardware, |
| | "END_DATE": end_date, |
| | "EVAL_HIGHER_IS_BETTER": metric_higher_is_better is True, |
| | "SUBMISSION_ID_COLUMN": submission_id_column, |
| | "SUBMISSION_COLUMNS": submission_columns, |
| | "SUBMISSION_ROWS": int(submission_rows), |
| | "EVAL_METRIC": metric, |
| | "LOGO": competition_logo, |
| | "DATASET": "", |
| | "SUBMISSION_FILENAMES": ["submission.csv"], |
| | "SCORING_METRIC": "", |
| | } |
| | teams_json = {} |
| | user_team_json = {} |
| |
|
| | logger.info(f"Creating competition: {competition_name}") |
| |
|
| | api = HfApi(token=user_token) |
| | api.create_repo( |
| | repo_id=f"{organization}/{competition_name}", |
| | repo_type="dataset", |
| | private=True, |
| | ) |
| |
|
| | conf_json = json.dumps(conf_json, indent=4) |
| | conf_json_bytes = conf_json.encode("utf-8") |
| | conf_json_buffer = io.BytesIO(conf_json_bytes) |
| | api.upload_file( |
| | path_or_fileobj=conf_json_buffer, |
| | path_in_repo="conf.json", |
| | repo_id=f"{organization}/{competition_name}", |
| | repo_type="dataset", |
| | ) |
| |
|
| | teams_json = json.dumps(teams_json, indent=4) |
| | teams_json_bytes = teams_json.encode("utf-8") |
| | teams_json_buffer = io.BytesIO(teams_json_bytes) |
| | api.upload_file( |
| | path_or_fileobj=teams_json_buffer, |
| | path_in_repo="teams.json", |
| | repo_id=f"{organization}/{competition_name}", |
| | repo_type="dataset", |
| | ) |
| |
|
| | user_team_json = json.dumps(user_team_json, indent=4) |
| | user_team_json_bytes = user_team_json.encode("utf-8") |
| | user_team_json_buffer = io.BytesIO(user_team_json_bytes) |
| | api.upload_file( |
| | path_or_fileobj=user_team_json_buffer, |
| | path_in_repo="user_team.json", |
| | repo_id=f"{organization}/{competition_name}", |
| | repo_type="dataset", |
| | ) |
| |
|
| | comp_desc = io.BytesIO(COMPETITION_DESC.encode()) |
| | api.upload_file( |
| | path_or_fileobj=comp_desc, |
| | path_in_repo="COMPETITION_DESC.md", |
| | repo_id=f"{organization}/{competition_name}", |
| | repo_type="dataset", |
| | ) |
| |
|
| | dataset_desc = io.BytesIO(DATASET_DESC.encode()) |
| | api.upload_file( |
| | path_or_fileobj=dataset_desc, |
| | path_in_repo="DATASET_DESC.md", |
| | repo_id=f"{organization}/{competition_name}", |
| | repo_type="dataset", |
| | ) |
| |
|
| | submission_desc = io.BytesIO(SUBMISSION_DESC.encode()) |
| | api.upload_file( |
| | path_or_fileobj=submission_desc, |
| | path_in_repo="SUBMISSION_DESC.md", |
| | repo_id=f"{organization}/{competition_name}", |
| | repo_type="dataset", |
| | ) |
| |
|
| | solution_csv = io.BytesIO(SOLUTION_CSV.encode()) |
| | api.upload_file( |
| | path_or_fileobj=solution_csv, |
| | path_in_repo="solution.csv", |
| | repo_id=f"{organization}/{competition_name}", |
| | repo_type="dataset", |
| | ) |
| |
|
| | rules = io.BytesIO(RULES.encode()) |
| | api.upload_file( |
| | path_or_fileobj=rules, |
| | path_in_repo="RULES.md", |
| | repo_id=f"{organization}/{competition_name}", |
| | repo_type="dataset", |
| | ) |
| |
|
| | |
| | api.create_repo( |
| | repo_id=f"{organization}/{competition_name}", |
| | repo_type="space", |
| | space_sdk="docker", |
| | space_hardware="cpu-basic" if competition_type == "script" else hardware, |
| | private=True, |
| | ) |
| | api.add_space_secret(repo_id=f"{organization}/{competition_name}", key="HF_TOKEN", value=user_token) |
| | api.add_space_secret( |
| | repo_id=f"{organization}/{competition_name}", |
| | key="COMPETITION_ID", |
| | value=f"{organization}/{competition_name}", |
| | ) |
| | readme = _create_readme(competition_name) |
| | api.upload_file( |
| | path_or_fileobj=readme, |
| | path_in_repo="README.md", |
| | repo_id=f"{organization}/{competition_name}", |
| | repo_type="space", |
| | ) |
| |
|
| | _dockerfile = io.BytesIO(DOCKERFILE.encode()) |
| | api.upload_file( |
| | path_or_fileobj=_dockerfile, |
| | path_in_repo="Dockerfile", |
| | repo_id=f"{organization}/{competition_name}", |
| | repo_type="space", |
| | ) |
| |
|
| | return gr.Markdown( |
| | value=f"""Created private dataset and competition space. |
| | To make competition public, you should make the space public. |
| | Please note that the dataset should always be kept private. |
| | |
| | Private dataset: https://huggingface.co/datasets/{organization}/{competition_name} |
| | |
| | Competition space: https://huggingface.co/spaces/{organization}/{competition_name} |
| | |
| | Note: there's still some work left. Now you must change the solution.csv file to your own solution, |
| | and make changes to *_desc.md files to reflect your competition. You may also change conf.json |
| | to suit your needs. Please refer to the [documentation](https://hf.co/docs/competitions) for more information. |
| | """ |
| | ) |
| |
|
| |
|
| | def main(): |
| | with gr.Blocks() as demo: |
| | gr.Markdown("# Hugging Face Competition Creator") |
| | token = gr.Textbox(label="Your Hugging Face write token", lines=1, type="password") |
| | with gr.Row(): |
| | organization = gr.Dropdown(label="Organization name", choices=[""]) |
| | competition_name = gr.Textbox(label="Competition name", lines=1) |
| | competition_logo = gr.Textbox(label="Competition logo", value="https://mysite.com/mylogo.png", lines=1) |
| | with gr.Group(): |
| | with gr.Row(): |
| | hardware = gr.Dropdown(label="Hardware to use", choices=HARDWARE_CHOICES, value=HARDWARE_CHOICES[0]) |
| | competition_type = gr.Dropdown( |
| | label="Competition type", choices=["generic", "script"], value="generic" |
| | ) |
| | time_limit = gr.Textbox( |
| | label="Time limit (s). Only used for script competitions", lines=1, value="3600" |
| | ) |
| | with gr.Row(): |
| | metric = gr.Dropdown(label="Metric to use", choices=METRIC_CHOICES, value=METRIC_CHOICES[0]) |
| | metric_higher_is_better = gr.Dropdown( |
| | label="Is higher metric better?", choices=[True, False], value=True |
| | ) |
| | with gr.Row(): |
| | submission_limit = gr.Textbox(label="Submission limit per day", lines=1, value="5") |
| | selection_limit = gr.Textbox(label="Final selection limit", lines=1, value="2") |
| | end_date = gr.Textbox(label="End date (YYYY-MM-DD)", lines=1, value="2024-12-31") |
| | with gr.Row(): |
| | submission_id_column = gr.Textbox(label="Submission id column", lines=1, value="id") |
| | submission_columns = gr.Textbox(label="Submission columns", lines=1, value="id,pred") |
| | submission_rows = gr.Textbox(label="Submission total rows (exclusing header)", lines=1, value="10000") |
| |
|
| | output_md = gr.Markdown("Click the button below to create the competition") |
| | create_competition = gr.Button(value="Create competition") |
| | token.change(check_if_user_can_create_competition, inputs=token, outputs=organization) |
| |
|
| | create_competition.click( |
| | _create, |
| | inputs=[ |
| | token, |
| | organization, |
| | competition_name, |
| | competition_logo, |
| | hardware, |
| | competition_type, |
| | time_limit, |
| | metric, |
| | metric_higher_is_better, |
| | submission_limit, |
| | selection_limit, |
| | end_date, |
| | submission_id_column, |
| | submission_columns, |
| | submission_rows, |
| | ], |
| | outputs=output_md, |
| | ) |
| | return demo |
| |
|
| |
|
| | if __name__ == "__main__": |
| | main().launch() |
| |
|