refactor: 설정 중앙화 및 FastAPI lifespan 적용
- 모든 IP, 경로, 포트 설정을 으로 이동하여 중앙 관리 - 하드코딩된 값을 제거하고 를 통해 설정을 동적으로 로드 - FastAPI의 구식 를 최신 이벤트 핸들러로 교체 - 코드의 유지보수성 및 확장성 향상
This commit is contained in:
@@ -24,5 +24,19 @@
|
|||||||
"html_template": "modern",
|
"html_template": "modern",
|
||||||
"include_toc": true,
|
"include_toc": true,
|
||||||
"include_summary": 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
|
import subprocess
|
||||||
|
|
||||||
# 실제 네트워크 설정
|
# 실제 네트워크 설정
|
||||||
MAC_MINI_IP = "192.168.1.122"
|
MAC_MINI_IP = "192.168.1.227"
|
||||||
NAS_IP = "192.168.1.227"
|
NAS_IP = "192.168.1.122"
|
||||||
|
|
||||||
# NAS 마운트 경로 (Finder에서 연결 시 생성되는 경로)
|
# NAS 마운트 경로 (Finder에서 연결 시 생성되는 경로)
|
||||||
NAS_MOUNT_POINT = Path("/Volumes/DS1525+")
|
NAS_MOUNT_POINT = Path("/Volumes/DS1525+")
|
||||||
|
|||||||
@@ -1,46 +1,29 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
Mac Mini (192.168.1.122) FastAPI + DS1525+ (192.168.1.227) 연동
|
Mac Mini FastAPI + DS1525+ 연동
|
||||||
백그라운드 AI 서비스 및 대시보드 통합 버전
|
백그라운드 AI 서비스 및 대시보드 통합 버전 (v2.1 - 설정 중앙화 및 Lifespan 적용)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from contextlib import asynccontextmanager
|
||||||
from fastapi import FastAPI, File, UploadFile, HTTPException, BackgroundTasks, Request
|
from fastapi import FastAPI, File, UploadFile, HTTPException, BackgroundTasks, Request
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from fastapi.responses import HTMLResponse, FileResponse, JSONResponse
|
from fastapi.responses import HTMLResponse, JSONResponse
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
|
||||||
import uuid
|
import uuid
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, List, Optional
|
from typing import Dict
|
||||||
import time
|
import time
|
||||||
import shutil
|
import shutil
|
||||||
from dataclasses import dataclass, asdict
|
|
||||||
import aiofiles
|
import aiofiles
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import subprocess
|
import subprocess
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
# 백그라운드 AI 서비스 임포트
|
# 중앙 설정 로더 및 AI 서비스 임포트
|
||||||
|
from config_loader import settings
|
||||||
from background_ai_service import ai_service
|
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(
|
logging.basicConfig(
|
||||||
level=logging.INFO,
|
level=logging.INFO,
|
||||||
@@ -48,17 +31,65 @@ logging.basicConfig(
|
|||||||
)
|
)
|
||||||
logger = logging.getLogger(__name__)
|
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(
|
app = FastAPI(
|
||||||
title="AI 번역 시스템 with 대시보드",
|
title="AI 번역 시스템 with 대시보드",
|
||||||
description=f"Mac Mini ({MAC_MINI_IP}) + DS1525+ ({NAS_IP}) 연동 + 실시간 모니터링",
|
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")
|
app.mount("/static", StaticFiles(directory=str(LOCAL_WORK_PATH / "static")), name="static")
|
||||||
templates = Jinja2Templates(directory=str(LOCAL_WORK_PATH / "templates"))
|
templates = Jinja2Templates(directory=str(LOCAL_WORK_PATH / "templates"))
|
||||||
|
|
||||||
# 작업 상태 관리 (백그라운드 서비스와 연동)
|
# 작업 상태 관리
|
||||||
processing_jobs: Dict[str, Dict] = {}
|
processing_jobs: Dict[str, Dict] = {}
|
||||||
|
|
||||||
def check_nas_connection():
|
def check_nas_connection():
|
||||||
@@ -99,54 +130,30 @@ def check_nas_connection():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
return {"status": "error", "error": str(e)}
|
return {"status": "error", "error": str(e)}
|
||||||
|
|
||||||
@app.on_event("startup")
|
def create_nas_folders():
|
||||||
async def startup_event():
|
"""NAS에 필요한 폴더 구조 자동 생성"""
|
||||||
"""서버 시작시 전체 시스템 상태 확인 및 백그라운드 서비스 시작"""
|
try:
|
||||||
logger.info(f"🚀 Mac Mini AI 번역 서버 시작 (v2.0)")
|
current_month = datetime.now().strftime("%Y-%m")
|
||||||
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']}")
|
|
||||||
|
|
||||||
# 필요한 폴더 구조 자동 생성
|
folders_to_create = [
|
||||||
try:
|
NAS_ORIGINALS_PATH / current_month / "pdfs",
|
||||||
current_month = datetime.now().strftime("%Y-%m")
|
NAS_ORIGINALS_PATH / current_month / "docs",
|
||||||
|
NAS_ORIGINALS_PATH / current_month / "txts",
|
||||||
folders_to_create = [
|
NAS_TRANSLATED_PATH / current_month / "english-to-korean",
|
||||||
NAS_ORIGINALS_PATH / current_month / "pdfs",
|
NAS_TRANSLATED_PATH / current_month / "japanese-to-korean",
|
||||||
NAS_ORIGINALS_PATH / current_month / "docs",
|
NAS_TRANSLATED_PATH / current_month / "korean-only",
|
||||||
NAS_ORIGINALS_PATH / current_month / "txts",
|
NAS_STATIC_HOSTING_PATH / "docs",
|
||||||
NAS_TRANSLATED_PATH / current_month / "english-to-korean",
|
NAS_STATIC_HOSTING_PATH / "assets",
|
||||||
NAS_TRANSLATED_PATH / current_month / "japanese-to-korean",
|
NAS_METADATA_PATH / "processing-logs"
|
||||||
NAS_TRANSLATED_PATH / current_month / "korean-only",
|
]
|
||||||
NAS_STATIC_HOSTING_PATH / "docs",
|
|
||||||
NAS_STATIC_HOSTING_PATH / "assets",
|
for folder in folders_to_create:
|
||||||
NAS_METADATA_PATH / "processing-logs"
|
folder.mkdir(parents=True, exist_ok=True)
|
||||||
]
|
|
||||||
|
logger.info(f"✅ 폴더 구조 확인/생성 완료")
|
||||||
for folder in folders_to_create:
|
|
||||||
folder.mkdir(parents=True, exist_ok=True)
|
except Exception as e:
|
||||||
|
logger.warning(f"⚠️ 폴더 생성 실패: {e}")
|
||||||
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. 연결 후 서버 재시작")
|
|
||||||
|
|
||||||
# ==========================================
|
# ==========================================
|
||||||
# 기존 엔드포인트들
|
# 기존 엔드포인트들
|
||||||
@@ -392,9 +399,9 @@ async def save_processing_metadata(job_id: str, original_path: Path, html_path:
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import uvicorn
|
import uvicorn
|
||||||
|
|
||||||
logger.info(f"🚀 Mac Mini AI 번역 서버 with 대시보드")
|
logger.info(f"🚀 Mac Mini AI 번역 서버 with 대시보드 (v2.1)")
|
||||||
logger.info(f"📡 서버 주소: http://{MAC_MINI_IP}:8080")
|
logger.info(f"📡 서버 주소: http://{MAC_MINI_IP}:{SERVER_PORT}")
|
||||||
logger.info(f"📊 대시보드: http://{MAC_MINI_IP}:8080/dashboard")
|
logger.info(f"📊 대시보드: http://{MAC_MINI_IP}:{SERVER_PORT}/dashboard")
|
||||||
logger.info(f"📁 NAS 주소: {NAS_IP}")
|
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