humanda5 commited on
Commit
0482473
·
1 Parent(s): 5430701

감정 모델 리팩토링 테스트

Browse files
npc_social_network/npc/emotion_config.py CHANGED
@@ -1,161 +1,138 @@
1
  # portfolio/npc_social_network/npc/emotion_config.py
2
  # 감정 초기 상태 및 decay 설정
3
 
4
- # 고차원 감정 상태 정의 (GoEmotions 기반, 보여주기용, 지금 내용은 엉망)
5
- # 1) 친구가 생일 파티를 열어줬다.( 기쁨 + ?? + 흥분)
6
- # 2) 과거 좋았던 일이 생각난다 (기쁨 + ?? + 몰입)
7
- # 3) 슬픈 일이지만, 어쩔 수 없다고 생각한다. (슬픔 + 공감 + 회의)
8
- # 4) 내가 싫어하는 사람이 사고를 당했다는 소식을 들어 기쁘다. (기쁨 + ?? + ??)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
- EMOTION_STATE_TEMPLATE = {
11
- # 기본 정서 (긍정)
12
- "core_positive":{
13
- "joy": 0, # 기쁨
14
- "satisfaction": 0, # 만족
15
- "gratitude": 0, # 감사
16
- "calm": 0, # 평온
17
- "anticipation": 0, # 기대
18
- "pride": 0, # 자부심
19
- "connectedness": 0 # 유대감
20
- },
21
- # 기본 정서 (부정)
22
- "core_negative": {
23
- "sadness": 0, # 슬픔
24
- "anger": 0, # 분노
25
- "anxiety": 0, # 불안
26
- "disgust": 0, # 혐오
27
- "fear": 0, # 공포
28
- "regret": 0, # 후회
29
- "frustration": 0 # 좌절
30
- },
31
- # 사회적 감정
32
- "social_emotion": {
33
- "jealousy": 0, # 질투
34
- "shame": 0, # 수치심
35
- "guilt": 0, # 죄책감
36
- "compassion": 0, # 동정심
37
- "awe": 0, # 경외심
38
- "empathy": 0 # 공감
39
- },
40
- # 인지적 상태
41
- "cognitive_state": {
42
- "confusion": 0, # 혼란
43
- "nervousness": 0, # 긴장
44
- "apathy": 0, # 무관심
45
- "excitement": 0, # 흥분
46
- "immersion": 0, # 몰입
47
- "skepticism": 0 # 회의
48
- }
 
 
 
 
 
 
 
 
49
  }
50
 
51
  # 감정별 회복 속도 (ms 단위가 아닌 단위당 감소 속도)
52
  EMOTION_DECAY_RATE = {
53
- # 기본 정서 (긍정)
54
- "joy": 0.7, # 기쁨
55
- "satisfaction": 0.8, # 만족
56
- "gratitude": 0.4, # 감사
57
- "calm": 0.2, # 평온
58
- "anticipation": 0.6, # 기대
59
- "pride": 0.8, # 자부심
60
- "connectedness": 0.5, # 유대감
61
-
62
- # 기본 정서 (부정) - 느림
63
- "sadness": 0.2, # 슬픔
64
- "anger": 0.5, # 분노
65
- "anxiety": 0.4, # 불안
66
- "disgust": 0.8, # 혐오
67
- "fear": 0.6, # 공포
68
- "regret": 0.3, # 후회
69
- "frustration": 0.5, # 좌절
70
-
71
- # 사회적 감정
72
- "jealousy": 0.4, # 질투
73
- "shame": 0.4, # 수치심
74
- "guilt": 0.4, # 죄책감
75
- "compassion": 0.8, # 동정심
76
- "awe": 0.8, # 경외심
77
- "empathy": 1, # 공감
78
-
79
- # 인지적 상태
80
- "confusion": 0.8, # 혼란
81
- "nervousness": 0.7, # 긴장
82
- "apathy": 0.4, # 무관심
83
- "excitement": 0.9, # 흥분
84
- "immersion": 0.6, # 몰입
85
- "skepticism": 0.5, # 회의
 
 
 
 
 
 
 
 
 
 
 
 
86
  }
87
 
88
  # 개성 템플릿(0~1 범위)
