rorshi commited on
Commit
ef82d45
·
1 Parent(s): 4345e70

구조별 모듈화

Browse files
npc_social_network/npc/emotion_config.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # portfolio/npc_social_network/npc/emotion_config.py
2
+ # 감정 초기 상태 및 decay 설정
3
+
4
+ # 고차원 감정 상태 정의 (GoEmotions 기반, 보여주기용)
5
+ EMOTION_STATE_TEMPLATE = {
6
+ # 기본 정서 (긍정)
7
+ "core_positive":{
8
+ "joy": 0, # 기쁨
9
+ "satisfaction": 0, # 만족
10
+ "gratitude": 0, # 감사
11
+ "calm": 0, # 평온
12
+ "anticipation": 0, # 기대
13
+ "pride": 0, # 자부심
14
+ "connectedness": 0 # 유대감
15
+ },
16
+ # 기본 정서 (부정)
17
+ "core_negative": {
18
+ "sadness": 0, # 슬픔
19
+ "anger": 0, # 분노
20
+ "anxiety": 0, # 불안
21
+ "disgust": 0, # 혐오
22
+ "fear": 0, # 공포
23
+ "regret": 0, # 후회
24
+ "frustration": 0 # 좌절
25
+ },
26
+ # 사회적 감정
27
+ "social_emotion": {
28
+ "jealousy": 0, # 질투
29
+ "shame": 0, # 수치심
30
+ "guilt": 0, # 죄책감
31
+ "compassion": 0, # 동정심
32
+ "awe": 0, # 경외심
33
+ "empathy": 0 # 공감
34
+ },
35
+ # 인지적 상태
36
+ "cognitive_state": {
37
+ "confusion": 0, # 혼란
38
+ "nervousness": 0, # 긴장
39
+ "apathy": 0, # 무관심
40
+ "excitement": 0, # 흥분
41
+ "immersion": 0, # 몰입
42
+ "skepticism": 0 # 회의
43
+ }
44
+ }
45
+
46
+ # 감정별 회복 속도 (ms 단위가 아닌 단위당 감소 속도)
47
+ EMOTION_DECAY_RATE = {
48
+ # 기본 정서 (긍정)
49
+ "joy": 1, # 기쁨
50
+ "satisfaction": 1, # 만족
51
+ "gratitude": 1, # 감사
52
+ "calm": 1, # 평온
53
+ "anticipation": 1, # 기대
54
+ "pride": 1, # 자부심
55
+ "connectedness": 1, # 유대감
56
+
57
+ # 기본 정서 (부정) - 느림
58
+ "sadness": 0.2, # 슬픔
59
+ "anger": 0.5, # 분노
60
+ "anxiety": 0.4, # 불안
61
+ "disgust": 0.8, # 혐오
62
+ "fear": 0.6, # 공포
63
+ "regret": 0.3, # 후회
64
+ "frustration": 0.5, # 좌절
65
+
66
+ # 사회적 감정
67
+ "jealousy": 0.4, # 질투
68
+ "shame": 0.4, # 수치심
69
+ "guilt": 0.4, # 죄책감
70
+ "compassion": 1, # 동정심
71
+ "awe": 1, # 경외심
72
+ "empathy": 1, # 공감
73
+
74
+ # 인지적 상태
75
+ "confusion": 0.8, # 혼란
76
+ "nervousness": 0.7, # 긴장
77
+ "apathy": 0.4, # 무관심
78
+ "excitement": 1.2, # 흥분
79
+ "immersion": 1.0, # 몰입
80
+ "skepticism": 0.5, # 회의
81
+ }
npc_social_network/npc/npc_base.py CHANGED
@@ -1,5 +1,8 @@
1
  # portfolio/npc_social_network/npc/npc_base.py
2
  from .npc_memory import Memory, MemoryStore
 
 
 
3
 
4
  # NPC 클래스 정의
5
  class NPC:
@@ -16,88 +19,16 @@ class NPC:
16
 
17
  # npc 기억
18
  self.memory_store = MemoryStore()
 
 
 
 
