From 4ef360448acdd0cd5f27396c702dca09802650b2 Mon Sep 17 00:00:00 2001 From: jwkim Date: Thu, 7 Aug 2025 16:54:46 +0900 Subject: [PATCH] =?UTF-8?q?edit=20:=20=EC=9D=B4=EB=AF=B8=EC=A7=80=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20api=20=EC=83=9D=EC=84=B1=EA=B0=AF=EC=88=98=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C,=20=EC=9D=B4=EB=AF=B8=EC=A7=80=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20api=20=EB=8D=B0=EC=9D=B4=ED=84=B0=EB=A5=BC=20return?= =?UTF-8?q?=ED=95=B4=EC=A3=BC=EB=8A=94=20api=20=EC=B6=94=EA=B0=80,=20=20?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=EB=B0=9B=EC=95=84=20=EA=B2=80=EC=83=89=ED=95=98?= =?UTF-8?q?=EB=8A=94=20api=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main_rest/app/models.py | 18 +++- main_rest/app/routes/services.py | 135 +++++++++++++++++++++++---- main_rest/app/utils/parsing_utils.py | 13 ++- vector_rest/app/models.py | 1 + vector_rest/app/routes/services.py | 6 ++ 5 files changed, 151 insertions(+), 22 deletions(-) diff --git a/main_rest/app/models.py b/main_rest/app/models.py index 3a99cdb..47269d9 100644 --- a/main_rest/app/models.py +++ b/main_rest/app/models.py @@ -587,9 +587,7 @@ class ImageGenerateReq(BaseModel): """ ### [Request] image generate request """ - prompt : str = Field(description='프롬프트', example='검은색 안경') - downloadCount : int = Field(1, description='이미지 생성 갯수', example=1) - + prompt : str = Field(description='프롬프트', example='검은색 안경') class BingCookieSetReq(BaseModel): """ @@ -615,6 +613,16 @@ class VectorImageSearchVitReq(BaseModel): modelType : str = Field(VitModelType.l14, description='pretrained model 타입', example=VitModelType.l14) indexType : str = Field(VitIndexType.l2, description='인덱스 타입', example=VitIndexType.l2) searchNum : int = Field(4, description='검색결과 이미지 갯수', example=4) + + +class VectorImageSearchVitInputImgReq(BaseModel): + """ + ### [Request] vector image search vit - input image + """ + inputImage : str = Field(description='base64 이미지', example='') + modelType : str = Field(VitModelType.l14, description='pretrained model 타입', example=VitModelType.l14) + indexType : str = Field(VitIndexType.l2, description='인덱스 타입', example=VitIndexType.l2) + searchNum : int = Field(4, description='검색결과 이미지 갯수', example=4) class VectorImageSearchVitDataReq(VectorImageSearchVitReq): @@ -623,6 +631,7 @@ class VectorImageSearchVitDataReq(VectorImageSearchVitReq): """ querySend: bool = Field(True, description='쿼리 이미지 전송 여부', example=True) + class VectorImageSearchVitReportReq(BaseModel): """ ### [Request] vector image search vit request @@ -631,6 +640,7 @@ class VectorImageSearchVitReportReq(BaseModel): modelType : str = Field(VitModelType.l14, description='pretrained model 타입', example=VitModelType.l14) indexType : str = Field(VitIndexType.l2, description='인덱스 타입', example=VitIndexType.l2) + class VectorImageResult(BaseModel): image : str = Field("", description='이미지 데이터', example='') percents: float = Field(0.0, description='percents 값', example='') @@ -665,7 +675,7 @@ class ImageGenerateDataRes(ResponseBase): """ ### image generate Data response """ - imageData : int = Field(0, description='실제 이미지 생성 갯수', example=1) + imageData : str = Field('', description='이미지 데이터', example='') @staticmethod def set_error(error,img_data=''): diff --git a/main_rest/app/routes/services.py b/main_rest/app/routes/services.py index 50525fb..b5a3b55 100644 --- a/main_rest/app/routes/services.py +++ b/main_rest/app/routes/services.py @@ -17,7 +17,7 @@ from typing import Annotated, List from main_rest.app.common import consts from main_rest.app import models as M from main_rest.app.utils.date_utils import D -from main_rest.app.utils.parsing_utils import image_to_base64_string +from main_rest.app.utils.parsing_utils import image_to_base64_string,save_base64_as_image_file from custom_logger.main_log import main_logger as LOG # from custom_apps.bingimagecreator.utils import DallEArgument,dalle3_generate_image @@ -123,22 +123,16 @@ router = APIRouter(prefix="/services") # LOG.error(traceback.format_exc()) # return response.set_error(e) -@router.post("/imageGenerate/imagen", summary="이미지 생성(AI) - imagen", response_model=M.ImageGenerateRes) +@router.post("/imageGenerate/imagen", summary="이미지 생성(AI) - imagen", response_model=M.ResponseBase) async def imagen(request: Request, request_body_info: M.ImageGenerateReq): """ ## 이미지 생성(AI) - imagen > imagen AI를 이용하여 이미지 생성 - - """ # imagen 사용중단 gemini로 변경 - response = M.ImageGenerateRes() + response = M.ResponseBase() try: - - if not download_range(request_body_info.downloadCount): - raise Exception(f"downloadCount is 1~4 (current value = {request_body_info.downloadCount})") - # NOTE(JWKIM) : imagen 사용 중단 # img_length = imagen_generate_image(prompt=request_body_info.prompt, # download_count=request_body_info.downloadCount @@ -162,7 +156,44 @@ async def imagen(request: Request, request_body_info: M.ImageGenerateReq): os.remove(temp_image_path) del temp_image_path - return response.set_message(img_len=1) + return response.set_message() + + except Exception as e: + LOG.error(traceback.format_exc()) + + # Clean up temporary files + if 'query_image_path' in locals(): + if os.path.exists(query_image_path): + os.remove(query_image_path) + del query_image_path + + return response.set_error(error=e) + +@router.post("/imageGenerate/imagen/data", summary="이미지 생성(AI) - imagen(data)", response_model=M.ImageGenerateDataRes) +async def imagen_data(request: Request, request_body_info: M.ImageGenerateReq): + """ + ## 이미지 생성(AI) - imagen + > imagen AI를 이용하여 이미지 데이터생성 + """ + # imagen 사용중단 gemini로 변경 + + response = M.ImageGenerateDataRes() + try: + # NOTE(JWKIM) : imagen 사용 중단 + # img_length = imagen_generate_image(prompt=request_body_info.prompt, + # download_count=request_body_info.downloadCount + # ) + temp_image_path = gemini_image(request_body_info.prompt) + + b64data = image_to_base64_string(temp_image_path) + + # Clean up temporary files + if 'temp_image_path' in locals(): + if os.path.exists(temp_image_path): + os.remove(temp_image_path) + del temp_image_path + + return response.set_message(b64data) except Exception as e: LOG.error(traceback.format_exc()) @@ -231,9 +262,6 @@ async def vactor_vit(request: Request, request_body_info: M.VectorImageSearchVit ## 벡터 이미지 검색(clip-vit) - imagen > imagen AI를 이용하여 이미지 생성 후 vector 검색 그후 결과 이미지 생성 - ### Requriements - > - googlecli 설치(https://cloud.google.com/sdk/docs/install?hl=ko#linux) - ### options > - modelType -> b32,b16,l14,l14_336 > - indexType -> l2,cos @@ -311,14 +339,11 @@ async def vactor_vit(request: Request, request_body_info: M.VectorImageSearchVit return response.set_error(error=e) @router.post("/vectorImageSearch/vit/imageGenerate/imagen/data", summary="벡터 이미지 검색(clip-vit) - imagen(data)", response_model=M.VectorImageSerachDataRes) -async def vactor_vit_report_data(request: Request, request_body_info: M.VectorImageSearchVitDataReq): +async def vactor_vit_data(request: Request, request_body_info: M.VectorImageSearchVitDataReq): """ ## 벡터 이미지 검색(clip-vit) - imagen > imagen AI를 이용하여 이미지 생성 후 vector 검색 그후 결과 이미지데이터 return - ### Requriements - > - googlecli 설치(https://cloud.google.com/sdk/docs/install?hl=ko#linux) - ### options > - modelType -> b32,b16,l14,l14_336 > - indexType -> l2,cos @@ -389,6 +414,82 @@ async def vactor_vit_report_data(request: Request, request_body_info: M.VectorIm del query_image_path return response.set_error(error=e) + + +@router.post("/vectorImageSearch/vit/inputImage/data", summary="벡터 이미지 검색(clip-vit) - input image(data)", response_model=M.VectorImageSerachDataRes) +async def vactor_vit_input_img_data(request: Request, request_body_info: M.VectorImageSearchVitInputImgReq): + """ + ## 벡터 이미지 검색(clip-vit) - inputimage + > 입력된 이미지로 vector 검색 그후 결과 이미지데이터 return + + ### Requriements + > - googlecli 설치(https://cloud.google.com/sdk/docs/install?hl=ko#linux) + + ### options + > - modelType -> b32,b16,l14,l14_336 + > - indexType -> l2,cos + + """ + response = M.VectorImageSerachDataRes() + query_image_data = '' + + try: + if request_body_info.modelType not in [M.VitModelType.b32, M.VitModelType.b16, M.VitModelType.l14, M.VitModelType.l14_336]: + raise Exception(f"modelType is invalid (current value = {request_body_info.modelType})") + + if request_body_info.indexType not in [M.VitIndexType.cos, M.VitIndexType.l2]: + raise Exception(f"indexType is invalid (current value = {request_body_info.indexType})") + + query_image_path = os.path.join(TEMP_FOLDER, f'input_{D.date_file_name()}_query.png') + save_base64_as_image_file(request_body_info.inputImage ,query_image_path) + + vector_request_data = {'query_image_path' : query_image_path, + 'index_type' : request_body_info.indexType, + 'model_type' : request_body_info.modelType, + 'search_num' : request_body_info.searchNum} + + vector_response = requests.post('http://localhost:51002/api/services/faiss/vector/search/vit', data=json.dumps(vector_request_data)) + + vector_response_dict = json.loads(vector_response.text) + + if vector_response.status_code != 200: + raise Exception(f"response error: {vector_response_dict['error']}") + + if vector_response_dict["error"] != None: + raise Exception(f"vector error: {vector_response_dict['error']}") + + result_image_paths = vector_response_dict.get('img_list').get('result_image_paths') + result_percents = vector_response_dict.get('img_list').get('result_percents') + + # 이미지 데이터 생성 + vector_image_results = [] + for img, percents in zip(result_image_paths, result_percents): + b64_data = image_to_base64_string(img) + float_percent = float(percents) + + info = M.VectorImageResult(image=b64_data,percents=float_percent) + + vector_image_results.append(info) + + # Clean up temporary files + if 'query_image_path' in locals(): + if os.path.exists(query_image_path): + os.remove(query_image_path) + del query_image_path + + return response.set_message(vector_result=vector_image_results,query_img=query_image_data) + + except Exception as e: + LOG.error(traceback.format_exc()) + + # Clean up temporary files + if 'query_image_path' in locals(): + if os.path.exists(query_image_path): + os.remove(query_image_path) + del query_image_path + + return response.set_error(error=e) + @router.post("/vectorImageSearch/vit/imageGenerate/imagen/report", summary="벡터 이미지 검색(clip-vit) - imagen, report 생성", response_model=M.ResponseBase) async def vactor_vit_report(request: Request, request_body_info: M.VectorImageSearchVitReportReq): diff --git a/main_rest/app/utils/parsing_utils.py b/main_rest/app/utils/parsing_utils.py index 0c4ccf0..e797202 100644 --- a/main_rest/app/utils/parsing_utils.py +++ b/main_rest/app/utils/parsing_utils.py @@ -58,4 +58,15 @@ def image_to_base64_string(image_path: str) -> str: raise IOError(f"Error reading image file {image_path}: {e}") except Exception as e: # 그 외 예외 처리 - raise Exception(f"An unexpected error occurred: {e}") \ No newline at end of file + raise Exception(f"An unexpected error occurred: {e}") + + +def save_base64_as_image_file(base64_data: str, output_path: str): + """ + Base64 문자열을 디코딩하여 이미지 파일로 저장합니다. + """ + # Base64 문자열을 디코딩하여 이진 데이터로 변환합니다. + decoded_data = base64.b64decode(base64_data) + with open(output_path, "wb") as image_file: + image_file.write(decoded_data) + \ No newline at end of file diff --git a/vector_rest/app/models.py b/vector_rest/app/models.py index 3b4efcf..85dd339 100644 --- a/vector_rest/app/models.py +++ b/vector_rest/app/models.py @@ -611,6 +611,7 @@ class VactorSearchVitReq(BaseModel): model_type : VitModelType = Field(VitModelType.l14, description='pretrained 모델 정보', example=VitModelType.l14) search_num : int = Field(4, description='검색결과 이미지 갯수', example=4) + class VactorSearchVitRes(ResponseBase): img_list : dict = Field({}, description='이미지 결과 리스트', example={}) diff --git a/vector_rest/app/routes/services.py b/vector_rest/app/routes/services.py index 19eb48f..15a9ce7 100644 --- a/vector_rest/app/routes/services.py +++ b/vector_rest/app/routes/services.py @@ -55,6 +55,9 @@ async def vactor_search(request: Request, request_body_info: M.VactorSearchReq): @router.post("/faiss/vector/search/vit/report", summary="vit search report", response_model=M.ResponseBase) async def vactor_report_vit(request: Request, request_body_info: M.VactorSearchVitReportReq): + """ + 이미지 경로를 입력받아 repport image 저장 + """ response = M.ResponseBase() try: if not os.path.exists(request_body_info.query_image_path): @@ -74,6 +77,9 @@ async def vactor_report_vit(request: Request, request_body_info: M.VactorSearchV @router.post("/faiss/vector/search/vit", summary="vit search", response_model=M.VactorSearchVitRes) async def vactor_vit(request: Request, request_body_info: M.VactorSearchVitReq): + """ + 이미지 경로 를 입력받아 vit 방식으로 검색 + """ response = M.VactorSearchVitRes() try: if not os.path.exists(request_body_info.query_image_path):