|
18 | 18 | from datetime import datetime |
19 | 19 | from zoneinfo import ZoneInfo |
20 | 20 | from typing import Any |
| 21 | +import re |
21 | 22 |
|
22 | 23 |
|
23 | 24 | def get_client() -> OpenAI: |
@@ -139,6 +140,27 @@ def get_batch_status(batch_id: str) -> Any: |
139 | 140 | return client.batches.retrieve(batch_id) |
140 | 141 |
|
141 | 142 |
|
| 143 | + # Extract classification results from the API responses |
| 144 | +def _safe_parse_model_text(s: str): |
| 145 | + t = s.strip() |
| 146 | + # strip ```json fences if present |
| 147 | + if t.startswith("```"): |
| 148 | + t = re.sub(r"^```(?:json)?\s*", "", t) |
| 149 | + t = re.sub(r"\s*```$", "", t) |
| 150 | + try: |
| 151 | + return json.loads(t), None |
| 152 | + except Exception: |
| 153 | + # try to repair {"label":"disapproval |
| 154 | + m = re.match(r'^\{"label":"([^"}\n]+)', t) |
| 155 | + if m: |
| 156 | + return {"label": m.group(1)}, "Truncated JSON repaired" |
| 157 | + # try label: disapproval |
| 158 | + m2 = re.match(r'^\s*label\s*[:=]\s*"?([^"}\n]+)"?\s*$', t, flags=re.I) |
| 159 | + if m2: |
| 160 | + return {"label": m2.group(1)}, "Non-JSON label recovered" |
| 161 | + return None, f"Unparsable JSON text: {t[:80]}" |
| 162 | + |
| 163 | + |
142 | 164 | def get_batch_results(batch_id: str) -> None: |
143 | 165 | """ |
144 | 166 | Download and save the results of a completed batch processing job. |
@@ -173,18 +195,28 @@ def get_batch_results(batch_id: str) -> None: |
173 | 195 | if line.strip() |
174 | 196 | ] |
175 | 197 |
|
176 | | - # Extract classification results from the API responses |
177 | | - responses = [] |
| 198 | + responses, bad_rows = [], [] |
| 199 | + |
178 | 200 | for res in results: |
179 | | - text_output = res['response']['body']['output'][0]['content'][0]['text'] |
180 | | - text_output_converted = json.loads(text_output) |
181 | | - metadata = res['response']['body']['metadata'] |
182 | | - combined = {**metadata, **text_output_converted} # Merge dictionaries |
| 201 | + body = res['response']['body'] |
| 202 | + text_output = body['output'][0]['content'][0]['text'] |
| 203 | + parsed, note = _safe_parse_model_text(text_output) |
| 204 | + |
| 205 | + if parsed is None: |
| 206 | + bad_rows.append({ |
| 207 | + "custom_id": res.get("custom_id"), |
| 208 | + "quote": body.get("metadata", {}).get("quote", ""), |
| 209 | + "raw_text": text_output |
| 210 | + }) |
| 211 | + continue |
| 212 | + |
| 213 | + metadata = body.get('metadata', {}) |
| 214 | + combined = {"custom_id": res.get("custom_id"), **metadata, **parsed} |
| 215 | + if note: |
| 216 | + combined["repair_note"] = note |
183 | 217 | responses.append(combined) |
184 | 218 |
|
185 | | - # Convert to DataFrame |
186 | | - # df = pd.DataFrame(responses) |
187 | | - # output = df.explode("label", ignore_index=True) |
| 219 | + # Now continue with your DF creation |
188 | 220 | df = to_long_df(responses) |
189 | 221 | save_as_csv(df) |
190 | 222 |
|
|
0 commit comments