最新可用

This commit is contained in:
2025-09-04 22:59:27 +08:00
parent ec6dbfde90
commit 30bf7c9fcb
42 changed files with 746 additions and 1967 deletions

View File

@ -1,6 +1,6 @@
import json
from fastapi import APIRouter, Query, HTTPException
from fastapi import APIRouter, Query, HTTPException,Request
from mysql.connector import Error as MySQLError
from ds.db import db
@ -108,7 +108,7 @@ def update_online_status_by_ip(client_ip: str, online_status: int) -> bool:
# 原有接口保持不变
# ------------------------------
@router.post("/add", response_model=APIResponse, summary="创建设备信息")
async def create_device(device_data: DeviceCreateRequest):
async def create_device(device_data: DeviceCreateRequest, request: Request): # 注入Request对象
# 原有代码保持不变
conn = None
cursor = None
@ -125,11 +125,10 @@ async def create_device(device_data: DeviceCreateRequest):
return APIResponse(
code=200,
message=f"设备IP {device_data.ip} 已存在,返回已有设备信息",
data=DeviceResponse(**existing_device)
data=DeviceResponse(** existing_device)
)
from fastapi import Request
request = Request(scope={"type": "http"})
# 直接使用注入的request对象获取用户代理
user_agent = request.headers.get("User-Agent", "").lower()
if user_agent == "default":
@ -184,7 +183,6 @@ async def create_device(device_data: DeviceCreateRequest):
finally:
db.close_connection(conn, cursor)
@router.get("/", response_model=APIResponse, summary="获取设备列表(支持筛选分页)")
async def get_device_list(
page: int = Query(1, ge=1, description="页码默认第1页"),

View File

@ -6,15 +6,15 @@ from schema.face_schema import FaceCreateRequest, FaceUpdateRequest, FaceRespons
from schema.response_schema import APIResponse
from middle.auth_middleware import get_current_user
from schema.user_schema import UserResponse
from ocr.feature_extraction import BinaryFaceFeatureHandler
from util.face_util import add_binary_data,get_average_feature
#初始化实例
router = APIRouter(
prefix="/faces",
tags=["人脸管理"]
)
# 创建 BinaryFaceFeatureHandler 的实例
binary_face_feature_handler = BinaryFaceFeatureHandler()
# ------------------------------
@ -33,6 +33,8 @@ async def create_face(
- ID 由数据库自动生成,无需前端传入
- 暂不处理文件内容eigenvalue 设为 None
"""
# 调用你的方法
conn = None
cursor = None
try:
@ -45,14 +47,24 @@ async def create_face(
# 把文件转为二进制数组
file_content = await file.read()
# 调用人脸识别得到特征值
# 计算特征值
flag, eigenvalue = add_binary_data(file_content)
if flag == False:
raise HTTPException(
status_code=500,
detail="未检测到人脸"
)
# 打印数组长度
print(f"文件大小:{len(file_content)} 字节")
# 2. 插入数据库:无需传 ID自增只传 name 和 eigenvalueNone
insert_query = """
INSERT INTO face (name, eigenvalue)
VALUES (%s, %s)
"""
cursor.execute(insert_query, (face_create.name, None))
cursor.execute(insert_query, (face_create.name, str(eigenvalue)))
conn.commit()
# 3. 获取数据库自动生成的 ID关键用 LAST_INSERT_ID() 查刚插入的记录)
@ -60,19 +72,45 @@ async def create_face(
cursor.execute(select_new_query)
created_face = cursor.fetchone()
if not created_face:
raise HTTPException(
status_code=500,
detail="创建人脸记录成功,但无法获取新创建的记录"
)
return APIResponse(
code=201,
message=f"人脸记录创建成功ID{created_face['id']},文件名:{file.filename}",
data=FaceResponse(**created_face)
data=FaceResponse(** created_face)
)
except MySQLError as e:
if conn:
conn.rollback()
raise Exception(f"创建人脸记录失败:{str(e)}") from e
# 改为使用HTTPException
raise HTTPException(
status_code=500,
detail=f"创建人脸记录失败:{str(e)}"
) from e
except Exception as e:
# 捕获其他可能的异常
raise HTTPException(
status_code=500,
detail=f"服务器错误:{str(e)}"
) from e
finally:
await file.close() # 关闭文件流
db.close_connection(conn, cursor)
# 调用人脸识别得到特征值(这里可以添加你的人脸识别逻辑)
flag, eigenvalue = add_binary_data(file_content)
if flag == False:
raise HTTPException(
status_code=500,
detail="未检测到人脸"
)
# 将 eigenvalue 转为 str
eigenvalue = str(eigenvalue)
# ------------------------------
# 2. 获取单个人脸记录不变用自增ID查询
@ -104,18 +142,21 @@ async def get_face(
data=FaceResponse(**face)
)
except MySQLError as e:
raise Exception(f"查询人脸记录失败:{str(e)}") from e
# 改为使用HTTPException
raise HTTPException(
status_code=500,
detail=f"查询人脸记录失败:{str(e)}"
) from e
finally:
db.close_connection(conn, cursor)
# 后续 3.获取所有、4.更新、5.删除 接口(不变,仅用数据库自增的 ID 操作,无需修改
# 后续 3.获取所有、4.更新、5.删除 接口(修复异常处理
# ------------------------------
# 3. 获取所有人脸记录(不变)
# ------------------------------
@router.get("", response_model=APIResponse, summary="获取所有人脸记录")
async def get_all_faces(
current_user: UserResponse = Depends(get_current_user)
):
conn = None
cursor = None
@ -130,10 +171,13 @@ async def get_all_faces(
return APIResponse(
code=200,
message="所有人脸记录查询成功",
data=[FaceResponse(**face) for face in faces]
data=[FaceResponse(** face) for face in faces]
)
except MySQLError as e:
raise Exception(f"查询所有人脸记录失败:{str(e)}") from e
raise HTTPException(
status_code=500,
detail=f"查询所有人脸记录失败:{str(e)}"
) from e
finally:
db.close_connection(conn, cursor)
@ -194,7 +238,10 @@ async def update_face(
except MySQLError as e:
if conn:
conn.rollback()
raise Exception(f"更新人脸记录失败:{str(e)}") from e
raise HTTPException(
status_code=500,
detail=f"更新人脸记录失败:{str(e)}"
) from e
finally:
db.close_connection(conn, cursor)
@ -234,7 +281,10 @@ async def delete_face(
except MySQLError as e:
if conn:
conn.rollback()
raise Exception(f"删除人脸记录失败:{str(e)}") from e
raise HTTPException(
status_code=500,
detail=f"删除人脸记录失败:{str(e)}"
) from e
finally:
db.close_connection(conn, cursor)
@ -249,38 +299,43 @@ def get_all_face_name_with_eigenvalue() -> dict:
conn = None
cursor = None
try:
# 1. 建立数据库连接并获取游标dictionary=True使结果以字典形式返回
conn = db.get_connection()
cursor = conn.cursor(dictionary=True)
# 只查询需要的字段,提高效率
# 2. 执行SQL查询只获取name非空的记录减少数据传输
query = "SELECT name, eigenvalue FROM face WHERE name IS NOT NULL"
cursor.execute(query)
faces = cursor.fetchall()
faces = cursor.fetchall() # 返回结果:列表套字典,如 [{"name":"张三","eigenvalue":...}, ...]
# 先收集所有名称对应的特征值列表(处理重复名称)
# 3. 收集同一名称对应的所有特征值(处理名称重复场景
name_to_eigenvalues = {}
for face in faces:
name = face["name"]
eigenvalue = face["eigenvalue"]
# 若名称已存在,追加特征值;否则新建列表存储
if name in name_to_eigenvalues:
name_to_eigenvalues[name].append(eigenvalue)
else:
name_to_eigenvalues[name] = [eigenvalue]
# 构建最终字典:重复名称取平均特征值,唯一名称直接取特征值
# 4. 构建最终字典:重复名称取平均,唯一名称直接取特征值
face_dict = {}
for name, eigenvalues in name_to_eigenvalues.items():
print("调用的特征值是:" + eigenvalues)
# 处理特征值:多个则求平均,单个则直接使用
if len(eigenvalues) > 1:
# 调用平均特征值计算方法
face_dict[name] = binary_face_feature_handler.get_average_feature(eigenvalues)
# 调用外部方法计算平均特征值需确保binary_face_feature_handler已正确导入
face_dict[name] = get_average_feature(eigenvalues)
else:
# 取列表中唯一的特征值避免value为列表类型
face_dict[name] = eigenvalues[0]
return face_dict
except MySQLError as e:
# 捕获数据库异常,添加上下文信息后重新抛出(便于定位问题)
raise Exception(f"获取人脸名称与特征值失败:{str(e)}") from e
finally:
# 确保资源释放
db.close_connection(conn, cursor)
# 5. 无论是否异常,均释放数据库连接和游标(避免资源泄漏)
db.close_connection(conn, cursor)