Skip to content

Commit 5372fbe

Browse files
committed
Refractord backend code
1 parent acadd54 commit 5372fbe

5 files changed

Lines changed: 76 additions & 85 deletions

File tree

backend/app/routes/face_clusters.py

Lines changed: 31 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import logging
22
from binascii import Error as Base64Error
33
import base64
4+
from typing import Annotated
45
import uuid
56
import os
6-
from fastapi import APIRouter, HTTPException, status
7+
from fastapi import APIRouter, HTTPException, Query, status
78
from app.database.face_clusters import (
89
db_get_cluster_by_id,
910
db_update_cluster,
@@ -22,7 +23,7 @@
2223
GetClusterImagesData,
2324
ImageInCluster,
2425
)
25-
from app.schemas.images import AddSingleBase64ImageRequest, AddSingleImageRequest
26+
from app.schemas.images import AddSingleBase64ImageRequest, AddSingleImageRequest, InputType
2627
from app.utils.faceSearch import perform_face_search
2728

2829

@@ -208,35 +209,32 @@ def get_cluster_images(cluster_id: str):
208209
"/face-search",
209210
responses={code: {"model": ErrorResponse} for code in [400, 500]},
210211
)
211-
def face_tagging(payload: AddSingleImageRequest):
212-
image_path = payload.path
213-
if not os.path.isfile(image_path):
214-
raise HTTPException(
215-
status_code=status.HTTP_400_BAD_REQUEST,
216-
detail=ErrorResponse(
217-
success=False,
218-
error="Invalid file path",
219-
message="The provided path is not a valid file",
220-
).model_dump(),
221-
)
222-
return perform_face_search(image_path)
223-
212+
def face_tagging(payload: AddSingleImageRequest | AddSingleBase64ImageRequest, input_type: Annotated[InputType, Query(description="Choose input type: 'path' or 'base64'")] = InputType.path):
213+
image_path = None
224214

225-
@router.post("/face-search-base64")
226-
def face_search_base64(payload: AddSingleBase64ImageRequest):
227-
base64_data = payload.base64_data
228-
if not base64_data:
229-
raise HTTPException(
230-
status_code=status.HTTP_400_BAD_REQUEST,
231-
detail=ErrorResponse(
232-
success=False,
233-
error="No base64 data",
234-
message="Base64 image data is required.",
235-
).model_dump(),
236-
)
215+
if input_type == InputType.path:
216+
if not os.path.isfile(payload.path):
217+
raise HTTPException(
218+
status_code=status.HTTP_400_BAD_REQUEST,
219+
detail=ErrorResponse(
220+
success=False,
221+
error="Invalid file path",
222+
message="The provided path is not a valid file",
223+
).model_dump(),
224+
)
225+
image_path = payload.path
237226

238-
image_path = None
239-
try:
227+
elif input_type == InputType.base64:
228+
base64_data = payload.base64_data
229+
if not base64_data:
230+
raise HTTPException(
231+
status_code=status.HTTP_400_BAD_REQUEST,
232+
detail=ErrorResponse(
233+
success=False,
234+
error="No base64 data",
235+
message="Base64 image data is required.",
236+
).model_dump(),
237+
)
240238
try:
241239
image_bytes = base64.b64decode(base64_data.split(",")[-1])
242240
except (Base64Error, ValueError):
@@ -251,14 +249,11 @@ def face_search_base64(payload: AddSingleBase64ImageRequest):
251249
image_id = str(uuid.uuid4())[:8]
252250
temp_dir = "temp_uploads"
253251
os.makedirs(temp_dir, exist_ok=True)
254-
image_path = os.path.join(temp_dir, f"{image_id}.jpeg")
252+
local_image_path = os.path.join(temp_dir, f"{image_id}.jpeg")
255253

256-
with open(image_path, "wb") as f:
254+
with open(local_image_path, "wb") as f:
257255
f.write(image_bytes)
258256

259-
result = perform_face_search(image_path)
260-
return result
257+
image_path = local_image_path
261258

262-
finally:
263-
if image_path and os.path.exists(image_path):
264-
os.remove(image_path)
259+
return perform_face_search(image_path)

backend/app/schemas/images.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1+
from enum import Enum
12
from pydantic import BaseModel
23
from typing import Optional, List, Union
34

45

6+
class InputType(str, Enum):
7+
path = "path"
8+
base64 = "base64"
9+
10+
511
# Request Model
612
class AddSingleImageRequest(BaseModel):
713
path: str

docs/backend/backend_python/openapi.json

