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 """ # make sure competition name is alphanumeric 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", ) # create competition space 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()