# 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 서비스 종료 완료")