Lines changed: 36 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,15 +1042,36 @@
10421042
],
10431043
"summary": "Face Tagging",
10441044
"operationId": "face_tagging_face_clusters_face_search_post",
1045+
"parameters": [
1046+
{
1047+
"name": "input_type",
1048+
"in": "query",
1049+
"required": false,
1050+
"schema": {
1051+
"$ref": "#/components/schemas/InputType",
1052+
"description": "Choose input type: 'path' or 'base64'",
1053+
"default": "path"
1054+
},
1055+
"description": "Choose input type: 'path' or 'base64'"
1056+
}
1057+
],
10451058
"requestBody": {
1059+
"required": true,
10461060
"content": {
10471061
"application/json": {
10481062
"schema": {
1049-
"$ref": "#/components/schemas/AddSingleImageRequest"
1063+
"anyOf": [
1064+
{
1065+
"$ref": "#/components/schemas/AddSingleImageRequest"
1066+
},
1067+
{
1068+
"$ref": "#/components/schemas/AddSingleBase64ImageRequest"
1069+
}
1070+
],
1071+
"title": "Payload"
10501072
}
10511073
}
1052-
},
1053-
"required": true
1074+
}
10541075
},
10551076
"responses": {
10561077
"200": {
@@ -1062,63 +1083,24 @@
10621083
}
10631084
},
10641085
"400": {
1065-
"description": "Bad Request",
10661086
"content": {
10671087
"application/json": {
10681088
"schema": {
10691089
"$ref": "#/components/schemas/app__schemas__face_clusters__ErrorResponse"
10701090
}
10711091
}
1072-
}
1092+
},
1093+
"description": "Bad Request"
10731094
},
10741095
"500": {
1075-
"description": "Internal Server Error",
10761096
"content": {
10771097
"application/json": {
10781098
"schema": {
10791099
"$ref": "#/components/schemas/app__schemas__face_clusters__ErrorResponse"
10801100
}
10811101
}
1082-
}
1083-
},
1084-
"422": {
1085-
"description": "Validation Error",
1086-
"content": {
1087-
"application/json": {
1088-
"schema": {
1089-
"$ref": "#/components/schemas/HTTPValidationError"
1090-
}
1091-
}
1092-
}
1093-
}
1094-
}
1095-
}
1096-
},
1097-
"/face-clusters/face-search-base64": {
1098-
"post": {
1099-
"tags": [
1100-
"Face Clusters"
1101-
],
1102-
"summary": "Face Search Base64",
1103-
"operationId": "face_search_base64_face_clusters_face_search_base64_post",
1104-
"requestBody": {
1105-
"content": {
1106-
"application/json": {
1107-
"schema": {
1108-
"$ref": "#/components/schemas/AddSingleBase64ImageRequest"
1109-
}
1110-
}
1111-
},
1112-
"required": true
1113-
},
1114-
"responses": {
1115-
"200": {
1116-
"description": "Successful Response",
1117-
"content": {
1118-
"application/json": {
1119-
"schema": {}
1120-
}
1121-
}
1102+
},
1103+
"description": "Internal Server Error"
11221104
},
11231105
"422": {
11241106
"description": "Validation Error",
@@ -2110,6 +2092,14 @@
21102092
"title": "ImageInCluster",
21112093
"description": "Represents an image that contains faces from a specific cluster."
21122094
},
2095+
"InputType": {
2096+
"type": "string",
2097+
"enum": [
2098+
"path",
2099+
"base64"
2100+
],
2101+
"title": "InputType"
2102+
},
21132103
"MetadataModel": {
21142104
"properties": {
21152105
"name": {

frontend/src/api/apiEndpoints.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ export const imagesEndpoints = {
44

55
export const faceClustersEndpoints = {
66
getAllClusters: '/face-clusters/',
7-
searchForFaces: '/face-clusters/face-search',
8-
searchForFacesBase64: '/face-clusters/face-search-base64',
7+
searchForFaces: '/face-clusters/face-search?input_type=path',
8+
searchForFacesBase64: '/face-clusters/face-search?input_type=base64',
99
renameCluster: (clusterId: string) => `/face-clusters/${clusterId}`,
1010
getClusterImages: (clusterId: string) => `/face-clusters/${clusterId}/images`,
1111
};

frontend/src/components/Navigation/Navbar/Navbar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export function Navbar() {
3535
<div className="relative mr-2 ml-2">
3636
<img
3737
src={
38-
queryImage?.includes('base64')
38+
queryImage?.startsWith('data:')
3939
? queryImage
4040
: convertFileSrc(queryImage)
4141
}

0 commit comments

Comments
 (0)