release
This commit is contained in:
parent
ceb05de7f3
commit
3d3f1e5383
@ -94,7 +94,8 @@ vector/
|
||||
| Method | Endpoint | 설명 | 요청 모델 | 응답 모델 |
|
||||
|--------|----------|------|-----------|-----------|
|
||||
| `POST` | `/find-reviews` | 리뷰 수집 및 Vector DB 저장 | VectorBuildRequest | FindReviewsResponse |
|
||||
| `POST` | `/action-recommendation` | AI 기반 비즈니스 추천 | ActionRecommendationRequest | ActionRecommendationSimpleResponse |
|
||||
| `POST` | `/action-recommendation` | AI 기반 비즈니스 추천 | ActionRecommendationRequest |
|
||||
| `GET` | `/store/{store_id}` | store_id로 매장 정보 조회 | Path Parameter | StoreInfoResponse ActionRecommendationSimpleResponse |
|
||||
|
||||
## 🚀 빠른 시작
|
||||
|
||||
@ -779,6 +780,80 @@ curl -X POST "http://vector-api.20.249.191.180.nip.io/action-recommendation" \
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 매장 정보 조회 API
|
||||
#### 요청 예시
|
||||
```bash
|
||||
curl -X GET "http://vector-api.20.249.191.180.nip.io/store/501745730"
|
||||
```
|
||||
|
||||
#### 응답 예시 (성공)
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "매장 정보 조회 성공: 맛있는 치킨집",
|
||||
"store_id": "501745730",
|
||||
"store_info": {
|
||||
"id": "501745730",
|
||||
"place_name": "맛있는 치킨집",
|
||||
"category_name": "음식점 > 치킨",
|
||||
"address_name": "서울특별시 강남구 역삼동 123-45",
|
||||
"phone": "02-123-4567",
|
||||
"place_url": "http://place.map.kakao.com/501745730",
|
||||
"x": "127.0276543",
|
||||
"y": "37.4979234"
|
||||
},
|
||||
"reviews": [
|
||||
{
|
||||
"reviewer_name": "김○○",
|
||||
"rating": 5,
|
||||
"date": "2024-06-10",
|
||||
"content": "치킨이 정말 맛있어요!",
|
||||
"badges": ["맛집", "친절", "빠른배달"],
|
||||
"likes": 12
|
||||
}
|
||||
],
|
||||
"review_summary": {
|
||||
"total_reviews": 23,
|
||||
"average_rating": 4.2,
|
||||
"rating_distribution": {
|
||||
"5": 12,
|
||||
"4": 8,
|
||||
"3": 2,
|
||||
"2": 1,
|
||||
"1": 0
|
||||
},
|
||||
"total_likes": 145,
|
||||
"common_keywords": ["맛집", "친절", "빠른배달", "바삭함"]
|
||||
},
|
||||
"metadata": {
|
||||
"store_id": "501745730",
|
||||
"store_name": "맛있는 치킨집",
|
||||
"food_category": "치킨",
|
||||
"region": "서울특별시 강남구 역삼동",
|
||||
"last_updated": "2024-06-17T10:30:00"
|
||||
},
|
||||
"last_updated": "2024-06-17T10:30:00",
|
||||
"total_reviews": 23,
|
||||
"execution_time": 0.15
|
||||
}
|
||||
```
|
||||
|
||||
#### 응답 예시 (실패)
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "매장 정보를 찾을 수 없습니다: store_id=999999",
|
||||
"store_id": "999999",
|
||||
"store_info": null,
|
||||
"reviews": null,
|
||||
"review_summary": null,
|
||||
"metadata": null,
|
||||
"last_updated": null,
|
||||
"total_reviews": 0,
|
||||
"execution_time": 0.05
|
||||
}
|
||||
```
|
||||
|
||||
## ⚙️ 환경 설정
|
||||
|
||||
### 필수 환경변수
|
||||
|
||||
@ -30,7 +30,7 @@ from contextlib import asynccontextmanager
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
import asyncio
|
||||
from fastapi import FastAPI, HTTPException, Depends
|
||||
from fastapi import FastAPI, HTTPException, Depends, Path
|
||||
from fastapi.responses import HTMLResponse, JSONResponse
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from pydantic import BaseModel, Field
|
||||
@ -673,4 +673,63 @@ async def health_check():
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
uvicorn.run(app, host=settings.HOST, port=settings.PORT)
|
||||
uvicorn.run(app, host=settings.HOST, port=settings.PORT)
|
||||
|
||||
@app.get(
|
||||
"/store/{store_id}",
|
||||
response_model=StoreInfoResponse,
|
||||
summary="매장 정보 조회",
|
||||
description="store_id를 이용하여 Vector DB에서 매장 기본정보와 리뷰 정보를 조회합니다"
|
||||
)
|
||||
async def get_store_info(
|
||||
store_id: str = Path(..., description="조회할 매장 ID", example="501745730"),
|
||||
vector_service: VectorService = Depends(get_vector_service)
|
||||
):
|
||||
"""🏪 store_id로 매장 정보 조회 API"""
|
||||
start_time = datetime.now()
|
||||
|
||||
try:
|
||||
logger.info(f"🔍 매장 정보 조회 요청: store_id={store_id}")
|
||||
|
||||
# Vector DB에서 매장 정보 조회
|
||||
store_data = vector_service.get_store_by_id(store_id)
|
||||
|
||||
execution_time = (datetime.now() - start_time).total_seconds()
|
||||
|
||||
if not store_data:
|
||||
return StoreInfoResponse(
|
||||
success=False,
|
||||
message=f"매장 정보를 찾을 수 없습니다: store_id={store_id}",
|
||||
store_id=store_id,
|
||||
execution_time=execution_time
|
||||
)
|
||||
|
||||
# 성공 응답
|
||||
store_info = store_data.get('store_info', {})
|
||||
reviews = store_data.get('reviews', [])
|
||||
review_summary = store_data.get('review_summary', {})
|
||||
metadata = store_data.get('metadata', {})
|
||||
|
||||
return StoreInfoResponse(
|
||||
success=True,
|
||||
message=f"매장 정보 조회 성공: {store_info.get('place_name', store_id)}",
|
||||
store_id=store_id,
|
||||
store_info=store_info,
|
||||
reviews=reviews,
|
||||
review_summary=review_summary,
|
||||
metadata=metadata,
|
||||
last_updated=store_data.get('combined_at'),
|
||||
total_reviews=len(reviews),
|
||||
execution_time=execution_time
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
execution_time = (datetime.now() - start_time).total_seconds()
|
||||
logger.error(f"❌ 매장 정보 조회 실패: store_id={store_id}, error={e}")
|
||||
|
||||
return StoreInfoResponse(
|
||||
success=False,
|
||||
message=f"매장 정보 조회 중 오류 발생: {str(e)}",
|
||||
store_id=store_id,
|
||||
execution_time=execution_time
|
||||
)
|
||||
@ -108,4 +108,26 @@ class VectorDBStatusResponse(BaseModel):
|
||||
"""Vector DB 상태 조회 응답"""
|
||||
success: bool = Field(description="조회 성공 여부")
|
||||
status: VectorDBStatus = Field(description="DB 상태 정보")
|
||||
message: str = Field(description="응답 메시지")
|
||||
message: str = Field(description="응답 메시지")
|
||||
|
||||
class StoreInfoRequest(BaseModel):
|
||||
"""매장 정보 조회 요청 모델"""
|
||||
store_id: str = Field(
|
||||
...,
|
||||
description="조회할 매장 ID",
|
||||
example="501745730"
|
||||
)
|
||||
|
||||
class StoreInfoResponse(BaseModel):
|
||||
"""매장 정보 조회 응답 모델"""
|
||||
success: bool = Field(description="조회 성공 여부")
|
||||
message: str = Field(description="응답 메시지")
|
||||
store_id: str = Field(description="매장 ID")
|
||||
store_info: Optional[Dict[str, Any]] = Field(None, description="매장 기본 정보")
|
||||
reviews: Optional[List[Dict[str, Any]]] = Field(None, description="리뷰 목록")
|
||||
review_summary: Optional[Dict[str, Any]] = Field(None, description="리뷰 요약 정보")
|
||||
metadata: Optional[Dict[str, Any]] = Field(None, description="Vector DB 메타데이터")
|
||||
last_updated: Optional[str] = Field(None, description="마지막 업데이트 시간")
|
||||
total_reviews: int = Field(default=0, description="총 리뷰 수")
|
||||
execution_time: Optional[float] = Field(None, description="실행 시간(초)")
|
||||
|
||||
@ -1178,4 +1178,64 @@ class VectorService:
|
||||
return {
|
||||
'added_count': added_count,
|
||||
'add_details': add_details
|
||||
}
|
||||
}
|
||||
|
||||
def get_store_by_id(self, store_id: str) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
store_id로 특정 매장의 정보를 조회합니다.
|
||||
|
||||
Args:
|
||||
store_id: 조회할 매장 ID
|
||||
|
||||
Returns:
|
||||
매장 정보 딕셔너리 또는 None
|
||||
"""
|
||||
try:
|
||||
if not self.is_ready():
|
||||
logger.warning("⚠️ VectorService가 준비되지 않음")
|
||||
return None
|
||||
|
||||
logger.info(f"🔍 매장 정보 조회 시작: store_id={store_id}")
|
||||
|
||||
# Vector DB에서 해당 store_id로 검색
|
||||
results = self.collection.get(
|
||||
where={"store_id": store_id},
|
||||
include=['documents', 'metadatas', 'ids']
|
||||
)
|
||||
|
||||
if not results or not results.get('metadatas') or not results['metadatas']:
|
||||
logger.warning(f"❌ 매장 정보를 찾을 수 없음: store_id={store_id}")
|
||||
return None
|
||||
|
||||
# 첫 번째 결과 사용 (store_id는 유니크해야 함)
|
||||
metadata = results['metadatas'][0]
|
||||
document = results['documents'][0] if results.get('documents') else None
|
||||
document_id = results['ids'][0] if results.get('ids') else None
|
||||
|
||||
logger.info(f"✅ 매장 정보 조회 성공: {metadata.get('store_name', 'Unknown')}")
|
||||
|
||||
# 문서에서 JSON 파싱 (combine_store_and_reviews 형태로 저장되어 있음)
|
||||
store_data = None
|
||||
if document:
|
||||
try:
|
||||
import json
|
||||
store_data = json.loads(document)
|
||||
except json.JSONDecodeError as e:
|
||||
logger.error(f"❌ JSON 파싱 실패: {e}")
|
||||
return None
|
||||
|
||||
# 응답 데이터 구성
|
||||
result = {
|
||||
"metadata": metadata,
|
||||
"document_id": document_id,
|
||||
"store_info": store_data.get('store_info') if store_data else None,
|
||||
"reviews": store_data.get('reviews', []) if store_data else [],
|
||||
"review_summary": store_data.get('review_summary', {}) if store_data else {},
|
||||
"combined_at": store_data.get('combined_at') if store_data else None
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ 매장 정보 조회 실패: store_id={store_id}, error={e}")
|
||||
return None
|
||||
Loading…
x
Reference in New Issue
Block a user