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):
|
def parse_logistics_table_images(self, image_urls, session):
|
||||||
"""识别物流表格截图,用 LLM 从 OCR 文本中提取快递单号和收件人。"""
|
"""识别物流表格截图,用 LLM 视觉能力直接从图片中提取快递单号和收件人。"""
|
||||||
|
import base64 as _b64
|
||||||
|
import json as _json
|
||||||
import logging as _log
|
import logging as _log
|
||||||
_logger = _log.getLogger(__name__)
|
from urllib import request as urllib_request
|
||||||
from backend.app.services.ai_service import ai_service
|
from backend.app.services.ai_service import read_image_bytes
|
||||||
from backend.app.core.config import get_settings
|
from backend.app.core.config import get_settings
|
||||||
|
|
||||||
|
_logger = _log.getLogger(__name__)
|
||||||
settings = get_settings()
|
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 = []
|
results = []
|
||||||
seen_tracking = set()
|
seen_tracking = set()
|
||||||
for url in image_urls:
|
for url in image_urls:
|
||||||
try:
|
try:
|
||||||
_logger.info("[parse_logistics_table_images] 处理图片: %s", url)
|
_logger.info("[parse_logistics_table_images] 处理图片: %s", url)
|
||||||
ctx = ai_service._ocr_and_parse_image(url)
|
image_bytes = read_image_bytes(url)
|
||||||
raw_text = ctx.get("raw_text", "")
|
image_b64 = _b64.b64encode(image_bytes).decode("utf-8")
|
||||||
_logger.info("[parse_logistics_table_images] OCR原始文本长度: %d, 前500字: %s",
|
suffix = url.rsplit(".", 1)[-1].lower() if "." in url else "jpeg"
|
||||||
len(raw_text), raw_text[:500])
|
mime = {"jpg": "image/jpeg", "jpeg": "image/jpeg", "png": "image/png", "bmp": "image/bmp"}.get(suffix, "image/jpeg")
|
||||||
if not raw_text.strip():
|
|
||||||
_logger.warning("[parse_logistics_table_images] OCR未识别到文字")
|
payload = _json.dumps({
|
||||||
continue
|
"model": settings.llm_parse_model,
|
||||||
# 用 LLM 从表格文本中提取快递单号和收件人
|
"messages": [
|
||||||
llm_items = self._llm_extract_logistics(raw_text, settings)
|
{"role": "system", "content": system_prompt},
|
||||||
_logger.info("[parse_logistics_table_images] LLM提取结果: %d条", len(llm_items))
|
{"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:
|
for item in llm_items:
|
||||||
tn = (item.get("tracking_number") or "").strip()
|
tn = (item.get("tracking_number") or "").strip()
|
||||||
if not tn or len(tn) < 10 or tn in seen_tracking:
|
if not tn or len(tn) < 10 or tn in seen_tracking:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user