release
This commit is contained in:
parent
c737cd8210
commit
c06d453cf4
@ -633,118 +633,69 @@ def _extract_store_id_from_place_url(place_url: str) -> Optional[str]:
|
||||
return None
|
||||
|
||||
@app.post(
|
||||
"/action-recommendation",
|
||||
response_model=ActionRecommendationResponse,
|
||||
summary="액션 추천 요청",
|
||||
description="점주가 Claude AI에게 액션 추천을 요청합니다."
|
||||
"/action-recommendation-simple",
|
||||
response_model=ActionRecommendationSimpleResponse,
|
||||
summary="간소화된 액션 추천 요청",
|
||||
description="JSON 추천 결과만 반환하는 최적화된 엔드포인트"
|
||||
)
|
||||
async def action_recommendation(
|
||||
async def action_recommendation_simple(
|
||||
request: ActionRecommendationRequest,
|
||||
claude_service: ClaudeService = Depends(get_claude_service),
|
||||
vector_service: VectorService = Depends(get_vector_service)
|
||||
):
|
||||
"""🧠 Claude AI 액션 추천 API"""
|
||||
"""🧠 최적화된 Claude AI 액션 추천 API - JSON만 반환"""
|
||||
try:
|
||||
logger.info(f"액션 추천 요청: store_id={request.store_id}")
|
||||
|
||||
start_time = datetime.now()
|
||||
|
||||
# 1단계: Vector DB에서 컨텍스트 조회
|
||||
logger.info(f"간소화된 액션 추천 요청: store_id={request.store_id}")
|
||||
|
||||
# 1단계: Vector DB에서 최적화된 컨텍스트 조회
|
||||
context_data = None
|
||||
try:
|
||||
db_status = vector_service.get_db_status()
|
||||
|
||||
if db_status.get('total_documents', 0) == 0:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail={
|
||||
"success": False,
|
||||
"error": "NO_VECTOR_DATA",
|
||||
"message": "Vector DB에 데이터가 없습니다. 먼저 /build-vector API를 호출하여 데이터를 구축해주세요.",
|
||||
"timestamp": datetime.now().isoformat()
|
||||
}
|
||||
)
|
||||
|
||||
# Vector DB에서 유사한 케이스 검색
|
||||
context_data = vector_service.search_similar_cases(request.store_id, request.context)
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
# 개선된 검색 메소드 사용
|
||||
context_data = vector_service.search_similar_cases_improved(
|
||||
request.store_id,
|
||||
request.context
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Vector DB 조회 실패: {e}")
|
||||
# Vector DB 조회 실패해도 일반적인 추천은 제공
|
||||
context_data = None
|
||||
|
||||
# 2단계: Claude AI 호출 (프롬프트 구성부터 파싱까지 모두 포함)
|
||||
logger.warning(f"Vector DB 조회 실패 (계속 진행): {e}")
|
||||
|
||||
# 2단계: Claude AI 호출 - JSON만 추출
|
||||
try:
|
||||
# 컨텍스트 구성
|
||||
full_context = f"가게 ID: {request.store_id}\n점주 요청: {request.context}"
|
||||
additional_context = context_data if context_data else None
|
||||
|
||||
# Claude AI 액션 추천 생성 (완전한 처리)
|
||||
claude_response, parsed_response = await claude_service.generate_action_recommendations(
|
||||
|
||||
# Claude AI 호출
|
||||
claude_response, parsed_json = await claude_service.generate_action_recommendations(
|
||||
context=full_context,
|
||||
additional_context=additional_context
|
||||
additional_context=context_data
|
||||
)
|
||||
|
||||
if not claude_response:
|
||||
raise Exception("Claude AI로부터 응답을 받지 못했습니다")
|
||||
|
||||
logger.info(f"Claude 응답 길이: {len(claude_response)} 문자")
|
||||
json_parse_success = parsed_response is not None
|
||||
|
||||
|
||||
if not parsed_json:
|
||||
# JSON 파싱 실패시 재시도
|
||||
logger.warning("JSON 파싱 실패 - 재시도")
|
||||
parsed_json = claude_service.parse_recommendation_response(claude_response)
|
||||
|
||||
if not parsed_json:
|
||||
raise Exception("Claude AI 응답을 JSON으로 파싱할 수 없습니다")
|
||||
|
||||
return ActionRecommendationSimpleResponse(
|
||||
success=True,
|
||||
recommendation=parsed_json
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Claude AI 호출 실패: {e}")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"AI 추천 생성 중 오류: {str(e)}"
|
||||
return ActionRecommendationSimpleResponse(
|
||||
success=False,
|
||||
error_message=f"AI 추천 생성 중 오류: {str(e)}"
|
||||
)
|
||||
|
||||
# 3단계: 응답 구성
|
||||
claude_execution_time = (datetime.now() - start_time).total_seconds()
|
||||
|
||||
# 가게 정보 추출 (Vector DB에서)
|
||||
store_name = request.store_id # 기본값
|
||||
food_category = "기타" # 기본값
|
||||
|
||||
try:
|
||||
store_context = vector_service.get_store_context(request.store_id)
|
||||
if store_context:
|
||||
store_name = store_context.get('store_name', request.store_id)
|
||||
food_category = store_context.get('food_category', '기타')
|
||||
except Exception as e:
|
||||
logger.warning(f"가게 정보 추출 실패: {e}")
|
||||
|
||||
response = ActionRecommendationResponse(
|
||||
success=True,
|
||||
message=f"액션 추천이 완료되었습니다. (실행시간: {claude_execution_time:.1f}초, JSON 파싱: {'성공' if json_parse_success else '실패'})",
|
||||
claude_input=full_context + (f"\n--- 동종 업체 분석 데이터 ---\n{additional_context}" if additional_context else ""),
|
||||
claude_response=claude_response,
|
||||
parsed_response=parsed_response,
|
||||
store_name=store_name,
|
||||
food_category=food_category,
|
||||
similar_stores_count=len(context_data.split("---")) if context_data else 0,
|
||||
execution_time=claude_execution_time,
|
||||
json_parse_success=json_parse_success
|
||||
)
|
||||
|
||||
logger.info(f"✅ 액션 추천 완료: Claude 응답 {len(claude_response) if claude_response else 0} 문자, JSON 파싱 {'성공' if json_parse_success else '실패'}, {claude_execution_time:.1f}초 소요")
|
||||
return response
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"❌ 액션 추천 요청 실패: {str(e)}")
|
||||
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail={
|
||||
"success": False,
|
||||
"error": "RECOMMENDATION_FAILED",
|
||||
"message": f"액션 추천 중 오류가 발생했습니다: {str(e)}",
|
||||
"timestamp": datetime.now().isoformat()
|
||||
}
|
||||
logger.error(f"액션 추천 처리 실패: {e}")
|
||||
return ActionRecommendationSimpleResponse(
|
||||
success=False,
|
||||
error_message=f"서버 내부 오류: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
@app.get(
|
||||
"/vector-status",
|
||||
response_model=VectorDBStatusResponse,
|
||||
|
||||
@ -57,6 +57,12 @@ class ActionRecommendationResponse(BaseModel):
|
||||
execution_time: Optional[float] = Field(None, description="Claude API 응답 시간(초)")
|
||||
json_parse_success: Optional[bool] = Field(None, description="JSON 파싱 성공 여부") # 새로 추가
|
||||
|
||||
class ActionRecommendationSimpleResponse(BaseModel):
|
||||
"""단순화된 액션 추천 응답 - JSON만 반환"""
|
||||
success: bool = Field(description="추천 성공 여부")
|
||||
recommendation: Optional[Dict[str, Any]] = Field(None, description="추천 결과 JSON")
|
||||
error_message: Optional[str] = Field(None, description="오류 메시지 (실패시에만)")
|
||||
|
||||
class VectorStoreDocument(BaseModel):
|
||||
"""Vector Store에 저장될 문서 구조"""
|
||||
store_id: str = Field(description="가게 ID")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user