# 감정 상태, 감정 업데이트, decay 처리 # portfolio/npc_social_network/npc/npc_emotion.py from .emotion_config import EMOTION_LIST, EMOTION_DECAY_RATE, EMOTION_CATEGORY_MAP class EmotionManager: def __init__(self, decay_rate, personality=None, initial_baseline=None): # 내부: float 감정 수치 관리용 버퍼 self._emotion_buffer = {emo: 0.0 for emo in EMOTION_LIST} # baseline 버퍼 추가 self._baseline_buffer = initial_baseline or {emo: 0.0 for emo in EMOTION_LIST} # 감정별 회복 속도 (ms 단위가 아닌 단위당 감소 속도) self.decay_rate = decay_rate self.personality = personality or {} def update_emotion(self, emotion: str, strength: float = 1.0, context: str = "general"): """ 특정 감정을 감정 상태에 반영 (카테고리 기반) """ if emotion not in self._emotion_buffer: print(f"[경고] '{emotion}'은(는) 정의된 감정이 아닙니다.") return # 개성 계수 반영 multiplier = self.personality.get("sensitive", 1.0) category = EMOTION_CATEGORY_MAP.get(emotion, None) if category == "core": multiplier *= self.personality.get("affect_bias", 1.0) elif category == "social": # 사회적 감정은 social context에서만 반영 if context != "social": return # 무시 multiplier *= self.personality.get("social_bias", 1.0) elif category == "cognitive": multiplier *= self.personality.get("cognitive_bias", 1.0) elif category == "complex": multiplier *= self.personality.get("complex_bias", 1.0) # 감정 반영 self._emotion_buffer[emotion] += strength * multiplier # clip 적용 (최대 100) self._emotion_buffer[emotion] = min(max(0.0, self._emotion_buffer[emotion]), 100.0) def decay_emotions(self): """ 시간이 지남에 따라 모든 감정이 서서히 감소 """ for emotion in EMOTION_LIST: rate = self.decay_rate.get(emotion, 0.5) modifier = 1.0 - self.personality.get("stoic", 0.0) self._emotion_buffer[emotion] = max(0.0, self._emotion_buffer[emotion] - rate * modifier) def get_state(self): """ 감정 상태 반환 (출력용, 정수로 변환) """ return {emo: int(self._emotion_buffer[emo]) for emo in EMOTION_LIST} def get_dominant_emotion(self, layer: str = None): """ 현재 가장 강한 감정 반환 (전체 감정 중 최대값 1개) """ if layer: # 특정 layer 대상 layer_emotions = [emo for emo, cat in EMOTION_CATEGORY_MAP.items() if cat == layer] if not layer_emotions: return None dominant_emo, score = max( ((emo, self._emotion_buffer[emo]) for emo in layer_emotions), key=lambda x: x[1], default=(None, 0.0) ) if score == 0.0: return None return dominant_emo else: # 전체 대상 dominant_emo, score = max(self._emotion_buffer.items(), key=lambda x:x[1]) if score == 0.0: return None return dominant_emo def get_buffer(self): """ emotion_buffer 복사본 반환 """ return self._emotion_buffer.copy() def get_current_emotions_state(self): """ 현재 감정 상태 반환 (dict) """ return self._emotion_buffer def get_top_emotions(self, top_n=5): """ 현재 감정 버퍼에서 상위 N개 감정 반환 :return: List of (emotion_name, value) tuples """ # 정렬 후 상위 N개 반환 sorted_emotions = sorted(self._emotion_buffer.items(), key=lambda x: x[1], reverse=True) top_emotions = sorted_emotions[:top_n] return top_emotions def set_baseline(self, baseline_buffer): """ baseline buffer를 외부에서 설정 (npc_base.py 초기화 시 사용) """ self._baseline_buffer = baseline_buffer.copy()