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)