refactor: 설정 중앙화 및 FastAPI lifespan 적용

- 모든 IP, 경로, 포트 설정을 으로 이동하여 중앙 관리
- 하드코딩된 값을 제거하고 를 통해 설정을 동적으로 로드
- FastAPI의 구식 를 최신  이벤트 핸들러로 교체
- 코드의 유지보수성 및 확장성 향상
This commit is contained in:
hyungi
2025-07-25 06:53:27 +09:00
parent 7d13f8f4c3
commit a00c6268ee
4 changed files with 167 additions and 79 deletions

View File

@@ -24,5 +24,19 @@
"html_template": "modern",
"include_toc": true,
"include_summary": true
},
"network": {
"mac_mini_ip": "192.168.1.122",
"nas_ip": "192.168.1.227",
"server_port": 8080
},
"paths": {
"nas_mount_point": "/Volumes/DS1525+",
"document_upload_base": "Document-upload",
"originals": "originals",
"translated": "translated",
"static_hosting": "static-hosting",
"metadata": "metadata",
"local_work_path": "~/Scripts/nllb-translation-system"
}
}

67
src/config_loader.py Normal file
View File

@@ -0,0 +1,67 @@
#!/usr/bin/env python3
"""
설정 파일(settings.json) 로더
프로젝트 전체에서 사용되는 설정을 중앙에서 관리하고 제공합니다.
"""
import json
from pathlib import Path
from typing import Dict, Any
class ConfigLoader:
def __init__(self, config_path: str = "config/settings.json"):
self.config_path = Path(config_path)
self.config = self._load_config()
def _load_config(self) -> Dict[str, Any]:
"""JSON 설정 파일을 읽어 딕셔너리로 반환합니다."""
if not self.config_path.exists():
raise FileNotFoundError(f"설정 파일을 찾을 수 없습니다: {self.config_path}")
with open(self.config_path, 'r', encoding='utf-8') as f:
config_data = json.load(f)
# 경로 설정에서 '~'를 실제 홈 디렉토리로 확장
if 'paths' in config_data:
for key, value in config_data['paths'].items():
if isinstance(value, str) and value.startswith('~/'):
config_data['paths'][key] = str(Path.home() / value[2:])
return config_data
def get_section(self, section_name: str) -> Dict[str, Any]:
"""설정의 특정 섹션을 반환합니다."""
return self.config.get(section_name, {})
@property
def network_config(self) -> Dict[str, Any]:
return self.get_section("network")
@property
def paths_config(self) -> Dict[str, Any]:
return self.get_section("paths")
@property
def models_config(self) -> Dict[str, Any]:
return self.get_section("models")
# 전역 설정 인스턴스 생성
# 프로젝트 어디서든 `from config_loader import settings`로 불러와 사용 가능
settings = ConfigLoader()
if __name__ == "__main__":
# 설정 로더 테스트
print("✅ 설정 로더 테스트")
print("-" * 30)
network = settings.network_config
print(f"네트워크 설정: {network}")
print(f" - 서버 IP: {network.get('mac_mini_ip')}")
print(f" - 서버 포트: {network.get('server_port')}")
paths = settings.paths_config
print(f"경로 설정: {paths}")
print(f" - 로컬 작업 경로: {paths.get('local_work_path')}")
print("-" * 30)
print("설정 로드 완료!")

View File

@@ -21,8 +21,8 @@ from datetime import datetime
import subprocess
# 실제 네트워크 설정
MAC_MINI_IP = "192.168.1.122"
NAS_IP = "192.168.1.227"
MAC_MINI_IP = "192.168.1.227"
NAS_IP = "192.168.1.122"
# NAS 마운트 경로 (Finder에서 연결 시 생성되는 경로)
NAS_MOUNT_POINT = Path("/Volumes/DS1525+")

View File