19
 
20
- # 고차원 감정 상태 정의 (GoEmotions 기반, 보여주기용)
21
- self.emotion_state = {
22
- # 기본 정서 (긍정)
23
- "core_positive":{
24
- "joy": 0, # 기쁨
25
- "satisfaction": 0, # 만족
26
- "gratitude": 0, # 감사
27
- "calm": 0, # 평온
28
- "anticipation": 0, # 기대
29
- "pride": 0, # 자부심
30
- "connectedness": 0 # 유대감
31
- },
32
- # 기본 정서 (부정)
33
- "core_negative": {
34
- "sadness": 0, # 슬픔
35
- "anger": 0, # 분노
36
- "anxiety": 0, # 불안
37
- "disgust": 0, # 혐오
38
- "fear": 0, # 공포
39
- "regret": 0, # 후회
40
- "frustration": 0 # 좌절
41
- },
42
- # 사회적 감정
43
- "social_emotion": {
44
- "jealousy": 0, # 질투
45
- "shame": 0, # 수치심
46
- "guilt": 0, # 죄책감
47
- "compassion": 0, # 동정심
48
- "awe": 0, # 경외심
49
- "empathy": 0 # 공감
50
- },
51
- # 인지적 상태
52
- "cognitive_state": {
53
- "confusion": 0, # 혼란
54
- "nervousness": 0, # 긴장
55
- "apathy": 0, # 무관심
56
- "excitement": 0, # 흥분
57
- "immersion": 0, # 몰입
58
- "skepticism": 0 # 회의
59
- }
60
- }
61
-
62
- # 감정별 회복 속도 (ms 단위가 아닌 단위당 감소 속도)
63
- self.emotion_decay_rate = {
64
- # 기본 정서 (긍정)
65
- "joy": 1, # 기쁨
66
- "satisfaction": 1, # 만족
67
- "gratitude": 1, # 감사
68
- "calm": 1, # 평온
69
- "anticipation": 1, # 기대
70
- "pride": 1, # 자부심
71
- "connectedness": 1, # 유대감
72
-
73
- # 기본 정서 (부정) - 느림
74
- "sadness": 0.2, # 슬픔
75
- "anger": 0.5, # 분노
76
- "anxiety": 0.4, # 불안
77
- "disgust": 0.8, # 혐오
78
- "fear": 0.6, # 공포
79
- "regret": 0.3, # 후회
80
- "frustration": 0.5, # 좌절
81
-
82
- # 사회적 감정
83
- "jealousy": 0.4, # 질투
84
- "shame": 0.4, # 수치심
85
- "guilt": 0.4, # 죄책감
86
- "compassion": 1, # 동정심
87
- "awe": 1, # 경외심
88
- "empathy": 1, # 공감
89
-
90
- # 인지적 상태
91
- "confusion": 0.8, # 혼란
92
- "nervousness": 0.7, # 긴장
93
- "apathy": 0.4, # 무관심
94
- "excitement": 1.2, # 흥분
95
- "immersion": 1.0, # 몰입
96
- "skepticism": 0.5, # 회의
97
- }
98
 
99
  # 내부: float 감정 수치 관리용 버퍼
100
- self._emotion_buffer = {emo: 0.0 for cat in self.emotion_state for emo in self.emotion_state[cat]}
101
 
102
  # 확장 가능 속성
103
  # self.emotion = "neutral"
@@ -118,13 +49,8 @@ class NPC:
118
 
119
  # 감정 상태와 직업에 따른 대사 생성 (대표 감정 하나 반영)
120
  def generate_dialogue(self):
121
- dominant = self.get_dominant_emotion()
122
- emotion_line = f"지금 저는 '{dominant}' 상태예요." if dominant else "기분이 안정돼 있어요."
123
- job_line = {
124
- "farmer": "밭일을 해야겠어요.",
125
- "blacksmith": "대장간에 불을 지펴야겠군요."
126
- }.get(self.job, "오늘도 바쁘네요.")
127
- return f"{emotion_line} {job_line}"
128
 
