Files
2025-08-11 18:56:38 +09:00

137 lines
4.5 KiB
Python

import logging
from contextlib import asynccontextmanager
from config.setting import SUMMARY_HTML_DIR
from fastapi import Depends, FastAPI, HTTPException, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from prometheus_fastapi_instrumentator import Instrumentator
from routers import *
from services.api_key_service import load_api_keys_from_file
from utils.checking_keys import get_admin_key, get_api_key
from utils.minio_utils import get_minio_client
from utils.redis_utils import get_redis_client
logging.basicConfig(
level=logging.INFO, format="%(asctime)s [%(levelname)s] %(name)s - %(message)s"
)
@asynccontextmanager
async def lifespan(app: FastAPI):
# 애플리케이션 시작 시 파일에서 API 키 로드
print("Loading API keys from file...")
load_api_keys_from_file()
yield
app = FastAPI(
title="LLM GATEWAY",
description="LLM 모델이 업로드된 문서를 분석하여 구조화된 JSON으로 변환하는 API 서비스입니다.",
docs_url=None,
lifespan=lifespan,
)
app.add_middleware(
CORSMiddleware,
allow_origins=[
"http://172.16.42.101",
"http://gsim.hanmaceng.co.kr",
"http://gsim.hanmaceng.co.kr:6464",
"https://overseas.projectmastercloud.com",
"http://localhost:5174", # 이민규 연구원
],
allow_origin_regex=r"http://(localhost:5174|172\.16\.\d{1,3}\.\d{1,3}|gsim\.hanmaceng\.co\.kr)(:\d+)?",
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# API 키 검증을 위한 의존성 설정
api_key_dependency = Depends(get_api_key)
admin_key_dependency = Depends(get_admin_key)
# ✅ Prometheus Metrics Exporter 활성화
instrumentator = Instrumentator()
# 커스텀 라벨 콜백 함수
def custom_labels(info):
# info.request 는 Starlette의 Request 객체
return {"job_id": info.request.headers.get("X-Job-ID", "unknown")}
instrumentator = Instrumentator()
instrumentator.add(custom_labels)
instrumentator.instrument(app).expose(app)
# ✅ 생성된 요약 HTML 결과 파일 서빙 경로 등록
app.mount(
"/view/generated_html", StaticFiles(directory=SUMMARY_HTML_DIR), name="summary_html"
)
app.mount(
"/static", StaticFiles(directory="/workspace/workspace/static"), name="static"
)
# 🔑 가이드북, 상태 확인, 문서는 API 키 없이 접근 가능
app.include_router(guide_router) # ✅ 가이드북 HTML 서빙
# ⭐️ 관리자 전용: API 키 관리 라우터 (마스터 키 필요, 문서에서 숨김)
app.include_router(
api_key_router,
dependencies=[admin_key_dependency],
include_in_schema=False,
)
# 🔑 아래의 모든 라우터는 일반 API 키 검증이 필요
app.include_router(model_router, dependencies=[api_key_dependency]) # ✅ 모델 관리 API
app.include_router(
download_router, dependencies=[api_key_dependency]
) # ✅ 다운로드 API
app.include_router(
general_router, dependencies=[api_key_dependency]
) # ✅ 일반 추론 API
app.include_router(
extract_router, dependencies=[api_key_dependency]
) # ✅ 문서 추출 API
app.include_router(dummy_router, dependencies=[api_key_dependency]) # ✅ 더미 API
app.include_router(ocr_router, dependencies=[api_key_dependency]) # ✅ OCR API
app.include_router(
stt_router, dependencies=[api_key_dependency], include_in_schema=False
) # STT로 호출하는 기능 임시 제외 - 2025.07.29
app.include_router(llm_summation, dependencies=[api_key_dependency])
app.include_router(yolo_router, dependencies=[api_key_dependency])
app.include_router(stt_router, dependencies=[api_key_dependency]) # ✅
# /docs URL에 커스터마이징된 Swagger UI 연결
app.mount(
"/docs", StaticFiles(directory="/workspace/swagger-ui", html=True), name="docs"
)
@app.get("/health/API")
async def health_check():
"""애플리케이션 상태 확인"""
return {"status": "API ok"}
@app.get("/health/Redis")
def redis_health_check():
client = get_redis_client()
if client is None:
raise HTTPException(status_code=500, detail="Redis connection failed")
try:
client.ping()
return {"status": "Redis ok"}
except Exception:
raise HTTPException(status_code=500, detail="Redis ping failed")
@app.get("/health/MinIO")
def minio_health_check():
try:
client = get_minio_client()
return {"status": "MinIO ok"}
except Exception as e:
raise HTTPException(
status_code=500, detail=f"MinIO health check failed: {str(e)}"
)