将模型返回的 CSV 文本解析为目标 JSON 结构。 目标结构:[{"text": "...", "number": int, "level": int}, ...]
(csv_text: str, source_file: str)
| 182 | try: |
| 183 | reader = csv.DictReader(StringIO(cleaned_text)) |
| 184 | # 检查必要的列 |
| 185 | if not {'title', 'page_number', 'level'}.issubset(set(reader.fieldnames or [])): |
| 186 | raise ValueError(f"CSV 缺少必要列 (title, page_number, level)。实际列:{reader.fieldnames}") |
| 187 | |
| 188 | for row in reader: |
| 189 | try: |
| 190 | title = row['title'].strip() |
| 191 | if not title: |
| 192 | continue |
| 193 | |
| 194 | # 尝试转换页码 |
| 195 | page_num_str = row['page_number'].strip() |
| 196 | page_num = int(page_num_str) if page_num_str else None |
| 197 | |
| 198 | # 尝试转换层级 |
| 199 | level_str = row['level'].strip() |
| 200 | level = int(level_str) if level_str else None |
| 201 | |
| 202 | if page_num is None or level is None: |
| 203 | write_log(f"警告:跳过无效行 (页码或层级非整数):{row} in {source_file}") |
| 204 | continue |
| 205 | |
| 206 | result_data.append({ |
| 207 | "text": title, |
| 208 | "number": page_num, |
| 209 | "level": level |
| 210 | }) |
| 211 | except (ValueError, KeyError) as e: |
| 212 | write_log(f"解析单行失败:{row}, 错误:{e}") |
| 213 | continue |
| 214 | |
| 215 | except Exception as e: |
| 216 | write_log(f"CSV 整体解析失败 {source_file}: {str(e)}") |
| 217 | raise e |
| 218 | |
| 219 | return result_data |
| 220 | |
| 221 | async def process_first_page(img_file: Path, csv_file: Path, output_path: Path) -> bool: |
| 222 | """ |
| 223 | 专门处理第一张图片,获取 CSV 格式的响应,并缓存为 Few-shot 示例。 |
| 224 | """ |
| 225 | write_log(f"正在处理首图作为示例:{img_file.name}") |
| 226 | |
| 227 | if not csv_file.exists(): |
| 228 | write_log(f"缺少对应的 CSV 文件,跳过首图处理:{img_file.name}") |
| 229 | return False |
| 230 | |
| 231 | csv_content = csv_file.read_text(encoding='utf-8') |
| 232 | |
| 233 | content_list = [ |
| 234 | {"type": "text", "text": "当前页图片(需处理,作为后续页面的参考示例):"}, |
| 235 | {"type": "text", "text": f"{PROMPT_TEXT}\n\n当前页提取的原始 CSV 数据如下:\n{csv_content}"}, |
| 236 | {"type": "image_url", "image_url": {"url": get_encoded_image(img_file)}} |
| 237 | ] |
| 238 | |
| 239 | messages = [{"role": "user", "content": content_list}] |
| 240 | |
| 241 | try: |
no test coverage detected