129
  # NPC가 새로운 기억을 저장하고 감정 상태에 반영
130
  def remember(self, content: str, importance: int = 5, emotion: str = None, strength: float = 1.0):
@@ -133,56 +59,33 @@ class NPC:
133
  if emotion:
134
  self.update_emotion(emotion, strength) # strength = importance / 5.0으로도 가능
135
 
136
- # 저장된 모든 기억(단기+장기)을 리스트로 반환
137
- def recall(self):
138
- return [m.content for m in self.memory_store.get_all_memories()]
139
-
140
- # 특정 감정을 감정 상태에 반영 (카테고리 기반)
141
- def update_emotion(self, emotion: str, strength: float = 1.0):
142
- if emotion in self._emotion_buffer:
143
- self._emotion_buffer[emotion] += strength
144
- self._emotion_buffer[emotion] = max(0.0, self._emotion_buffer[emotion])
145
-
146
  # 시간이 지남에 따라 모든 감정이 서서히 감소
147
  def decay_emotion(self):
148
- for emotion_key in self._emotion_buffer:
149
- rate = self.emotion_decay_rate.get(emotion_key, 1.0)
150
-
151
- self._emotion_buffer[emotion_key] -= rate
152
- if self._emotion_buffer[emotion_key] < 0:
153
- self._emotion_buffer[emotion_key] = 0.0
154
-
155
- # 정수 기반 출력용 감정 상태 반환
156
- def get_current_emotion_state(self):
157
- display_state = {cat: {} for cat in self.emotion_state}
158
- for cat_name, emotions_in_cat in self.emotion_state.items():
159
- for emo_name in emotions_in_cat:
160
- if emo_name in self._emotion_buffer:
161
- display_state[cat_name][emo_name] = self._emotion_buffer[emo_name]
162
- else:
163
- display_state[cat_name][emo_name] = 0.0
164
- return display_state
165
 
166
- # 현재 가장 강한 감정 반환 (전체 감정 중 최댓값 1개)
167
- def get_dominant_emotion(self):
168
- max_value = 0.0
169
- max_emotion = None
170
- for emo, val in self._emotion_buffer.items():
171
- if val > max_value:
172
- max_value = val
173
- max_emotion = emo
174
- return max_emotion
175
 
176
  # 복합 감정 계산 (상위 N개 감정 반환)
177
  def get_composite_emotion_state(self, top_n: int = 3):
178
- sorted_emotions = sorted(self._emotion_buffer.items(), key=lambda x: x[1], reverse=True)
 
179
  composite = [(emo,round(score, 2)) for emo, score in sorted_emotions[:top_n] if score > 0]
180
  return composite # 예 [('fear', 2.0), ('anger'), 1.5]
181
 
182
  # 감정 상태 요약 텍스트 생성
183
  def summarize_emotional_state(self):
184
- nonzero = [v for v in self._emotion_buffer.values() if v > 0]
 
185
  avg_strength = round(sum(nonzero) / len(nonzero), 2) if nonzero else 0.0
186
- composite = self.get_composite_emotion_state()
 
187
  composite_str = ", ".join(f"{emo}({val})" for emo, val in composite)
188
  return f"감정 평균 강도: {avg_strength} / 대표 감정: {composite_str if composite else '없음' }"
 
1
  # portfolio/npc_social_network/npc/npc_base.py
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
6
 
7
  # NPC 클래스 정의
8
  class NPC:
 
19
 
20
  # npc 기억
21
  self.memory_store = MemoryStore()
22
+ # 감정 상태 및 감정 관리자 초기화
23
+ self.emotion_state = EMOTION_STATE_TEMPLATE
24
+ self.emotion_decay_rate = EMOTION_DECAY_RATE
25
+ self.emotion = EmotionManager(self.emotion_state, self.emotion_decay_rate)
26
 
27
+ # 행동 관리자
28
+ self.behavior = BehaviorManager()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
 
30
  # 내부: float 감정 수치 관리용 버퍼