89
  PERSONALITY_TEMPLATE = {
90
- "sensitive" : 0.8, # 감정 반응 강도 증가
91
- "stoic": 0.2, # 감정 반응 둔화
92
- "positive_bias": 0.6, # 긍정 감정에 민감
93
- "negative_bias": 0.4, # 부정 감정에 민감
94
- "sociality" : 0.5, # 사회적 감정 민감
95
- }
96
-
97
- # 긍정/부정 감정 전역 리스트
98
- AFFECT_EMOTIONS = {
99
- "positive": ["joy", "satisfaction", "gratitude", "calm", "anticipation", "pride", "connectedness"],
100
- "negative": ["sadness", "anger", "anxiety", "disgust", "fear", "regret", "frustration"]
101
- }
102
-
103
- # 사회적 감정 전역 리스트
104
- SOCIAL_EMOTIONS = [
105
- "jealousy", "shame", "guilt", "compassion", "awe", "empathy"
106
- ]
107
-
108
- # 인지적 감정 전역 리스트
109
- COGNITIVE_STATES = [
110
- "confusion", "nervousness", "apathy", "excitement", "immersion", "skepticism"
111
- ]
112
-
113
-
114
- """
115
- 🌟 균형 잡힌 복합 감정 모델 정의( 이쪽으로 변형하는게 더 고차원 일 것 같음, ComplexEmotions)
116
- 1️⃣ 기본 감정 (Core Emotions)
117
- Joy (기쁨)
118
- Sadness (슬픔)
119
- Anger (분노)
120
- Fear (공포)
121
- Disgust (혐오)
122
- Surprise (놀람)
123
-
124
- 2️⃣ 사회적 감정 (Social Emotions)
125
- Gratitude (감사)
126
- Shame (수치심)
127
- Guilt (죄책감)
128
- Pride (자부심)
129
- Jealousy (질투)
130
- Compassion (연민/동정)
131
- Love (사랑/애정)
132
- Admiration (존경/감탄)
133
- Empathy (공감)
134
- Awe (경외심)
135
- Attachment (애착)
136
- Comfort (위로 추구)
137
-
138
- 3️⃣ 인지적 상태 (Cognitive States)
139
- Anticipation (기대)
140
- Curiosity (호기심)
141
- Confusion (혼란)
142
- Interest (흥미)
143
- Engagement (몰입)
144
- Boredom (지루함)
145
- Relief (안도)
146
- Anxiety (불안 / 긴장)
147
- Calm (평온)
148
-
149
- Skepticism (회의)
150
-
151
- 4️⃣ 복합 감정 (Mixed / Complex Emotions)
152
- Nostalgia (향수)
153
- Bittersweet (달콤쌉싸름함)
154
- Schadenfreude (남의 불행에서 느끼는 기쁨)
155
- Hope (희망)
156
- Resentment (분개)
157
- Anticipatory joy (기대 속의 기쁨)
158
- Regret (후회)
159
- Rumination (반추)
160
- Groundedness (안정감)
161
- """
 
1
  # portfolio/npc_social_network/npc/emotion_config.py
2
  # 감정 초기 상태 및 decay 설정
3
 
4
+ # 고차원 감정 상태 정의
5
+ # 균형 잡힌 복합 감정 모델 정의를 위해 GoEmotions 바탕으로 설계 (ComplexEmotions이라 명명)
6
+ EMOTION_LIST = [
7
+ # Core Emotions (기본 감정)
8
+ # 기쁨, 슬픔, 분노, 공포, 혐오,
9
+ # 놀람, 중립
10
+ "joy", "sadness", "anger", "fear", "disgust",
11
+ "surprise", "neutral",
12
+
13
+ # Social Emotions (사회적 감정)
14
+ # 감사, 수치심, 죄책감, 자부심, 질투, 연민/동정,
15
+ # 사랑/애정, 존경/감탄, 공감, 경외심, 애착, 위로 추구
16
+ "gratitude", "shame", "guilt", "pride", "jealousy", "compassion",
17
+ "love", "admiration", "empathy", "awe", "attachment", "comfort",
18
+
19
+ # Cognitive States (인지적 상태)
20
+ # 기대, 호기심, 혼란, 흥미, 몰입
21
+ # 지루함, 안도, 불안/긴장, 평온, 회의
22
+ "anticipation", "curiosity", "confusion", "interest", "engagement",
23
+ "boredom", "relief", "anxiety", "calm", "skepticism",
24
+
25
+ # Complex Emotions (복합 감정)
26
+ # 향수, 달콤쌉싸름함, 남의 불행에서 느끼는 행복, 희망, 분개
27
+ # 기대 속의 기쁨, 후회, 반추, 안정감
28
+ "nostalgia", "bittersweet", "schadenfreude", "hope", "resentment",
29
+ "anticipatory_joy", "regret", "rumination", "groundedness",
30
+ ]
31
 
32
+ # 감정 : 카테고리 맵
33
+ EMOTION_CATEGORY_MAP = {
34
+ # Core
35
+ "joy": "core",
36
+ "sadness": "core",
37
+ "anger": "core",
38
+ "fear": "core",
39
+ "disgust": "core",
40
+ "surprise": "core",
41
+ "neutral": "core",
42
+
43
+ # Social
44
+ "gratitude": "social",
45
+ "shame": "social",
46
+ "guilt": "social",
47
+ "pride": "social",
48
+ "jealousy": "social",
49
+ "compassion": "social",
50
+ "love": "social",
51
+ "admiration": "social",
52
+ "empathy": "social",
53
+ "awe": "social",
54
+ "attachment": "social",
55
+ "comfort": "social",
56
+
57
+ # Cognitive
58
+ "anticipation": "cognitive",
59
+ "curiosity": "cognitive",
60
+ "confusion": "cognitive",
61
+ "interest": "cognitive",
62
+ "engagement": "cognitive",
63
+ "boredom": "cognitive",
64
+ "relief": "cognitive",
65
+ "anxiety": "cognitive",
66
+ "calm": "cognitive",
67
+ "skepticism": "cognitive",
68
+
69
+ # Complex
70
+ "nostalgia": "complex",
71
+ "bittersweet": "complex",
72
+ "schadenfreude": "complex",
73
+ "hope": "complex",
74
+ "resentment": "complex",
75
+ "anticipatory_joy": "complex",
76
+ "regret": "complex",
77
+ "rumination": "complex",
78
+ "groundedness": "complex",
79
  }
80
 
81
  # 감정별 회복 속도 (ms 단위가 아닌 단위당 감소 속도)
