import logging import sys from contextlib import asynccontextmanager from fastapi import BackgroundTasks, FastAPI from config import settings from db import kcgdb, snpdb from scheduler import get_last_run, run_analysis_cycle, start_scheduler, stop_scheduler logging.basicConfig( level=getattr(logging, settings.LOG_LEVEL, logging.INFO), format='%(asctime)s [%(levelname)s] %(name)s: %(message)s', stream=sys.stdout, ) logger = logging.getLogger(__name__) @asynccontextmanager async def lifespan(application: FastAPI): from cache.vessel_store import vessel_store logger.info('starting KCG Prediction Service') snpdb.init_pool() kcgdb.init_pool() # 인메모리 캐시 초기 로드 (24시간) logger.info('loading initial vessel data (%dh)...', settings.INITIAL_LOAD_HOURS) vessel_store.load_initial(settings.INITIAL_LOAD_HOURS) logger.info('initial load complete: %s', vessel_store.stats()) start_scheduler() yield stop_scheduler() snpdb.close_pool() kcgdb.close_pool() logger.info('KCG Prediction Service stopped') app = FastAPI( title='KCG Prediction Service', version='2.1.0', lifespan=lifespan, ) # AI 해양분석 채팅 라우터 from chat.router import router as chat_router app.include_router(chat_router) @app.get('/health') def health_check(): from cache.vessel_store import vessel_store return { 'status': 'ok', 'snpdb': snpdb.check_health(), 'kcgdb': kcgdb.check_health(), 'store': vessel_store.stats(), } @app.get('/api/v1/analysis/status') def analysis_status(): return get_last_run() @app.post('/api/v1/analysis/trigger') def trigger_analysis(background_tasks: BackgroundTasks): background_tasks.add_task(run_analysis_cycle) return {'message': 'analysis cycle triggered'}