完成人脸计算任务调用方法
This commit is contained in:
315
src/api/routes/algorithm_router.py
Normal file
315
src/api/routes/algorithm_router.py
Normal file
@@ -0,0 +1,315 @@
|
||||
"""
|
||||
人脸特征计算算法路由
|
||||
提供人脸特征计算的HTTP接口
|
||||
"""
|
||||
|
||||
import os
|
||||
import logging
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Dict, Any
|
||||
|
||||
from fastapi import APIRouter, HTTPException, BackgroundTasks
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from src.config import settings
|
||||
from src.database.connection import db_manager
|
||||
from src.models.face_feature import SurFaceFeature, FeatureStatus
|
||||
from src.repositories.face_feature_repository import FaceFeatureRepository
|
||||
from src.face_recognition_algorithm import FaceRecognitionAlgorithm
|
||||
|
||||
# 创建路由器
|
||||
router = APIRouter(prefix="/algorithm", tags=["algorithm"])
|
||||
|
||||
# 初始化人脸识别算法
|
||||
face_algorithm = FaceRecognitionAlgorithm(use_gpu=settings.FACE_USE_GPU, use_npu=settings.FACE_USE_NPU)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def process_feature_calculation(feature_id: int) -> bool:
|
||||
"""
|
||||
处理单个人脸特征计算
|
||||
|
||||
参数:
|
||||
feature_id: 特征记录ID
|
||||
|
||||
返回:
|
||||
是否成功处理
|
||||
"""
|
||||
try:
|
||||
with db_manager.get_session() as session:
|
||||
repository = FaceFeatureRepository(session)
|
||||
|
||||
# 获取特征记录
|
||||
feature = repository.get_by_id(feature_id)
|
||||
if not feature:
|
||||
logger.error(f"特征记录不存在: {feature_id}")
|
||||
return False
|
||||
|
||||
# 检查是否已经处理完成
|
||||
if feature.status in [FeatureStatus.SUCCESS, FeatureStatus.FAILED]:
|
||||
logger.info(f"特征记录已处理完成: {feature_id}, 状态: {feature.status_name}")
|
||||
return True
|
||||
|
||||
# 检查是否超时
|
||||
if feature.status == FeatureStatus.PROCESSING:
|
||||
if feature.start_time:
|
||||
timeout_duration = timedelta(hours=settings.FACE_CAL_FEATURE_TIMEOUT_HOURS)
|
||||
if datetime.now() - feature.start_time > timeout_duration:
|
||||
# 超时处理
|
||||
feature.status = FeatureStatus.FAILED
|
||||
feature.finish_time = datetime.now()
|
||||
session.commit()
|
||||
logger.warning(f"特征计算超时: {feature_id}")
|
||||
return False
|
||||
else:
|
||||
# 没有开始时间,重置状态
|
||||
feature.status = FeatureStatus.NOT_STARTED
|
||||
session.commit()
|
||||
|
||||
# 处理未开始的计算
|
||||
if feature.status == FeatureStatus.NOT_STARTED:
|
||||
# 设置状态为计算中
|
||||
feature.status = FeatureStatus.PROCESSING
|
||||
feature.start_time = datetime.now()
|
||||
session.commit()
|
||||
logger.info(f"开始计算特征: {feature_id}")
|
||||
|
||||
# 构建图片路径
|
||||
if not feature.pic_id:
|
||||
logger.error(f"特征记录缺少图片ID: {feature_id}")
|
||||
feature.status = FeatureStatus.FAILED
|
||||
feature.finish_time = datetime.now()
|
||||
session.commit()
|
||||
return False
|
||||
|
||||
image_path = os.path.join(settings.FACE_REGISTER_IMAGE_RESOURCE_DIR, feature.pic_id)
|
||||
|
||||
# 检查图片文件是否存在
|
||||
if not os.path.exists(image_path):
|
||||
logger.error(f"图片文件不存在: {image_path}")
|
||||
feature.status = FeatureStatus.FAILED
|
||||
feature.finish_time = datetime.now()
|
||||
session.commit()
|
||||
return False
|
||||
|
||||
# 提取人脸特征
|
||||
try:
|
||||
feature_vector = face_algorithm.extract_face_feature(str(image_path))
|
||||
|
||||
if feature_vector is not None:
|
||||
# 转换为二进制数据
|
||||
feature_bytes = feature_vector.tobytes()
|
||||
feature.feature_data = feature_bytes
|
||||
feature.status = FeatureStatus.SUCCESS
|
||||
feature.finish_time = datetime.now()
|
||||
session.commit()
|
||||
logger.info(f"特征计算成功: {feature_id}, 特征向量长度: {len(feature_vector)}")
|
||||
return True
|
||||
else:
|
||||
logger.error(f"特征提取失败: {feature_id}")
|
||||
feature.status = FeatureStatus.FAILED
|
||||
feature.finish_time = datetime.now()
|
||||
session.commit()
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"特征计算过程中出错: {feature_id}, 错误: {str(e)}")
|
||||
feature.status = FeatureStatus.FAILED
|
||||
feature.finish_time = datetime.now()
|
||||
session.commit()
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"处理特征计算时发生异常: {feature_id}, 错误: {str(e)}")
|
||||
return False
|
||||
|
||||
|
||||
def process_pending_features() -> Dict[str, Any]:
|
||||
"""
|
||||
处理所有待处理的人脸特征计算
|
||||
|
||||
返回:
|
||||
处理结果统计
|
||||
"""
|
||||
try:
|
||||
with db_manager.get_session() as session:
|
||||
repository = FaceFeatureRepository(session)
|
||||
|
||||
# 查找需要处理的记录
|
||||
# 条件: feature_type = FACE_MODEL_VERSION 且 status = 0 (未开始)
|
||||
pending_features = repository.get_features_by_type_and_status(
|
||||
feature_type=settings.FACE_MODEL_VERSION,
|
||||
status=FeatureStatus.NOT_STARTED
|
||||
)
|
||||
|
||||
# 查找可能超时的记录 (status = 1 且超时)
|
||||
timeout_features = []
|
||||
processing_features = repository.get_features_by_type_and_status(
|
||||
feature_type=settings.FACE_MODEL_VERSION,
|
||||
status=FeatureStatus.PROCESSING
|
||||
)
|
||||
|
||||
for feature in processing_features:
|
||||
if feature.start_time:
|
||||
timeout_duration = timedelta(hours=settings.FACE_CAL_FEATURE_TIMEOUT_HOURS)
|
||||
if datetime.now() - feature.start_time > timeout_duration:
|
||||
timeout_features.append(feature)
|
||||
|
||||
total_pending = len(pending_features)
|
||||
total_timeout = len(timeout_features)
|
||||
|
||||
logger.info(f"发现待处理特征: {total_pending}个, 超时特征: {total_timeout}个")
|
||||
|
||||
# 处理超时记录
|
||||
timeout_success = 0
|
||||
for feature in timeout_features:
|
||||
feature.status = FeatureStatus.FAILED
|
||||
feature.finish_time = datetime.now()
|
||||
timeout_success += 1
|
||||
|
||||
if timeout_features:
|
||||
session.commit()
|
||||
|
||||
# 处理待处理记录
|
||||
processed_count = 0
|
||||
success_count = 0
|
||||
|
||||
for feature in pending_features:
|
||||
processed_count += 1
|
||||
if process_feature_calculation(feature.id):
|
||||
success_count += 1
|
||||
|
||||
# 每处理10个记录输出一次进度
|
||||
if processed_count % 10 == 0:
|
||||
logger.info(f"处理进度: {processed_count}/{total_pending}")
|
||||
|
||||
return {
|
||||
"total_pending": total_pending,
|
||||
"total_timeout": total_timeout,
|
||||
"processed_count": processed_count,
|
||||
"success_count": success_count,
|
||||
"timeout_handled": timeout_success
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"批量处理特征计算时发生异常: {str(e)}")
|
||||
return {
|
||||
"total_pending": 0,
|
||||
"total_timeout": 0,
|
||||
"processed_count": 0,
|
||||
"success_count": 0,
|
||||
"timeout_handled": 0,
|
||||
"error": str(e)
|
||||
}
|
||||
|
||||
|
||||
@router.post("/start-feature-calculation", summary="开始人脸特征计算")
|
||||
async def start_feature_calculation(background_tasks: BackgroundTasks):
|
||||
"""
|
||||
开始处理人脸特征计算
|
||||
|
||||
此接口会:
|
||||
1. 查找所有feature_type为当前模型版本且status为0的记录
|
||||
2. 将状态改为1,设置开始时间
|
||||
3. 提取人脸特征值
|
||||
4. 对于status为1且超时的记录,标记为失败
|
||||
|
||||
返回处理结果统计
|
||||
"""
|
||||
try:
|
||||
# 在后台任务中处理,避免阻塞请求
|
||||
result = process_pending_features()
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"message": "特征计算处理完成",
|
||||
"data": result
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"启动特征计算失败: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=f"启动特征计算失败: {str(e)}")
|
||||
|
||||
|
||||
@router.get("/feature-calculation-status", summary="获取特征计算状态")
|
||||
async def get_feature_calculation_status():
|
||||
"""
|
||||
获取当前特征计算的状态统计
|
||||
"""
|
||||
try:
|
||||
with db_manager.get_session() as session:
|
||||
repository = FaceFeatureRepository(session)
|
||||
|
||||
# 获取统计信息
|
||||
stats = repository.get_statistics()
|
||||
|
||||
# 获取当前模型版本的特定统计
|
||||
current_model_stats = {
|
||||
"total": repository.count_by_type_and_status(
|
||||
feature_type=settings.FACE_MODEL_VERSION
|
||||
),
|
||||
"not_started": repository.count_by_type_and_status(
|
||||
feature_type=settings.FACE_MODEL_VERSION,
|
||||
status=FeatureStatus.NOT_STARTED
|
||||
),
|
||||
"processing": repository.count_by_type_and_status(
|
||||
feature_type=settings.FACE_MODEL_VERSION,
|
||||
status=FeatureStatus.PROCESSING
|
||||
),
|
||||
"success": repository.count_by_type_and_status(
|
||||
feature_type=settings.FACE_MODEL_VERSION,
|
||||
status=FeatureStatus.SUCCESS
|
||||
),
|
||||
"failed": repository.count_by_type_and_status(
|
||||
feature_type=settings.FACE_MODEL_VERSION,
|
||||
status=FeatureStatus.FAILED
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"data": {
|
||||
"overall_stats": stats,
|
||||
"current_model_stats": current_model_stats,
|
||||
"model_version": settings.FACE_MODEL_VERSION,
|
||||
"timeout_hours": settings.FACE_CAL_FEATURE_TIMEOUT_HOURS
|
||||
}
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取特征计算状态失败: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=f"获取特征计算状态失败: {str(e)}")
|
||||
|
||||
|
||||
@router.post("/calculate-single-feature/{feature_id}", summary="计算单个特征")
|
||||
async def calculate_single_feature(feature_id: int):
|
||||
"""
|
||||
计算单个特征记录的人脸特征
|
||||
|
||||
参数:
|
||||
feature_id: 特征记录ID
|
||||
"""
|
||||
try:
|
||||
success = process_feature_calculation(feature_id)
|
||||
|
||||
if success:
|
||||
return {
|
||||
"success": True,
|
||||
"message": f"特征计算完成: {feature_id}"
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"success": False,
|
||||
"message": f"特征计算失败: {feature_id}"
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"计算单个特征失败: {feature_id}, 错误: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=f"计算单个特征失败: {str(e)}")
|
||||
|
||||
|
||||
# 导出路由器
|
||||
__all__ = ["router"]
|
||||
Reference in New Issue
Block a user