@@ -107,61 +107,61 @@ def evaluate_many(
107107 ) -> Dict :
108108 """
109109 Evaluate a single model on data_items with parallel processing.
110-
110+
111111 Args:
112112 data_items: List of data items to evaluate
113113 model: Model instance to evaluate
114114 max_out_len: Maximum output length for model generation
115115 batch_size: Batch size for processing (if None, will be auto-calculated)
116116 save_path: Base path to save results
117117 n_jobs: Number of parallel jobs (-1 for all available cores)
118-
118+
119119 Returns:
120120 Dictionary containing evaluation results
121121 """
122122 import multiprocessing as mp
123123 from concurrent .futures import ThreadPoolExecutor , as_completed
124124 import math
125-
125+
126126 if not data_items :
127127 print ("❌ No data items provided" )
128128 return {"error" : "No data items provided" }
129-
129+
130130 # Set number of jobs
131131 if n_jobs == - 1 :
132132 n_jobs = mp .cpu_count ()
133-
133+
134134 # Calculate batch size if not provided
135135 if batch_size is None :
136136 batch_size = max (1 , math .ceil (len (data_items ) / n_jobs ))
137-
137+
138138 print (f"🔄 Starting parallel evaluation on { len (data_items )} items..." )
139139 print (f"📝 Model: { type (model ).__name__ } " )
140140 print (f"⚡ Using { n_jobs } parallel workers with batch size { batch_size } " )
141-
141+
142142 # Split data into batches
143143 batches = [
144- data_items [i : i + batch_size ]
144+ data_items [i : i + batch_size ]
145145 for i in range (0 , len (data_items ), batch_size )
146146 ]
147-
147+
148148 print (f"📦 Split into { len (batches )} batches" )
149-
149+
150150 # Build prompts for all items
151151 print ("📝 Building prompts..." )
152152 all_prompts = [self ._build_prompt (item ) for item in data_items ]
153-
153+
154154 # Split prompts into batches
155155 prompt_batches = [
156- all_prompts [i : i + batch_size ]
156+ all_prompts [i : i + batch_size ]
157157 for i in range (0 , len (all_prompts ), batch_size )
158158 ]
159-
159+
160160 def process_batch (batch_data ):
161161 """Process a batch of prompts and return responses."""
162162 batch_prompts , batch_indices = batch_data
163163 batch_responses = []
164-
164+
165165 for i , prompt in enumerate (batch_prompts ):
166166 try :
167167 response = model .generate (prompt , max_out_len )
@@ -171,41 +171,41 @@ def process_batch(batch_data):
171171 original_index = batch_indices [i ]
172172 print (f"\n ⚠️ Error on item { original_index + 1 } : { e } " )
173173 batch_responses .append (f"Error: { str (e )} " )
174-
174+
175175 return batch_indices , batch_responses
176-
176+
177177 # Prepare batch data with indices
178178 batch_data_list = []
179179 for i , prompt_batch in enumerate (prompt_batches ):
180180 start_idx = i * batch_size
181181 end_idx = min (start_idx + batch_size , len (data_items ))
182182 batch_indices = list (range (start_idx , end_idx ))
183183 batch_data_list .append ((prompt_batch , batch_indices ))
184-
184+
185185 # Execute parallel processing
186186 all_responses = [None ] * len (data_items )
187-
187+
188188 with ThreadPoolExecutor (max_workers = n_jobs ) as executor :
189189 # Submit all batch tasks
190190 future_to_batch = {
191- executor .submit (process_batch , batch_data ): batch_data [1 ][0 ]
191+ executor .submit (process_batch , batch_data ): batch_data [1 ][0 ]
192192 for batch_data in batch_data_list
193193 }
194-
194+
195195 # Collect results as they complete
196196 for future in tqdm (
197- as_completed (future_to_batch ),
197+ as_completed (future_to_batch ),
198198 total = len (future_to_batch ),
199199 desc = "Processing batches" ,
200- unit = "batch"
200+ unit = "batch" ,
201201 ):
202202 try :
203203 batch_indices , batch_responses = future .result ()
204204 for idx , response in zip (batch_indices , batch_responses ):
205205 all_responses [idx ] = response
206206 except Exception as e :
207207 print (f"❌ Error processing batch: { e } " )
208-
208+
209209 # Process responses and calculate results
210210 print ("🔍 Processing responses..." )
211211 processed_items = []
@@ -225,27 +225,27 @@ def process_batch(batch_data):
225225 item_copy ["pass" ] = is_correct
226226
227227 processed_items .append (item_copy )
228-
228+
229229 # Save results
230230 saved_files = self ._save_results (processed_items , save_path )
231231 print (f"💾 Results saved to: { saved_files } " )
232-
232+
233233 # Calculate metrics
234234 print ("📊 Calculating metrics..." )
235235 metrics = self ._calculate_metrics (processed_items )
236-
236+
237237 # Print results
238238 self ._print_results (metrics )
239-
239+
240240 return {
241241 "metrics" : metrics ,
242242 "saved_files" : saved_files ,
243243 "total_items" : len (data_items ),
244244 "parallel_info" : {
245245 "n_jobs" : n_jobs ,
246246 "batch_size" : batch_size ,
247- "n_batches" : len (batches )
248- }
247+ "n_batches" : len (batches ),
248+ },
249249 }
250250
251251 def _save_results (self , results_data : List [Dict ], save_path : str ) -> List [str ]:
@@ -302,7 +302,10 @@ def _calculate_metrics(self, processed_items: List[Dict]) -> Dict:
302302 sub_category = item .get ("sub_category" , "Unknown" )
303303
304304 # Check if prediction exists
305- if not prediction or prediction .strip () == "" :
305+ # 兼容 prediction 可能为 float(如 OpenEvaluator),也可能为 str(如 ChoiceEvaluator)
306+ if prediction is None or (
307+ isinstance (prediction , str ) and prediction .strip () == ""
308+ ):
306309 no_prediction += 1
307310
308311 # Use the pre-calculated "pass" field
0 commit comments