第二代仪评指标联识别接口

This commit is contained in:
BBIT-Kai
2025-09-30 13:48:59 +08:00
parent d71518931c
commit 3fb43c09f3
14 changed files with 323 additions and 36 deletions
+5 -4
View File
@@ -485,7 +485,7 @@ def get_ticket_image_list(user_id):
"created_at": MyUtils.format_datetime(row[0]),
"file_name": row[1],
"resolution": row[2],
"size": round(row[3], 2),
"size": round(row[3] / 1024, 2),
"name": row[4],
"moisture_content": row[5],
"cocoon_weight": row[6],
@@ -493,7 +493,6 @@ def get_ticket_image_list(user_id):
"fresh_shell_weight": row[8],
"sample_count": row[9],
"barcode": row[10],
# "oss_url": f"http://{SERVER_PATH_OSS}:9000/image-ticket/{row[11]}",
"oss_url": get_temp_url("image-ticket", row[11]),
"net_weight_total": row[12],
"evaluator": row[13],
@@ -513,6 +512,7 @@ def insert_ticket_image(
moisture_content,
cocoon_weight,
defective_pupa_count,
dead_pupa_count,
fresh_shell_weight,
sample_count,
barcode,
@@ -527,11 +527,11 @@ def insert_ticket_image(
"""
INSERT INTO ticket_images (
created_by, file_name, resolution, size, name,
moisture_content, cocoon_weight, defective_pupa_count,
moisture_content, cocoon_weight, defective_pupa_count, dead_pupa_count,
fresh_shell_weight, sample_count, barcode, oss,
net_weight_total, evaluator, reviewer, created_at
)
VALUES (%s, %s, %s, %s, %s,
VALUES (%s, %s, %s, %s, %s, %s,
%s, %s, %s, %s, %s,
%s, %s, %s, %s, %s, NOW())
RETURNING id
@@ -545,6 +545,7 @@ def insert_ticket_image(
moisture_content,
cocoon_weight,
defective_pupa_count,
dead_pupa_count,
fresh_shell_weight,
sample_count,
barcode,
+67
View File
@@ -0,0 +1,67 @@
import json
import re
from langchain.schema import HumanMessage
from config.llm import *
from llm.ticketLLM import decode_barcode
def get_ticket_response_v2(image_url: str, needBarcode: bool = False):
# 构建 prompt
prompt_text = f"""
你是一位专业的图像分析AI。你的任务是仔细分析提供的图片内容,并按JSON格式输出结果。
## JSON输出结构及字段说明:
# 蚕茧检测信息数据模型
该模型用于描述蚕茧检测信息,每条记录包含以下字段:
## 1. 下足茧重量 (`cocoon_weight`)
- **类型**:浮点数
- **描述**:下足茧的重量,单位为克(可带小数)
## 2. 非蛹粒数 (`defective_pupa_count`)
- **类型**:整数
- **描述**:不合格蛹的数量,即非好蛹的个数
## 3. 僵蛹粒数 (`dead_pupa_count`)
- **类型**:整数
- **描述**:僵蚕蛹的数量
## 4. 鲜壳量 (`fresh_shell_weight`)
- **类型**:浮点数
- **描述**:鲜壳重量,单位为克(可带小数)
## 5. 小样粒数 (`sample_count`)
- **类型**:整数
- **描述**:检测使用的小样数量,即用于检测的茧粒数
---
### 注意事项
- 所有字段都是必填的(required),在 JSON 实例中必须提供值
- 浮点数字段可以包含小数,整数字段只能是整数
- `evaluator` 和 `reviewer` 可以为空字符串,但字段必须存在
- 如果图片与上述内容无关,则字段值为默认值,例如0、0.0、""
最后,只输出严格的 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)
print("needBarcode:", needBarcode)
if needBarcode:
jsonRes["barcode"] = decode_barcode(image_url)
return jsonRes
+7
View File
@@ -0,0 +1,7 @@
from pydantic import BaseModel
class F8ImageRequestV2(BaseModel):
title: str
image: str
needBarcode: bool
+24
View File
@@ -5,6 +5,7 @@ from fastapi import APIRouter
from config.app import F8_SERVER_USER_ID
from models.BaseResponse import BaseResponse
from models.F8ImageRequest import F8ImageRequest
from models.F8ImageRequestV2 import F8ImageRequestV2
from service.vision import process_ticket_image
from utils import MyUtils
@@ -20,6 +21,29 @@ async def cocoonTicket(data: F8ImageRequest):
img_bytes = base64.b64decode(input_data)
json_data = await MyUtils.async_task(
process_ticket_image,
1,
True,
img_bytes,
f"{data.title}.jpg",
data.title,
F8_SERVER_USER_ID,
)
return BaseResponse(data=json_data)
except Exception as e:
return BaseResponse(status=False, message=f"解析失败: {str(e)}", data=None)
@f8Router.post("/createTicketImageTaskV2")
async def cocoonTicket(data: F8ImageRequestV2):
input_data = data.image
if "," in input_data:
input_data = input_data.split(",")[1]
try:
img_bytes = base64.b64decode(input_data)
json_data = await MyUtils.async_task(
process_ticket_image,
2,
data.needBarcode,
img_bytes,
f"{data.title}.jpg",
data.title,
+1 -1
View File
@@ -36,7 +36,7 @@ async def createTicketImageTask(
try:
contents = await file.read()
json_data = await MyUtils.async_task(
process_ticket_image, contents, file.filename, projectName, user_id
process_ticket_image, 1, True, contents, file.filename, projectName, user_id
)
return BaseResponse(data=json_data)
except Exception as e:
+15 -8
View File
@@ -5,10 +5,13 @@ import config.minIO as minIO
import db.postgres as pg
from config.minIO import minio_client
from llm.ticketLLM import *
from llm.ticketLLMv2 import get_ticket_response_v2
def process_ticket_image(
img_bytes: bytes,
version: int,
needBarcode: bool = False,
img_bytes=None,
file_name: str = None,
project_name: str = None,
user_id: UUID = None,
@@ -18,6 +21,8 @@ def process_ticket_image(
"""
# 上传到 OSS,使用 UUID 做对象名
if img_bytes is None:
img_bytes = []
object_name = str(uuid.uuid4())
file_bytes = BytesIO(img_bytes)
bucket_name = "image-ticket"
@@ -28,15 +33,16 @@ def process_ticket_image(
oss_url = minIO.get_temp_url(bucket_name, object_name)
# 调用分析方法获取 JSON
json_data = get_ticket_response(oss_url)
# 解析条码
barcode = decode_barcode(BytesIO(img_bytes))
json_data["barcode"] = barcode
if version == 1:
json_data = get_ticket_response(oss_url)
elif version == 2:
json_data = get_ticket_response_v2(oss_url, needBarcode)
else:
json_data = get_ticket_response(oss_url)
# 获取图片分辨率和大小
img = Image.open(BytesIO(img_bytes))
resolution = f"{img.width}x{img.height}"
size_kb = len(img_bytes) / 1024
size_kb = round(len(img_bytes) / 1024, 2)
# 插入数据库
pg.insert_ticket_image(
@@ -45,12 +51,13 @@ def process_ticket_image(
resolution=resolution,
size=size_kb,
name=project_name if project_name else object_name[:8],
dead_pupa_count=json_data.get("moisture_content") if version == 2 else 0,
moisture_content=json_data.get("moisture_content"),
cocoon_weight=json_data.get("cocoon_weight"),
defective_pupa_count=json_data.get("defective_pupa_count"),
fresh_shell_weight=json_data.get("fresh_shell_weight"),
sample_count=json_data.get("sample_count"),
barcode=barcode,
barcode=json_data.get("barcode"),
oss=object_name,
net_weight_total=json_data.get("net_weight_total"),
evaluator=json_data.get("evaluator"),