From a04b6c97aa4dd1e4e72cef0889883d1f3390fef6 Mon Sep 17 00:00:00 2001 From: hiondal Date: Mon, 16 Jun 2025 00:42:59 +0000 Subject: [PATCH] release --- vector/app/main.py | 112 ++++++++++++++++++++--------- vector/app/models/vector_models.py | 20 ++++++ 2 files changed, 99 insertions(+), 33 deletions(-) diff --git a/vector/app/main.py b/vector/app/main.py index 8476d7e..586c92d 100644 --- a/vector/app/main.py +++ b/vector/app/main.py @@ -37,13 +37,15 @@ from pydantic import BaseModel, Field # 프로젝트 모듈 import from app.config.settings import settings -from app.models.restaurant_models import RestaurantSearchRequest, ErrorResponse +from app.models.restaurant_models import RestaurantInfo from app.models.vector_models import ( VectorBuildRequest, VectorBuildResponse, ActionRecommendationRequest, ActionRecommendationResponse, ActionRecommendationSimpleResponse, - VectorDBStatusResponse, VectorDBStatus + VectorDBStatusResponse, VectorDBStatus, + FindReviewsResponse, StoredDataInfo ) + from app.services.restaurant_service import RestaurantService from app.services.review_service import ReviewService from app.services.vector_service import VectorService @@ -371,18 +373,24 @@ async def root(): @app.post("/find-reviews", response_model=FindReviewsResponse) async def find_reviews( - request: FindReviewsRequest, + request: VectorBuildRequest, # VectorBuildRequest 재사용 vector_service: VectorService = Depends(get_vector_service), restaurant_service: RestaurantService = Depends(get_restaurant_service), review_service: ReviewService = Depends(get_review_service) ): """ - 지역과 가게명으로 리뷰를 찾아 Vector DB에 저장합니다. + 지역과 가게명으로 리뷰를 찾아 Vector DB에 저장하고, + 실제 저장된 JSON 구조를 응답으로 리턴합니다. 🔥 본인 가게 리뷰는 반드시 포함됩니다. + + Note: force_rebuild 파라미터는 이 API에서는 무시됩니다. """ start_time = datetime.now() logger.info(f"🔍 리뷰 검색 요청: {request.region} - {request.store_name}") + # force_rebuild 파라미터는 find-reviews에서는 무시 + # (VectorBuildRequest를 재사용하지만 이 기능은 사용하지 않음) + try: # 1단계: 본인 가게 검색 logger.info("1단계: 본인 가게 검색 중...") @@ -392,9 +400,9 @@ async def find_reviews( if not target_restaurant: logger.error(f"❌ 본인 가게를 찾을 수 없음: {request.store_name}") - raise HTTPException( - status_code=404, - detail=f"'{request.store_name}' 가게를 찾을 수 없습니다. 가게명과 지역을 정확히 입력해주세요." + return FindReviewsResponse( + success=False, + message=f"'{request.store_name}' 가게를 찾을 수 없습니다. 가게명과 지역을 정확히 입력해주세요." ) logger.info(f"✅ 본인 가게 찾기 성공: {target_restaurant.place_name}") @@ -427,6 +435,7 @@ async def find_reviews( review_results.append((target_restaurant.id, target_store_info, target_reviews)) # 동종 업체 리뷰 수집 (본인 가게 제외) + similar_store_names = [] for store in similar_stores[:10]: # 최대 10개 동종 업체 if store.id != target_restaurant.id: # 본인 가게 제외 store_info, reviews = await review_service.collect_store_reviews( @@ -434,8 +443,9 @@ async def find_reviews( ) if store_info and reviews: review_results.append((store.id, store_info, reviews)) + similar_store_names.append(store.place_name) - # 6단계: Vector DB 저장 + # 6단계: Vector DB 저장 및 저장 데이터 수집 logger.info("6단계: Vector DB 저장 중...") try: target_store_info_dict = { @@ -449,6 +459,26 @@ async def find_reviews( 'y': target_restaurant.y } + # Vector DB에 저장하기 전에 저장될 데이터 구조 생성 + stored_data = {} + + # combine_store_and_reviews 함수를 사용하여 실제 저장될 JSON 구조 생성 + from app.utils.data_utils import combine_store_and_reviews + import json + + for store_id, store_info, reviews in review_results: + # Vector DB에 저장되는 실제 JSON 구조 생성 + json_data = combine_store_and_reviews(store_info, reviews) + parsed_data = json.loads(json_data) + + store_key = store_info.get('name', store_id) + stored_data[store_key] = StoredDataInfo( + store_info=parsed_data['store_info'], + reviews=parsed_data['reviews'], + review_summary=parsed_data['review_summary'], + combined_at=parsed_data['combined_at'] + ) + # Vector DB에 저장 vector_result = await vector_service.build_vector_store( target_store_info_dict, review_results, food_category, request.region @@ -461,42 +491,58 @@ async def find_reviews( except Exception as e: logger.error(f"❌ Vector DB 구축 실패: {e}") - raise HTTPException( - status_code=500, - detail=f"Vector DB 구축 중 오류가 발생했습니다: {str(e)}" + return FindReviewsResponse( + success=False, + message=f"Vector DB 구축 중 오류가 발생했습니다: {str(e)}", + target_store={ + 'id': target_restaurant.id, + 'place_name': target_restaurant.place_name, + 'category_name': target_restaurant.category_name, + 'address_name': target_restaurant.address_name, + 'phone': target_restaurant.phone, + 'place_url': target_restaurant.place_url, + 'x': target_restaurant.x, + 'y': target_restaurant.y + }, + food_category=food_category ) - # 성공 응답 + # 성공 응답 - Vector DB 저장 데이터 포함 total_reviews = sum(len(reviews) for _, _, reviews in review_results) + execution_time = (datetime.now() - start_time).total_seconds() return FindReviewsResponse( success=True, - message=f"✅ 본인 가게 리뷰 포함 보장 완료! (총 {len(review_results)}개 가게, {total_reviews}개 리뷰)", - target_store=RestaurantInfo( - id=target_restaurant.id, - place_name=target_restaurant.place_name, - category_name=target_restaurant.category_name, - address_name=target_restaurant.address_name, - phone=target_restaurant.phone, - place_url=target_restaurant.place_url, - x=target_restaurant.x, - y=target_restaurant.y - ), - total_stores=len(review_results), - total_reviews=total_reviews, + message=f"✅ 본인 가게 '{target_restaurant.place_name}' 리뷰 분석 완료! " + f"총 {total_reviews}개 리뷰, {len(review_results)}개 업체 분석됨", + target_store={ + 'id': target_restaurant.id, + 'place_name': target_restaurant.place_name, + 'category_name': target_restaurant.category_name, + 'address_name': target_restaurant.address_name, + 'phone': target_restaurant.phone, + 'place_url': target_restaurant.place_url, + 'x': target_restaurant.x, + 'y': target_restaurant.y + }, food_category=food_category, - region=request.region + total_reviews=total_reviews, + total_stores=len(review_results), + execution_time=execution_time, + stored_data=stored_data, + sample_similar_stores=similar_store_names[:5] # 상위 5개만 샘플로 제공 ) - except HTTPException: - raise except Exception as e: - logger.error(f"❌ 전체 프로세스 실패: {e}") - raise HTTPException( - status_code=500, - detail=f"서비스 처리 중 예상치 못한 오류가 발생했습니다: {str(e)}" + execution_time = (datetime.now() - start_time).total_seconds() + logger.error(f"❌ find_reviews 처리 실패: {str(e)}") + + return FindReviewsResponse( + success=False, + message=f"처리 중 오류가 발생했습니다: {str(e)}", + execution_time=execution_time ) - + @app.post( "/action-recommendation-simple", response_model=ActionRecommendationSimpleResponse, diff --git a/vector/app/models/vector_models.py b/vector/app/models/vector_models.py index 3322254..e3e20b2 100644 --- a/vector/app/models/vector_models.py +++ b/vector/app/models/vector_models.py @@ -20,6 +20,26 @@ class VectorBuildRequest(BaseModel): example=False ) +class StoredDataInfo(BaseModel): + """Vector DB에 저장된 데이터 정보""" + store_info: Dict[str, Any] = Field(description="가게 정보") + reviews: List[Dict[str, Any]] = Field(description="리뷰 목록") + review_summary: Dict[str, Any] = Field(description="리뷰 요약 정보") + combined_at: str = Field(description="데이터 결합 시간") + +class FindReviewsResponse(BaseModel): + """리뷰 검색 응답 모델 - Vector DB 저장 데이터 포함""" + success: bool = Field(description="검색 성공 여부") + message: str = Field(description="응답 메시지") + target_store: Optional[Dict[str, Any]] = Field(None, description="본인 가게 정보") + food_category: Optional[str] = Field(None, description="추출된 음식 카테고리") + total_reviews: int = Field(default=0, description="총 수집된 리뷰 수") + total_stores: int = Field(default=0, description="분석된 동종 업체 수") + execution_time: Optional[float] = Field(None, description="실행 시간(초)") + # Vector DB 저장 데이터 + stored_data: Optional[Dict[str, StoredDataInfo]] = Field(None, description="Vector DB에 저장된 데이터") + sample_similar_stores: List[str] = Field(default=[], description="동종 업체 샘플 목록") + class VectorBuildResponse(BaseModel): """Vector DB 구축 응답 모델""" success: bool = Field(description="구축 성공 여부")