223 lines
7.7 KiB
Python
223 lines
7.7 KiB
Python
# app/main.py
|
|
"""
|
|
HealthSync AI - FastAPI 메인 애플리케이션 (MVC 패턴) - 벡터DB 및 Redis 연동 추가
|
|
"""
|
|
from fastapi import FastAPI, Request
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from fastapi.responses import RedirectResponse, JSONResponse
|
|
from fastapi.exceptions import RequestValidationError
|
|
from fastapi.openapi.utils import get_openapi
|
|
from app.views.status_views import status_router
|
|
from app.views.mission_views import mission_router
|
|
from app.views.health_views import health_router
|
|
from app.views.chat_views import chat_router
|
|
from app.config.settings import settings
|
|
from app.models.base import ErrorResponse
|
|
from app.utils.vector_client import pinecone_client
|
|
from app.utils.redis_client import redis_client
|
|
import time
|
|
import logging
|
|
from datetime import datetime
|
|
|
|
# 로깅 설정
|
|
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
|
logger = logging.getLogger("HealthSync_AI")
|
|
|
|
# FastAPI 앱 생성
|
|
app = FastAPI(
|
|
title=settings.app_name,
|
|
description=f"""
|
|
{settings.app_description}
|
|
|
|
### 🚀 주요 기능
|
|
|
|
- **🎯 AI 미션 추천**: 개인 건강 데이터 기반 맞춤형 건강 미션 추천
|
|
- **🔬 AI 건강 진단**: 건강검진 데이터 3줄 요약 진단
|
|
- **💬 AI 건강 상담**: 개인 건강 데이터 기반 맞춤형 건강 상담 챗봇
|
|
- **🎉 미션 축하**: AI 기반 개인화된 미션 달성 축하 메시지
|
|
- **🔔 유사 미션 소식**: 벡터DB 기반 유사 사용자 미션 완료 소식
|
|
- **🏥 건강 상태 분석**: 건강검진 데이터 종합 분석
|
|
- **💡 개인화 서비스**: 직업군별 특화된 건강 관리 솔루션
|
|
|
|
### 🔧 기술 스택
|
|
|
|
- **Framework**: FastAPI {settings.app_version}
|
|
- **Pattern**: MVC (Model-View-Controller)
|
|
- **Language**: Python 3.11+
|
|
- **Database**: PostgreSQL
|
|
- **VectorDB**: Pinecone (유사도 검색)
|
|
- **Cache**: Redis (스마트 캐싱)
|
|
- **AI**: Claude API
|
|
- **Docs**: OpenAPI 3.0
|
|
|
|
---
|
|
|
|
💡 **Tip**: 왼쪽 사이드바에서 API 엔드포인트를 탐색해보세요!
|
|
""",
|
|
version=settings.app_version,
|
|
docs_url="/api/intelligence/docs",
|
|
redoc_url="/api/intelligence/redoc",
|
|
openapi_url="/api/intelligence/openapi.json"
|
|
)
|
|
|
|
|
|
# OpenAPI 스키마 커스터마이징
|
|
def custom_openapi():
|
|
if app.openapi_schema:
|
|
return app.openapi_schema
|
|
|
|
openapi_schema = get_openapi(
|
|
title=settings.app_name,
|
|
version=settings.app_version,
|
|
description=settings.app_description,
|
|
routes=app.routes,
|
|
)
|
|
|
|
# OpenAPI 3.1.0 명시적 설정
|
|
openapi_schema["openapi"] = "3.1.0"
|
|
|
|
# 서버 정보 추가
|
|
openapi_schema["servers"] = [
|
|
{
|
|
"url": f"http://{settings.host}:{settings.port}",
|
|
"description": "Development server"
|
|
}
|
|
]
|
|
|
|
# 태그 정보 추가
|
|
openapi_schema["tags"] = [
|
|
{
|
|
"name": "🏥 Status Check",
|
|
"description": "시스템 상태 확인 및 데이터베이스 연결 테스트"
|
|
},
|
|
{
|
|
"name": "🎯 Mission Management",
|
|
"description": "AI 기반 건강 미션 추천 및 축하 메시지"
|
|
},
|
|
{
|
|
"name": "🔬 Health Analysis",
|
|
"description": "건강검진 데이터 AI 분석 및 3줄 요약 진단"
|
|
},
|
|
{
|
|
"name": "💬 Chat Consultation",
|
|
"description": "개인 건강 데이터 기반 AI 건강 상담 챗봇"
|
|
}
|
|
]
|
|
|
|
app.openapi_schema = openapi_schema
|
|
return app.openapi_schema
|
|
|
|
|
|
app.openapi = custom_openapi
|
|
|
|
# CORS 미들웨어 설정
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=settings.cors_origins,
|
|
allow_credentials=True,
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
|
|
# 요청 처리 시간 미들웨어
|
|
@app.middleware("http")
|
|
async def add_process_time_header(request: Request, call_next):
|
|
start_time = time.time()
|
|
logger.info(f"📥 Request: {request.method} {request.url.path}")
|
|
|
|
response = await call_next(request)
|
|
|
|
process_time = time.time() - start_time
|
|
response.headers["X-Process-Time"] = str(round(process_time, 4))
|
|
response.headers["X-Service"] = settings.app_name
|
|
|
|
logger.info(
|
|
f"📤 Response: {request.method} {request.url.path} - Status: {response.status_code} - Time: {process_time:.4f}s")
|
|
return response
|
|
|
|
|
|
# API 라우터 등록
|
|
app.include_router(status_router, prefix=settings.api_v1_prefix)
|
|
app.include_router(mission_router, prefix=settings.api_v1_prefix)
|
|
app.include_router(health_router, prefix=settings.api_v1_prefix)
|
|
app.include_router(chat_router, prefix=settings.api_v1_prefix)
|
|
|
|
|
|
@app.get("/", include_in_schema=False)
|
|
async def root():
|
|
"""루트 경로 - API 문서로 리다이렉트"""
|
|
return RedirectResponse(url="/api/intelligence/docs")
|
|
|
|
|
|
@app.get("/docs", include_in_schema=False)
|
|
async def docs_redirect():
|
|
"""docs 경로 - API 문서로 리다이렉트"""
|
|
return RedirectResponse(url="/api/intelligence/docs")
|
|
|
|
|
|
# 예외 처리
|
|
@app.exception_handler(RequestValidationError)
|
|
async def validation_exception_handler(request: Request, exc: RequestValidationError):
|
|
error_response = ErrorResponse(
|
|
error_code="VALIDATION_ERROR",
|
|
message="입력 데이터 검증에 실패했습니다.",
|
|
details={"errors": exc.errors()},
|
|
timestamp=datetime.now()
|
|
)
|
|
|
|
return JSONResponse(
|
|
status_code=422,
|
|
content=error_response.model_dump(mode='json')
|
|
)
|
|
|
|
|
|
@app.on_event("startup")
|
|
async def startup_event():
|
|
logger.info(f"🚀 {settings.app_name} v{settings.app_version} 서비스 시작")
|
|
|
|
# 벡터DB 및 Redis 연결 초기화
|
|
try:
|
|
logger.info("🔗 외부 서비스 연결 초기화 중...")
|
|
|
|
# Pinecone 벡터DB 초기화
|
|
if settings.pinecone_api_key and settings.pinecone_api_key != "your_pinecone_api_key_here":
|
|
await pinecone_client.initialize()
|
|
logger.info("✅ Pinecone 벡터DB 연결 완료")
|
|
else:
|
|
logger.warning("⚠️ Pinecone API 키가 설정되지 않음 - 유사 미션 소식 기능 비활성화")
|
|
|
|
# Redis 캐시 연결
|
|
if settings.redis_host:
|
|
await redis_client.connect()
|
|
logger.info("✅ Redis 캐시 연결 완료")
|
|
else:
|
|
logger.warning("⚠️ Redis 설정이 없음 - 캐싱 기능 비활성화")
|
|
|
|
except Exception as e:
|
|
logger.error(f"❌ 외부 서비스 연결 실패: {str(e)}")
|
|
logger.warning("⚠️ 일부 기능이 제한될 수 있습니다.")
|
|
|
|
# API 엔드포인트 정보 출력
|
|
logger.info(f"📝 API 문서: http://{settings.host}:{settings.port}/api/missions/docs")
|
|
logger.info(f"🎯 미션 추천 API: http://{settings.host}:{settings.port}/api/missions/recommend")
|
|
logger.info(f"🎉 미션 축하 API: http://{settings.host}:{settings.port}/api/missions/celebrate")
|
|
logger.info(f"🔔 유사 미션 소식 API: http://{settings.host}:{settings.port}/api/missions/similar-news")
|
|
logger.info(f"📊 사용자 벡터 저장 API: http://{settings.host}:{settings.port}/api/missions/upsert-vector")
|
|
logger.info(f"🔬 건강 진단 API: http://{settings.host}:{settings.port}/api/health/diagnosis")
|
|
logger.info(f"💬 건강 상담 API: http://{settings.host}:{settings.port}/api/chat/consultation")
|
|
|
|
|
|
@app.on_event("shutdown")
|
|
async def shutdown_event():
|
|
logger.info("🛑 HealthSync AI 서비스 종료 중...")
|
|
|
|
# 외부 서비스 연결 해제
|
|
try:
|
|
if redis_client._connected:
|
|
await redis_client.disconnect()
|
|
logger.info("✅ Redis 연결 해제 완료")
|
|
except Exception as e:
|
|
logger.error(f"❌ Redis 연결 해제 실패: {str(e)}")
|
|
|
|
logger.info("🛑 HealthSync AI 서비스 종료 완료") |