@@ -1,46 +1,29 @@
#!/usr/bin/env python3
"""
Mac Mini (192.168.1.122) FastAPI + DS1525+ (192.168.1.227) 연동
백그라운드 AI 서비스 및 대시보드 통합 버전
Mac Mini FastAPI + DS1525+ 연동
백그라운드 AI 서비스 및 대시보드 통합 버전 (v2.1 - 설정 중앙화 및 Lifespan 적용)
"""
from contextlib import asynccontextmanager
from fastapi import FastAPI, File, UploadFile, HTTPException, BackgroundTasks, Request
from fastapi.templating import Jinja2Templates
from fastapi.staticfiles import StaticFiles
from fastapi.responses import HTMLResponse, FileResponse, JSONResponse
from fastapi.responses import HTMLResponse, JSONResponse
import asyncio
import json
import uuid
from pathlib import Path
from typing import Dict, List, Optional
from typing import Dict
import time
import shutil
from dataclasses import dataclass, asdict
import aiofiles
from datetime import datetime
import subprocess
import logging
# 백그라운드 AI 서비스 임포트
# 중앙 설정 로더 및 AI 서비스 임포트
from config_loader import settings
from background_ai_service import ai_service
# 실제 네트워크 설정
MAC_MINI_IP = "192.168.1.122"
NAS_IP = "192.168.1.227"
# NAS 마운트 경로 (Finder에서 연결 시 생성되는 경로)
NAS_MOUNT_POINT = Path("/Volumes/DS1525+")
DOCUMENT_UPLOAD_BASE = NAS_MOUNT_POINT / "Document-upload"
# 세부 경로들
NAS_ORIGINALS_PATH = DOCUMENT_UPLOAD_BASE / "originals"
NAS_TRANSLATED_PATH = DOCUMENT_UPLOAD_BASE / "translated"
NAS_STATIC_HOSTING_PATH = DOCUMENT_UPLOAD_BASE / "static-hosting"
NAS_METADATA_PATH = DOCUMENT_UPLOAD_BASE / "metadata"
# 로컬 작업 디렉토리
LOCAL_WORK_PATH = Path.home() / "Scripts" / "nllb-translation-system"
# 로깅 설정
logging.basicConfig(
level=logging.INFO,
@@ -48,17 +31,65 @@ logging.basicConfig(
)
logger = logging.getLogger(__name__)
# 설정에서 값 불러오기
network_cfg = settings.network_config
paths_cfg = settings.paths_config
MAC_MINI_IP = network_cfg.get("mac_mini_ip")
NAS_IP = network_cfg.get("nas_ip")
SERVER_PORT = network_cfg.get("server_port")
NAS_MOUNT_POINT = Path(paths_cfg.get("nas_mount_point"))
DOCUMENT_UPLOAD_BASE = NAS_MOUNT_POINT / paths_cfg.get("document_upload_base")
NAS_ORIGINALS_PATH = DOCUMENT_UPLOAD_BASE / paths_cfg.get("originals")
NAS_TRANSLATED_PATH = DOCUMENT_UPLOAD_BASE / paths_cfg.get("translated")
NAS_STATIC_HOSTING_PATH = DOCUMENT_UPLOAD_BASE / paths_cfg.get("static_hosting")
NAS_METADATA_PATH = DOCUMENT_UPLOAD_BASE / paths_cfg.get("metadata")
LOCAL_WORK_PATH = Path(paths_cfg.get("local_work_path"))
@asynccontextmanager
async def lifespan(app: FastAPI):
"""FastAPI 라이프사이클 이벤트 핸들러"""
logger.info(f"🚀 Mac Mini AI 번역 서버 시작 (v2.1)")
logger.info(f"📍 Mac Mini IP: {MAC_MINI_IP}")
logger.info(f"📍 NAS IP: {NAS_IP}")
logger.info("-" * 50)
# 백그라운드 AI 서비스 시작
await ai_service.start_service()
# NAS 연결 및 폴더 구조 확인
nas_status = check_nas_connection()
if nas_status["status"] == "connected":
logger.info(f"✅ NAS 연결 정상: {nas_status['mount_point']}")
create_nas_folders()
else:
logger.error(f"❌ NAS 연결 실패: {nas_status['error']}")
logger.info("해결 방법:")
logger.info("1. NAS 전원 및 네트워크 상태 확인")
logger.info("2. Finder에서 DS1525+ 수동 연결:")
logger.info(f" - 이동 → 서버에 연결 → smb://{NAS_IP}")
logger.info("3. 연결 후 서버 재시작")
yield
# 종료 시 실행될 코드 (필요 시)
logger.info("👋 서버 종료.")
app = FastAPI(
title="AI 번역 시스템 with 대시보드",
description=f"Mac Mini ({MAC_MINI_IP}) + DS1525+ ({NAS_IP}) 연동 + 실시간 모니터링",
version="2.0.0"
version="2.1.0",
lifespan=lifespan
)
# 정적 파일 및 템플릿
app.mount("/static", StaticFiles(directory=str(LOCAL_WORK_PATH / "static")), name="static")
templates = Jinja2Templates(directory=str(LOCAL_WORK_PATH / "templates"))
# 작업 상태 관리 (백그라운드 서비스와 연동)
# 작업 상태 관리
processing_jobs: Dict[str, Dict] = {}
def check_nas_connection():
@@ -99,54 +130,30 @@ def check_nas_connection():
except Exception as e:
return {"status": "error", "error": str(e)}
@app.on_event("startup")
async def startup_event():
"""서버 시작시 전체 시스템 상태 확인 및 백그라운드 서비스 시작"""
logger.info(f"🚀 Mac Mini AI 번역 서버 시작 (v2.0)")
logger.info(f"📍 Mac Mini IP: {MAC_MINI_IP}")
logger.info(f"📍 NAS IP: {NAS_IP}")
logger.info("-" * 50)
# 백그라운드 AI 서비스 시작
await ai_service.start_service()
# NAS 연결 상태 확인
nas_status = check_nas_connection()
if nas_status["status"] == "connected":
logger.info(f"✅ NAS 연결 정상: {nas_status['mount_point']}")
def create_nas_folders():
"""NAS에 필요한 폴더 구조 자동 생성"""
try:
current_month = datetime.now().strftime("%Y-%m")
# 필요한 폴더 구조 자동 생성
try:
current_month = datetime.now().strftime("%Y-%m")
folders_to_create = [
NAS_ORIGINALS_PATH / current_month / "pdfs",
NAS_ORIGINALS_PATH / current_month / "docs",
NAS_ORIGINALS_PATH / current_month / "txts",
NAS_TRANSLATED_PATH / current_month / "english-to-korean",
NAS_TRANSLATED_PATH / current_month / "japanese-to-korean",
NAS_TRANSLATED_PATH / current_month / "korean-only",
NAS_STATIC_HOSTING_PATH / "docs",
NAS_STATIC_HOSTING_PATH / "assets",
NAS_METADATA_PATH / "processing-logs"
]
for folder in folders_to_create:
folder.mkdir(parents=True, exist_ok=True)
logger.info(f"✅ 폴더 구조 확인/생성 완료")
except Exception as e:
logger.warning(f"⚠️ 폴더 생성 실패: {e}")
else:
logger.error(f"❌ NAS 연결 실패: {nas_status['error']}")
logger.info("해결 방법:")
logger.info("1. NAS 전원 및 네트워크 상태 확인")
logger.info("2. Finder에서 DS1525+ 수동 연결:")
logger.info(f" - 이동 → 서버에 연결 → smb://{NAS_IP}")
logger.info("3. 연결 후 서버 재시작")
folders_to_create = [
NAS_ORIGINALS_PATH / current_month / "pdfs",
NAS_ORIGINALS_PATH / current_month / "docs",
NAS_ORIGINALS_PATH / current_month / "txts",
NAS_TRANSLATED_PATH / current_month / "english-to-korean",
NAS_TRANSLATED_PATH / current_month / "japanese-to-korean",
NAS_TRANSLATED_PATH / current_month / "korean-only",
NAS_STATIC_HOSTING_PATH / "docs",
NAS_STATIC_HOSTING_PATH / "assets",
NAS_METADATA_PATH / "processing-logs"
]
for folder in folders_to_create:
folder.mkdir(parents=True, exist_ok=True)
logger.info(f"✅ 폴더 구조 확인/생성 완료")
except Exception as e:
logger.warning(f"⚠️ 폴더 생성 실패: {e}")
# ==========================================
# 기존 엔드포인트들
@@ -392,9 +399,9 @@ async def save_processing_metadata(job_id: str, original_path: Path, html_path:
if __name__ == "__main__":
import uvicorn
logger.info(f"🚀 Mac Mini AI 번역 서버 with 대시보드")
logger.info(f"📡 서버 주소: http://{MAC_MINI_IP}:8080")
logger.info(f"📊 대시보드: http://{MAC_MINI_IP}:8080/dashboard")
logger.info(f"🚀 Mac Mini AI 번역 서버 with 대시보드 (v2.1)")
logger.info(f"📡 서버 주소: http://{MAC_MINI_IP}:{SERVER_PORT}")
logger.info(f"📊 대시보드: http://{MAC_MINI_IP}:{SERVER_PORT}/dashboard")
logger.info(f"📁 NAS 주소: {NAS_IP}")
uvicorn.run(app, host="0.0.0.0", port=8080)
uvicorn.run(app, host="0.0.0.0", port=SERVER_PORT)