From 8b7ad2e973ebbcfb37e9e0ee68228f45799ff6a7 Mon Sep 17 00:00:00 2001 From: jwkim Date: Tue, 2 Dec 2025 14:15:49 +0900 Subject: [PATCH] =?UTF-8?q?edit=20:=20=EB=B2=A1=ED=84=B0=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1=20=EA=B4=80=EB=A0=A8=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- .../__init__.py | 0 .../FEATURE_VECTOR_SIMILARITY_FAISS/const.py | 27 ++-- .../faiss_functions.py | 36 +++--- .../faiss_similarity_search.py | 36 +++--- .../feature_extraction_model.py | 0 .../fem_openaiclipvit.py | 0 .../report_utils.py | 0 .../FEATURE_VECTOR_SIMILARITY_FAISS/utils.py | 10 +- custom_logger/custom_log.py | 2 +- main_rest/app/models.py | 7 +- main_rest/app/routes/services.py | 17 ++- make_vector_files.py | 117 ++++++++++++++++++ vector_rest/app/routes/dev.py | 2 +- vector_rest/app/routes/services.py | 3 +- 15 files changed, 188 insertions(+), 71 deletions(-) mode change 100755 => 100644 custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/__init__.py mode change 100755 => 100644 custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/const.py mode change 100755 => 100644 custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/faiss_functions.py mode change 100755 => 100644 custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/faiss_similarity_search.py mode change 100755 => 100644 custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/feature_extraction_model.py mode change 100755 => 100644 custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/fem_openaiclipvit.py mode change 100755 => 100644 custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/report_utils.py create mode 100644 make_vector_files.py diff --git a/README.md b/README.md index 263a9e6..224e55e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# FM_TEST_REST_SERVER +# GLASSES_AI_SERVER RESTful API Server diff --git a/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/__init__.py b/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/__init__.py old mode 100755 new mode 100644 diff --git a/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/const.py b/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/const.py old mode 100755 new mode 100644 index f7356fb..5d687e6 --- a/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/const.py +++ b/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/const.py @@ -18,24 +18,23 @@ ViTL14_336 = "clip-vit-large-patch14-336" #download/save path PRETRAINED_MODEL_PATH = "./datas" -FAISS_VECTOR_PATH = "./datas/Eyewear_001~500_ComponentsCapture_20251121" -VECTOR_IMG_LIST_PATH = "./datas/Eyewear_001~500_ComponentsCapture_20251121" - -INDEX_IMAGES_PATH = "./datas/eyewear_all" +FAISS_VECTOR_PATH = "./datas" +IMG_LIST_PATH = "../Eyewear_data" +# INDEX_IMAGES_PATH = "./datas/eyewear_all" class VectorSearchItem: glass = "glass" - bridge = "Bridge" - hinge = "Hinges" - lens = "Lens" - nosepad = "Nose pad" - other = "other" - padarm = "Padarm" - rim = "Rim" - rivet = "Rivet" - soltex = "Soltex" + tips = "Tips" temple = "Temple" - templetip = "Temple tip" + rim = "Rim" + rim2 = "Rim2" + noesPad = "Nose pad" + noseArm = "Nose arm" + lens = "Lens" + endPiece = "End piece" + hinges = "Hinges" + screw = "Screw" + bridge = "Bridge" class ImageDepths: parts = "Parts" diff --git a/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/faiss_functions.py b/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/faiss_functions.py old mode 100755 new mode 100644 index b99f7d1..f29f906 --- a/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/faiss_functions.py +++ b/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/faiss_functions.py @@ -104,34 +104,28 @@ def get_clip_info(model, query_image_path, item_info, top_k=4): """ 이미지 유사도 검색 """ - index_file_path = os.path.join(VECTOR_IMG_LIST_PATH,f'{model.name}_{os.path.basename(model.value[1].trained_model)}_{model.value[1].index_type}_{item_info}_{DEFAULT_INDEX_NAME_SUFFIX}') - txt_file_path = os.path.join(VECTOR_IMG_LIST_PATH,f'{model.name}_{os.path.basename(model.value[1].trained_model)}_{model.value[1].index_type}_{item_info}.txt') + index_file_path = os.path.join(FAISS_VECTOR_PATH,f'{model.name}_{os.path.basename(model.value[1].trained_model)}_{model.value[1].index_type}_{item_info}_{DEFAULT_INDEX_NAME_SUFFIX}') + txt_file_path = os.path.join(FAISS_VECTOR_PATH,f'{model.name}_{os.path.basename(model.value[1].trained_model)}_{model.value[1].index_type}_{item_info}.txt') + + if not os.path.exists(index_file_path) or not os.path.exists(txt_file_path): + raise FileNotFoundError(f"Index file {index_file_path} or txt file {txt_file_path} does not exist.") + vector_model = VectorSimilarity(model_info=model, index_file_path=index_file_path, txt_file_path=txt_file_path) - image_lists = [] - if not os.path.exists(txt_file_path): - if item_info == VectorSearchItem.glass: - image_lists = find_glass_folder_images(VECTOR_IMG_LIST_PATH) - else: - image_lists = find_parts_folder_images(VECTOR_IMG_LIST_PATH, item_info) - - if image_lists: - with open(txt_file_path, 'w') as f: - for img_path in image_lists: - f.write(f"{img_path}\n") - else: - with open(txt_file_path, 'r') as f: - image_lists = [line.strip() for line in f.readlines()] + # image_lists = [] + + # with open(txt_file_path, 'r') as f: + # image_lists = [line.strip() for line in f.readlines()] # vector_model.create_feature_extraction_model(FEMUsageInfo.openaiclipvit) - vector_model.save_index_from_files(images_path_lists=image_lists, - save_index_dir=FAISS_VECTOR_PATH, - save_txt_dir=VECTOR_IMG_LIST_PATH, - item_info=item_info, - index_type=model.value[1].index_type) + # vector_model.save_index_from_files(images_path_lists=image_lists, + # save_index_dir=FAISS_VECTOR_PATH, + # 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) diff --git a/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/faiss_similarity_search.py b/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/faiss_similarity_search.py old mode 100755 new mode 100644 index 37b324a..dfabde0 --- a/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/faiss_similarity_search.py +++ b/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/faiss_similarity_search.py @@ -372,33 +372,33 @@ class VectorSimilarity: return inference_times, result_img_paths, result_percents -def test(): - """ - module test function - """ - log.info('\nModule: faiss_similarity_search.py') +# def test(): +# """ +# module test function +# """ +# log.info('\nModule: faiss_similarity_search.py') - # index_file_path = f'{FILE_BASE_PATH}openaiclipvit_clip-vit-base-patch32_index.faiss' - model = FEMUsageInfo.openaiclip_vit_l14_cos - index_file_path = os.path.join(VECTOR_IMG_LIST_PATH,f'{model.name}_{os.path.basename(model.value[1].trained_model)}_{model.value[1].index_type}_{DEFAULT_INDEX_NAME_SUFFIX}') +# # index_file_path = f'{FILE_BASE_PATH}openaiclipvit_clip-vit-base-patch32_index.faiss' +# model = FEMUsageInfo.openaiclip_vit_l14_cos +# index_file_path = os.path.join(VECTOR_IMG_LIST_PATH,f'{model.name}_{os.path.basename(model.value[1].trained_model)}_{model.value[1].index_type}_{DEFAULT_INDEX_NAME_SUFFIX}') - cm = VectorSimilarity(model_info=model, - index_file_path=index_file_path, - txt_file_path=os.path.join(VECTOR_IMG_LIST_PATH,f'{model.name}_{os.path.basename(model.value[1].trained_model)}_{model.value[1].index_type}.txt')) +# cm = VectorSimilarity(model_info=model, +# index_file_path=index_file_path, +# txt_file_path=os.path.join(VECTOR_IMG_LIST_PATH,f'{model.name}_{os.path.basename(model.value[1].trained_model)}_{model.value[1].index_type}.txt')) - # cm.create_feature_extraction_model(FEMUsageInfo.openaiclipvit) +# # cm.create_feature_extraction_model(FEMUsageInfo.openaiclipvit) - cm.save_index_from_files(images_path_lists=INDEX_IMAGES_PATH, - save_index_dir=FAISS_VECTOR_PATH, - save_txt_dir=VECTOR_IMG_LIST_PATH, - index_type=model.value[1].index_type) +# cm.save_index_from_files(images_path_lists=INDEX_IMAGES_PATH, +# save_index_dir=FAISS_VECTOR_PATH, +# save_txt_dir=VECTOR_IMG_LIST_PATH, +# index_type=model.value[1].index_type) - cm.query_faiss(os.path.join(INDEX_IMAGES_PATH,"img1.png")) +# cm.query_faiss(os.path.join(INDEX_IMAGES_PATH,"img1.png")) if __name__ == '__main__': """ test module """ - test() + # test() diff --git a/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/feature_extraction_model.py b/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/feature_extraction_model.py old mode 100755 new mode 100644 diff --git a/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/fem_openaiclipvit.py b/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/fem_openaiclipvit.py old mode 100755 new mode 100644 diff --git a/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/report_utils.py b/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/report_utils.py old mode 100755 new mode 100644 diff --git a/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/utils.py b/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/utils.py index 7c2dca8..6904d53 100644 --- a/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/utils.py +++ b/custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/utils.py @@ -21,6 +21,12 @@ def search_glass_parts(image_path_list): return result def file_name_to_parts(file_path): + """ + 파일경로로 파츠이름 파싱 + + :param file_path: 파일경로 + :return: 파츠이름 + """ filename, ext = os.path.splitext(os.path.basename(file_path)) name_list = filename.split('_') @@ -28,4 +34,6 @@ def file_name_to_parts(file_path): result = name_list[2:][0] return result - \ No newline at end of file + +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/custom_logger/custom_log.py b/custom_logger/custom_log.py index abf1718..25b225d 100644 --- a/custom_logger/custom_log.py +++ b/custom_logger/custom_log.py @@ -2,7 +2,7 @@ """ @file : custom_log.py @author: hsj100 -@license: DAOOLDNS +@license: A2TEC @brief: @section Modify History - 2024-05-08 오후 2:33 hsj100 base diff --git a/main_rest/app/models.py b/main_rest/app/models.py index ad1b7fe..e29d4e0 100644 --- a/main_rest/app/models.py +++ b/main_rest/app/models.py @@ -583,11 +583,6 @@ class VitModelType: l14_336 = "l14_336" -class PartsType(str, Enum): - bridge = VectorSearchItem.bridge - hinge = VectorSearchItem.hinge - - class ImageGenerateReq(BaseModel): """ ### [Request] image generate request @@ -663,7 +658,7 @@ class VectorGlassesImageResult(BaseModel): class VectorPartsImageResult(BaseModel): - image : str = Field("", description='이미지 데이터', example='') + image : str | None = Field("", description='이미지 데이터', example='') percents: float = Field(0.0, description='percents 값', example='') imageInfo : str = Field("", description='원본이미지 이름', example='') #=============================================================================== diff --git a/main_rest/app/routes/services.py b/main_rest/app/routes/services.py index 3ae581d..d32c378 100644 --- a/main_rest/app/routes/services.py +++ b/main_rest/app/routes/services.py @@ -446,7 +446,7 @@ async def image_generator(request: Request, request_body_info: M.ImageGenerateRe full_prompt = f"{request_body_info.prefix}, {request_body_info.prompt}" if request_body_info.prefix else f"{request_body_info.prompt}" - temp_image_path = gemini_image(full_prompt) #TODO(jwkim) imagen3 으로 변경예정 + temp_image_path = gemini_image(full_prompt) if os.path.exists(temp_image_path): image_data = image_to_base64_string(temp_image_path) @@ -483,7 +483,7 @@ async def vactor_vit_input_glasses_img_data(request: Request, request_body_info: > 입력이미지(inputImage)는 base64로 변환된 데이터 입력 ### Output - > - 결과(vectorResult)는 base64로 변환된 데이터(image), 유사도(percents)가 쌍으로 나오며, 요청한 searchNum 갯수에 맞춰서 결과가 나옴 + > - 결과(vectorResult)는 base64로 변환된 데이터(image), 유사도(percents), 파츠정보(parts)가 쌍으로 나오며, 요청한 searchNum 갯수에 맞춰서 결과가 나옴 > - queryImage는 Input시 입력한 inputImage 이미지 데이터 ### Options @@ -534,7 +534,9 @@ async def vactor_vit_input_glasses_img_data(request: Request, request_body_info: vector_image_results = [] for img, percents, parts in zip(result_image_paths, result_percents, result_parts): - b64_data = image_to_base64_string(img) + b64_data = None + if os.path.exists(img): + b64_data = image_to_base64_string(img) float_percent = float(percents) info = M.VectorGlassesImageResult(image=b64_data, percents=float_percent, imageInfo=os.path.split(img)[-1], parts=parts) @@ -568,7 +570,8 @@ async def vactor_vit_input_parts_img_data(request: Request, request_body_info: M > 입력된 이미지로 vector 검색 그후 결과 이미지데이터 return ### Input - > 입력이미지(inputImage)는 파츠이미지 이름 (확장자 포함) + > 입력이미지(inputImage)는 파츠 이미지파일 이름 (확장자 포함) + > ⚠️ /vectorImageSearch/vit/inputImage/data/glasses API response인 parts 값중 하나를 선택 ### Output > - 결과(vectorResult)는 base64로 변환된 데이터(image), 유사도(percents)가 쌍으로 나오며, 요청한 searchNum 갯수에 맞춰서 결과가 나옴 @@ -592,7 +595,7 @@ async def vactor_vit_input_parts_img_data(request: Request, request_body_info: M raise Exception(f"indexType is invalid (current value = {request_body_info.indexType})") glass_name = f"{request_body_info.inputImage.split('_')[0]}_{request_body_info.inputImage.split('_')[1]}" - query_image_path = os.path.join(VECTOR_IMG_LIST_PATH, glass_name, ImageDepths.parts, request_body_info.inputImage) + query_image_path = os.path.join(IMG_LIST_PATH, glass_name, ImageDepths.parts, request_body_info.inputImage) query_image_data = image_to_base64_string(query_image_path) vector_request_data = {'query_image_path' : query_image_path, @@ -617,7 +620,9 @@ async def vactor_vit_input_parts_img_data(request: Request, request_body_info: M vector_image_results = [] for img, percents in zip(result_image_paths, result_percents): - b64_data = image_to_base64_string(img) + b64_data = None + if os.path.exists(img): + b64_data = image_to_base64_string(img) float_percent = float(percents) info = M.VectorPartsImageResult(image=b64_data, percents=float_percent, imageInfo=os.path.split(img)[-1]) diff --git a/make_vector_files.py b/make_vector_files.py new file mode 100644 index 0000000..9c75fca --- /dev/null +++ b/make_vector_files.py @@ -0,0 +1,117 @@ +# from custom_apps.FEATURE_VECTOR_SIMILARITY_FAISS.faiss_functions import get_clip_info +import os +from custom_apps.FEATURE_VECTOR_SIMILARITY_FAISS.faiss_similarity_search import VectorSimilarity +from custom_apps.FEATURE_VECTOR_SIMILARITY_FAISS.const import * +from custom_apps.FEATURE_VECTOR_SIMILARITY_FAISS.faiss_functions import get_models, find_glass_folder_images, find_parts_folder_images +from vector_rest.app import models as VM + +def make_image_files(item_info, index_type:VM.VitIndexType, model_type:VM.VitModelType): + model = get_models(index_type=index_type, model_type=model_type) + + txt_file_path = os.path.join(FAISS_VECTOR_PATH,f'{model.name}_{os.path.basename(model.value[1].trained_model)}_{model.value[1].index_type}_{item_info}.txt') + + image_lists = [] + if not os.path.exists(txt_file_path): + if item_info == VectorSearchItem.glass: + image_lists = find_glass_folder_images(IMG_LIST_PATH) + else: + image_lists = find_parts_folder_images(IMG_LIST_PATH, item_info) + + if image_lists: + with open(txt_file_path, 'w') as f: + for img_path in image_lists: + f.write(f"{img_path}\n") + else: + temp_path = os.path.join(FAISS_VECTOR_PATH,f'{model.name}_{os.path.basename(model.value[1].trained_model)}_{model.value[1].index_type}_{item_info}.bak') + + try: + os.rename(txt_file_path, temp_path) + + if item_info == VectorSearchItem.glass: + image_lists = find_glass_folder_images(IMG_LIST_PATH) + else: + image_lists = find_parts_folder_images(IMG_LIST_PATH, item_info) + + if image_lists: + with open(txt_file_path, 'w') as f: + for img_path in image_lists: + f.write(f"{img_path}\n") + + except Exception as e: + print(f"Error updating image file list: {e}") + + finally: + if os.path.exists(txt_file_path): + os.remove(temp_path) + else: + os.rename(temp_path, txt_file_path) + + return txt_file_path + +def make_vector_files(item_info, index_type:VM.VitIndexType, model_type:VM.VitModelType): + model = get_models(index_type=index_type, model_type=model_type) + + txt_file_path = make_image_files(item_info=item_info, index_type=index_type, model_type=model_type) + + index_file_path = os.path.join(IMG_LIST_PATH,f'{model.name}_{os.path.basename(model.value[1].trained_model)}_{model.value[1].index_type}_{item_info}_{DEFAULT_INDEX_NAME_SUFFIX}') + + if not os.path.exists(index_file_path): + + vector_model = VectorSimilarity(model_info=model, + index_file_path=index_file_path, + txt_file_path=txt_file_path) + + with open(txt_file_path, 'r') as f: + image_lists = [line.strip() for line in f.readlines()] + + vector_model.save_index_from_files(images_path_lists=image_lists, + save_index_dir=FAISS_VECTOR_PATH, + save_txt_dir=IMG_LIST_PATH, + item_info=item_info, + index_type=model.value[1].index_type) + + else: + temp_path = os.path.join(IMG_LIST_PATH,f'{model.name}_{os.path.basename(model.value[1].trained_model)}_{model.value[1].index_type}_{item_info}_{DEFAULT_INDEX_NAME_SUFFIX}.bak') + + try: + os.rename(index_file_path, temp_path) + + vector_model = VectorSimilarity(model_info=model, + index_file_path=index_file_path, + txt_file_path=txt_file_path) + + with open(txt_file_path, 'r') as f: + image_lists = [line.strip() for line in f.readlines()] + + vector_model.save_index_from_files(images_path_lists=image_lists, + save_index_dir=FAISS_VECTOR_PATH, + save_txt_dir=IMG_LIST_PATH, + item_info=item_info, + index_type=model.value[1].index_type) + except Exception as e: + print(f"Error updating vector file: {e}") + finally: + if os.path.exists(index_file_path): + os.remove(temp_path) + else: + os.rename(temp_path, index_file_path) + + print(f"Vector file created: {index_file_path} :::::::::: item_info: {item_info}, index_type: {index_type}, model_type: {model_type}") + + return index_file_path + +if __name__ == '__main__': + + import time + class_attributes = dict(VectorSearchItem.__dict__) + + pure_data_dict = { + key: value + for key, value in class_attributes.items() + if not key.startswith('__') + } + + 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 diff --git a/vector_rest/app/routes/dev.py b/vector_rest/app/routes/dev.py index 4669d94..67e95e4 100644 --- a/vector_rest/app/routes/dev.py +++ b/vector_rest/app/routes/dev.py @@ -39,7 +39,7 @@ def send_mail(): sender = 'jolimola@gmail.com' sender_pw = '!ghkdtmdwns1' # recipient = 'hsj100@a2tec.co.kr' - recipient = 'jwkim@daooldns.co.kr' + recipient = 'jwkim@a2tec.co.kr' list_cc = ['cc1@gmail.com', 'cc2@naver.com'] str_cc = ','.join(list_cc) diff --git a/vector_rest/app/routes/services.py b/vector_rest/app/routes/services.py index 7b48865..2a15c2f 100644 --- a/vector_rest/app/routes/services.py +++ b/vector_rest/app/routes/services.py @@ -110,7 +110,7 @@ async def vactor_vit(request: Request, request_body_info: M.VectorSearchVitReq): @router.post("/faiss/vector/search/vit/parts", summary="vit search parts", response_model=M.VectorSearchVitRes) async def vactor_vit_parts(request: Request, request_body_info: M.VectorSearchVitReq): """ - 이미지 경로 를 입력받아 vit 방식으로 검색 + 이미지 경로 를 입력받아 vit 방식으로 parts 검색 """ response = M.VectorSearchVitRes() try: @@ -119,7 +119,6 @@ async def vactor_vit_parts(request: Request, request_body_info: M.VectorSearchVi model = get_models(index_type=request_body_info.index_type, model_type=request_body_info.model_type) - #TODO parts 데이터 확인필요 parts = file_name_to_parts(request_body_info.query_image_path) report_info = get_clip_info(model=model,