feat: rag 서비스 Event Hub 연동 및 연관 회의록 API 추가

This commit is contained in:
djeon
2025-10-29 15:29:40 +09:00
parent 5859b1c498
commit ad7975efbd
20 changed files with 2855 additions and 22 deletions
+206
View File
@@ -0,0 +1,206 @@
"""
Redis 캐싱 유틸리티
"""
import redis
import json
import logging
from typing import Optional, Any
from functools import wraps
logger = logging.getLogger(__name__)
class RedisCache:
"""Redis 캐싱 클래스"""
def __init__(
self,
host: str = "localhost",
port: int = 6379,
db: int = 0,
password: Optional[str] = None,
decode_responses: bool = True
):
"""
초기화
Args:
host: Redis 호스트
port: Redis 포트
db: Redis DB 번호
password: Redis 비밀번호
decode_responses: 응답 디코딩 여부
"""
try:
self.client = redis.Redis(
host=host,
port=port,
db=db,
password=password,
decode_responses=decode_responses
)
# 연결 테스트
self.client.ping()
logger.info(f"Redis 연결 성공: {host}:{port}")
except Exception as e:
logger.warning(f"Redis 연결 실패: {str(e)} - 캐싱 비활성화")
self.client = None
def get(self, key: str) -> Optional[Any]:
"""
캐시에서 값 조회
Args:
key: 캐시 키
Returns:
캐시된 값 또는 None
"""
if not self.client:
return None
try:
value = self.client.get(key)
if value:
logger.debug(f"캐시 HIT: {key}")
return json.loads(value)
logger.debug(f"캐시 MISS: {key}")
return None
except Exception as e:
logger.error(f"캐시 조회 실패 ({key}): {str(e)}")
return None
def set(self, key: str, value: Any, ttl: int = 3600) -> bool:
"""
캐시에 값 저장
Args:
key: 캐시 키
value: 저장할 값
ttl: 만료 시간 (초)
Returns:
성공 여부
"""
if not self.client:
return False
try:
serialized = json.dumps(value, ensure_ascii=False)
self.client.setex(key, ttl, serialized)
logger.debug(f"캐시 저장: {key} (TTL: {ttl}s)")
return True
except Exception as e:
logger.error(f"캐시 저장 실패 ({key}): {str(e)}")
return False
def delete(self, key: str) -> bool:
"""
캐시 삭제
Args:
key: 캐시 키
Returns:
성공 여부
"""
if not self.client:
return False
try:
self.client.delete(key)
logger.debug(f"캐시 삭제: {key}")
return True
except Exception as e:
logger.error(f"캐시 삭제 실패 ({key}): {str(e)}")
return False
def delete_pattern(self, pattern: str) -> int:
"""
패턴 매칭으로 여러 캐시 삭제
Args:
pattern: 캐시 키 패턴 (예: "minutes:*")
Returns:
삭제된 키 개수
"""
if not self.client:
return 0
try:
keys = self.client.keys(pattern)
if keys:
count = self.client.delete(*keys)
logger.info(f"캐시 일괄 삭제: {count}개 키 ({pattern})")
return count
return 0
except Exception as e:
logger.error(f"캐시 패턴 삭제 실패 ({pattern}): {str(e)}")
return 0
def exists(self, key: str) -> bool:
"""
캐시 존재 여부 확인
Args:
key: 캐시 키
Returns:
존재 여부
"""
if not self.client:
return False
try:
return self.client.exists(key) > 0
except Exception as e:
logger.error(f"캐시 존재 확인 실패 ({key}): {str(e)}")
return False
def cached(prefix: str, ttl: int = 3600, key_builder=None):
"""
함수 결과 캐싱 데코레이터
Args:
prefix: 캐시 키 prefix
ttl: 만료 시간 (초)
key_builder: 캐시 키 생성 함수 (선택사항)
Example:
@cached(prefix="minutes:", ttl=1800)
def get_minutes_by_id(minutes_id: str):
...
"""
def decorator(func):
@wraps(func)
def wrapper(self, *args, **kwargs):
# Redis 캐시 인스턴스 확인
cache = getattr(self, '_cache', None)
if not cache or not cache.client:
return func(self, *args, **kwargs)
# 캐시 키 생성
if key_builder:
cache_key = key_builder(*args, **kwargs)
else:
# 기본: 첫 번째 인자를 키로 사용
cache_key = f"{prefix}{args[0] if args else ''}"
# 캐시 조회
cached_value = cache.get(cache_key)
if cached_value is not None:
return cached_value
# 함수 실행
result = func(self, *args, **kwargs)
# 결과 캐싱
if result is not None:
cache.set(cache_key, result, ttl)
return result
return wrapper
return decorator