1+ #!/usr/bin/env python3
2+
3+ """Aggregate results from multiple llm_as_judge.json files
4+ and save as a compressed parquet file for efficient storage and loading.
5+ """
6+
7+ import argparse
8+ import json
9+ from pathlib import Path
10+ from typing import Any
11+
12+ import pandas as pd
13+
14+ from codeclash .analysis .llm_as_judge .utils import Instance
15+ from codeclash .utils .log import get_logger
16+
17+ logger = get_logger ("AggregateResults" , emoji = "📊" )
18+
19+
20+ def aggregate_results_to_dataframe (input_dir : Path ) -> pd .DataFrame :
21+ """Aggregate all llm_as_judge.json results from the input directory into a DataFrame.
22+
23+ Returns:
24+ DataFrame with flattened structure containing all evaluation data
25+ """
26+ rows = []
27+ llm_judge_files = list (input_dir .rglob ("llm_as_judge.json" ))
28+
29+ logger .info (f"Found { len (llm_judge_files )} llm_as_judge.json files" )
30+
31+ for file_path in llm_judge_files :
32+ logger .debug (f"Processing { file_path } " )
33+
34+ try :
35+ content = file_path .read_text ().strip ()
36+ if not content :
37+ logger .warning (f"Skipping empty file: { file_path } " )
38+ continue
39+
40+ file_data = json .loads (content )
41+
42+ # Process each data_id and instance
43+ for data_id , instances in file_data .items ():
44+ for instance_id , instance_data in instances .items ():
45+ # Extract instance metadata
46+ instance = Instance .model_validate (instance_data ["instance" ])
47+ model_name , opponent_model_name = instance .get_lm_name_self_opponent ()
48+
49+ # Create a flat row with all information
50+ row = {
51+ "data_id" : data_id ,
52+ "instance_id" : instance_id ,
53+ "tournament_name" : instance .tournament_name ,
54+ "player_name" : instance .player_name ,
55+ "round_number" : instance .round_number ,
56+ "model_name" : model_name ,
57+ "opponent_model_name" : opponent_model_name ,
58+ }
59+
60+ # Add all evaluation results
61+ if "result" in instance_data :
62+ result_data = instance_data ["result" ]
63+ for key , value in result_data .items ():
64+ row [key ] = value
65+
66+ rows .append (row )
67+
68+ except json .JSONDecodeError as e :
69+ logger .error (f"Failed to parse JSON in { file_path } : { e } " )
70+ except Exception as e :
71+ logger .error (f"Error processing { file_path } : { e } " , exc_info = True )
72+
73+ df = pd .DataFrame (rows )
74+ logger .info (f"Created DataFrame with { len (df )} rows and { len (df .columns )} columns" )
75+
76+ return df
77+
78+
79+ def main () -> None :
80+ parser = argparse .ArgumentParser (description = "Aggregate LLM-as-judge evaluation results to Parquet" )
81+ parser .add_argument ("input_dir" , type = Path , help = "Path to the input directory containing tournament results" )
82+ parser .add_argument ("-o" , "--output-file" , type = Path ,
83+ help = "Path to the output Parquet file" , default = "aggregated_results.parquet" )
84+ args = parser .parse_args ()
85+
86+ if not args .input_dir .exists ():
87+ logger .error (f"Input directory does not exist: { args .input_dir } " )
88+ return
89+
90+ logger .info (f"Aggregating results from { args .input_dir } " )
91+ df = aggregate_results_to_dataframe (args .input_dir )
92+
93+ df .to_parquet (args .output_file , compression = "snappy" , index = False )
94+ logger .info (f"Wrote aggregated results to { args .output_file } " )
95+
96+
97+ if __name__ == "__main__" :
98+ main ()
0 commit comments