Spaces:
Sleeping
Sleeping
humanda5
commited on
Commit
·
24c2c08
1
Parent(s):
8f5cce3
Complete step 19:인생 단계에 따른 NPC Personality 변화 적용
Browse files
npc_social_network/models/llm_helper.py
CHANGED
@@ -32,4 +32,30 @@ def query_llm_for_emotion(user_input):
|
|
32 |
반드시 감정 이름을 한 개만 출력하세요. (예: joy)
|
33 |
"""
|
34 |
# 예시 결과 (추후 LLM 연결 시 교체)
|
35 |
-
return "joy"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
반드시 감정 이름을 한 개만 출력하세요. (예: joy)
|
33 |
"""
|
34 |
# 예시 결과 (추후 LLM 연결 시 교체)
|
35 |
+
return "joy"
|
36 |
+
|
37 |
+
def query_llm_for_response_with_context(npc_name, npc_job, emotion_state, recent_memories,
|
38 |
+
personality, relationship_with_player):
|
39 |
+
"""
|
40 |
+
LLM에 컨텍스트 정보를 전달하여 자연스러운 대사 생성
|
41 |
+
"""
|
42 |
+
memory_text = "\n".join([f"- {m.content}" for m in recent_memories])
|
43 |
+
emotion_text = ", ".join([f"{emo}({score})" for emo, score in emotion_state])
|
44 |
+
|
45 |
+
# 최근 대화 내용은 기억에 다 들어가나?
|
46 |
+
# 행동이 들어갈 거니까, 기억도 단순 문장형이 아니라 가공해서 기억하고,
|
47 |
+
# 대화 내용은 가장 최근 대화 내용을 넘겨주는 방식이 좋을거 같은데, 시간이 지나면 잊혀지고
|
48 |
+
prompt = f"""
|
49 |
+
NPC 이름: {npc_name}
|
50 |
+
NPC 직업: {npc_job}
|
51 |
+
현재 감정 상태: {emotion_text}
|
52 |
+
최근 기억:
|
53 |
+
{memory_text}
|
54 |
+
현재 플레이어와의 관계: {relationship_with_player}
|
55 |
+
Personality: {personality}
|
56 |
+
|
57 |
+
위 정보를 참고하여, 한국어로 자연스럽고 상황에 맞는 대화 문장을 생성하세요.
|
58 |
+
"""
|
59 |
+
|
60 |
+
# 임시 응답 (LLM 연결 시 교체)
|
61 |
+
return f"{npc_name}이(가) 말했습니다. '오늘은 기분이 좋아요!' "
|
npc_social_network/npc/emotion_config.py
CHANGED
@@ -153,4 +153,15 @@ NEGATIVE_RELATION_EMOTIONS = [
|
|
153 |
COGNITIVE_RELATION_EMOTIONS = [
|
154 |
"compassion", "awe", "attachment", "anticipation", "curiosity",
|
155 |
"nostalgia", "bittersweet", "rumination", "groundedness", "comfort",
|
156 |
-
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
153 |
COGNITIVE_RELATION_EMOTIONS = [
|
154 |
"compassion", "awe", "attachment", "anticipation", "curiosity",
|
155 |
"nostalgia", "bittersweet", "rumination", "groundedness", "comfort",
|
156 |
+
]
|
157 |
+
|
158 |
+
# 인생 단계별 Personality 변화율 정의
|
159 |
+
AGE_PROFILE = {
|
160 |
+
"infancy_and_toddlerhood": 3.0, # (0-3 세) Temperament & attachment foundation — change rate very high
|
161 |
+
"early_childhood": 2.0, # (3-6 세) Initial personality structure emergence — high change rate
|
162 |
+
"middle_childhood": 1.5, # (6-12 세) Personality structure solidification — still high change rate
|
163 |
+
"adolescence": 1.0, # (12-18 세) Identity formation — moderate to high change rate
|
164 |
+
"young_adulthood": 0.5, # (18-30 세) Personality stabilization — moderate change rate
|
165 |
+
"middle_adulthood": 0.2, # (30-65 세) Personality highly stable — low change rate
|
166 |
+
"older_adulthood": 0.02 # (65- 세) Personality largely fixed — minimal change
|
167 |
+
}
|
npc_social_network/npc/npc_base.py
CHANGED
@@ -3,9 +3,9 @@ from .npc_memory import Memory, MemoryStore
|
|
3 |
from .npc_emotion import EmotionManager
|
4 |
from .npc_behavior import BehaviorManager
|
5 |
from .emotion_config import EMOTION_LIST, EMOTION_CATEGORY_MAP, EMOTION_DECAY_RATE, PERSONALITY_TEMPLATE
|
6 |
-
from .emotion_config import POSITIVE_RELATION_EMOTIONS, NEGATIVE_RELATION_EMOTIONS, COGNITIVE_RELATION_EMOTIONS
|
7 |
from .npc_relationship import RelationshipManager
|
8 |
-
from ..models.llm_helper import query_llm_for_emotion, query_llm_for_response
|
9 |
import random
|
10 |
import copy
|
11 |
|
@@ -62,16 +62,43 @@ class NPC:
|
|
62 |
# baseline buffer를 EmotionManager에 등록
|
63 |
self.emotion.set_baseline(baseline_buffer)
|
64 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
65 |
# Personality 변화 속도 개별 설정
|
66 |
self.personality_change_rate = {
|
67 |
-
"sensitive":
|
68 |
-
"stoic":
|
69 |
-
"cognitive_bias":
|
70 |
}
|
71 |
|
72 |
# Personality baseline 저장 (초기값 복사)
|
73 |
self.personality_baseline = copy.deepcopy(self.personality)
|
74 |
|
|
|
|
|
|
|
75 |
def move(self):
|
76 |
"""
|
77 |
이동
|
@@ -91,50 +118,82 @@ class NPC:
|
|
91 |
x, y = self.get_position()
|
92 |
screen.blit(self.image, (x * tile_size, y * tile_size))
|
93 |
|
94 |
-
def generate_dialogue(self):
|
95 |
-
"""
|
96 |
-
|
97 |
-
"""
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
109 |
else:
|
110 |
-
#
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
132 |
|
133 |
-
def remember(self, content: str, importance: int = 5, emotion: str = None, strength: float = 1.0):
|
134 |
"""
|
135 |
NPC가 새로운 기억을 저장하고 감정 상태에 반영
|
136 |
"""
|
137 |
-
memory = Memory(content=content, importance = importance, emotion=emotion or "neutral")
|
138 |
self.memory_store.add_memory(memory)
|
139 |
if emotion:
|
140 |
self.update_emotion(emotion, strength) # strength = importance / 5.0으로도 가능
|
@@ -322,14 +381,97 @@ class NPC:
|
|
322 |
def update_personality(self):
|
323 |
"""
|
324 |
Memory / Emotion 기반으로 Personality 변화 적용
|
325 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
326 |
recent_memories = self.memory_store.get_recent_memories(limit=10) # 최근 10개 Memory 사용(이것보단 중요도가 큰(즉 충격이 큰) 기억이 성격 형성에 영향을 주는게 자연스럽지)
|
327 |
|
328 |
# Personality 변화 반영
|
329 |
# 나중에 NPC 일정 나이가 되면 성격 형성이 되어 변경되지 않도록 발전 가능, 보다 인간적
|
330 |
# 그리고 생성된 성격에 따라서 기억(사건)에 따른 감정 영향에 가중치를 받도록 확장 가능 (같은 사건이여도 성격에 따라 받아들이는게 다르도록)
|
331 |
for m in recent_memories:
|
332 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
333 |
if m.emotion in POSITIVE_RELATION_EMOTIONS:
|
334 |
self.personality["sensitive"] = min(1.0, self.personality["sensitive"] + self.personality_change_rate["sensitive"] * weight)
|
335 |
self.personality["stoic"] = max(0.0, self.personality["stoic"] - self.personality_change_rate["stoic"] * weight)
|
@@ -340,12 +482,22 @@ class NPC:
|
|
340 |
if m.emotion in COGNITIVE_RELATION_EMOTIONS:
|
341 |
self.personality["cognitive_bias"] = min(1.0, self.personality["cognitive_bias"] + self.personality_change_rate["cognitive_bias"] * weight)
|
342 |
|
343 |
-
# Baseline 복원 적용 (
|
344 |
-
decay_rate =
|
|
|
|
|
|
|
|
|
345 |
|
346 |
for key in self.personality.keys():
|
347 |
self.personality[key] += (self.personality_baseline[key] - self.personality[key]) * decay_rate
|
348 |
|
349 |
# 디버그 출력
|
350 |
print(f"[Personality Update] {self.name} → sensitive: {self.personality['sensitive']:.2f}, "
|
351 |
-
f"stoic: {self.personality['stoic']:.2f}, cognitive_bias: {self.personality['cognitive_bias']:.2f}", flush=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
from .npc_emotion import EmotionManager
|
4 |
from .npc_behavior import BehaviorManager
|
5 |
from .emotion_config import EMOTION_LIST, EMOTION_CATEGORY_MAP, EMOTION_DECAY_RATE, PERSONALITY_TEMPLATE
|
6 |
+
from .emotion_config import POSITIVE_RELATION_EMOTIONS, NEGATIVE_RELATION_EMOTIONS, COGNITIVE_RELATION_EMOTIONS, AGE_PROFILE
|
7 |
from .npc_relationship import RelationshipManager
|
8 |
+
from ..models.llm_helper import query_llm_for_emotion, query_llm_for_response, query_llm_for_response_with_context
|
9 |
import random
|
10 |
import copy
|
11 |
|
|
|
62 |
# baseline buffer를 EmotionManager에 등록
|
63 |
self.emotion.set_baseline(baseline_buffer)
|
64 |
|
65 |
+
# Personality 성격 프로필 기반
|
66 |
+
# profile: stable / emotional / logical (추후 더 추가)
|
67 |
+
personality_profile = {
|
68 |
+
"stable": {
|
69 |
+
"sensitive": (0.002, 0.004),
|
70 |
+
"stoic": (0.002, 0.004),
|
71 |
+
"cognitive_bias": (0.002, 0.004)
|
72 |
+
},
|
73 |
+
"emotional":{
|
74 |
+
"sensitive": (0.006, 0.01),
|
75 |
+
"stoic": (0.002, 0.004),
|
76 |
+
"cognitive_bias": (0.004, 0.006)
|
77 |
+
},
|
78 |
+
"logical":{
|
79 |
+
"sensitive": (0.002, 0.004),
|
80 |
+
"stoic": (0.004, 0.006),
|
81 |
+
"cognitive_bias":(0.006, 0.01)
|
82 |
+
},
|
83 |
+
}
|
84 |
+
|
85 |
+
# 프로필 지정 → 기본은 "stable", 나중에 NPC마다 다르게 부여
|
86 |
+
profile_type = "stable"
|
87 |
+
profile = personality_profile[profile_type]
|
88 |
+
|
89 |
# Personality 변화 속도 개별 설정
|
90 |
self.personality_change_rate = {
|
91 |
+
"sensitive": random.uniform(*profile["sensitive"]),
|
92 |
+
"stoic": random.uniform(*profile["stoic"]),
|
93 |
+
"cognitive_bias": random.uniform(*profile["cognitive_bias"]),
|
94 |
}
|
95 |
|
96 |
# Personality baseline 저장 (초기값 복사)
|
97 |
self.personality_baseline = copy.deepcopy(self.personality)
|
98 |
|
99 |
+
# 인생 단계 profile 추가
|
100 |
+
self.personality_stage = "adolescence" # 기본 "adolescence", NPC마다 다르게 설정 가능
|
101 |
+
|
102 |
def move(self):
|
103 |
"""
|
104 |
이동
|
|
|
118 |
x, y = self.get_position()
|
119 |
screen.blit(self.image, (x * tile_size, y * tile_size))
|
120 |
|
121 |
+
def generate_dialogue(self, use_llm=True):
|
122 |
+
"""
|
123 |
+
대화 생성 함수
|
124 |
+
"""
|
125 |
+
if use_llm:
|
126 |
+
# LLM 기반 generate
|
127 |
+
npc_reply = query_llm_for_response_with_context(
|
128 |
+
npc_name = self.name,
|
129 |
+
npc_job = self.job,
|
130 |
+
emotion_state = self.get_composite_emotion_state(),
|
131 |
+
recent_memories = self.memory_store.get_recent_memories(limit=5),
|
132 |
+
personality = self.personality,
|
133 |
+
relationship_with_player = self.get_relationship_description("플레이어"),
|
134 |
+
)
|
135 |
+
|
136 |
+
# Memory 기록
|
137 |
+
self.remember(
|
138 |
+
content = f"[NPC: {self.name}] LLM 대사: '{npc_reply}'",
|
139 |
+
importance = 7,
|
140 |
+
emotion = self.emotion.get_dominant_emotion()
|
141 |
+
)
|
142 |
+
|
143 |
+
# Personality 업데이트
|
144 |
+
self.update_personality()
|
145 |
+
|
146 |
+
# Emotion update는 LLM 기반 generate 에서는 따로 역매핑이 애매하므로 dominant_emotion만 반영 (원하면 감정 분석 결과 기반으로 개선 가능)
|
147 |
+
dominant_emotion = self.emotion.get_dominant_emotion()
|
148 |
+
if dominant_emotion:
|
149 |
+
self.update_emotion(dominant_emotion, strength=2.0)
|
150 |
+
|
151 |
+
return npc_reply
|
152 |
else:
|
153 |
+
# 감정 상태와 직업에 따른 복합 행동 시퀀스 기반 대사 생성 + Behavior Trace Memory 기록
|
154 |
+
behavior_output, behavior_trace = self.behavior.perform_sequence(
|
155 |
+
self.name, self.job, emotion_buffer=self._emotion_buffer, return_trace = True
|
156 |
+
)
|
157 |
+
|
158 |
+
# 단계별 dominant emotion sequence 계산
|
159 |
+
dominant_emotions = self.behavior.get_layer_dominant_emotions(self._emotion_buffer)
|
160 |
+
dominant_sequence = self.behavior.decide_layered_sequence(dominant_emotions)
|
161 |
+
|
162 |
+
# dominant_sequence가 empty인 경우 방어적 처리
|
163 |
+
if dominant_sequence:
|
164 |
+
dominant_score = max([score for _, score in dominant_sequence])
|
165 |
+
else:
|
166 |
+
# dominant_sequence가 비었으면 기본값 사용 (예: 감정 없음 상태)
|
167 |
+
dominant_score = 5
|
168 |
+
|
169 |
+
# 중요도 제한
|
170 |
+
importance = min(int(dominant_score), 10) # importance 1~10제한
|
171 |
+
|
172 |
+
# Behavior Trace를 Memory에 기록
|
173 |
+
memory_entry = Memory(
|
174 |
+
content=f"행동 수행: {behavior_trace}",
|
175 |
+
importance=importance,
|
176 |
+
emotion = self.emotion.get_dominant_emotion(),
|
177 |
+
behavior_trace = behavior_trace
|
178 |
+
)
|
179 |
+
self.memory_store.add_memory(memory_entry)
|
180 |
+
|
181 |
+
# 행동에 해당하는 감정에 update_emotion 호출 (역매핑)
|
182 |
+
for action, score in behavior_trace:
|
183 |
+
emotion_name = self.behavior.action_to_emotion.get(action)
|
184 |
+
if emotion_name:
|
185 |
+
self.update_emotion(emotion_name, strength=score)
|
186 |
+
|
187 |
+
# Personality 업데이트
|
188 |
+
self.update_personality()
|
189 |
+
|
190 |
+
return behavior_output
|
191 |
|
192 |
+
def remember(self, content: str, importance: int = 5, emotion: str = None, strength: float = 1.0, memory_type:str = "Event"):
|
193 |
"""
|
194 |
NPC가 새로운 기억을 저장하고 감정 상태에 반영
|
195 |
"""
|
196 |
+
memory = Memory(content=content, importance = importance, emotion=emotion or "neutral", memory_type=memory_type)
|
197 |
self.memory_store.add_memory(memory)
|
198 |
if emotion:
|
199 |
self.update_emotion(emotion, strength) # strength = importance / 5.0으로도 가능
|
|
|
381 |
def update_personality(self):
|
382 |
"""
|
383 |
Memory / Emotion 기반으로 Personality 변화 적용
|
384 |
+
- MemoryType 별 가중치 + EmotionInfluence 별 가중치 모두 반영
|
385 |
+
"""
|
386 |
+
# MemoryType 별 weight
|
387 |
+
memory_type_weight = {
|
388 |
+
"Dialogue": 0.5,
|
389 |
+
"Behavior": 1.0,
|
390 |
+
"Event": 1.5,
|
391 |
+
"RelationshipChange": 2.0
|
392 |
+
}
|
393 |
+
|
394 |
+
# EmotionInfluence 별 weight
|
395 |
+
emotion_influence_weight = {
|
396 |
+
# Core
|
397 |
+
"joy": 0.8,
|
398 |
+
"sadness": 1.3,
|
399 |
+
"anger": 1.5,
|
400 |
+
"fear": 1.4,
|
401 |
+
"disgust": 1.2,
|
402 |
+
"surprise": 1.0,
|
403 |
+
"neutral": 0.5,
|
404 |
+
|
405 |
+
# Social
|
406 |
+
"gratitude": 0.9,
|
407 |
+
"shame": 1.3,
|
408 |
+
"guilt": 1.3,
|
409 |
+
"pride": 0.9,
|
410 |
+
"jealousy": 1.2,
|
411 |
+
"compassion": 1.1,
|
412 |
+
"love": 0.8,
|
413 |
+
"admiration": 0.9,
|
414 |
+
"empathy": 0.9,
|
415 |
+
"awe": 1.1,
|
416 |
+
"attachment": 1.0,
|
417 |
+
"comfort": 0.8,
|
418 |
+
|
419 |
+
# Cognitive
|
420 |
+
"anticipation": 0.7,
|
421 |
+
"curiosity": 0.7,
|
422 |
+
"confusion": 1.0,
|
423 |
+
"interest": 0.8,
|
424 |
+
"engagement": 0.8,
|
425 |
+
"boredom": 0.6,
|
426 |
+
"relief": 0.7,
|
427 |
+
"anxiety": 1.1,
|
428 |
+
"calm": 0.6,
|
429 |
+
"skepticism": 0.9,
|
430 |
+
|
431 |
+
# Complex
|
432 |
+
"nostalgia": 1.2,
|
433 |
+
"bittersweet": 1.1,
|
434 |
+
"schadenfreude": 1.4,
|
435 |
+
"hope": 1.0,
|
436 |
+
"resentment": 1.3,
|
437 |
+
"anticipatory_joy": 0.9,
|
438 |
+
"regret": 1.3,
|
439 |
+
"rumination": 1.4,
|
440 |
+
"groundedness": 0.8
|
441 |
+
}
|
442 |
+
|
443 |
recent_memories = self.memory_store.get_recent_memories(limit=10) # 최근 10개 Memory 사용(이것보단 중요도가 큰(즉 충격이 큰) 기억이 성격 형성에 영향을 주는게 자연스럽지)
|
444 |
|
445 |
# Personality 변화 반영
|
446 |
# 나중에 NPC 일정 나이가 되면 성격 형성이 되어 변경되지 않도록 발전 가능, 보다 인간적
|
447 |
# 그리고 생성된 성격에 따라서 기억(사건)에 따른 감정 영향에 가중치를 받도록 확장 가능 (같은 사건이여도 성격에 따라 받아들이는게 다르도록)
|
448 |
for m in recent_memories:
|
449 |
+
# MemoryType 별 weight 적용
|
450 |
+
type_weight = memory_type_weight.get(m.memory_type, 1.0) # 기본값 1.0
|
451 |
+
# EmotionInfluence 별 weight 적용
|
452 |
+
emotion_weight = emotion_influence_weight.get(m.emotion, 1.0)
|
453 |
+
|
454 |
+
# Personality bias 적용 (성격에 따라, 같은 사건에 받는 감정이 다르도록)
|
455 |
+
category = EMOTION_CATEGORY_MAP.get(m.emotion, "core")
|
456 |
+
if category == "core":
|
457 |
+
personality_bias = self.personality["affect_bias"]
|
458 |
+
elif category == "social":
|
459 |
+
personality_bias = self.personality["social_bias"]
|
460 |
+
elif category == "cognitive":
|
461 |
+
personality_bias = self.personality["cognitive_bias"]
|
462 |
+
elif category == "complex":
|
463 |
+
personality_bias = self.personality["complex_bias"]
|
464 |
+
else:
|
465 |
+
personality_bias = 1.0
|
466 |
+
|
467 |
+
# sensitive / stoic 반영
|
468 |
+
emotion_bias_factor = personality_bias * self.personality["sensitive"] * (1.0 - self.personality["stoic"])
|
469 |
+
|
470 |
+
# 인생 단계별 변화율 적용
|
471 |
+
stage_factor = AGE_PROFILE.get(self.personality_stage, 1.0)
|
472 |
+
|
473 |
+
# 최종 weight 계산
|
474 |
+
weight = stage_factor * (m.importance / 10.0) * type_weight * emotion_weight * emotion_bias_factor # importance 1~10 → 0.1 ~ 1.0
|
475 |
if m.emotion in POSITIVE_RELATION_EMOTIONS:
|
476 |
self.personality["sensitive"] = min(1.0, self.personality["sensitive"] + self.personality_change_rate["sensitive"] * weight)
|
477 |
self.personality["stoic"] = max(0.0, self.personality["stoic"] - self.personality_change_rate["stoic"] * weight)
|
|
|
482 |
if m.emotion in COGNITIVE_RELATION_EMOTIONS:
|
483 |
self.personality["cognitive_bias"] = min(1.0, self.personality["cognitive_bias"] + self.personality_change_rate["cognitive_bias"] * weight)
|
484 |
|
485 |
+
# Baseline 복원 적용 (adaptive decay)
|
486 |
+
# decay_rate = base_rate * (1 + stoic - sensitive)
|
487 |
+
base_decay = 0.001
|
488 |
+
decay_rate = base_decay * (1.0 + self.personality["stoic"] - self.personality["sensitive"])
|
489 |
+
# 안정적 범위 클램핑
|
490 |
+
decay_rate = max(0.0005, min(decay_rate, 0.005))
|
491 |
|
492 |
for key in self.personality.keys():
|
493 |
self.personality[key] += (self.personality_baseline[key] - self.personality[key]) * decay_rate
|
494 |
|
495 |
# 디버그 출력
|
496 |
print(f"[Personality Update] {self.name} → sensitive: {self.personality['sensitive']:.2f}, "
|
497 |
+
f"stoic: {self.personality['stoic']:.2f}, cognitive_bias: {self.personality['cognitive_bias']:.2f}", flush=True)
|
498 |
+
|
499 |
+
def decay_memory(self):
|
500 |
+
"""
|
501 |
+
시간이 지남에 따라 기억 importance 감소
|
502 |
+
"""
|
503 |
+
self.memory_store.decay_memories()
|
npc_social_network/npc/npc_memory.py
CHANGED
@@ -12,14 +12,15 @@ class Memory:
|
|
12 |
- is_long_term: 장기 기억 여부
|
13 |
- behavior_trace: 기억을 통한 행동 추적
|
14 |
"""
|
15 |
-
def __init__(self, content: str, timestamp: datetime = None,
|
16 |
-
|
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:
|
@@ -70,3 +71,25 @@ class MemoryStore:
|
|
70 |
all_memories = self.get_all_memories()
|
71 |
all_memories.sort(key=lambda m: m.timestamp, reverse=True)
|
72 |
return all_memories[:limit]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
- is_long_term: 장기 기억 여부
|
13 |
- behavior_trace: 기억을 통한 행동 추적
|
14 |
"""
|
15 |
+
def __init__(self, content: str, timestamp: datetime = None, importance: int = 1,
|
16 |
+
emotion: str = "neutral", behavior_trace: str = None, memory_type: str = "Event"):
|
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 |
+
self.memory_type = memory_type
|
24 |
|
25 |
|
26 |
class MemoryStore:
|
|
|
71 |
all_memories = self.get_all_memories()
|
72 |
all_memories.sort(key=lambda m: m.timestamp, reverse=True)
|
73 |
return all_memories[:limit]
|
74 |
+
|
75 |
+
def decay_memories(self, min_importance=1, decay_rate_short=0.05, decay_rate_long=0.01):
|
76 |
+
"""
|
77 |
+
MemoryType에 따라 decay 적용
|
78 |
+
- 단기 기억은 decay_rate_short 만큼 importance 감소 (기본 5% 감소)
|
79 |
+
- 장기 기억은 decay_rate_long 만큼 importance 감소 (기본 1% 감소)
|
80 |
+
- 기억 타입에 따른 importance 차등 감소 (대화, 행동, 사건, 관계)
|
81 |
+
"""
|
82 |
+
decay_rates = {
|
83 |
+
"Dialogue": 0.10, # 대화 (빠른 decay)
|
84 |
+
"Behavior": 0.05, # 행동
|
85 |
+
"Event": 0.02, # 사건
|
86 |
+
"RelationshipChange": 0.01 # 관계 (느린 decay)
|
87 |
+
}
|
88 |
+
|
89 |
+
for mem in self.short_term:
|
90 |
+
rate = decay_rates.get(mem.memory_type, 0.05)
|
91 |
+
mem.importance = max(min_importance, mem.importance * (1.0 - decay_rate_short) * (1.0 - rate))
|
92 |
+
|
93 |
+
for mem in self.long_term:
|
94 |
+
rate = decay_rates.get(mem.memory_type, 0.02)
|
95 |
+
mem.importance = max(min_importance, mem.importance * (1.0 - decay_rate_long) * (1.0 - rate))
|