From 80f5e50c3177e6f99860fcd9e2137c01f89df2cd Mon Sep 17 00:00:00 2001 From: jwkim Date: Fri, 2 Jan 2026 09:45:29 +0900 Subject: [PATCH] =?UTF-8?q?edit=20:=20=EC=95=88=EA=B2=BD=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20=EA=B2=80=EC=83=89=EC=8B=9C=20temp=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=20=EC=82=AC=EC=9A=A9=20=EC=95=88=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../faiss_functions.py | 9 ++- .../faiss_similarity_search.py | 67 ++++++++++++++++++- .../FEATURE_VECTOR_SIMILARITY_FAISS/utils.py | 25 +++++++ main_rest/app/routes/services.py | 9 ++- make_vector_files.py | 4 +- vector_rest/app/routes/services.py | 4 +- 6 files changed, 107 insertions(+), 11 deletions(-) diff --git a/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/faiss_functions.py b/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/faiss_functions.py index 6b36568..5421bc1 100644 --- a/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/faiss_functions.py +++ b/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/faiss_functions.py @@ -126,8 +126,13 @@ def get_clip_info(model, query_image_path, item_info, top_k=4): # save_txt_dir=VECTOR_IMG_LIST_PATH, # item_info=item_info, # index_type=model.value[1].index_type) - - inference_times, result_img_paths, result_percents = vector_model.query_faiss(query_image_path, top_k=top_k) + + if os.path.exists(query_image_path): + inference_times, result_img_paths, result_percents = vector_model.query_faiss(query_image_path, top_k=top_k) + elif query_image_path is None or query_image_path == "": + raise ValueError("query_image is None or empty.") + else: + inference_times, result_img_paths, result_percents = vector_model.query_faiss_image_data(query_image_path, top_k=top_k) for i in range(len(result_percents)): if float(result_percents[i]) < 0.0: diff --git a/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/faiss_similarity_search.py b/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/faiss_similarity_search.py index dfabde0..06b85fe 100644 --- a/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/faiss_similarity_search.py +++ b/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/faiss_similarity_search.py @@ -53,7 +53,7 @@ from custom_apps.FEATURE_VECTOR_SIMILARITY_FAISS import feature_extraction_model # 사용할 이미지 임베딩 모델 클래스 추가 from custom_apps.FEATURE_VECTOR_SIMILARITY_FAISS.fem_openaiclipvit import FEOpenAIClipViT from custom_apps.FEATURE_VECTOR_SIMILARITY_FAISS.const import * - +from custom_apps.FEATURE_VECTOR_SIMILARITY_FAISS.utils import get_base64_bytes """ Definition @@ -218,6 +218,24 @@ class VectorSimilarity: image_data_np = Image.open(image_file).convert('RGB') feature_vectors = self.fem_model.image_embedding(image_data_np) return feature_vectors + + def image_embedding_from_b64data(self, b64_data=None): + """ + 이미지 데이터(base64)에서 특징 벡터 추출 + :param image_data_np: 이미지 데이터(numpy) + :return: 특징 벡터 or None + """ + import io + feature_vectors = None + + if b64_data is None: + log.error(f'invalid data[{b64_data}]') + return feature_vectors + + image = Image.open(io.BytesIO(b64_data)).convert("RGB") + + feature_vectors = self.fem_model.image_embedding(image) + return feature_vectors def image_embedding_from_data(self, image_data_np=None): """ @@ -371,6 +389,53 @@ class VectorSimilarity: result_percents.append(f"{((1 - dist)*100):.2f}") return inference_times, result_img_paths, result_percents + + def query_faiss_image_data(self, query_image_data=None, top_k=4): + + if os.path.exists(self.txt_file_path): + with open(self.txt_file_path, 'r') as f: + image_paths = [line.strip() for line in f.readlines()] + else: + logging.error("Image path list TXT file not found.") + image_paths = [] + + b64_data = get_base64_bytes(query_image_data) + + start_vector_time = datetime.now() + index = self.load_index(self.index_file_path) + query_vector = self.image_embedding_from_b64data(b64_data) + end_vector_time = datetime.now() + + diff_vector_time = self.time_diff(start_vector_time,end_vector_time) + + if self.index_type == INDEX_TYPE_COSINE: + faiss.normalize_L2(query_vector) + + start_search_time = datetime.now() + distances, indices = index.search(query_vector, top_k) + end_search_time = datetime.now() + + diff_search_time = self.time_diff(start_search_time,end_search_time) + diff_total_time = self.time_diff(start_vector_time,end_search_time) + inference_times = f"Total time - {diff_total_time}, vector_time - {diff_vector_time}, search_time - {diff_search_time}" + + result_img_paths = [] + result_percents = [] + + # 결과 + # for i in range(top_k): + # print(f"{i + 1}: {image_paths[indices[0][i]]}, Distance: {distances[0][i]}") + for idx, dist in zip(indices[0], distances[0]): + log.debug(f"{idx} (거리: {dist:.4f})") + + result_img_paths.append(image_paths[idx]) + + if self.index_type == INDEX_TYPE_COSINE: + result_percents.append(f"{dist*100:.2f}") + else: + result_percents.append(f"{((1 - dist)*100):.2f}") + + return inference_times, result_img_paths, result_percents # def test(): # """ diff --git a/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/utils.py b/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/utils.py index 2301c9a..58e3eb8 100644 --- a/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/utils.py +++ b/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/utils.py @@ -1,4 +1,5 @@ import os +import base64 from pathlib import Path from custom_apps.FEATURE_VECTOR_SIMILARITY_FAISS.const import * @@ -43,5 +44,29 @@ def file_name_to_parts(file_path): return result + +def get_base64_bytes(data: str) -> bytes: + """ + 문자열을 검사하여 유효한 Base64라면 디코딩된 bytes 데이터를 반환하고, + 그렇지 않으면 ValueError 예외를 발생시킵니다. + """ + + try: + # 1. 입력 문자열 전처리 (공백 제거 등) + stripped_data = data.strip() + + # 2. bytes로 인코딩 (b64decode는 bytes-like object를 필요로 함) + encoded_input = stripped_data.encode('ascii') + + # 3. Base64 디코딩 수행 (validate=True로 엄격한 검사) + # 성공 시 b'...' 형태의 바이트 데이터가 생성됨 + decoded_bytes = base64.b64decode(encoded_input, validate=True) + + return decoded_bytes + + except Exception as e: + # Base64 형식이 아니거나 패딩 오류 등 발생 시 + raise ValueError(f"유효한 Base64 데이터가 아닙니다. 변환 불가: {e}") + if __name__ == '__main__': print(file_name_to_parts(os.path.join(FAISS_VECTOR_PATH,"Glass_001",ImageDepths.parts,"Glass_001_Temple_L.png"))) \ No newline at end of file diff --git a/main_rest/app/routes/services.py b/main_rest/app/routes/services.py index 90e41a0..0fa3881 100644 --- a/main_rest/app/routes/services.py +++ b/main_rest/app/routes/services.py @@ -507,9 +507,12 @@ async def vactor_vit_input_glasses_img_data(request: Request, request_body_info: raise Exception(f"indexType is invalid (current value = {request_body_info.indexType})") query_image_data = request_body_info.inputImage - query_image_path = os.path.join(TEMP_FOLDER, f'input_{D.date_file_name()}_query.png') - os.makedirs(TEMP_FOLDER, exist_ok=True) - save_base64_as_image_file(request_body_info.inputImage ,query_image_path) + + # query_image_path = os.path.join(TEMP_FOLDER, f'input_{D.date_file_name()}_query.png') + # os.makedirs(TEMP_FOLDER, exist_ok=True) + # save_base64_as_image_file(request_body_info.inputImage ,query_image_path) + + query_image_path = query_image_data vector_request_data = {'query_image_path' : query_image_path, 'index_type' : request_body_info.indexType, diff --git a/make_vector_files.py b/make_vector_files.py index 0632d5f..6f5175a 100644 --- a/make_vector_files.py +++ b/make_vector_files.py @@ -117,6 +117,4 @@ if __name__ == '__main__': } for item_key, item_value in pure_data_dict.items(): - make_vector_files(item_info=item_value, index_type=VM.VitIndexType.l2, model_type=VM.VitModelType.b32) - - # time.sleep(5) # huggingface api 요청 제한 회피 위해 대기 TODO(jwkim) huggingface 로그인은 한번만 진행하게 변경 \ No newline at end of file + make_vector_files(item_info=item_value, index_type=VM.VitIndexType.l2, model_type=VM.VitModelType.b32) \ No newline at end of file diff --git a/vector_rest/app/routes/services.py b/vector_rest/app/routes/services.py index 2a15c2f..5d761a9 100644 --- a/vector_rest/app/routes/services.py +++ b/vector_rest/app/routes/services.py @@ -84,8 +84,8 @@ async def vactor_vit(request: Request, request_body_info: M.VectorSearchVitReq): """ response = M.VectorSearchVitRes() try: - if not os.path.exists(request_body_info.query_image_path): - raise FileNotFoundError(f"File {request_body_info.query_image_path} does not exist.") + # if not os.path.exists(request_body_info.query_image_path): + # raise FileNotFoundError(f"File {request_body_info.query_image_path} does not exist.") model = get_models(index_type=request_body_info.index_type, model_type=request_body_info.model_type)