Spaces:
Paused
Paused
| """ | |
| Interactive Task Creation CLI Module | |
| Provides an interactive command-line interface for creating new annotation tasks. | |
| Guides users through configuration and generates a YAML config file. | |
| """ | |
| import os | |
| import click | |
| import yaml | |
| # Common annotation types shown in the interactive prompt. | |
| # The full set of supported types is in the schema registry. | |
| COMMON_ANNOTATION_TYPES = [ | |
| "radio", | |
| "multiselect", | |
| "text", | |
| "likert", | |
| "slider", | |
| "span", | |
| "bws", | |
| "pairwise", | |
| "ranking", | |
| ] | |
| def create_task_cli(): | |
| """ | |
| Interactive task creation wizard. | |
| Walks the user through server setup, data files, annotation schemes, | |
| and output settings, then writes a YAML config file. | |
| """ | |
| click.echo("Welcome to the Potato annotation task creation wizard!") | |
| click.echo("This will generate a .yaml config file for your annotation task.") | |
| click.echo("You can edit the file afterwards to add advanced features.\n") | |
| click.echo("— Server setup —\n") | |
| task_name = click.prompt("Task name (shown to annotators)", default="My Annotation Task") | |
| port = click.prompt("Server port", default=8000, type=click.IntRange(1, 65535)) | |
| click.echo("\n— Data files —\n") | |
| data_files = [] | |
| fname = click.prompt("Path to your data file (JSONL)") | |
| data_files.append(fname) | |
| while click.confirm("Add another data file?", default=False): | |
| fname = click.prompt("Path to data file") | |
| data_files.append(fname) | |
| id_key = click.prompt("Which field in the data is the item ID?", default="id") | |
| text_key = click.prompt("Which field is the item text?", default="text") | |
| click.echo("\n— Annotation schemes —\n") | |
| annotation_schemes = [] | |
| while True: | |
| atype = click.prompt( | |
| "Annotation type", | |
| type=click.Choice(COMMON_ANNOTATION_TYPES, case_sensitive=False), | |
| ) | |
| name = click.prompt("Internal name for this scheme (used in output)") | |
| desc = click.prompt("Description/question shown to annotators") | |
| scheme = { | |
| "annotation_type": atype, | |
| "name": name, | |
| "description": desc, | |
| } | |
| if atype in ("radio", "multiselect"): | |
| labels = [] | |
| click.echo("Enter labels one at a time (empty line to finish):") | |
| while True: | |
| label = click.prompt(" Label", default="", show_default=False) | |
| if not label: | |
| break | |
| labels.append(label) | |
| scheme["labels"] = labels | |
| elif atype == "likert": | |
| size = click.prompt("Scale size", default=5, type=int) | |
| min_label = click.prompt("Label for minimum", default="Strongly Disagree") | |
| max_label = click.prompt("Label for maximum", default="Strongly Agree") | |
| scheme["size"] = size | |
| scheme["min_label"] = min_label | |
| scheme["max_label"] = max_label | |
| elif atype == "slider": | |
| scheme["min_value"] = click.prompt("Minimum value", default=0, type=int) | |
| scheme["max_value"] = click.prompt("Maximum value", default=100, type=int) | |
| elif atype == "bws": | |
| size = click.prompt("Tuple size (items shown at once)", default=4, type=int) | |
| scheme["size"] = size | |
| elif atype == "ranking": | |
| labels = [] | |
| click.echo("Enter options to rank (empty line to finish):") | |
| while True: | |
| label = click.prompt(" Option", default="", show_default=False) | |
| if not label: | |
| break | |
| labels.append(label) | |
| scheme["labels"] = labels | |
| annotation_schemes.append(scheme) | |
| if not click.confirm("\nAdd another annotation scheme?", default=False): | |
| break | |
| click.echo("\n— Output settings —\n") | |
| output_dir = click.prompt("Output directory for annotations", default="annotation_output") | |
| codebook_url = click.prompt("Annotation codebook URL (optional)", default="") | |
| auto_export = click.confirm("Auto-export annotations in CSV/JSONL?", default=False) | |
| export_format = None | |
| if auto_export: | |
| export_format = click.prompt( | |
| "Export format", | |
| type=click.Choice(["csv", "tsv", "jsonl"], case_sensitive=False), | |
| default="csv", | |
| ) | |
| # Build config | |
| config = { | |
| "annotation_task_name": task_name, | |
| "port": port, | |
| "data_files": data_files, | |
| "item_properties": { | |
| "id_key": id_key, | |
| "text_key": text_key, | |
| }, | |
| "annotation_schemes": annotation_schemes, | |
| "output_annotation_dir": output_dir, | |
| "annotation_codebook_url": codebook_url, | |
| "user_config": { | |
| "allow_all_users": True, | |
| "users": [], | |
| }, | |
| } | |
| if export_format: | |
| config["export_annotation_format"] = export_format | |
| click.echo("\n— Save config —\n") | |
| config_file = click.prompt("Path for the config file", default="config.yaml") | |
| if os.path.exists(config_file): | |
| if not click.confirm(f"{config_file} already exists. Overwrite?", default=False): | |
| click.echo("Aborted.") | |
| return | |
| with open(config_file, "w", encoding="utf-8") as f: | |
| yaml.dump(config, f, default_flow_style=False, sort_keys=False, allow_unicode=True) | |
| click.echo(f"\nConfig written to {config_file}") | |
| click.echo(f"Start annotating with: potato start {config_file}") | |