33import os
44import sys
55import time
6+ from typing import Optional , List
67
78import pandas as pd
9+ from rich .console import Console
10+ from rich .progress import Progress , SpinnerColumn , TextColumn , BarColumn , TaskProgressColumn
11+ from rich .table import Table
12+ from rich import print
813from dotenv import load_dotenv
914from parxy_core .models import Document
1015
@@ -64,7 +69,7 @@ def evaluate(
6469):
6570
6671 logging .basicConfig (
67- level = logging .DEBUG ,
72+ level = logging .WARNING ,
6873 format = "%(asctime)s : %(levelname)s : %(name)s : %(message)s"
6974 )
7075
@@ -89,51 +94,84 @@ def evaluate(
8994
9095 metrics_fn = list ([get_metric (metric ) for metric in metrics_name ])
9196
97+ console = Console ()
98+
9299 logging .debug (f"Input folder: { input_folder } " )
93100 logging .debug (f"Output folder: { output_folder } " )
94- logging .debug (f"Metric: { metrics_name } " )
101+ logging .debug (f"Metrics: { metrics_name } " )
102+
103+ # Get total number of files to process
104+ files = os .listdir (input_folder )
105+ total_files = len (files )
95106
96107 res_list = []
97- for filename in os .listdir (input_folder ):
98- logging .debug (f"Processing { filename } " )
99-
100- # Read the parsing result
101- with open (os .path .join (input_folder , filename ), "r" ) as f :
102- doc = Document (** json .loads (f .read ()))
103-
104- # Read the ground truth
105- try :
106- with open (os .path .join (golden_folder , filename ), "r" ) as f :
107- golden_doc = Document (** json .loads (f .read ()))
108- except FileNotFoundError :
109- logging .error (f"File [{ filename } ] does not exist!" )
110- continue
111-
112- base_data = {
113- "filename" : filename ,
114- "collection" : golden_doc .source_data ["collection" ],
115- "doc_category" : golden_doc .source_data ["doc_category" ],
116- "original_filename" : golden_doc .source_data ["original_filename" ],
117- "page_no" : golden_doc .source_data ["page_no" ],
118- "processing_time_seconds" : doc .source_data ["processing_time_seconds" ],
119- }
120-
121- # merge all metrics dicts into one
122- metrics_dict = {}
123- for metric_fn in metrics_fn :
124- metrics_dict .update (metric_fn (golden_doc , doc ))
125-
126- # merge base data + metrics
127- row = {** base_data , ** metrics_dict }
128- res_list .append (row )
129-
130- logging .debug (f"Processed { len (res_list )} documents." )
108+ with Progress (
109+ SpinnerColumn (),
110+ TextColumn ("[progress.description]{task.description}" ),
111+ BarColumn (),
112+ TaskProgressColumn (),
113+ console = console ,
114+ transient = True
115+ ) as progress :
116+ task = progress .add_task ("Evaluating documents..." , total = total_files )
117+
118+ for filename in files :
119+ progress .update (task , description = f"Processing { filename } ..." )
120+
121+ # Read the parsing result
122+ with open (os .path .join (input_folder , filename ), "r" ) as f :
123+ doc = Document (** json .loads (f .read ()))
124+
125+ # Read the ground truth
126+ try :
127+ with open (os .path .join (golden_folder , filename ), "r" ) as f :
128+ golden_doc = Document (** json .loads (f .read ()))
129+ except FileNotFoundError :
130+ logging .error (f"File [{ filename } ] does not exist!" )
131+ progress .advance (task )
132+ continue
133+
134+ base_data = {
135+ "filename" : filename ,
136+ "collection" : golden_doc .source_data ["collection" ],
137+ "doc_category" : golden_doc .source_data ["doc_category" ],
138+ "original_filename" : golden_doc .source_data ["original_filename" ],
139+ "page_no" : golden_doc .source_data ["page_no" ],
140+ "processing_time_seconds" : doc .source_data ["processing_time_seconds" ],
141+ }
142+
143+ # merge all metrics dicts into one
144+ metrics_dict = {}
145+ for metric_fn in metrics_fn :
146+ metrics_dict .update (metric_fn (golden_doc , doc ))
147+
148+ # merge base data + metrics
149+ row = {** base_data , ** metrics_dict }
150+ res_list .append (row )
151+ progress .advance (task )
152+
131153 timestamp_str = str (time .time ()).replace ("." , "" )
132154 res_df = pd .DataFrame (res_list )
133155 input_folder_name = input_folder .replace (os .sep , "/" ).replace ("\\ " , "/" )
134156 input_folder_name = input_folder_name .split ("/" )[- 1 ].replace (" " , "_" ).lower ()
135- res_df .to_csv (os .path .join (output_folder , f"eval_{ input_folder_name } _{ timestamp_str } .csv" ), index = False )
136- logging .debug (f"Results written to { output_folder } /eval_{ input_folder_name } _{ timestamp_str } .csv" )
157+ output_file = f"eval_{ input_folder_name } _{ timestamp_str } .csv"
158+ output_path = os .path .join (output_folder , output_file )
159+ res_df .to_csv (output_path , index = False )
137160
161+ print (f"\n [green]✓[/green] Evaluation completed. Results saved to: [blue]{ output_path } [/blue]" )
162+
163+ # Print evaluation statistics
164+ table = Table ()
165+ table .add_column ("Metric" )
166+ table .add_column ("Value" , justify = "right" , style = "green" )
167+
168+ table .add_row ("Documents processed" , str (len (res_list )))
169+ table .add_row ("Average parsing time" , f"{ res_df ['processing_time_seconds' ].mean ():.2f} s" )
170+
171+ for metric_column in metrics_name :
172+ if metric_column in res_df .columns and not res_df [metric_column ].isna ().all ():
173+ if res_df [metric_column ].dtype in ['float64' , 'int64' ]:
174+ table .add_row (metric_column , f"{ res_df [metric_column ].mean ():.4f} " )
175+
176+ console .print (table )
138177
139- # TODO: print out some basic data from res_df, like average score for each metric and average processing_time_seconds
0 commit comments