chawin.chen commited on
Commit ·
9a7c81e
1
Parent(s): 2919cc4
fix
Browse files- api_routes.py +32 -7
- face_analyzer.py +3 -3
api_routes.py
CHANGED
|
@@ -1497,7 +1497,7 @@ async def analyze_face(
|
|
| 1497 |
return JSONResponse(
|
| 1498 |
content={
|
| 1499 |
"success": False,
|
| 1500 |
-
"message": "
|
| 1501 |
"face_count": 0,
|
| 1502 |
"faces": [],
|
| 1503 |
}
|
|
@@ -1559,6 +1559,31 @@ async def analyze_face(
|
|
| 1559 |
raise HTTPException(status_code=500, detail=f"分析过程中出现内部错误: {str(e)}")
|
| 1560 |
|
| 1561 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1562 |
@api_router.post("/image_search", response_model=ImageFileList, tags=["图像搜索"])
|
| 1563 |
@log_api_params
|
| 1564 |
async def search_by_image(
|
|
@@ -1741,7 +1766,7 @@ async def list_outputs(
|
|
| 1741 |
None) else ""
|
| 1742 |
nickname_filter = request.nickname.strip() if getattr(request, "nickname",
|
| 1743 |
None) else None
|
| 1744 |
-
|
| 1745 |
# 业务逻辑:如果 search_type 为空,默认只显示非裁剪的人脸图
|
| 1746 |
is_cropped_filter = 0 if not search_type else None
|
| 1747 |
|
|
@@ -1786,7 +1811,7 @@ async def list_outputs(
|
|
| 1786 |
if category not in (
|
| 1787 |
None, "all") and record_category != category:
|
| 1788 |
continue
|
| 1789 |
-
|
| 1790 |
# 向量搜索结果也根据 is_cropped_filter 进行过滤
|
| 1791 |
record_is_cropped = bool(record.get("is_cropped_face")) if record else "_face" in file_path
|
| 1792 |
if is_cropped_filter is not None and record_is_cropped != bool(is_cropped_filter):
|
|
@@ -3626,7 +3651,7 @@ async def compress_image(
|
|
| 3626 |
# 异步执行图片向量化并入库,不阻塞主流程
|
| 3627 |
if CLIP_AVAILABLE:
|
| 3628 |
asyncio.create_task(handle_image_vector_async(compressed_path, compressed_filename))
|
| 3629 |
-
|
| 3630 |
await _record_output_file(
|
| 3631 |
file_path=compressed_path,
|
| 3632 |
nickname=nickname,
|
|
@@ -4599,10 +4624,10 @@ async def face_similarity_verification(
|
|
| 4599 |
h = region.get("h", 0)
|
| 4600 |
x_end = min(source_image.shape[1], x + w)
|
| 4601 |
y_end = min(source_image.shape[0], y + h)
|
| 4602 |
-
|
| 4603 |
if x_end <= x or y_end <= y:
|
| 4604 |
return source_image.copy(), False
|
| 4605 |
-
|
| 4606 |
result_img = source_image.copy()
|
| 4607 |
# 绘制绿色矩形框,厚度根据图片尺寸动态调整
|
| 4608 |
thickness = max(2, int(round(min(source_image.shape[:2]) / 200)))
|
|
@@ -4656,7 +4681,7 @@ async def face_similarity_verification(
|
|
| 4656 |
face_img2 = image2[y2:y2_end, x2:x2_end]
|
| 4657 |
|
| 4658 |
# face_path1 和 face_path2 已经通过 _get_save_path 生成
|
| 4659 |
-
|
| 4660 |
# 直接保存裁剪图,不进行特征点绘制
|
| 4661 |
if save_image_high_quality(face_img1, face_path1, quality=SAVE_QUALITY):
|
| 4662 |
await _record_output_file(
|
|
|
|
| 1497 |
return JSONResponse(
|
| 1498 |
content={
|
| 1499 |
"success": False,
|
| 1500 |
+
"message": "Please upload a clear front-facing photo without any obstructions.",
|
| 1501 |
"face_count": 0,
|
| 1502 |
"faces": [],
|
| 1503 |
}
|
|
|
|
| 1559 |
raise HTTPException(status_code=500, detail=f"分析过程中出现内部错误: {str(e)}")
|
| 1560 |
|
| 1561 |
|
| 1562 |
+
@api_router.post(path="/app/analyze", tags=["App专用"])
|
| 1563 |
+
@log_api_params
|
| 1564 |
+
async def app_analyze_face(
|
| 1565 |
+
request: Request,
|
| 1566 |
+
file: UploadFile = File(None),
|
| 1567 |
+
files: list[UploadFile] = File(None),
|
| 1568 |
+
images: str = Form(None),
|
| 1569 |
+
nickname: str = Form(None, description="操作者昵称"),
|
| 1570 |
+
model: ModelType = Query(
|
| 1571 |
+
ModelType.HYBRID, description="选择使用的模型: howcuteami, deepface 或 hybrid"
|
| 1572 |
+
),
|
| 1573 |
+
):
|
| 1574 |
+
"""
|
| 1575 |
+
App专用人脸分析接口,参数与原 /analyze 保持完全一致并透传。
|
| 1576 |
+
"""
|
| 1577 |
+
return await analyze_face(
|
| 1578 |
+
request=request,
|
| 1579 |
+
file=file,
|
| 1580 |
+
files=files,
|
| 1581 |
+
images=images,
|
| 1582 |
+
nickname=nickname,
|
| 1583 |
+
model=model
|
| 1584 |
+
)
|
| 1585 |
+
|
| 1586 |
+
|
| 1587 |
@api_router.post("/image_search", response_model=ImageFileList, tags=["图像搜索"])
|
| 1588 |
@log_api_params
|
| 1589 |
async def search_by_image(
|
|
|
|
| 1766 |
None) else ""
|
| 1767 |
nickname_filter = request.nickname.strip() if getattr(request, "nickname",
|
| 1768 |
None) else None
|
| 1769 |
+
|
| 1770 |
# 业务逻辑:如果 search_type 为空,默认只显示非裁剪的人脸图
|
| 1771 |
is_cropped_filter = 0 if not search_type else None
|
| 1772 |
|
|
|
|
| 1811 |
if category not in (
|
| 1812 |
None, "all") and record_category != category:
|
| 1813 |
continue
|
| 1814 |
+
|
| 1815 |
# 向量搜索结果也根据 is_cropped_filter 进行过滤
|
| 1816 |
record_is_cropped = bool(record.get("is_cropped_face")) if record else "_face" in file_path
|
| 1817 |
if is_cropped_filter is not None and record_is_cropped != bool(is_cropped_filter):
|
|
|
|
| 3651 |
# 异步执行图片向量化并入库,不阻塞主流程
|
| 3652 |
if CLIP_AVAILABLE:
|
| 3653 |
asyncio.create_task(handle_image_vector_async(compressed_path, compressed_filename))
|
| 3654 |
+
|
| 3655 |
await _record_output_file(
|
| 3656 |
file_path=compressed_path,
|
| 3657 |
nickname=nickname,
|
|
|
|
| 4624 |
h = region.get("h", 0)
|
| 4625 |
x_end = min(source_image.shape[1], x + w)
|
| 4626 |
y_end = min(source_image.shape[0], y + h)
|
| 4627 |
+
|
| 4628 |
if x_end <= x or y_end <= y:
|
| 4629 |
return source_image.copy(), False
|
| 4630 |
+
|
| 4631 |
result_img = source_image.copy()
|
| 4632 |
# 绘制绿色矩形框,厚度根据图片尺寸动态调整
|
| 4633 |
thickness = max(2, int(round(min(source_image.shape[:2]) / 200)))
|
|
|
|
| 4681 |
face_img2 = image2[y2:y2_end, x2:x2_end]
|
| 4682 |
|
| 4683 |
# face_path1 和 face_path2 已经通过 _get_save_path 生成
|
| 4684 |
+
|
| 4685 |
# 直接保存裁剪图,不进行特征点绘制
|
| 4686 |
if save_image_high_quality(face_img1, face_path1, quality=SAVE_QUALITY):
|
| 4687 |
await _record_output_file(
|
face_analyzer.py
CHANGED
|
@@ -817,7 +817,7 @@ class EnhancedFaceAnalyzer:
|
|
| 817 |
:return: 分析结果
|
| 818 |
"""
|
| 819 |
if image is None:
|
| 820 |
-
raise ValueError("
|
| 821 |
|
| 822 |
# 检测人脸
|
| 823 |
face_boxes = self._detect_faces(image)
|
|
@@ -825,7 +825,7 @@ class EnhancedFaceAnalyzer:
|
|
| 825 |
if not face_boxes:
|
| 826 |
return {
|
| 827 |
"success": False,
|
| 828 |
-
"message": "
|
| 829 |
"face_count": 0,
|
| 830 |
"faces": [],
|
| 831 |
"annotated_image": None,
|
|
@@ -834,7 +834,7 @@ class EnhancedFaceAnalyzer:
|
|
| 834 |
|
| 835 |
results = {
|
| 836 |
"success": True,
|
| 837 |
-
"message": f"
|
| 838 |
"face_count": len(face_boxes),
|
| 839 |
"faces": [],
|
| 840 |
"model_used": model_type.value,
|
|
|
|
| 817 |
:return: 分析结果
|
| 818 |
"""
|
| 819 |
if image is None:
|
| 820 |
+
raise ValueError("invalid image input")
|
| 821 |
|
| 822 |
# 检测人脸
|
| 823 |
face_boxes = self._detect_faces(image)
|
|
|
|
| 825 |
if not face_boxes:
|
| 826 |
return {
|
| 827 |
"success": False,
|
| 828 |
+
"message": "Please upload a clear front-facing photo without any obstructions.",
|
| 829 |
"face_count": 0,
|
| 830 |
"faces": [],
|
| 831 |
"annotated_image": None,
|
|
|
|
| 834 |
|
| 835 |
results = {
|
| 836 |
"success": True,
|
| 837 |
+
"message": f"success detected {len(face_boxes)} faces",
|
| 838 |
"face_count": len(face_boxes),
|
| 839 |
"faces": [],
|
| 840 |
"model_used": model_type.value,
|