import re from typing import Optional from pydantic_settings import BaseSettings class Settings(BaseSettings): # snpdb (궤적 데이터 소스) SNPDB_HOST: str = '211.208.115.83' SNPDB_PORT: int = 5432 SNPDB_NAME: str = 'snpdb' SNPDB_USER: str = 'snp' SNPDB_PASSWORD: str = 'snp#8932' # kcgdb (분석 결과 저장 — kcgaidb 통합 DB) KCGDB_HOST: str = '211.208.115.83' KCGDB_PORT: int = 5432 KCGDB_NAME: str = 'kcgaidb' KCGDB_SCHEMA: str = 'kcg' KCGDB_USER: str = 'kcg-app' KCGDB_PASSWORD: str = 'Kcg2026ai' # 스케줄러 SCHEDULER_INTERVAL_MIN: int = 5 # 인메모리 캐시 CACHE_WINDOW_HOURS: int = 24 INITIAL_LOAD_HOURS: int = 24 STATIC_INFO_REFRESH_MIN: int = 60 PERMIT_REFRESH_MIN: int = 30 SNPDB_SAFE_DELAY_MIN: int = 12 SNPDB_BACKFILL_BUCKETS: int = 3 # 파이프라인 TRAJECTORY_HOURS: int = 6 MMSI_PREFIX: str = '412' MIN_TRAJ_POINTS: int = 100 # signal-batch API (gc-signal-batch — 정적정보 보강용) SIGNAL_BATCH_URL: str = 'http://192.168.1.18:18090/signal-batch' SIGNAL_BATCH_TIMEOUT: int = 60 # Ollama (LLM) OLLAMA_BASE_URL: str = 'http://localhost:11434' OLLAMA_MODEL: str = 'qwen3:14b' # CPU-only: 14b 권장, GPU 있으면 32b OLLAMA_TIMEOUT_SEC: int = 300 # Redis REDIS_HOST: str = 'localhost' REDIS_PORT: int = 6379 REDIS_PASSWORD: str = '' # 로깅 LOG_LEVEL: str = 'INFO' model_config = {'env_file': '.env', 'env_file_encoding': 'utf-8', 'extra': 'ignore'} settings = Settings() _SQL_IDENTIFIER = re.compile(r'^[A-Za-z_][A-Za-z0-9_]*$') def qualified_table(table_name: str, schema: Optional[str] = None) -> str: resolved_schema = schema or settings.KCGDB_SCHEMA if not _SQL_IDENTIFIER.fullmatch(resolved_schema): raise ValueError(f'Invalid schema name: {resolved_schema!r}') if not _SQL_IDENTIFIER.fullmatch(table_name): raise ValueError(f'Invalid table name: {table_name!r}') return f'{resolved_schema}.{table_name}'