82
  EMOTION_DECAY_RATE = {
83
+ # Core (기본 감정)
84
+ "joy": 0.6, # 기쁨
85
+ "sadness": 0.3, # 슬픔
86
+ "anger": 0.4, # 분노
87
+ "fear": 0.4, # 공포
88
+ "disgust": 0.5, # 혐오
89
+ "surprise": 0.8, # 놀람
90
+ "neutral": 1.2, # 중립
91
+
92
+ # Social (사회적 감정)
93
+ "gratitude": 0.6, # 감사
94
+ "shame": 0.3, # 수치심
95
+ "guilt": 0.3, # 죄책감
96
+ "pride": 0.6, # 자부심
97
+ "jealousy": 0.4, # 질투
98
+ "compassion": 0.7, # 연민/동정
99
+ "love": 0.2, # 사랑/애정
100
+ "admiration": 0.7, # 존경/감탄
101
+ "empathy": 0.7, # 공감
102
+ "awe": 0.8, # 경외심
103
+ "attachment": 0.2, # 애착
104
+ "comfort": 0.6, # 위로 추구
105
+
106
+ # Cognitive (인지적 상태)
107
+ "anticipation": 0.6, # 기대
108
+ "curiosity": 0.8, # 호기심
109
+ "confusion": 0.5, # 혼란
110
+ "interest": 0.8, # 흥미
111
+ "engagement": 0.7, # 몰입
112
+ "boredom": 0.4, # 지루함
113
+ "relief": 0.8, # 안도
114
+ "anxiety": 0.5, # 불안/긴장
115
+ "calm": 0.7, # 평온
116
+ "skepticism": 0.5, # 회의
117
+
118
+ # Complex (복합 감정)
119
+ "nostalgia": 0.2, # 향수
120
+ "bittersweet": 0.3, # 달콤쌉싸름함
121
+ "schadenfreude": 0.5, # 남의 불행에서 느끼는 기쁨
122
+ "hope": 0.6, # 희망
123
+ "resentment": 0.4, # 분개
124
+ "anticipatory_joy": 0.6, # 기대 속의 기쁨
125
+ "regret": 0.3, # 후회
126
+ "rumination": 0.3, # 반추
127
+ "groundedness": 0.8 # 안정감
128
  }
129
 
130
  # 개성 템플릿(0~1 범위)
