fix: 物流表格截图识别改用LLM视觉能力,移除阿里云OCR SDK依赖
服务器未安装alibabacloud_ocr_api20210707 SDK导致识别失败。 改为直接将图片base64发给qwen-plus LLM视觉接口识别表格, 跳过OCR步骤,减少依赖链路。 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
a7382188b7
commit
94e1b66ec8
@ -2400,27 +2400,63 @@ class OrderService:
|
||||
|
||||
|
||||
def parse_logistics_table_images(self, image_urls, session):
|
||||
"""识别物流表格截图,用 LLM 从 OCR 文本中提取快递单号和收件人。"""
|
||||
"""识别物流表格截图,用 LLM 视觉能力直接从图片中提取快递单号和收件人。"""
|
||||
import base64 as _b64
|
||||
import json as _json
|
||||
import logging as _log
|
||||
_logger = _log.getLogger(__name__)
|
||||
from backend.app.services.ai_service import ai_service
|
||||
from urllib import request as urllib_request
|
||||
from backend.app.services.ai_service import read_image_bytes
|
||||
from backend.app.core.config import get_settings
|
||||
|
||||
_logger = _log.getLogger(__name__)
|
||||
settings = get_settings()
|
||||
api_key = settings.llm_parse_api_key or settings.aliyun_ai_access_key_id
|
||||
|
||||
system_prompt = (
|
||||
"你是物流信息提取助手。从物流表格截图中提取每一行的快递单号和收件人姓名。\n"
|
||||
"表格通常包含:运单号、运单状态、件数、体积、计费重量、付款方式、运费、"
|
||||
"保价费、包装服务费、信息费、代收货款、签收费、声明价值、产品类型、"
|
||||
"增值服务、服务方式、业务属性、托寄物、寄件人、收件人、目的网点 等列。\n\n"
|
||||
"严格按以下 JSON 数组格式输出,不要添加任何其他内容:\n"
|
||||
'[{"tracking_number":"运单号","express_company":"快递公司名或null","recipient_name":"收件人姓名"}]'
|
||||
)
|
||||
|
||||
results = []
|
||||
seen_tracking = set()
|
||||
for url in image_urls:
|
||||
try:
|
||||
_logger.info("[parse_logistics_table_images] 处理图片: %s", url)
|
||||
ctx = ai_service._ocr_and_parse_image(url)
|
||||
raw_text = ctx.get("raw_text", "")
|
||||
_logger.info("[parse_logistics_table_images] OCR原始文本长度: %d, 前500字: %s",
|
||||
len(raw_text), raw_text[:500])
|
||||
if not raw_text.strip():
|
||||
_logger.warning("[parse_logistics_table_images] OCR未识别到文字")
|
||||
continue
|
||||
# 用 LLM 从表格文本中提取快递单号和收件人
|
||||
llm_items = self._llm_extract_logistics(raw_text, settings)
|
||||
_logger.info("[parse_logistics_table_images] LLM提取结果: %d条", len(llm_items))
|
||||
image_bytes = read_image_bytes(url)
|
||||
image_b64 = _b64.b64encode(image_bytes).decode("utf-8")
|
||||
suffix = url.rsplit(".", 1)[-1].lower() if "." in url else "jpeg"
|
||||
mime = {"jpg": "image/jpeg", "jpeg": "image/jpeg", "png": "image/png", "bmp": "image/bmp"}.get(suffix, "image/jpeg")
|
||||
|
||||
payload = _json.dumps({
|
||||
"model": settings.llm_parse_model,
|
||||
"messages": [
|
||||
{"role": "system", "content": system_prompt},
|
||||
{"role": "user", "content": [
|
||||
{"type": "image_url", "image_url": {"url": f"data:{mime};base64,{image_b64}"}},
|
||||
{"type": "text", "text": "请从这个物流表格截图中提取每一行的快递单号和收件人姓名:"},
|
||||
]},
|
||||
],
|
||||
"temperature": 0.1,
|
||||
"max_tokens": 4096,
|
||||
}).encode("utf-8")
|
||||
|
||||
req = urllib_request.Request(
|
||||
url=settings.llm_parse_api_url, data=payload,
|
||||
headers={"Content-Type": "application/json", "Authorization": f"Bearer {api_key}"},
|
||||
method="POST",
|
||||
)
|
||||
with urllib_request.urlopen(req, timeout=60) as resp:
|
||||
result = _json.loads(resp.read().decode("utf-8"))
|
||||
|
||||
content = result["choices"][0]["message"]["content"]
|
||||
_logger.info("[parse_logistics_table_images] LLM响应: %s", content[:500])
|
||||
llm_items = self._extract_json_array(content)
|
||||
_logger.info("[parse_logistics_table_images] 提取结果: %d条", len(llm_items))
|
||||
|
||||
for item in llm_items:
|
||||
tn = (item.get("tracking_number") or "").strip()
|
||||
if not tn or len(tn) < 10 or tn in seen_tracking:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user