31
+ self._emotion_buffer = self.emotion.get_buffer()
32
 
33
  # 확장 가능 속성
34
  # self.emotion = "neutral"
 
49
 
50
  # 감정 상태와 직업에 따른 대사 생성 (대표 감정 하나 반영)
51
  def generate_dialogue(self):
52
+ dominant = self.emotion.get_dominant_emotion()
53
+ return self.behavior.perform(self.name, self.job, dominant)
 
 
 
 
 
54
 
55
  # NPC가 새로운 기억을 저장하고 감정 상태에 반영
56
  def remember(self, content: str, importance: int = 5, emotion: str = None, strength: float = 1.0):
 
59
  if emotion:
60
  self.update_emotion(emotion, strength) # strength = importance / 5.0으로도 가능
61
 
62
+ # 특정 감정을 감정 상태에 반영
63
+ def update_emotion(self, emotion:str, strength: float = 1.0):
64
+ self.emotion.update_emotion(emotion, strength)
65
+ self._emotion_buffer = self.emotion.get_buffer()
66
+
 
 
 
 
 
67
  # 시간이 지남에 따라 모든 감정이 서서히 감소
68
  def decay_emotion(self):
69
+ self.emotion.decay_emotion()
70
+ self._emotion_buffer = self.emotion.get_buffer()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
 
72
+ # 저장된 모든 기억(단기+장기)을 리스트로 반환
73
+ def recall(self):
74
+ return [m.content for m in self.memory_store.get_all_memories()]
 
 
 
 
 
 
75
 
76
  # 복합 감정 계산 (상위 N개 감정 반환)
77
  def get_composite_emotion_state(self, top_n: int = 3):
78
+ buffer = self.emotion.get_buffer() # EmotionManager에서 최신 감정 상태 복사본 가져오기
79
+ sorted_emotions = sorted(buffer.items(), key=lambda x: x[1], reverse=True)
80
  composite = [(emo,round(score, 2)) for emo, score in sorted_emotions[:top_n] if score > 0]
81
  return composite # 예 [('fear', 2.0), ('anger'), 1.5]
82
 
83
  # 감정 상태 요약 텍스트 생성
84
  def summarize_emotional_state(self):
85
+ buffer = self.emotion.get_buffer() # EmotionManager에서 최신 감정 상태 복사본 가져오기
86
+ nonzero = [v for v in buffer.values() if v > 0]
87
  avg_strength = round(sum(nonzero) / len(nonzero), 2) if nonzero else 0.0
88
+ composite = sorted(buffer.items(), key=lambda x: x[1], reverse=True)
89
+ composite = [(emo, round(score, 2)) for emo, score in composite[:3] if score > 0]
90
  composite_str = ", ".join(f"{emo}({val})" for emo, val in composite)
91
  return f"감정 평균 강도: {avg_strength} / 대표 감정: {composite_str if composite else '없음' }"
npc_social_network/npc/npc_behavior.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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(self, dominant_emotion):
43
+ return self.mapping.get(dominant_emotion, "idle")
44
+
45
+ def perform(self, name, job, emotion):
46
+ action = self.decide(emotion)
47
+ behavior_lines = {
48
+ "jump": f"{name}은(는) 기뻐서 깡충 뜁니다!",
49
+ "shout": f"{name}은(는) 화가 나서 소리를 지릅니다!",
50
+ "run_away": f"{name}은(는) 무서워 도망갑니다!",
51
+ "sit_down": f"{name}은(는) 슬퍼서 주저앉습니다....",
52
+ "wave": f"{name}은(는) 손을 흔듭니다.",
53
+ "sigh": f"{name}은(는) 한숨을 쉽니다..."
54
+ }
55
+ msg = behavior_lines.get(action, f"{name}은(는) {action} 행동을 합니다.")
56
+ job_line = {"farmer": "밭일도 해야 하겠군요.", "blacksmith": "대장간 불도 지펴야죠."}.get(job, "오늘도 바쁜 하루네요.")
57
+ return f"{msg} {job_line}"