Browse Source

chore: 日志中区分图表识别与文本识别([PaddleOCR 图表识别] / [PaddleOCR 文本识别])

Co-authored-by: Cursor <cursoragent@cursor.com>
何文松 2 weeks ago
parent
commit
974d87f967
2 changed files with 85 additions and 119 deletions
  1. 39 56
      pdf_converter_v2/paddleocr_fallback.py
  2. 46 63
      pdf_converter_v2/utils/paddleocr_fallback.py

+ 39 - 56
pdf_converter_v2/paddleocr_fallback.py

@@ -506,16 +506,14 @@ def call_paddleocr(image_path: str) -> Optional[Dict[str, Any]]:
     try:
         # 检查图片文件是否存在
         if not os.path.exists(image_path):
-            logger.error(f"[PaddleOCR] 图片文件不存在: {image_path}")
+            logger.error(f"[PaddleOCR 图表识别] 图片文件不存在: {image_path}")
             return None
         
-        # 生成输出目录和基础文件名
+        # 生成输出目录和基础文件名(图表识别:开启 use_chart_recognition)
         image_dir = os.path.dirname(image_path)
         image_basename = os.path.splitext(os.path.basename(image_path))[0]
         save_path_base = os.path.join(image_dir, image_basename)
         
-        # 构建paddleocr命令,添加所有参数(NPU 下需加 --device npu:0,否则走 CPU 易段错误)
-        # PaddleOCR会在save_path下创建目录,文件保存在该目录内
         cmd = [
             "paddleocr", "doc_parser", "-i", image_path,
             "--precision", "fp32",
@@ -525,15 +523,8 @@ def call_paddleocr(image_path: str) -> Optional[Dict[str, Any]]:
             "--save_path", save_path_base
         ] + _paddle_ocr_device_args()
         
-        # 设置环境变量,限制GPU内存使用
-        # env = os.environ.copy()
-        # 设置PaddlePaddle的GPU内存分配策略,使用更保守的内存分配
-        # env["FLAGS_fraction_of_gpu_memory_to_use"] = "0.3"  # 只使用30%的GPU内存
-        # env["FLAGS_allocator_strategy"] = "auto_growth"  # 使用自动增长策略,避免一次性分配过多内存
-        
-        logger.info(f"[PaddleOCR] 执行命令: {' '.join(cmd)}")
+        logger.info(f"[PaddleOCR 图表识别] 执行命令: {' '.join(cmd)}")
         
-        # 执行命令
         result = subprocess.run(
             cmd,
             capture_output=True,
@@ -543,49 +534,41 @@ def call_paddleocr(image_path: str) -> Optional[Dict[str, Any]]:
         )
         
         if result.returncode != 0:
-            logger.error(f"[PaddleOCR] 命令执行失败,返回码: {result.returncode}")
-            logger.error(f"[PaddleOCR] 错误输出: {result.stderr}")
+            logger.error(f"[PaddleOCR 图表识别] 命令执行失败,返回码: {result.returncode}")
+            logger.error(f"[PaddleOCR 图表识别] 错误输出: {result.stderr}")
             return None
         
-        # 从保存的Markdown文件中读取结果
-        # PaddleOCR会在save_path下创建目录,文件路径为: {save_path}/{basename}.md
         md_file = os.path.join(save_path_base, f"{image_basename}.md")
         if os.path.exists(md_file):
-            logger.info(f"[PaddleOCR] 从Markdown文件读取结果: {md_file}")
+            logger.info(f"[PaddleOCR 图表识别] 从Markdown文件读取结果: {md_file}")
             try:
                 with open(md_file, 'r', encoding='utf-8') as f:
                     markdown_content = f.read()
                     if markdown_content.strip():
-                        # 将markdown内容转换为标准格式
-                        # 为了兼容现有代码,我们需要将markdown转换回parsing_res_list格式
-                        # 但实际上,我们可以直接返回markdown内容,让调用方处理
-                        # 这里我们返回一个特殊标记,表示这是markdown格式
-                        logger.info(f"[PaddleOCR] 成功读取Markdown文件,内容长度: {len(markdown_content)} 字符")
-                        # 返回markdown内容,使用特殊键标记
+                        logger.info(f"[PaddleOCR 图表识别] 成功读取Markdown文件,内容长度: {len(markdown_content)} 字符")
                         return {"markdown_content": markdown_content}
                     else:
-                        logger.warning("[PaddleOCR] Markdown文件内容为空")
+                        logger.warning("[PaddleOCR 图表识别] Markdown文件内容为空")
             except Exception as e:
-                logger.exception(f"[PaddleOCR] 读取Markdown文件失败: {e}")
+                logger.exception(f"[PaddleOCR 图表识别] 读取Markdown文件失败: {e}")
         else:
-            logger.warning(f"[PaddleOCR] Markdown文件不存在: {md_file}")
+            logger.warning(f"[PaddleOCR 图表识别] Markdown文件不存在: {md_file}")
         
-        # 如果Markdown文件不存在或读取失败,尝试从stdout解析
         output_text = result.stdout.strip()
         if output_text:
-            logger.info("[PaddleOCR] 从stdout解析输出")
+            logger.info("[PaddleOCR 图表识别] 从stdout解析输出")
             parsed_result = parse_paddleocr_output(output_text)
-            logger.info(f"[PaddleOCR] 解析成功,获得 {len(parsed_result.get('parsing_res_list', []))} 个区块")
+            logger.info(f"[PaddleOCR 图表识别] 解析成功,获得 {len(parsed_result.get('parsing_res_list', []))} 个区块")
             return parsed_result
         else:
-            logger.warning("[PaddleOCR] stdout输出为空,且未找到Markdown文件")
+            logger.warning("[PaddleOCR 图表识别] stdout输出为空,且未找到Markdown文件")
             return None
         
     except subprocess.TimeoutExpired:
-        logger.error("[PaddleOCR] 命令执行超时")
+        logger.error("[PaddleOCR 图表识别] 命令执行超时")
         return None
     except Exception as e:
-        logger.exception(f"[PaddleOCR] 调用失败: {e}")
+        logger.exception(f"[PaddleOCR 图表识别] 调用失败: {e}")
         return None
     finally:
         # 无论成功或失败,都尝试重启mineru服务
@@ -855,7 +838,7 @@ def call_paddleocr_ocr(image_path: str, save_path: str) -> tuple[Optional[List[s
     mineru_stopped = stop_mineru_service()
     try:
         if not os.path.exists(image_path):
-            logger.error(f"[PaddleOCR OCR] 图片文件不存在: {image_path}")
+            logger.error(f"[PaddleOCR 文本识别] 图片文件不存在: {image_path}")
             return None, None
 
         image_basename = os.path.splitext(os.path.basename(image_path))[0]
@@ -876,7 +859,7 @@ def call_paddleocr_ocr(image_path: str, save_path: str) -> tuple[Optional[List[s
         if VL_REC_SERVER_URL:
             cmd.extend(["--vl_rec_server_url", VL_REC_SERVER_URL])
 
-        logger.info(f"[PaddleOCR OCR] 执行命令(doc_parser): {' '.join(cmd)}")
+        logger.info(f"[PaddleOCR 文本识别] 执行命令(doc_parser): {' '.join(cmd)}")
 
         result = subprocess.run(
             cmd,
@@ -887,11 +870,11 @@ def call_paddleocr_ocr(image_path: str, save_path: str) -> tuple[Optional[List[s
         )
 
         if result.returncode != 0:
-            logger.error(f"[PaddleOCR OCR] doc_parser 执行失败,返回码: {result.returncode}")
+            logger.error(f"[PaddleOCR 文本识别] doc_parser 执行失败,返回码: {result.returncode}")
             if result.stderr and ("too many values to unpack" in result.stderr or "Exception from the 'cv' worker" in result.stderr):
-                logger.warning("[PaddleOCR OCR] doc_parser 报 cv worker 解包错误,详见 README_STARTUP.md。")
+                logger.warning("[PaddleOCR 文本识别] doc_parser 报 cv worker 解包错误,详见 README_STARTUP.md。")
             if result.stderr:
-                logger.error(f"[PaddleOCR OCR] 错误输出: {result.stderr}")
+                logger.error(f"[PaddleOCR 文本识别] 错误输出: {result.stderr}")
             return None, None
 
         texts = []
@@ -903,7 +886,7 @@ def call_paddleocr_ocr(image_path: str, save_path: str) -> tuple[Optional[List[s
                 if md_content.strip():
                     texts = markdown_to_plain_text(md_content)
             except Exception as e:
-                logger.exception(f"[PaddleOCR OCR] 读取 Markdown 失败: {e}")
+                logger.exception(f"[PaddleOCR 文本识别] 读取 Markdown 失败: {e}")
         if not texts and result.stdout.strip():
             parsed = parse_paddleocr_output(result.stdout.strip())
             for item in parsed.get("parsing_res_list", []):
@@ -914,7 +897,7 @@ def call_paddleocr_ocr(image_path: str, save_path: str) -> tuple[Optional[List[s
                     else:
                         texts.append(block)
         if not texts:
-            logger.warning("[PaddleOCR OCR] doc_parser 未得到文本")
+            logger.warning("[PaddleOCR 文本识别] doc_parser 未得到文本")
             return None, None
 
         json_file = os.path.join(save_path, f"{image_basename}_res.json")
@@ -922,17 +905,17 @@ def call_paddleocr_ocr(image_path: str, save_path: str) -> tuple[Optional[List[s
             with open(json_file, "w", encoding="utf-8") as f:
                 json.dump({"rec_texts": texts}, f, ensure_ascii=False, indent=0)
         except Exception as e:
-            logger.exception(f"[PaddleOCR OCR] 写入 rec_texts JSON 失败: {e}")
+            logger.exception(f"[PaddleOCR 文本识别] 写入 rec_texts JSON 失败: {e}")
             return texts, None
 
-        logger.info(f"[PaddleOCR OCR] doc_parser 成功提取 {len(texts)} 个文本片段,JSON: {json_file}")
+        logger.info(f"[PaddleOCR 文本识别] doc_parser 成功提取 {len(texts)} 个文本片段,JSON: {json_file}")
         return texts, json_file
 
     except subprocess.TimeoutExpired:
-        logger.error("[PaddleOCR OCR] 命令执行超时")
+        logger.error("[PaddleOCR 文本识别] 命令执行超时")
         return None, None
     except Exception as e:
-        logger.exception(f"[PaddleOCR OCR] 调用失败: {e}")
+        logger.exception(f"[PaddleOCR 文本识别] 调用失败: {e}")
         return None, None
     finally:
         if mineru_stopped:
@@ -951,7 +934,7 @@ def call_paddleocr_doc_parser_for_text(image_path: str, save_path: str) -> tuple
     """
     try:
         if not os.path.exists(image_path):
-            logger.error(f"[PaddleOCR DocParser] 图片文件不存在: {image_path}")
+            logger.error(f"[PaddleOCR 图表识别] 图片文件不存在: {image_path}")
             return None, None
         
         # 生成输出目录和基础文件名
@@ -970,7 +953,7 @@ def call_paddleocr_doc_parser_for_text(image_path: str, save_path: str) -> tuple
             "--save_path", save_path_base
         ] + _paddle_ocr_device_args()
         
-        logger.info(f"[PaddleOCR DocParser] 执行命令: {' '.join(cmd)}")
+        logger.info(f"[PaddleOCR 图表识别] 执行命令: {' '.join(cmd)}")
         
         # 执行命令
         result = subprocess.run(
@@ -982,8 +965,8 @@ def call_paddleocr_doc_parser_for_text(image_path: str, save_path: str) -> tuple
         )
         
         if result.returncode != 0:
-            logger.error(f"[PaddleOCR DocParser] 命令执行失败,返回码: {result.returncode}")
-            logger.error(f"[PaddleOCR DocParser] 错误输出: {result.stderr}")
+            logger.error(f"[PaddleOCR 图表识别] 命令执行失败,返回码: {result.returncode}")
+            logger.error(f"[PaddleOCR 图表识别] 错误输出: {result.stderr}")
             return None, None
         
         # 查找保存的Markdown文件
@@ -995,10 +978,10 @@ def call_paddleocr_doc_parser_for_text(image_path: str, save_path: str) -> tuple
             md_files = sorted(Path(save_path_base).rglob("*.md"))
             if md_files:
                 md_file = str(md_files[0])
-                logger.info(f"[PaddleOCR DocParser] 在子目录中找到Markdown文件: {md_file}")
+                logger.info(f"[PaddleOCR 图表识别] 在子目录中找到Markdown文件: {md_file}")
         
         if not os.path.exists(md_file):
-            logger.warning(f"[PaddleOCR DocParser] Markdown文件不存在: {md_file}")
+            logger.warning(f"[PaddleOCR 图表识别] Markdown文件不存在: {md_file}")
             return None, None
         
         # 读取Markdown文件并转换为纯文本
@@ -1007,23 +990,23 @@ def call_paddleocr_doc_parser_for_text(image_path: str, save_path: str) -> tuple
                 markdown_content = f.read()
             
             if not markdown_content.strip():
-                logger.warning("[PaddleOCR DocParser] Markdown文件内容为空")
+                logger.warning("[PaddleOCR 图表识别] Markdown文件内容为空")
                 return [], md_file
             
             # 将Markdown转换为纯文本列表
             plain_text_lines = markdown_to_plain_text(markdown_content)
-            logger.info(f"[PaddleOCR DocParser] 成功提取 {len(plain_text_lines)} 行纯文本,Markdown文件: {md_file}")
+            logger.info(f"[PaddleOCR 图表识别] 成功提取 {len(plain_text_lines)} 行纯文本,Markdown文件: {md_file}")
             return plain_text_lines, md_file
                 
         except Exception as e:
-            logger.exception(f"[PaddleOCR DocParser] 读取Markdown文件失败: {e}")
+            logger.exception(f"[PaddleOCR 图表识别] 读取Markdown文件失败: {e}")
             return None, md_file
             
     except subprocess.TimeoutExpired:
-        logger.error("[PaddleOCR DocParser] 命令执行超时")
+        logger.error("[PaddleOCR 图表识别] 命令执行超时")
         return None, None
     except Exception as e:
-        logger.exception(f"[PaddleOCR DocParser] 调用失败: {e}")
+        logger.exception(f"[PaddleOCR 图表识别] 调用失败: {e}")
         return None, None
 
 
@@ -1812,7 +1795,7 @@ def fallback_parse_with_paddleocr(
             return None
         
         # 使用doc_parser模式解析文档结构
-        logger.info("[PaddleOCR备用] 使用doc_parser模式解析文档结构")
+        logger.info("[PaddleOCR备用] 使用doc_parser模式解析文档结构(图表识别)")
         paddleocr_result = call_paddleocr(image_path)
         if not paddleocr_result:
             logger.error("[PaddleOCR备用] PaddleOCR解析失败")
@@ -1867,7 +1850,7 @@ def fallback_parse_with_paddleocr(
             return None
         
         # 调用paddleocr ocr提取关键词来补充数据(作为doc_parser的补充)
-        logger.info("[PaddleOCR备用] 调用OCR提取关键词补充数据")
+        logger.info("[PaddleOCR备用] 调用文本识别提取关键词补充数据")
         ocr_save_path = os.path.dirname(image_path)  # 使用图片所在目录作为保存路径
         ocr_texts, _ = call_paddleocr_ocr(image_path, ocr_save_path)
         

+ 46 - 63
pdf_converter_v2/utils/paddleocr_fallback.py

@@ -403,7 +403,7 @@ def call_paddleocr(image_path: str) -> Optional[Dict[str, Any]]:
     try:
         # 检查图片文件是否存在
         if not os.path.exists(image_path):
-            logger.error(f"[PaddleOCR] 图片文件不存在: {image_path}")
+            logger.error(f"[PaddleOCR 图表识别] 图片文件不存在: {image_path}")
             return None
         
         # 生成输出目录和基础文件名
@@ -411,8 +411,7 @@ def call_paddleocr(image_path: str) -> Optional[Dict[str, Any]]:
         image_basename = os.path.splitext(os.path.basename(image_path))[0]
         save_path_base = os.path.join(image_dir, image_basename)
         
-        # 构建paddleocr命令,添加所有参数(NPU 下需加 --device npu:0,否则走 CPU 易段错误)
-        # PaddleOCR会在save_path下创建目录,文件保存在该目录内
+        # 构建paddleocr命令(图表识别:开启 use_chart_recognition / use_layout_detection)
         cmd = [
             _get_paddleocr_executable(), "doc_parser", "-i", image_path,
             "--precision", "fp32",
@@ -434,7 +433,7 @@ def call_paddleocr(image_path: str) -> Optional[Dict[str, Any]]:
         # env["FLAGS_fraction_of_gpu_memory_to_use"] = "0.3"  # 只使用30%的GPU内存
         # env["FLAGS_allocator_strategy"] = "auto_growth"  # 使用自动增长策略,避免一次性分配过多内存
         
-        logger.info(f"[PaddleOCR] 执行命令: {' '.join(cmd)}")
+        logger.info(f"[PaddleOCR 图表识别] 执行命令: {' '.join(cmd)}")
         
         # 执行命令(env 含 LD_PRELOAD 与 PADDLE_PDX_DISABLE_MODEL_SOURCE_CHECK,避免 static TLS / 模型源检查)
         result = subprocess.run(
@@ -447,59 +446,52 @@ def call_paddleocr(image_path: str) -> Optional[Dict[str, Any]]:
         )
         
         if result.returncode != 0:
-            logger.error(f"[PaddleOCR] 命令执行失败,返回码: {result.returncode}")
+            logger.error(f"[PaddleOCR 图表识别] 命令执行失败,返回码: {result.returncode}")
             # doc_parser 已知问题:PP-DocLayoutV3 返回 3 值而管道按 2 值解包,报 "too many values to unpack (expected 2)"
             if result.stderr and ("too many values to unpack" in result.stderr or "Exception from the 'cv' worker" in result.stderr):
                 logger.warning(
-                    "[PaddleOCR] doc_parser 报 cv worker 解包错误,多为 PaddleX 与 PP-DocLayoutV3 不兼容。"
-                    " 可尝试: pip install -U paddlex;或仅需文字时改用 ocr 模式。详见 README_STARTUP.md。"
+                    "[PaddleOCR 图表识别] doc_parser 报 cv worker 解包错误,多为 PaddleX 与 PP-DocLayoutV3 不兼容。"
+                    " 可尝试: pip install -U paddlex;或仅需文字时改用 文本识别。详见 README_STARTUP.md。"
                 )
             # 完整 stderr 便于排查(NPU 初始化日志较长,真正错误常在末尾)
             if result.stderr:
-                logger.error(f"[PaddleOCR] stderr: {result.stderr}")
+                logger.error(f"[PaddleOCR 图表识别] stderr: {result.stderr}")
             if result.stdout:
-                logger.error(f"[PaddleOCR] stdout(末 2000 字符): {result.stdout[-2000:] if len(result.stdout) > 2000 else result.stdout}")
+                logger.error(f"[PaddleOCR 图表识别] stdout(末 2000 字符): {result.stdout[-2000:] if len(result.stdout) > 2000 else result.stdout}")
             return None
         
         # 从保存的Markdown文件中读取结果
-        # PaddleOCR会在save_path下创建目录,文件路径为: {save_path}/{basename}.md
         md_file = os.path.join(save_path_base, f"{image_basename}.md")
         if os.path.exists(md_file):
-            logger.info(f"[PaddleOCR] 从Markdown文件读取结果: {md_file}")
+            logger.info(f"[PaddleOCR 图表识别] 从Markdown文件读取结果: {md_file}")
             try:
                 with open(md_file, 'r', encoding='utf-8') as f:
                     markdown_content = f.read()
                     if markdown_content.strip():
-                        # 将markdown内容转换为标准格式
-                        # 为了兼容现有代码,我们需要将markdown转换回parsing_res_list格式
-                        # 但实际上,我们可以直接返回markdown内容,让调用方处理
-                        # 这里我们返回一个特殊标记,表示这是markdown格式
-                        logger.info(f"[PaddleOCR] 成功读取Markdown文件,内容长度: {len(markdown_content)} 字符")
-                        # 返回markdown内容,使用特殊键标记
+                        logger.info(f"[PaddleOCR 图表识别] 成功读取Markdown文件,内容长度: {len(markdown_content)} 字符")
                         return {"markdown_content": markdown_content}
                     else:
-                        logger.warning("[PaddleOCR] Markdown文件内容为空")
+                        logger.warning("[PaddleOCR 图表识别] Markdown文件内容为空")
             except Exception as e:
-                logger.exception(f"[PaddleOCR] 读取Markdown文件失败: {e}")
+                logger.exception(f"[PaddleOCR 图表识别] 读取Markdown文件失败: {e}")
         else:
-            logger.warning(f"[PaddleOCR] Markdown文件不存在: {md_file}")
+            logger.warning(f"[PaddleOCR 图表识别] Markdown文件不存在: {md_file}")
         
-        # 如果Markdown文件不存在或读取失败,尝试从stdout解析
         output_text = result.stdout.strip()
         if output_text:
-            logger.info("[PaddleOCR] 从stdout解析输出")
+            logger.info("[PaddleOCR 图表识别] 从stdout解析输出")
             parsed_result = parse_paddleocr_output(output_text)
-            logger.info(f"[PaddleOCR] 解析成功,获得 {len(parsed_result.get('parsing_res_list', []))} 个区块")
+            logger.info(f"[PaddleOCR 图表识别] 解析成功,获得 {len(parsed_result.get('parsing_res_list', []))} 个区块")
             return parsed_result
         else:
-            logger.warning("[PaddleOCR] stdout输出为空,且未找到Markdown文件")
+            logger.warning("[PaddleOCR 图表识别] stdout输出为空,且未找到Markdown文件")
             return None
         
     except subprocess.TimeoutExpired:
-        logger.error("[PaddleOCR] 命令执行超时")
+        logger.error("[PaddleOCR 图表识别] 命令执行超时")
         return None
     except Exception as e:
-        logger.exception(f"[PaddleOCR] 调用失败: {e}")
+        logger.exception(f"[PaddleOCR 图表识别] 调用失败: {e}")
         return None
 
 
@@ -764,14 +756,14 @@ def call_paddleocr_ocr(image_path: str, save_path: str) -> tuple[Optional[List[s
     """
     try:
         if not os.path.exists(image_path):
-            logger.error(f"[PaddleOCR OCR] 图片文件不存在: {image_path}")
+            logger.error(f"[PaddleOCR 文本识别] 图片文件不存在: {image_path}")
             return None, None
 
         image_basename = os.path.splitext(os.path.basename(image_path))[0]
         save_path_base = os.path.join(save_path, image_basename)
         os.makedirs(save_path_base, exist_ok=True)
 
-        # 使用与 call_paddleocr 一致的不识别图表的 doc_parser 参数(无 --use_table_recognition)
+        # 使用不识别图表的 doc_parser 参数(文本识别,无 --use_table_recognition)
         cmd = [
             _get_paddleocr_executable(), "doc_parser", "-i", image_path,
             "--precision", "fp32",
@@ -786,7 +778,7 @@ def call_paddleocr_ocr(image_path: str, save_path: str) -> tuple[Optional[List[s
         if VL_REC_SERVER_URL:
             cmd.extend(["--vl_rec_server_url", VL_REC_SERVER_URL])
 
-        logger.info(f"[PaddleOCR OCR] 执行命令(doc_parser): {' '.join(cmd)}")
+        logger.info(f"[PaddleOCR 文本识别] 执行命令(doc_parser): {' '.join(cmd)}")
 
         result = subprocess.run(
             cmd,
@@ -798,11 +790,11 @@ def call_paddleocr_ocr(image_path: str, save_path: str) -> tuple[Optional[List[s
         )
 
         if result.returncode != 0:
-            logger.error(f"[PaddleOCR OCR] doc_parser 执行失败,返回码: {result.returncode}")
+            logger.error(f"[PaddleOCR 文本识别] doc_parser 执行失败,返回码: {result.returncode}")
             if result.stderr and ("too many values to unpack" in result.stderr or "Exception from the 'cv' worker" in result.stderr):
-                logger.warning("[PaddleOCR OCR] doc_parser 报 cv worker 解包错误,详见 README_STARTUP.md。")
+                logger.warning("[PaddleOCR 文本识别] doc_parser 报 cv worker 解包错误,详见 README_STARTUP.md。")
             if result.stderr:
-                logger.error(f"[PaddleOCR OCR] 错误输出: {result.stderr}")
+                logger.error(f"[PaddleOCR 文本识别] 错误输出: {result.stderr}")
             return None, None
 
         texts = []
@@ -814,7 +806,7 @@ def call_paddleocr_ocr(image_path: str, save_path: str) -> tuple[Optional[List[s
                 if md_content.strip():
                     texts = markdown_to_plain_text(md_content)
             except Exception as e:
-                logger.exception(f"[PaddleOCR OCR] 读取 Markdown 失败: {e}")
+                logger.exception(f"[PaddleOCR 文本识别] 读取 Markdown 失败: {e}")
         if not texts and result.stdout.strip():
             parsed = parse_paddleocr_output(result.stdout.strip())
             for item in parsed.get("parsing_res_list", []):
@@ -825,7 +817,7 @@ def call_paddleocr_ocr(image_path: str, save_path: str) -> tuple[Optional[List[s
                     else:
                         texts.append(block)
         if not texts:
-            logger.warning("[PaddleOCR OCR] doc_parser 未得到文本")
+            logger.warning("[PaddleOCR 文本识别] doc_parser 未得到文本")
             return None, None
 
         json_file = os.path.join(save_path, f"{image_basename}_res.json")
@@ -833,17 +825,17 @@ def call_paddleocr_ocr(image_path: str, save_path: str) -> tuple[Optional[List[s
             with open(json_file, "w", encoding="utf-8") as f:
                 json.dump({"rec_texts": texts}, f, ensure_ascii=False, indent=0)
         except Exception as e:
-            logger.exception(f"[PaddleOCR OCR] 写入 rec_texts JSON 失败: {e}")
+            logger.exception(f"[PaddleOCR 文本识别] 写入 rec_texts JSON 失败: {e}")
             return texts, None
 
-        logger.info(f"[PaddleOCR OCR] doc_parser 成功提取 {len(texts)} 个文本片段,JSON: {json_file}")
+        logger.info(f"[PaddleOCR 文本识别] doc_parser 成功提取 {len(texts)} 个文本片段,JSON: {json_file}")
         return texts, json_file
 
     except subprocess.TimeoutExpired:
-        logger.error("[PaddleOCR OCR] 命令执行超时")
+        logger.error("[PaddleOCR 文本识别] 命令执行超时")
         return None, None
     except Exception as e:
-        logger.exception(f"[PaddleOCR OCR] 调用失败: {e}")
+        logger.exception(f"[PaddleOCR 文本识别] 调用失败: {e}")
         return None, None
 
 
@@ -859,16 +851,15 @@ def call_paddleocr_doc_parser_for_text(image_path: str, save_path: str) -> tuple
     """
     try:
         if not os.path.exists(image_path):
-            logger.error(f"[PaddleOCR DocParser] 图片文件不存在: {image_path}")
+            logger.error(f"[PaddleOCR 图表识别] 图片文件不存在: {image_path}")
             return None, None
         
-        # 生成输出目录和基础文件名
+        # 生成输出目录和基础文件名(图表识别:开启 use_chart_recognition)
         image_dir = os.path.dirname(image_path)
         image_basename = os.path.splitext(os.path.basename(image_path))[0]
         save_path_base = os.path.join(save_path, image_basename)
         os.makedirs(save_path_base, exist_ok=True)
         
-        # 构建paddleocr doc_parser命令(NPU 下需加 --device npu:0,否则走 CPU 易段错误)
         cmd = [
             _get_paddleocr_executable(), "doc_parser", "-i", image_path,
             "--precision", "fp32",
@@ -877,14 +868,12 @@ def call_paddleocr_doc_parser_for_text(image_path: str, save_path: str) -> tuple
             "--use_chart_recognition", "True",
             "--save_path", save_path_base
         ] + _paddle_ocr_device_args()
-        
-        # 添加 VL 识别后端配置(如果已配置)
         if VL_REC_BACKEND:
             cmd.extend(["--vl_rec_backend", VL_REC_BACKEND])
         if VL_REC_SERVER_URL:
             cmd.extend(["--vl_rec_server_url", VL_REC_SERVER_URL])
         
-        logger.info(f"[PaddleOCR DocParser] 执行命令: {' '.join(cmd)}")
+        logger.info(f"[PaddleOCR 图表识别] 执行命令: {' '.join(cmd)}")
         
         # 执行命令(env 含 LD_PRELOAD 与 PADDLE_PDX_DISABLE_MODEL_SOURCE_CHECK)
         result = subprocess.run(
@@ -897,53 +886,47 @@ def call_paddleocr_doc_parser_for_text(image_path: str, save_path: str) -> tuple
         )
         
         if result.returncode != 0:
-            logger.error(f"[PaddleOCR DocParser] 命令执行失败,返回码: {result.returncode}")
+            logger.error(f"[PaddleOCR 图表识别] 命令执行失败,返回码: {result.returncode}")
             if result.stderr and ("too many values to unpack" in result.stderr or "Exception from the 'cv' worker" in result.stderr):
                 logger.warning(
-                    "[PaddleOCR DocParser] 报 cv worker 解包错误,多为 PaddleX 与 PP-DocLayoutV3 不兼容。"
-                    " 可尝试: pip install -U paddlex;或改用 ocr 模式提取文字。详见 README_STARTUP.md。"
+                    "[PaddleOCR 图表识别] 报 cv worker 解包错误,多为 PaddleX 与 PP-DocLayoutV3 不兼容。"
+                    " 可尝试: pip install -U paddlex;或改用 文本识别 提取文字。详见 README_STARTUP.md。"
                 )
-            logger.error(f"[PaddleOCR DocParser] 错误输出: {result.stderr}")
+            logger.error(f"[PaddleOCR 图表识别] 错误输出: {result.stderr}")
             return None, None
 
-        # 查找保存的Markdown文件
-        # PaddleOCR会在save_path下创建目录,文件路径为: {save_path}/{basename}.md
         md_file = os.path.join(save_path_base, f"{image_basename}.md")
-        
-        # 也可能在子目录中
         if not os.path.exists(md_file):
             md_files = sorted(Path(save_path_base).rglob("*.md"))
             if md_files:
                 md_file = str(md_files[0])
-                logger.info(f"[PaddleOCR DocParser] 在子目录中找到Markdown文件: {md_file}")
+                logger.info(f"[PaddleOCR 图表识别] 在子目录中找到Markdown文件: {md_file}")
         
         if not os.path.exists(md_file):
-            logger.warning(f"[PaddleOCR DocParser] Markdown文件不存在: {md_file}")
+            logger.warning(f"[PaddleOCR 图表识别] Markdown文件不存在: {md_file}")
             return None, None
         
-        # 读取Markdown文件并转换为纯文本
         try:
             with open(md_file, 'r', encoding='utf-8') as f:
                 markdown_content = f.read()
             
             if not markdown_content.strip():
-                logger.warning("[PaddleOCR DocParser] Markdown文件内容为空")
+                logger.warning("[PaddleOCR 图表识别] Markdown文件内容为空")
                 return [], md_file
             
-            # 将Markdown转换为纯文本列表
             plain_text_lines = markdown_to_plain_text(markdown_content)
-            logger.info(f"[PaddleOCR DocParser] 成功提取 {len(plain_text_lines)} 行纯文本,Markdown文件: {md_file}")
+            logger.info(f"[PaddleOCR 图表识别] 成功提取 {len(plain_text_lines)} 行纯文本,Markdown文件: {md_file}")
             return plain_text_lines, md_file
                 
         except Exception as e:
-            logger.exception(f"[PaddleOCR DocParser] 读取Markdown文件失败: {e}")
+            logger.exception(f"[PaddleOCR 图表识别] 读取Markdown文件失败: {e}")
             return None, md_file
             
     except subprocess.TimeoutExpired:
-        logger.error("[PaddleOCR DocParser] 命令执行超时")
+        logger.error("[PaddleOCR 图表识别] 命令执行超时")
         return None, None
     except Exception as e:
-        logger.exception(f"[PaddleOCR DocParser] 调用失败: {e}")
+        logger.exception(f"[PaddleOCR 图表识别] 调用失败: {e}")
         return None, None
 
 
@@ -1732,7 +1715,7 @@ def fallback_parse_with_paddleocr(
             return None
         
         # 使用doc_parser模式解析文档结构
-        logger.info("[PaddleOCR备用] 使用doc_parser模式解析文档结构")
+        logger.info("[PaddleOCR备用] 使用doc_parser模式解析文档结构(图表识别)")
         paddleocr_result = call_paddleocr(image_path)
         if not paddleocr_result:
             logger.error("[PaddleOCR备用] PaddleOCR解析失败")
@@ -1787,7 +1770,7 @@ def fallback_parse_with_paddleocr(
             return None
         
         # 调用paddleocr ocr提取关键词来补充数据(作为doc_parser的补充)
-        logger.info("[PaddleOCR备用] 调用OCR提取关键词补充数据")
+        logger.info("[PaddleOCR备用] 调用文本识别提取关键词补充数据")
         ocr_save_path = os.path.dirname(image_path)  # 使用图片所在目录作为保存路径
         ocr_texts, _ = call_paddleocr_ocr(image_path, ocr_save_path)