新增证件识别接口

This commit is contained in:
BBIT-Kai
2025-10-29 13:53:55 +08:00
parent a1f0d0ad55
commit aff1b85ab0
14 changed files with 720 additions and 74 deletions
+152
View File
@@ -0,0 +1,152 @@
from typing import TypedDict
from langchain_core.messages import HumanMessage
from langgraph.graph import StateGraph, END
from config.llm import llmVision
# -------- 定义状态 --------
class State(TypedDict):
image_url: str # 证件照
type: int # 证件类别
content: str # 最终内容
def analyze_card(state: State, prompt_text: str):
messages = [
HumanMessage(
content=[
{"type": "text", "text": prompt_text},
{"type": "image_url", "image_url": {"url": state["image_url"]}},
]
)
]
return llmVision.invoke(messages).content
# -------- 定义节点 --------
def decide_source(state: State, max_retry=3):
choice = analyze_card(
state,
"""
请根据图片内容判断其中的证件类型,并输出对应代号。
代号说明:
-1: 并非证件
0:身份证
1:银行卡
只输出代号数字,不要输出任何文字、标点或解释。
你的输出是:
""",
)
print("图片类型是", choice)
try:
choice = int(choice)
state["type"] = choice
if choice == -1:
state["content"] = '{"result": "暂不支持此证件"}'
except ValueError:
state["type"] = -1
state["content"] = '{"result": "暂不支持此证件"}'
return state
def idcard(state: State):
state["content"] = analyze_card(
state,
"""
你是一个 OCR 信息提取专家,请从图片中识别出身份证的全部可见信息,并输出严格的 JSON 格式。
要求:
1. 无论是正面还是反面,都要识别所有字段。
2. 如果某个字段无法辨认,请将值设为 null。
3. 只输出 JSON,不要输出任何解释或多余内容。
4. 严格保持 JSON 格式,键名统一为英文。
5. "side" 字段为身份证方向,填写:人像面 或 国徽面。
JSON 示例格式:
{
"side": "国徽面",
"name": "持证人姓名",
"gender": "性别",
"ethnicity": "民族",
"id_number": "身份证号",
"birth_date": "出生日期",
"address": "住址",
"issuing_authority": "签发机关",
"valid_period_start": "有效期开始日期",
"valid_period_end": "有效期结束日期",
"notes": "其他可见文字或备注"
}
请确保输出的 JSON 可以被严格解析。
""",
)
return state
def bankcard(state: State):
state["content"] = analyze_card(
state,
"""
你是一个 OCR 信息提取专家,请从图片中识别出银行卡上的全部可见信息,并输出严格的 JSON 格式。
要求:
1. 识别卡号、发卡行、持卡人、有效期等关键信息。
2. 如果某个字段无法辨认,请将值设为 null。
3. 只输出 JSON,不要输出任何解释或附加内容。
4. 严格保持 JSON 格式,键名统一为英文。
JSON 示例格式:
{
"bank_name": "发卡行名称",
"card_number": "卡号",
"card_holder": "持卡人姓名",
"expiry_date": "有效期",
"card_type": "卡种类型(如借记卡/信用卡/Visa/MasterCard",
"issuer_country": "发卡国家",
"notes": "其他可见文字或符号"
}
请确保输出的 JSON 可以被严格解析。
""",
)
return state
# ------------------------------------------------------------------------ 构建有向图 --------
workflow = StateGraph(State)
workflow.add_node("decide", decide_source)
workflow.add_node("idcard", idcard)
workflow.add_node("bankcard", bankcard)
workflow.set_entry_point("decide")
# 条件边:根据 path 决定走向
workflow.add_conditional_edges(
"decide",
lambda state: state["type"],
{
-1: END,
0: "idcard",
1: "bankcard",
},
)
workflow.add_edge("idcard", END)
workflow.add_edge("bankcard", END)
graph = workflow.compile()
import re
# 执行函数
def get_license_response(image_url: str):
final_state = graph.invoke(
{
"image_url": image_url,
}
)
# 去掉 ```json 和 ``` 包裹
final_state["content"] = final_state["content"]
final_state["content"] = re.sub(
r"^```json\s*|\s*```$", "", final_state["content"].strip()
)
print("最终识别内容:", final_state["content"])
return final_state
-60
View File
@@ -1,60 +0,0 @@
from typing import Optional
from pydantic import BaseModel, Field
from langchain_core.messages import HumanMessage
from config.llm import *
from langchain.prompts import PromptTemplate
from langchain.prompts import PromptTemplate
from langchain.schema import HumanMessage
import os
import base64
from langchain.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import JsonOutputParser
from langchain.schema import HumanMessage
from pydantic import BaseModel, Field
from pydantic import BaseModel, Field
import json
import re
import json
import requests
import cv2
import numpy as np
import requests
class CocoonSample(BaseModel):
moisture_content: float = Field(
...,
description="茧的含水量,单位为百分比(%),浮点数"
)
cocoon_weight: float = Field(
...,
description="下足茧的重量,单位为克,可带小数"
)
defective_pupa_count: int = Field(
...,
description="非好蛹粒数,即不合格蛹的数量,整数"
)
fresh_shell_weight: float = Field(
...,
description="鲜壳重量,单位为克,可带小数"
)
sample_count: int = Field(
...,
description="小样粒数,用于检测的茧粒数,整数"
)
net_weight_total: float = Field(
...,
description="所有样品的净重合计,单位为克,浮点数"
)
evaluator: Optional[str] = Field(
None,
description="仪评人姓名,可能为空"
)
reviewer: Optional[str] = Field(
None,
description="复核人员姓名,可能为空"
)