""" 유연한 지식(Context) 제공자 패턴 모듈. LLM Worker가 추출한 키워드를 받아 관련 지식 DB(또는 Mock)에서 추가 컨텍스트 딕셔너리를 반환합니다. 향후 RAG 서버로 코드 수정 없이 확장할 수 있습니다. """ from abc import ABC, abstractmethod import logging from typing import List, Dict, Any from app.core.config import settings logger = logging.getLogger("uvicorn.error") class ContextProvider(ABC): """지식 제공자 추상 클래스""" @abstractmethod def get_extended_context(self, keywords: List[str]) -> List[Dict[str, Any]]: pass class MockContextProvider(ContextProvider): """개발 및 데모를 위한 하드코딩된 Mock 지식 제공자""" def __init__(self): # 데모용 지식 딕셔너리 self._mock_db = { "검측차": { "title": "검측차 (Inspection Train)", "desc": "선로, 전차선, 신호 등의 상태를 주행하며 실시간으로 점검하는 특수 목적 차량. 주로 야간 작업에 투입됨." }, "다대포": { "title": "다대포 해수욕장역 (Dadaepo Beach)", "desc": "부산 도시철도 1호선의 종착역. 회차선 및 차량 유치선 존재." }, "tcms": { "title": "TCMS (열차종합제어장치)", "desc": "Train Control and Monitoring System. 열차의 각종 주요 기기를 제어하고 실시간 상태를 감시, 진단하는 시스템." }, "관제": { "title": "관제 센터 (Control Center)", "desc": "전체 철도 시스템의 운행 상황을 실시간 모니터링하고 통제, 지시를 내리는 종합 사령실." } } def get_extended_context(self, keywords: List[str]) -> List[Dict[str, Any]]: results = [] found_keys = set() for kw in keywords: kw_lower = kw.lower() for key, val in self._mock_db.items(): if key in found_keys: continue # 키워드가 DB 키에 포함되거나, DB 키가 키워드에 포함된 경우 매칭 if key.lower() in kw_lower or kw_lower in key.lower(): results.append({ "keyword": key, "title": val["title"], "desc": val["desc"] }) found_keys.add(key) return results class CSVContextProvider(ContextProvider): """ [Chapter 6.1] 대규모 도메인 사전(CSV) 기반의 지식 제공자. O(1) 검색 최적화 및 동음이의어(리스트 Value) 중복 처리를 허용합니다. """ def get_extended_context(self, keywords: List[str]) -> List[Dict[str, Any]]: from app.core.dictionary import RAILWAY_TERMS_DICT results = [] found_keys = set() for kw in keywords: kw_clean = kw.strip() if not kw_clean: continue entries = RAILWAY_TERMS_DICT.get(kw_clean) if entries: for entry in entries: # 동음이의어 방지용 해시 (keyword+desc) unique_hash = f"{kw_clean}_{entry['desc'][:20]}" if unique_hash not in found_keys: results.append({ "keyword": entry.get("category", "일반 용어"), # Frontend tag "title": kw_clean, # Frontend subtitle "desc": entry.get("desc", "") # Frontend text }) found_keys.add(unique_hash) return results def get_context_service() -> ContextProvider: """설정된 CONTEXT_PROVIDER 환경 변수에 따라 적절한 구현체를 반환하는 팩토리 함수""" provider_type = getattr(settings, "CONTEXT_PROVIDER", "mock").strip().lower() if provider_type == "mock": return MockContextProvider() elif provider_type == "csv": return CSVContextProvider() # elif provider_type == "rag": # return RAGContextProvider() # 향후 구축 시 연결 else: logger.warning(f"[Context Service] 알 수 없는 프로바이더 '{provider_type}', Mock Provider로 폴백합니다.") return MockContextProvider() # 전역 싱글톤 인스턴스 (워커에서 Import 용) context_service = get_context_service()