refactor: 설정 중앙화 및 FastAPI lifespan 적용
- 모든 IP, 경로, 포트 설정을 으로 이동하여 중앙 관리 - 하드코딩된 값을 제거하고 를 통해 설정을 동적으로 로드 - FastAPI의 구식 를 최신 이벤트 핸들러로 교체 - 코드의 유지보수성 및 확장성 향상
This commit is contained in:
@@ -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
67
src/config_loader.py
Normal 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("설정 로드 완료!")
|
||||
@@ -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+")
|
||||
|
||||
@@ -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)
|
||||
Reference in New Issue
Block a user