131
  PERSONALITY_TEMPLATE = {
132
+ "affect_bias": 1.0, # Core emotion 영향
133
+ "social_bias": 1.0, # Social emotion 영향
134
+ "cognitive_bias": 1.0, # Cognitive state 영향
135
+ "complex_bias": 1.0, # Complex emotion 영향
136
+ "sensitive": 1.0, # 전체 감정 반응 강도
137
+ "stoic": 0.0 # 전체 감정 둔화 정도 (감쇠 가속도에 영향)
138
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
npc_social_network/npc/npc_base.py CHANGED
@@ -2,12 +2,21 @@
2
  from .npc_memory import Memory, MemoryStore
3
  from .npc_emotion import EmotionManager
4
  from .npc_behavior import BehaviorManager
5
- from .emotion_config import EMOTION_STATE_TEMPLATE, EMOTION_DECAY_RATE, PERSONALITY_TEMPLATE
6
  from .npc_relationship import RelationshipManager
7
 
8
- # 감정의 기본 성향 정의
9
- positive_emotions = ["joy", "gratitude", "connectedness", "empathy", "pride"]
10
- negative_emotions = ["anger", "disgust", "fear", "regret", "shame"]
 
 
 
 
 
 
 
 
 
11
 
12
  # NPC 클래스 정의
13
  class NPC:
@@ -26,12 +35,11 @@ class NPC:
26
  # npc 기억
27
  self.memory_store = MemoryStore()
28
  # 감정 상태 등 감정 관리자 초기화
29
- self.emotion_state = EMOTION_STATE_TEMPLATE
30
  self.emotion_decay_rate = EMOTION_DECAY_RATE
31
  self.personality = personality or PERSONALITY_TEMPLATE
32
  self.relationships = RelationshipManager() # 관계 시스템 초기화
33
 
34
- self.emotion = EmotionManager(self.emotion_state, self.emotion_decay_rate, self.personality)
35
 
36
  # 행동 관리자
37
  self.behavior = BehaviorManager()
@@ -66,7 +74,18 @@ class NPC:
66
  감정 상태와 직업에 따른 복합 행동 시퀀스 기반 대사 생성
67
  """
68
  composite = self.get_composite_emotion_state(top_n=3) # 상위 3개 감정 사용
69
- return self.behavior.perform_sequence(self.name, self.job, composite)
 
 
 
 
 
 
 
 
 
 
 
70
 
71
  def remember(self, content: str, importance: int = 5, emotion: str = None, strength: float = 1.0):
72
  """
@@ -132,11 +151,11 @@ class NPC:
132
  base = 5.0 # 기본 영향력
133
 
134
  # 감정 종류별 base 수정
135
- if emotion in positive_emotions:
136
  base += 2.0
137
  # 긍정 감정은 positive = True일 때만 +로 반영, positive = False일 경우 최소한으로 영향
138
  return base if positive else 0.0
139
- elif emotion in negative_emotions:
140
  base += 3.0
141
  # 부정 감정은 positive = False일 때만 -로 반영, positive = True일 경우 최소한으로 영향
142
  return -base if not positive else 0.0
@@ -163,23 +182,15 @@ class NPC:
163
  for mem in memories[-5:]: # 최근 5개 기억 기준
164
  if mem.importance >= 7: # 중요 기억만 반영
165
  # 감정 성향에 따라 positive 결정 및 영향력 계산
166
- if mem.emotion in positive_emotions:
167
- delta = self._get_emotion_influence(mem.emotion, positive=True if mem.importance >= 7 else False)
168
- elif mem.emotion in negative_emotions:
169
- delta = self._get_emotion_influence(mem.emotion, positive=False if mem.importance >= 4 else True)
170
- else:
171
- delta = 0.0
172
  base_influence += delta
173
 
174
- # 현재 감정 상태 영향 추가 반영
175
  if dominant_emotion:
176
- if dominant_emotion in positive_emotions:
177
- emo_influence = self._get_emotion_influence(dominant_emotion, positive=True)
178
- elif dominant_emotion in negative_emotions:
179
- emo_influence = self._get_emotion_influence(dominant_emotion, positive=False)
180
- else:
181
- emo_influence = 0.0
182
-
183
  base_influence += emo_influence * 0.5 # 현재 감정은 보조적 영향
184
 
185
  # 관계 갱신
 
2
  from .npc_memory import Memory, MemoryStore
3
  from .npc_emotion import EmotionManager
4
  from .npc_behavior import BehaviorManager
5
+ from .emotion_config import EMOTION_CATEGORY_MAP, EMOTION_DECAY_RATE, PERSONALITY_TEMPLATE
6
  from .npc_relationship import RelationshipManager
7
 
8
+ # 관계에 긍/부정 영향으로 해석할 감정 매핑 정의 (논문 설계 기반 적용)
9
+ POSITIVE_RELATION_EMOTIONS = [
10
+ "joy", "surprise", "gratitude", "pride", "love",
11
+ "admiration", "empathy", "comfort", "hope", "anticipatory_joy",
12
+ "calm", "engagement", "relief", "interest",
13
+ ]
14
+
15
+ NEGATIVE_RELATION_EMOTIONS = [
16
+ "sadness", "anger", "fear", "disgust", "shame",
17
+ "guilt", "jealousy", "resentment", "regret", "schadenfreude",
18
+ "anxiety", "confusion", "skepticism", "boredom",
19
+ ]
20
 
21
  # NPC 클래스 정의
22
  class NPC:
 
35
  # npc 기억
36
  self.memory_store = MemoryStore()
37
  # 감정 상태 등 감정 관리자 초기화
 
38
  self.emotion_decay_rate = EMOTION_DECAY_RATE
39
  self.personality = personality or PERSONALITY_TEMPLATE
40
  self.relationships = RelationshipManager() # 관계 시스템 초기화
41
 
42
+ self.emotion = EmotionManager(self.emotion_decay_rate, self.personality)
43
 
44
  # 행동 관리자
45
  self.behavior = BehaviorManager()
 
74
  감정 상태와 직업에 따른 복합 행동 시퀀스 기반 대사 생성
75
  """
76
  composite = self.get_composite_emotion_state(top_n=3) # 상위 3개 감정 사용
77
+ behavior_output, behavior_trace = self.behavior.perform_sequence(
78
+ self.name, self.job, emotion_buffer=self._emotion_buffer, return_trace = True
79
+ )
80
+ # Behavior Trace를 Memory에 기록
81
+ memory_entry = Memory(
82
+ content=f"행동 수행: {behavior_trace}",
83
+ importance=5, # 기본 importance (튜닝 가능)
84
+ emotion = self.emotion.get_dominant_emotion(),
85
+ behavior_trace = behavior_trace
86
+ )
87
+ self.memory_store.add_memory(memory_entry)
88
+ return behavior_output
89
 
90
  def remember(self, content: str, importance: int = 5, emotion: str = None, strength: float = 1.0):
91
  """
 
151
  base = 5.0 # 기본 영향력
152
 
153
  # 감정 종류별 base 수정
154
+ if emotion in POSITIVE_RELATION_EMOTIONS:
155
  base += 2.0
156
  # 긍정 감정은 positive = True일 때만 +로 반영, positive = False일 경우 최소한으로 영향
157
  return base if positive else 0.0
158
+ elif emotion in NEGATIVE_RELATION_EMOTIONS:
159
  base += 3.0
160
  # 부정 감정은 positive = False일 때만 -로 반영, positive = True일 경우 최소한으로 영향
161
  return -base if not positive else 0.0
 
182
  for mem in memories[-5:]: # 최근 5개 기억 기준
183
  if mem.importance >= 7: # 중요 기억만 반영
184
  # 감정 성향에 따라 positive 결정 및 영향력 계산
185
+ # 중요 기억만 반영
186
+ is_positive = mem.emotion in POSITIVE_RELATION_EMOTIONS
187
+ delta = self._get_emotion_influence(mem.emotion, positive=is_positive)
 
 
 
188
  base_influence += delta
189
 
190
+ # 현재 감정 상태 영향 추가 반영 (보조적 반영)
191
  if dominant_emotion:
192
+ is_positive = dominant_emotion in POSITIVE_RELATION_EMOTIONS
193
+ emo_influence = self._get_emotion_influence(dominant_emotion, positive=is_positive)
 
 
 
 
 
194
  base_influence += emo_influence * 0.5 # 현재 감정은 보조적 영향
195
 
196
  # 관계 갱신
npc_social_network/npc/npc_behavior.py CHANGED
@@ -1,83 +1,168 @@
1
  # 감정-행동 연동 매핑 및 행동 생성
2
  # portfolio/npc_social_network/npc/npc_behavior.py
3
 
 
 
4
  class BehaviorManager:
5
  def __init__(self):
6
  self.mapping = {
7
- # 기본 정서 (긍정)
8
- "joy": "jump", # 기쁨 : 점프 뛰다
9
- "satisfaction": "nod", # 만족 : 고개를 끄덕이다
10
- "gratitude": "thank", # 감사 : 감사하다
11
- "calm": "relax", # 평온 : 진정하다
12
- "anticipation": "prepare", # 기대 : 준비하다
13
- "pride": "show_off", # 자부심 : 자랑하다
14
- "connectedness": "wave", # 유대감 : 손을 흔들다
15
 
16
- # 기본 정서 (부정) - 느림
17
- "sadness": "sit_down", # 슬픔 : 주저 앉는다
18
- "anger": "shout", # 분노 : 소리치다.
19
- "anxiety": "look_around", # 불안 : 주위를 살핀다
20
- "disgust": "avoid", # 혐오 : 피하다
21
- "fear": "run_away", # 공포 : 도망치다
22
- "regret": "look_down", # 후회 : 아래를 보다
23
- "frustration": "sigh", # 좌절 : 한숨 쉬다
 
 
 
 
 
24
 
25
- # 사회적 감정
26
- "jealousy": "glare", # 질투 : 노려보다
27
- "shame": "hide_face", # 수치심 : 얼굴을 감추다
28
- "guilt": "apologize", # 죄책감 : 미안하다고 말함
29
- "compassion": "console", # 동정심 : 위로하는 행동
30
- "awe": "gasp", # 경외심 : 감탄하며 숨을 들이쉼
31
- "empathy": "listen_carefully", # 공감 : 공감하며 집중해서 경청
 
 
 
 
32
 
33
- # 인지적 상태
34
- "confusion": "scratch_head",# 혼란 : 머리를 긁적이다
35
- "nervousness": "fidget", # 긴장 : 불안해서 몸을 계속 움직임
36
- "apathy": "idle", # 무관심 : 아무것도 하지 않음
37
- "excitement": "move_fast", # 흥분 : 빠르게 움직이다
38
- "immersion": "focus", # 몰입 : 집중하는 모습
39
- "skepticism": "raise_eyebrow", # 회의 : 의심스러운 듯 눈썹을 찌푸림
 
 
 
40
  }
41
 
42
- def decide_sequence(self, composite_emotions):
 
 
 
 
 
 
 
 
 
43
  """
44
- 복합 감정 상태(composite_emotions: [(emotions, score), ...])에 따른 행동 시퀀스 결정
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  """
46
  sequence = []
47
- for emo, score in composite_emotions:
48
- action = self.mapping.get(emo)
49
- if action:
50
- sequence.append((action, score)) # (행동, 감정 강도 형태로 저장)
 
 
 
51
  return sequence
52
 
53
- def perform_sequence(self, name, job, composite_emotion):
54
  """
55
- 행동 시퀀스를 텍스트로 구성하여 출력
56
  """
57
- sequence = self.decide_sequence(composite_emotion)
 
58
  if not sequence:
59
- return f"{name}은(는) 특별한 행동을 하지 않습니다."
 
 
 
 
60
 
61
  # 행동 텍스트 템플릿
62
  behavior_lines = {
63
- "jump": f"기뻐서 깡충 뜁니다.",
64
- "shout": f"화가 나서 소리를 지릅니다!",
65
- "run_away": f"무서워 도망갑니다!",
66
- "sit_down": f"슬퍼서 주저앉습니다....",
67
- "wave": f"손을 흔듭니다.",
68
- "sigh": f"한숨을 쉽니다...",
69
- "thank": f"감사한 마음을 표현합니다.",
70
- "console": f"상대방을 따듯하게 위로합니다.",
71
- "avoid": f"뒤로 물러서 피하려 합니다.",
 
 
 
 
72
  "show_off": "자랑스러운 모습을 보여줍니다.",
73
- # 나머지는 기본 fallback 사용
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  }
75
 
76
  # 행동 문장 생성
77
  lines = []
 
78
  for action, score in sequence:
79
  msg = behavior_lines.get(action, f"{action} 행동을 합니다.")
80
  lines.append(f"({round(score,1)}) {msg}")
 
81
 
82
  # 직업 라인 추가
83
  job_line = {
@@ -85,5 +170,11 @@ class BehaviorManager:
85
  "blacksmith": "대장간 불도 지펴야죠.",
86
  }.get(job, "오늘도 바쁜 하루네요.")
87
 
 
 
 
88
  # 최종 출력 문장
89
- return f"{name} 행동 시퀀스: \n" + "\n".join(lines) + f"\n{job_line}"
 
 
 
 
1
  # 감정-행동 연동 매핑 및 행동 생성
2
  # portfolio/npc_social_network/npc/npc_behavior.py
3
 
4
+ from .emotion_config import EMOTION_CATEGORY_MAP
5
+
6
  class BehaviorManager:
7
  def __init__(self):
8
  self.mapping = {
9
+ # Core (기본 감정)
10
+ "joy": "jump", # 기쁨 : 점프 뛰다
11
+ "sadness": "sit_down", # 슬픔 : 주저 앉다
12
+ "anger": "shout", # 분노 : 소리치다
13
+ "fear": "run_away", # 공포 : 도망치다
14
+ "disgust": "avoid", # 혐오 : 피하다
15
+ "surprise": "gasp", # 놀람 : 감탄하며 숨을 들이쉼
16
+ "neutral": "idle", # 중립 : 아무것도 하지 않음
17
 
18
+ # Social (사회적 감정)
19
+ "gratitude": "thank", # 감사 : 감사하다
20
+ "shame": "hide_face", # 수치심 : 얼굴을 감추다
21
+ "guilt": "apologize", # 죄책감 : 미안하다고 말함
22
+ "pride": "show_off", # 자부심 : 자랑하다
23
+ "jealousy": "glare", # 질투 : 노려보다
24
+ "compassion": "console", # 연민/동정 : 위로하다
25
+ "love": "embrace", # 사랑/애정 : 포옹하다
26
+ "admiration": "cheer", # 존경/감탄 : 환호하다
27
+ "empathy": "listen_carefully", # 공감 : 집중하다
28
+ "awe": "gasp", # 경외심 : 감탄하며 숨을 들이쉼
29
+ "attachment": "hold_hands", # 애착 : 소유하다
30
+ "comfort": "pat", # 위로 추구 : 토닥거리다
31
 
32
+ # Cognitive (인지적 상태)
33
+ "anticipation": "prepare", # 기대 : 준비하다
34
+ "curiosity": "inspect", # 호기심 : 살펴보다
35
+ "confusion": "scratch_head", # 혼란 : 머리를 긁다
36
+ "interest": "lean_forward", # 흥미 : 집중하다
37
+ "engagement": "focus", # 몰입 : 집중하다
38
+ "boredom": "idle", # 지루함 : 아무것도 하지 않음
39
+ "relief": "exhale", # 안도 : 숨을 내쉬다
40
+ "anxiety": "fidget", # 불안/긴장 : 안절부절 못하다
41
+ "calm": "relax", # 평온 : 진정하다
42
+ "skepticism": "raise_eyebrow", # 회의 : 눈썹을 올리다
43
 
44
+ # Complex (복합 감정)
45
+ "nostalgia": "stare_into_distance", # 향수
46
+ "bittersweet": "smile_then_look_down", # 달콤쌉싸름함
47
+ "schadenfreude": "smirk", # 남의 불행에서 느끼는 기쁨
48
+ "hope": "brighten_up", # 희망
49
+ "resentment": "scowl", # 분개
50
+ "anticipatory_joy": "rub_hands", # 기대 속의 기쁨
51
+ "regret": "look_down", # 후회
52
+ "rumination": "mutter_to_self", # 반추
53
+ "groundedness": "steady_posture", # 안정감
54
  }
55
 
56
+ # Layer 우선 순위 / weight 설정 (튜닝 가능)
57
+ self.layer_priority = ["core", "social", "cognitive", "complex"]
58
+ self.layer_weights = {
59
+ "core" : 1.0,
60
+ "social" : 0.8,
61
+ "cognitive" : 0.6,
62
+ "complex" : 0.4,
63
+ }
64
+
65
+ def get_layer_dominant_emotions(self, buffer):
66
  """
67
+ layer별 dominant emotion 계산
68
+ """
69
+ layer_emotions = {layer: [] for layer in self.layer_priority}
70
+ for emo, val in buffer.items():
71
+ if val > 0:
72
+ layer = EMOTION_CATEGORY_MAP.get(emo)
73
+ if layer:
74
+ layer_emotions[layer].append((emo, val))
75
+
76
+ # 각 layer에서 가장 강한 감정 추출
77
+ layer_dominant = {}
78
+ for layer, emos in layer_emotions.items():
79
+ if emos:
80
+ dominant_emo = max(emos, key=lambda x: x[1])
81
+ layer_dominant[layer] = dominant_emo
82
+
83
+ return layer_dominant
84
+
85
+ def decide_layered_sequence(self, layer_dominant_emotions):
86
+ """
87
+ layer priority + weight 기반 시퀀스 생성
88
  """
89
  sequence = []
90
+ for layer in self.layer_priority:
91
+ if layer in layer_dominant_emotions:
92
+ emo, score = layer_dominant_emotions[layer]
93
+ weighted_score = round(score * self.layer_weights[layer], 2)
94
+ action = self.mapping.get(emo)
95
+ if action:
96
+ sequence.append((action, weighted_score))
97
  return sequence
98
 
99
+ def perform_sequence(self, name, job, emotion_buffer, return_trace=False):
100
  """
101
+ Layer-aware Behavior 시퀀스 구성 + Behavior Trace 반환
102
  """
103
+ layer_dominant_emotions = self.get_layer_dominant_emotions(emotion_buffer)
104
+ sequence = self.decide_layered_sequence(layer_dominant_emotions)
105
  if not sequence:
106
+ behavior_output = f"{name}은(는) 특별한 행동을 하지 않습니다."
107
+ if return_trace:
108
+ return behavior_output, "특별한 행동 없음"
109
+ else:
110
+ return behavior_output
111
 
112
  # 행동 텍스트 템플릿
113
  behavior_lines = {
114
+ # Core
115
+ "jump": "기뻐서 깡충 뜁니다.",
116
+ "sit_down": "슬퍼서 주저앉습니다....",
117
+ "shout": "화가 나서 소리를 지릅니다!",
118
+ "run_away": "무서워 도망갑니다!",
119
+ "avoid": "뒤로 물러서 피하려 합니다.",
120
+ "gasp": "깜짝 놀랍니다.",
121
+ "idle": "가만히 있습니다.",
122
+
123
+ # Social
124
+ "thank": "감사한 마음을 표현합니다.",
125
+ "hide_face": "수치심에 얼굴을 가립니다.",
126
+ "apologize": "미안하다고 말합니다.",
127
  "show_off": "자랑스러운 모습을 보여줍니다.",
128
+ "glare": "상대를 노려봅니다.",
129
+ "console": "상대방을 따뜻하게 위로합니다.",
130
+ "embrace": "상대를 포옹합니다.",
131
+ "cheer": "감탄하며 응원합니다.",
132
+ "listen_carefully": "상대의 말을 집중해서 듣습니다.",
133
+ "hold_hands": "손을 잡습니다.",
134
+ "pat": "가볍게 등을 두드려 위로합니다.",
135
+
136
+ # Cognitive
137
+ "prepare": "무언가를 준비합니다.",
138
+ "inspect": "유심히 관찰합니다.",
139
+ "scratch_head": "머리를 긁적입니다.",
140
+ "lean_forward": "앞으로 숙이며 집중합니다.",
141
+ "focus": "몰입하여 집중합니다.",
142
+ "exhale": "안도하며 숨을 쉽니다.",
143
+ "fidget": "불안하게 몸을 움직입니다.",
144
+ "relax": "평온하게 휴식합니다.",
145
+ "raise_eyebrow": "의심스럽게 눈썹을 치켜뜹니다.",
146
+
147
+ # Complex
148
+ "stare_into_distance": "먼 곳을 바라보며 회상에 잠깁니다.",
149
+ "smile_then_look_down": "미소를 짓다가 고개를 숙입니다.",
150
+ "smirk": "비웃는 표정을 짓습니다.",
151
+ "brighten_up": "기대감에 눈빛이 빛납니다.",
152
+ "scowl": "인상을 찌푸립니다.",
153
+ "rub_hands": "들뜬 마음에 손을 비빕니다.",
154
+ "look_down": "고개를 숙이며 후회합니다.",
155
+ "mutter_to_self": "혼잣말을 중얼거립니다.",
156
+ "steady_posture": "안정된 자세를 유지합니다.",
157
  }
158
 
159
  # 행동 문장 생성
160
  lines = []
161
+ trace_lines = []
162
  for action, score in sequence:
163
  msg = behavior_lines.get(action, f"{action} 행동을 합니다.")
164
  lines.append(f"({round(score,1)}) {msg}")
165
+ trace_lines.append(f"{action}({round(score, 1)})")
166
 
167
  # 직업 라인 추가
168
  job_line = {
 
170
  "blacksmith": "대장간 불도 지펴야죠.",
171
  }.get(job, "오늘도 바쁜 하루네요.")
172
 
173
+ behavior_output = f"{name} 행동 시퀀스: \n" + "\n".join(lines) + f"\n{job_line}"
174
+ behavior_trace = ", ".join(trace_lines)
175
+
176
  # 최종 출력 문장
177
+ if return_trace:
178
+ return behavior_output, behavior_trace
179
+ else:
180
+ return behavior_output
npc_social_network/npc/npc_emotion.py CHANGED
@@ -1,60 +1,83 @@
1
  # 감정 상태, 감정 업데이트, decay 처리
2
  # portfolio/npc_social_network/npc/npc_emotion.py
3
- from .emotion_config import AFFECT_EMOTIONS, SOCIAL_EMOTIONS, COGNITIVE_STATES
4
 
5
  class EmotionManager:
6
- def __init__(self, emotion_state, decay_rate, personality = None):
7
- # 고차원 감정 상태 (GoEmotions 기반)
8
- self.emotion_state = emotion_state
9
  # 감정별 회복 속도 (ms 단위가 아닌 단위당 감소 속도)
10
  self.decay_rate = decay_rate
11
- # 내부: float 감정 수치 관리용 버퍼
12
- self._emotion_buffer = {emo: 0.0 for cat in emotion_state.values() for emo in cat}
13
  self.personality = personality or {}
14
 
15
- # 특정 감정을 감정 상태에 반영 (카테고리 기반)
16
- def update_emotion(self, emotion: str, strength: float = 1.0):
 
 
17
  if emotion not in self._emotion_buffer:
18
  print(f"[경고] '{emotion}'은(는) 정의된 감정이 아닙니다.")
19
  return
20
 
21
  # 개성 계수 반영
22
- multiplier = 1.0
23
- if emotion in AFFECT_EMOTIONS["positive"]:
24
- multiplier *= self.personality.get("positive_bias", 1)
25
- elif emotion in AFFECT_EMOTIONS["negative"]:
26
- multiplier *= self.personality.get("negative_bias", 1)
27
 
28
- # 개성 계수 반영
29
- multiplier *= self.personality.get("sensitive", 1)
 
 
 
 
 
 
 
 
 
 
30
 
 
31
  self._emotion_buffer[emotion] += strength * multiplier
32
- for category in self.emotion_state:
33
- if emotion in self.emotion_state[category]:
34
- self.emotion_state[category][emotion] = int(self._emotion_buffer[emotion])
35
- break
36
 
37
-
38
- # 시간이 지남에 따라 모든 감정이 서서히 감소
39
  def decay_emotion(self):
40
- for emotion, value in self._emotion_buffer.items():
 
 
 
41
  rate = self.decay_rate.get(emotion, 0.5)
42
- modifier = 1.0 - self.personality.get("stoic", 0)
43
- self._emotion_buffer[emotion] = max(0.0, value - rate * modifier)
44
-
45
- for category in self.emotion_state:
46
- for emotion in self.emotion_state[category]:
47
- self.emotion_state[category][emotion] = int(self._emotion_buffer[emotion])
48
 
49
- # 정수 기반 출력용 감정 상태 반환
50
  def get_state(self):
51
- return {cat: {emo: int(self._emotion_buffer[emo]) for emo in emos} for cat, emos in self.emotion_state.items()}
 
 
 
52
 
53
- # 현재 가장 강한 감정 반환 (전체 감정 최댓값 1개)
54
- def get_dominant_emotion(self):
55
- if not self._emotion_buffer:
56
- return "neutral"
57
- return max(self._emotion_buffer.items(), key=lambda x: x[1])[0]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
 
59
  def get_buffer(self):
 
 
 
60
  return self._emotion_buffer.copy()
 
1
  # 감정 상태, 감정 업데이트, decay 처리
2
  # portfolio/npc_social_network/npc/npc_emotion.py
3
+ from .emotion_config import EMOTION_LIST, EMOTION_DECAY_RATE, EMOTION_CATEGORY_MAP
4
 
5
  class EmotionManager:
6
+ def __init__(self, decay_rate, personality = None):
7
+ # 내부: float 감정 수치 관리용 버퍼
8
+ self._emotion_buffer = {emo: 0.0 for emo in EMOTION_LIST}
9
  # 감정별 회복 속도 (ms 단위가 아닌 단위당 감소 속도)
10
  self.decay_rate = decay_rate
 
 
11
  self.personality = personality or {}
12
 
13
+ def update_emotion(self, emotion: str, strength: float = 1.0, context: str = "general"):
14
+ """
15
+ 특정 감정을 감정 상태에 반영 (카테고리 기반)
16
+ """
17
  if emotion not in self._emotion_buffer:
18
  print(f"[경고] '{emotion}'은(는) 정의된 감정이 아닙니다.")
19
  return
20
 
21
  # 개성 계수 반영
22
+ multiplier = self.personality.get("sensitive", 1.0)
 
 
 
 
23
 
24
+ category = EMOTION_CATEGORY_MAP.get(emotion, None)
25
+ if category == "core":
26
+ multiplier *= self.personality.get("affect_bias", 1.0)
27
+ elif category == "social":
28
+ # 사회적 감정은 social context에서만 반영
29
+ if context != "social":
30
+ return # 무시
31
+ multiplier *= self.personality.get("social_bias", 1.0)
32
+ elif category == "cognitive":
33
+ multiplier *= self.personality.get("cognitive_bias", 1.0)
34
+ elif category == "complex":
35
+ multiplier *= self.personality.get("complex_bias", 1.0)
36
 
37
+ # 감정 반영
38
  self._emotion_buffer[emotion] += strength * multiplier
 
 
 
 
39
 
 
 
40
  def decay_emotion(self):
41
+ """
42
+ 시간이 지남에 따라 모든 감정이 서서히 감소
43
+ """
44
+ for emotion in EMOTION_LIST:
45
  rate = self.decay_rate.get(emotion, 0.5)
46
+ modifier = 1.0 - self.personality.get("stoic", 0.0)
47
+ self._emotion_buffer[emotion] = max(0.0, self._emotion_buffer[emotion] - rate * modifier)
 
 
 
 
48
 
 
49
  def get_state(self):
50
+ """
51
+ 감정 상태 반환 (출력용, 정수로 변환)
52
+ """
53
+ return {emo: int(self._emotion_buffer[emo]) for emo in EMOTION_LIST}
54
 
55
+ def get_dominant_emotion(self, layer: str = None):
56
+ """
57
+ 현재 가장 강한 감정 반환 (전체 감정 중 최대값 1개)
58
+ """
59
+ if layer:
60
+ # 특정 layer 대상
61
+ layer_emotions = [emo for emo, cat in EMOTION_CATEGORY_MAP.items() if cat == layer]
62
+ if not layer_emotions:
63
+ return None
64
+ dominant_emo, score = max(
65
+ ((emo, self._emotion_buffer[emo]) for emo in layer_emotions),
66
+ key=lambda x: x[1],
67
+ default=(None, 0.0)
68
+ )
69
+ if score == 0.0:
70
+ return None
71
+ return dominant_emo
72
+ else:
73
+ # 전체 대상
74
+ dominant_emo, score = max(self._emotion_buffer.items(), key=lambda x:x[1])
75
+ if score == 0.0:
76
+ return None
77
+ return dominant_emo
78
 
79
  def get_buffer(self):
80
+ """
81
+ emotion_buffer 복사본 반환
82
+ """
83
  return self._emotion_buffer.copy()
npc_social_network/npc/npc_memory.py CHANGED
@@ -10,13 +10,16 @@ class Memory:
10
  - importance: 중요도 (1~10)
11
  - emotion: 감정 태그 (기쁨, 슬픔, 분노, 중립 등)
12
  - is_long_term: 장기 기억 여부
 
13
  """
14
- def __init__(self, content: str, timestamp: datetime = None, importance: int = 1, emotion: str = "중립"):
 
15
  self.content = content
16
  self.timestamp = timestamp or datetime.now()
17
  self.importance = importance
18
  self.emotion = emotion
19
  self.is_long_term = False
 
20
 
21
 
22
  class MemoryStore:
 
10
  - importance: 중요도 (1~10)
11
  - emotion: 감정 태그 (기쁨, 슬픔, 분노, 중립 등)
12
  - is_long_term: 장기 기억 여부
13
+ - behavior_trace: 기억을 통한 행동 추적
14
  """
15
+ def __init__(self, content: str, timestamp: datetime = None,
16
+ importance: int = 1, emotion: str = "neutral", behavior_trace: str = None):
17
  self.content = content
18
  self.timestamp = timestamp or datetime.now()
19
  self.importance = importance
20
  self.emotion = emotion
21
  self.is_long_term = False
22
+ self.behavior_trace = behavior_trace
23
 
24
 
25
  class MemoryStore: