Update: Refactor to absolute imports, fix QPS limits, and enhance Gitea sync with SQLite support

This commit is contained in:
2026-07-21 10:25:29 +08:00
parent ef04fc5627
commit 97d9d98b4c
67 changed files with 1691 additions and 457 deletions
+27 -21
View File
@@ -7,9 +7,9 @@ OCR服务模块
from typing import Dict, List, Optional, Tuple, Union, Any, Callable
import os
from ..config.settings import ConfigManager
from ..core.utils.log_utils import get_logger
from ..core.ocr.table_ocr import OCRProcessor
from app.config.settings import ConfigManager
from app.core.utils.log_utils import get_logger
from app.core.ocr.table_ocr import OCRProcessor
logger = get_logger(__name__)
@@ -62,16 +62,10 @@ class OCRService:
if not self._is_valid_image(image_path):
logger.error(f"不支持的文件类型: {image_path}")
return None
# 检查是否已处理
excel_file = self._get_excel_path(image_path)
if os.path.exists(excel_file):
logger.info(f"文件已处理过,跳过OCR识别: {image_path}")
# 即使 xlsx 已存在,仍补写 meta.json(首次 OCR 后可能未生成)
meta_path = str(excel_file).replace('.xlsx', '.meta.json')
if not os.path.exists(meta_path):
self._write_meta_json(str(excel_file), {}, image_path)
return excel_file
# 不再做 xlsx 已存在就跳过的判断(xlsx 可能被业务层重命名过),
# 跳过逻辑交给 OCRProcessor 内部的 record_manager.is_processed(image_path)
# —— 由它读 processed_files.json(业务层会同步更新 xlsx 路径)
# 执行OCR识别
result = self.ocr_processor.process_image(image_path)
@@ -212,24 +206,36 @@ class OCRService:
base = Path(excel_path)
meta_path = base.with_suffix('.meta.json')
# 0) 优先:调百度通用文字识别(/accurate),覆盖全图文字(含手写抬头/日期)
# 0) 优先:调百度通用票务识别(/general_ocr),精准捕获表头(含手写抬头/日期)
general_text = ''
general_lines = []
try:
# OCRService.ocr_processor = core.ocr.table_ocr.OCRProcessor
# 其 .ocr_client = BaiduOCRClient (process_image 时初始化)
client = getattr(self.ocr_processor, 'ocr_client', None)
if client is None:
# 显式触发一次 process_image 准备流程 (不会重复 OCR)
try:
self.ocr_processor._ensure_ocr_client()
except Exception:
pass
client = getattr(self.ocr_processor, 'ocr_client', None)
if client and hasattr(client, 'recognize_general') and image_path and os.path.exists(str(image_path)):
# 关键:在进行第二次 OCR (票务识别) 前稍微等待,避免触发 QPS 限制
import time
time.sleep(0.5)
# 优先使用票务识别 (Ticket OCR)
if client and hasattr(client, 'recognize_ticket') and image_path and os.path.exists(str(image_path)):
logger.info("使用通用票务识别捕获表头元数据...")
words = client.recognize_ticket(str(image_path))
if words:
general_lines = [(w.get('words') or '').strip() for w in words if (w.get('words') or '').strip()]
general_text = '\n'.join(general_lines)
logger.info(f"票务识别获取 {len(general_lines)} 行文字")
# 如果票务识别无结果或不可用,则兜底使用高精度文字识别
if not general_lines and client and hasattr(client, 'recognize_general') and image_path and os.path.exists(str(image_path)):
logger.info("尝试高精度文字识别作为兜底...")
words = client.recognize_general(str(image_path))
if words:
# 按 location.top 排序(顶部先),方便后续提取供应商/日期
def _top(w):
loc = w.get('location') or {}
try:
@@ -239,9 +245,9 @@ class OCRService:
words_sorted = sorted(words, key=_top)
general_lines = [(w.get('words') or '').strip() for w in words_sorted if (w.get('words') or '').strip()]
general_text = '\n'.join(general_lines)
logger.info(f"通用识别获取 {len(general_lines)} 行文字")
logger.info(f"通用高精度识别获取 {len(general_lines)} 行文字")
except Exception as e:
logger.warning(f"通用识别失败(不影响主流程): {e}")
logger.warning(f"获取元数据识别失败(不影响主流程): {e}")
# 1) 表格识别 header/body 拼表内文字(已在前面逻辑处理)
ocr_text = ''