from config.env import ComprefaceConfig from compreface import CompreFace from compreface.service import RecognitionService from compreface.collections import FaceCollection from compreface.common.typed_dict import AllOptionsDict, check_fields_by_name import httpx import json import os RECOGNITION_ROOT_API: str = '/api/v1/recognition' RECOGNIZE_API: str = RECOGNITION_ROOT_API + '/recognize' RECOGNIZE_CRUD_API: str = RECOGNITION_ROOT_API + '/faces' SUBJECTS_CRUD_API: str = RECOGNITION_ROOT_API + '/subjects' DETECTION_API: str = '/api/v1/detection/detect' VERIFICATION_API: str = '/api/v1/verification' compre_face: CompreFace = CompreFace(ComprefaceConfig.COMPREFACE_BASE_URL, ComprefaceConfig.COMPERFACE_BASE_PORT) # recognition: RecognitionService = compre_face.init_face_recognition(ComprefaceConfig.COMPREFACE_API_KEY) # face_collection: FaceCollection = recognition.get_face_collection() class ComprefaceUtil: api_key: str = ComprefaceConfig.COMPREFACE_API_KEY api_key_detection: str = ComprefaceConfig.COMPREFACE_API_KEY_DETECTION @classmethod async def send_request(cls, method: str, url: str, headers: dict, body: str | None=None, data=None, files=None ,json=True): async with httpx.AsyncClient(verify=False) as client: response = await client.request( method, url, headers=headers, content=body, data=data, files=files, timeout=5 # timeout 单位秒 ) if response.status_code in (301, 302, 303, 307, 308): location = response.headers.get("Location") # 可能需要处理成 GET 请求或保留原方法 response = await client.get(location, headers=headers) response.raise_for_status() if json: return response.json() return response # 添加人脸到指定分组下, subject 为分组名称 @classmethod async def face_addition(cls, image: str = '' or bytes, subject: str = '') -> dict: client_url: str = RECOGNIZE_CRUD_API url: str = ComprefaceConfig.COMPREFACE_BASE_URL + ':' + ComprefaceConfig.COMPERFACE_BASE_PORT + client_url + '?subject=' + subject # Validation loop and adding fields to the url. m = await multipart_constructor(image) result = await cls.send_request("post" , url , headers={'x-api-key': cls.api_key} , files=m) return result # 人脸识别 @classmethod async def face_recognition(cls, image: str = '' or bytes, options: AllOptionsDict = {}) -> dict: client_url: str = RECOGNIZE_API url: str = ComprefaceConfig.COMPREFACE_BASE_URL + ':' + ComprefaceConfig.COMPERFACE_BASE_PORT + client_url+"?" # url: str = "http://10.0.0.202:8000/api/v1/recognition/recognize?face_plugins=landmarks&face_plugins=gender&face_plugins=age&face_plugins=pose" for key in options.keys(): # Checks fields with necessary rules. # key - key field by options. check_fields_by_name(key, options[key]) url += '&' + key + "=" + str(options[key]) m = await multipart_constructor(image) result = await cls.send_request("post" , url , headers={'x-api-key': cls.api_key} , files=m) return result # 人脸检测 @classmethod async def face_detection(cls, image: str = '' or bytes, options: AllOptionsDict = {}) -> dict: client_url: str = DETECTION_API url: str = ComprefaceConfig.COMPREFACE_BASE_URL + ':' + ComprefaceConfig.COMPERFACE_BASE_PORT + client_url+"?" for key in options.keys(): # Checks fields with necessary rules. # key - key field by options. # check_fields_by_name(key, options[key]) url += '&' + key + "=" + str(options[key]) m = await multipart_constructor(image) result = await cls.send_request("post" , url , headers={'x-api-key': cls.api_key_detection} , files=m) return result # 获取所有subjects @classmethod async def get_all_subjects(cls) -> dict: """获取所有已注册的人脸subjects Returns: dict: 包含subjects列表的字典 """ client_url: str = SUBJECTS_CRUD_API url: str = ComprefaceConfig.COMPREFACE_BASE_URL + ':' + ComprefaceConfig.COMPERFACE_BASE_PORT + client_url result = await cls.send_request("get" , url , headers={'x-api-key': cls.api_key}) return result # 删除指定的subject @classmethod async def delete_subject(cls, subject: str) -> dict: """删除指定的subject及其所有人脸数据 Args: subject (str): 要删除的subject名称 Returns: dict: 删除操作的结果 """ client_url: str = SUBJECTS_CRUD_API + '/' + subject url: str = ComprefaceConfig.COMPREFACE_BASE_URL + ':' + ComprefaceConfig.COMPERFACE_BASE_PORT + client_url result = await cls.send_request("delete" , url , headers={'x-api-key': cls.api_key}) return result async def get_file(image: str = '' or bytes): if not os.path.isfile(image): if type(image) != bytes: async with httpx.AsyncClient() as client: response = await client.get(image, timeout=5) file = response.content else: file = image file = ('image.jpg', file) else: name_img: str = os.path.basename(image) file = (name_img, open(image, 'rb')) return file async def multipart_constructor(image: str = '' or bytes): return {"file": await get_file(image)} # def multipart_constructor_with_two_images(source_image: str = '' or bytes, target_image: str = '' or bytes): # return MultipartEncoder( # fields={'source_image': get_file( # source_image), 'target_image': get_file(target_image)} # )