kcg-ai-monitoring/prediction/config.py
htlee e2fc355b2c feat: S2 prediction 분석 엔진 모노레포 이식
iran prediction 47개 Python 파일을 prediction/ 디렉토리로 복제:
- algorithms/ 14개 분석 알고리즘 (어구추론, 다크베셀, 스푸핑, 환적, 위험도 등)
- pipeline/ 7단계 분류 파이프라인
- cache/vessel_store (24h 슬라이딩 윈도우)
- db/ 어댑터 (snpdb 원본조회, kcgdb 결과저장)
- chat/ AI 채팅 (Ollama, 후순위)
- data/ 정적 데이터 (기선, 특정어업수역 GeoJSON)

config.py를 kcgaidb로 재구성 (DB명, 사용자, 비밀번호)
DB 연결 검증 완료 (kcgaidb 37개 테이블 접근 확인)
Makefile에 dev-prediction / dev-all 타겟 추가
CLAUDE.md에 prediction 섹션 추가

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 12:56:51 +09:00

67 lines
1.8 KiB
Python

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
# 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}'