From d5e69d1debc6df412f0862cb47ea90deebcd5dbf Mon Sep 17 00:00:00 2001 From: vin Date: Sat, 23 Aug 2025 13:29:32 -0400 Subject: add helper script for reviewing input into dataset --- highlight.py | 4 +- review.py | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 review.py diff --git a/highlight.py b/highlight.py index 361a0d2..ffcdd2c 100644 --- a/highlight.py +++ b/highlight.py @@ -1,6 +1,7 @@ import sys import json import re +import pathlib from datetime import timedelta # ANSI escape codes for terminal colors @@ -100,7 +101,8 @@ def visualize_entry(entry: dict): def main(filepath: str): try: - with open(filepath, 'r', encoding='utf-8') as f: + p = pathlib.Path(filepath) + with p.open('r', encoding='utf-8') as f: for line in f: try: entry = json.loads(line) diff --git a/review.py b/review.py new file mode 100644 index 0000000..3c34eac --- /dev/null +++ b/review.py @@ -0,0 +1,121 @@ +import sys +import os +import json +import subprocess +import re +from datetime import timedelta + +# --- Configuration --- +HIGHLIGHT_SCRIPT_NAME = "highlight.py" +GOOD_DATASET_FILE = "dataset.jsonl" +BAD_FILES_LOG = "errors.txt" +PROGRESS_FILE = ".curation_progress.log" + +# --- Unbuffered Input (Cross-Platform) --- +try: + # Unix-like systems (Linux, macOS) + import tty, termios + def getch(): + fd = sys.stdin.fileno() + old_settings = termios.tcgetattr(fd) + try: + tty.setraw(sys.stdin.fileno()) + ch = sys.stdin.read(1) + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + return ch +except ImportError: + # Windows + import msvcrt + def getch(): + return msvcrt.getch().decode() + +# --- Main Curation Logic --- + +def review_files(file_paths: list[str]): + """ + Iterates through files, displays them for review, and sorts them based on user input. + """ + if not os.path.exists(HIGHLIGHT_SCRIPT_NAME): + print(f"Error: The visualization script '{HIGHLIGHT_SCRIPT_NAME}' was not found in this directory.") + sys.exit(1) + + # Load the set of already processed files + processed_files = set() + if os.path.exists(PROGRESS_FILE): + with open(PROGRESS_FILE, 'r', encoding='utf-8') as f: + processed_files = {line.strip() for line in f} + + total_files = len(file_paths) + for i, filepath in enumerate(file_paths): + if filepath in processed_files: + print(f"Skipping already processed file: {filepath}") + continue + + print("-" * 80) + print(f"Reviewing file ({i + 1}/{total_files}): {filepath}") + + # 1. Run highlight.py and pipe its output to the user's pager + try: + pager_cmd = os.environ.get("PAGER", "less").split() + highlight_process = subprocess.Popen( + ["python", HIGHLIGHT_SCRIPT_NAME, filepath], + stdout=subprocess.PIPE, + text=True, + encoding='utf-8' + ) + pager_process = subprocess.Popen(pager_cmd, stdin=highlight_process.stdout) + highlight_process.stdout.close() + return_code = pager_process.wait() + if return_code != 0: + print(f"Warning: Pager exited with code {return_code}.") + except FileNotFoundError: + print(f"Error: Pager command not found. Is '{os.environ.get('PAGER', 'less')}' installed?") + continue + except Exception as e: + print(f"An error occurred while running the subprocess: {e}") + continue + + # 2. Prompt for user decision + while True: + print("\nWas this file's labeling correct? (y/n): ", end="", flush=True) + choice = getch().lower() + print(choice) + + if choice == 'y': + print(f" -> Appending {filepath} to {GOOD_DATASET_FILE}") + try: + with open(filepath, 'r', encoding='utf-8') as infile, \ + open(GOOD_DATASET_FILE, 'a', encoding='utf-8') as outfile: + for line in infile: + outfile.write(line) + except Exception as e: + print(f"Error appending to dataset file: {e}") + break + elif choice == 'n': + print(f" -> Logging {filepath} to {BAD_FILES_LOG}") + try: + with open(BAD_FILES_LOG, 'a', encoding='utf-8') as errfile: + errfile.write(filepath + '\n') + except Exception as e: + print(f"Error writing to log file: {e}") + break + elif choice in ['\x03', 'q']: # Handle Ctrl+C or 'q' to quit + print("\nExiting review process.") + sys.exit(0) + else: + print("Invalid input. Please press 'y' for yes or 'n' for no.") + + # Log the file as processed after a decision has been made + with open(PROGRESS_FILE, 'a', encoding='utf-8') as f: + f.write(filepath + '\n') + +if __name__ == "__main__": + if len(sys.argv) < 2: + print("Usage: python curate_dataset.py ...") + print("Or: python curate_dataset.py /path/to/*/*.jsonl") + sys.exit(1) + + review_files(sys.argv[1:]) + print("-" * 80) + print("Curation complete.") \ No newline at end of file -- cgit v1.2.3