专门处理第一张图片,获取 CSV 格式的响应,并缓存为 Few-shot 示例。
(img_file: Path, csv_file: Path, output_path: Path)
| 240 | |
| 241 | try: |
| 242 | for attempt in range(MAX_RETRIES): |
| 243 | try: |
| 244 | response = await client.chat.completions.create( |
| 245 | model=LLM_CONFIG["model"], |
| 246 | messages=messages, |
| 247 | extra_body={"enable_thinking": False}, |
| 248 | timeout=REQUEST_TIMEOUT, |
| 249 | temperature=0, |
| 250 | ) |
| 251 | |
| 252 | content = response.choices[0].message.content.strip() |
| 253 | |
| 254 | # 本地解析 CSV 转为 JSON 保存 |
| 255 | try: |
| 256 | parsed_data = parse_csv_response(content, img_file.name) |
| 257 | except Exception as parse_err: |
| 258 | write_log(f"首图 CSV 解析失败:{parse_err}") |
| 259 | if attempt == MAX_RETRIES - 1: |
| 260 | return False |
| 261 | await asyncio.sleep(2 ** attempt) |
| 262 | continue |
| 263 | |
| 264 | if parsed_data: |
| 265 | # 排序 |
| 266 | sorted_data = sorted(parsed_data, key=lambda x: x['number']) |
| 267 | |
| 268 | # 保存首图结果文件 |
| 269 | output_file = output_path / f"{img_file.stem}_merged.json" |
| 270 | with open(output_file, 'w', encoding='utf-8') as f: |
| 271 | json.dump(sorted_data, f, ensure_ascii=False, indent=2) |
| 272 | |
| 273 | # 存入全局变量作为 Few-shot 示例 (存储原始 CSV 字符串) |
| 274 | FIRST_PAGE_EXAMPLE["image_base64"] = get_encoded_image(img_file) |
| 275 | FIRST_PAGE_EXAMPLE["result_csv_str"] = content |
| 276 | |
| 277 | print(f"首图处理完成并已缓存为示例:{img_file.name}") |
| 278 | return True |
| 279 | else: |
| 280 | write_log(f"首图解析结果为空:{img_file.name}") |
| 281 | if attempt == MAX_RETRIES - 1: |
| 282 | return False |
| 283 | await asyncio.sleep(2 ** attempt) |
| 284 | |
| 285 | except (APIError, Timeout) as e: |
| 286 | write_log(f"首图第 {attempt+1} 次 API 请求失败 ({type(e).__name__}): {str(e)}") |
| 287 | if attempt == MAX_RETRIES - 1: |
| 288 | return False |
| 289 | await asyncio.sleep(2 ** attempt) |
| 290 | except Exception as e: |
| 291 | write_log(f"首图处理异常 {img_file.name}: {str(e)}") |
| 292 | if attempt == MAX_RETRIES - 1: |
| 293 | return False |
| 294 | await asyncio.sleep(2 ** attempt) |
| 295 | |
| 296 | return False |
| 297 | finally: |
| 298 | IMAGE_CACHE.pop(img_file, None) |
| 299 |
no test coverage detected