(p)
| 365 | raw_save_path = os.path.join(initial_data_dir, raw_filename) |
| 366 | |
| 367 | b64_img = create_concat_image_b64(doc, p, p, save_path=img_save_path) |
| 368 | if not b64_img: |
| 369 | return p, False, None |
| 370 | |
| 371 | prompt = f"""这是一张 PDF 页面的图片,物理页码为 {p}。 |
| 372 | 请判断这一页是否是目录。目录的严格定义为:这张图中是否能提取出多个标题 - 页码对。 |
| 373 | 【输出要求】: |
| 374 | 1. 仅输出 JSON 格式,不要包含任何 markdown 标记。 |
| 375 | 2. 如果是目录,输出:{{"is_toc": true}} |
| 376 | 3. 如果不是目录,输出:{{"is_toc": false}}""" |
| 377 | |
| 378 | try: |
| 379 | completion = await client.chat.completions.create( |
| 380 | model=model, |
| 381 | messages=[ |
| 382 | { |
| 383 | "role": "user", |
| 384 | "content": [ |
| 385 | {"type": "text", "text": prompt}, |
| 386 | {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{b64_img}"}}, |
| 387 | ] |
| 388 | } |
| 389 | ], |
| 390 | extra_body={"enable_thinking": False}, |
| 391 | temperature=0, |
| 392 | ) |
| 393 | raw_content = completion.choices[0].message.content.strip() |
| 394 | |
| 395 | with open(raw_save_path, 'w', encoding='utf-8') as f: |
| 396 | json.dump({"page": p, "raw_response": raw_content}, f, ensure_ascii=False, indent=2) |
| 397 | |
| 398 | clean_text = re.sub(r'^```(?:json)?\s*', '', raw_content, flags=re.MULTILINE) |
| 399 | clean_text = re.sub(r'\s*```$', '', clean_text, flags=re.MULTILINE) |
| 400 | data = json.loads(clean_text) |
| 401 | is_toc = data.get("is_toc", False) |
| 402 | |
| 403 | detail_filename = f"single_vote_detail_{p}.json" |
| 404 | detail_save_path = os.path.join(initial_data_dir, detail_filename) |
| 405 | detail_data = { |
| 406 | "page": p, |
| 407 | "parsed_result": {"is_toc": is_toc}, |
| 408 | "raw_response": raw_content, |
| 409 | "image_saved_as": img_filename |
| 410 | } |
| 411 | with open(detail_save_path, 'w', encoding='utf-8') as f: |
| 412 | json.dump(detail_data, f, ensure_ascii=False, indent=2) |
| 413 | |
| 414 | return p, is_toc, raw_content |
| 415 | except Exception as e: |
| 416 | logger.error(f"单页投票失败 (页码 {p}): {e}") |
| 417 | return p, False, None |
| 418 | |
| 419 | conflict_tasks = [resolve_conflict(p) for p in conflict_pages] |
| 420 | conflict_results = await asyncio.gather(*conflict_tasks) |
| 421 | |
| 422 | for p, is_toc, _ in conflict_results: |
| 423 | if is_toc: |
| 424 | final_toc_pages.append(p) |
no test coverage detected