From a00c6268eecb6fcdd774ca23f052e07c955730f8 Mon Sep 17 00:00:00 2001 From: hyungi Date: Fri, 25 Jul 2025 06:53:27 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20=EC=84=A4=EC=A0=95=20=EC=A4=91?= =?UTF-8?q?=EC=95=99=ED=99=94=20=EB=B0=8F=20FastAPI=20lifespan=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 모든 IP, 경로, 포트 설정을 으로 이동하여 중앙 관리 - 하드코딩된 값을 제거하고 를 통해 설정을 동적으로 로드 - FastAPI의 구식 를 최신 이벤트 핸들러로 교체 - 코드의 유지보수성 및 확장성 향상 --- config/settings.json | 14 +++ src/config_loader.py | 67 ++++++++++++++ src/fastapi_final.py | 4 +- src/fastapi_with_dashboard.py | 161 ++++++++++++++++++---------------- 4 files changed, 167 insertions(+), 79 deletions(-) create mode 100644 src/config_loader.py diff --git a/config/settings.json b/config/settings.json index c1fc8f7..b6a7900 100644 --- a/config/settings.json +++ b/config/settings.json @@ -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" } } diff --git a/src/config_loader.py b/src/config_loader.py new file mode 100644 index 0000000..8059af0 --- /dev/null +++ b/src/config_loader.py @@ -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("설정 로드 완료!") \ No newline at end of file diff --git a/src/fastapi_final.py b/src/fastapi_final.py index 15ecce1..78e5378 100644 --- a/src/fastapi_final.py +++ b/src/fastapi_final.py @@ -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+") diff --git a/src/fastapi_with_dashboard.py b/src/fastapi_with_dashboard.py index 71d5d76..8dff7b4 100644 --- a/src/fastapi_with_dashboard.py +++ b/src/fastapi_with_dashboard.py @@ -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) \ No newline at end of file + uvicorn.run(app, host="0.0.0.0", port=SERVER_PORT) \ No newline at end of file