Files
2025-12-31 17:49:17 +08:00

153 lines
4.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import json
import re
from langchain_core.messages import HumanMessage
from config.llm import *
def get_ticket_response(image_url: str):
# 构建 prompt
prompt_text = f"""
你是一位专业的图像分析AI。你的任务是仔细分析提供的图片内容,并按JSON格式输出结果。
## JSON输出结构及字段说明:
# 蚕茧检测信息数据模型(ImageDescription
该模型用于描述蚕茧检测信息,每条记录包含以下字段:
## 1. 含水率 (`moisture_content`)
- **类型**:浮点数
- **描述**:茧的含水量,单位为百分比(%)
## 2. 下足茧重量 (`cocoon_weight`)
- **类型**:浮点数
- **描述**:下足茧的重量,单位为克(可带小数)
## 3. 非好蛹粒数 (`defective_pupa_count`)
- **类型**:整数
- **描述**:不合格蛹的数量,即非好蛹的个数
## 4. 鲜壳量 (`fresh_shell_weight`)
- **类型**:浮点数
- **描述**:鲜壳重量,单位为克(可带小数)
## 5. 小样粒数 (`sample_count`)
- **类型**:整数
- **描述**:检测使用的小样数量,即用于检测的茧粒数
## 6. 净重合计 (`net_weight_total`)
- **类型**:浮点数
- **描述**:所有样品的净重总和,单位为克
## 7. 仪评人姓名 (`evaluator`)
- **类型**:字符串
- **描述**:进行仪器检测的人员姓名,可能为空
## 8. 复核人员姓名 (`reviewer`)
- **类型**:字符串
- **描述**:复核人员姓名,可能为空
---
### 注意事项
- 所有字段都是必填的(required),在 JSON 实例中必须提供值
- 浮点数字段可以包含小数,整数字段只能是整数
- `evaluator` 和 `reviewer` 可以为空字符串,但字段必须存在
最后,只输出严格的 JSON 格式,不要包含其他文字、markdown等内容。
"""
messages = [
HumanMessage(
content=[
{"type": "text", "text": prompt_text},
{"type": "image_url", "image_url": {"url": image_url}},
]
)
]
# 直接调用模型
llmRes = llmVision.invoke(messages).content
# 去掉 ```json 和 ``` 包裹
cleaned = re.sub(r"^```json\s*|\s*```$", "", llmRes.strip())
# 解析 JSON
jsonRes = json.loads(cleaned)
jsonRes["barcode"] = decode_barcode(image_url)
return jsonRes
import os
import base64
import tempfile
import requests
from pyzxing import BarCodeReader
from PIL import Image
from io import BytesIO
from fastapi import UploadFile
def decode_barcode(input_data) -> str:
"""
自动识别输入类型并解析条码:
- URL 字符串
- Base64 字符串
- UploadFile / bytes / 文件对象
返回第一个条码的内容,解析失败返回空字符串
"""
# ---------------- 输入处理 ----------------
img = None
# URL
if isinstance(input_data, str) and (
input_data.startswith("http://") or input_data.startswith("https://")
):
response = requests.get(input_data)
response.raise_for_status()
img = Image.open(BytesIO(response.content))
# Base64 字符串
elif isinstance(input_data, str):
# 过滤 data URI 前缀
if "," in input_data:
input_data = input_data.split(",")[1]
try:
img_data = base64.b64decode(input_data)
img = Image.open(BytesIO(img_data))
except Exception:
raise ValueError("无法解析 Base64 字符串")
# UploadFile / bytes / 文件对象
elif isinstance(input_data, UploadFile):
content = input_data.file.read()
input_data.file.seek(0)
img = Image.open(BytesIO(content))
elif isinstance(input_data, bytes):
img = Image.open(BytesIO(input_data))
elif hasattr(input_data, "read"): # 文件对象
content = input_data.read()
if hasattr(input_data, "seek"):
input_data.seek(0)
img = Image.open(BytesIO(content))
else:
raise ValueError("不支持的输入类型")
# ---------------- 临时文件处理 ----------------
tmp_fd, tmp_path = tempfile.mkstemp(suffix=".png")
try:
with open(tmp_path, "wb") as f:
img.save(f, format="PNG")
# ---------------- 调用 pyzxing ----------------
reader = BarCodeReader()
result = reader.decode(tmp_path)
if result:
parsed = result[0].get("parsed", "")
if isinstance(parsed, bytes):
parsed = parsed.decode("utf-8")
return parsed
return ""
finally:
os.close(tmp_fd)
if os.path.exists(tmp_path):
os.remove(tmp_path)