hgzero/ai-python/main.py
Minseo-Jo 92c18f71c0 AI 서비스 재시작 스크립트 개선 및 STT 서비스 수정
- AI 서비스 reload 설정 비활성화 (포트 충돌 방지)
- start.sh 삭제 및 restart.sh로 대체
- STT 서비스 로깅 및 WebSocket 핸들러 개선
- 회의 안건 섹션 마이그레이션 SQL 추가

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-29 10:51:19 +09:00

129 lines
3.4 KiB
Python

"""AI Service - FastAPI 애플리케이션"""
import logging
import asyncio
import uvicorn
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from contextlib import asynccontextmanager
from app.config import get_settings
from app.api.v1 import suggestions
from app.services.eventhub_service import start_eventhub_listener
# 로깅 설정
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
settings = get_settings()
@asynccontextmanager
async def lifespan(app: FastAPI):
"""애플리케이션 생명주기 관리"""
logger.info("=" * 60)
logger.info(f"AI Service (Python) 시작 - Port: {settings.port}")
logger.info(f"Claude Model: {settings.claude_model}")
logger.info(f"Redis: {settings.redis_host}:{settings.redis_port}")
logger.info("=" * 60)
# Event Hub 리스너 시작 (백그라운드 태스크)
logger.info("Event Hub 리스너 백그라운드 시작...")
asyncio.create_task(start_eventhub_listener())
yield
logger.info("AI Service 종료")
# FastAPI 애플리케이션
app = FastAPI(
title=settings.app_name,
version="1.0.0",
description="""
## 실시간 AI 제안사항 서비스 (Python)
회의 중 실시간으로 텍스트를 분석하여 AI 제안사항을 생성하고 SSE(Server-Sent Events)로 스트리밍합니다.
### 주요 기능
- 🎯 실시간 회의 분석
- 🤖 Claude AI 기반 제안사항 생성
- 📡 SSE 스트리밍
- ⚡ Redis 캐시 연동
### 인증
현재 버전은 인증이 필요하지 않습니다.
""",
lifespan=lifespan,
docs_url="/swagger-ui.html", # Spring Boot 스타일
redoc_url="/redoc",
openapi_url="/v3/api-docs", # Spring Boot 스타일 OpenAPI JSON
openapi_tags=[
{
"name": "AI Suggestions",
"description": "AI 제안사항 실시간 스트리밍 API"
},
{
"name": "Health",
"description": "서비스 상태 확인"
}
]
)
# CORS 설정 (개발 환경: 모든 origin 허용)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # 개발 환경에서 모든 origin 허용
allow_credentials=False, # allow_origins=["*"]일 때는 False여야 함
allow_methods=["*"],
allow_headers=["*"],
)
# 라우터 등록
app.include_router(
suggestions.router,
prefix="/api/ai/suggestions",
tags=["AI Suggestions"]
)
@app.get("/")
async def root():
"""루트 엔드포인트"""
return {
"service": settings.app_name,
"version": "1.0.0",
"status": "running",
"endpoints": {
"test": "/api/ai/suggestions/test",
"stream": "/api/ai/suggestions/meetings/{meeting_id}/stream",
"swagger": "/swagger-ui.html"
}
}
@app.get("/health", tags=["Health"])
async def health_check():
"""
헬스 체크 엔드포인트
Kubernetes liveness/readiness probe에서 사용
"""
return {
"status": "healthy",
"service": settings.app_name,
"port": settings.port
}
if __name__ == "__main__":
uvicorn.run(
"main:app",
host=settings.host,
port=settings.port,
reload=False, # reload=True는 포트 충돌 발생 가능
log_level=settings.log_level.lower()
)