rorshi commited on
Commit
146c098
·
1 Parent(s): b25a43f

이슈 수정 ver3

Browse files
npc_social_network/data/saves/simulation_state.pkl DELETED
Binary file (13 kB)
 
npc_social_network/data/vectorstores/alice.faiss DELETED
Binary file (1.58 kB)
 
npc_social_network/data/vectorstores/bob.faiss DELETED
Binary file (1.58 kB)
 
npc_social_network/data/vectorstores/charlie.faiss DELETED
Binary file (1.58 kB)
 
npc_social_network/data/vectorstores/diana.faiss DELETED
Binary file (1.58 kB)
 
npc_social_network/data/vectorstores/elin.faiss DELETED
Binary file (1.58 kB)
 
npc_social_network/npc/npc_base.py CHANGED
@@ -12,7 +12,7 @@ from .personality_config import AGE_PROFILE, PERSONALITY_PROFILE
12
  from .npc_relationship import RelationshipManager
13
  from ..models.llm_helper import query_llm_with_prompt, query_llm_for_emotion, summarize_memories, analyze_gossip
14
  from ..models.llm_prompt_builder import build_npc_prompt
15
- from .npc_memory_embedder import search_similar_memories
16
  from .npc_planner import PlannerManager
17
  from typing import TYPE_CHECKING
18
  if TYPE_CHECKING:
@@ -81,6 +81,7 @@ class NPC:
81
  self.name = name
82
  self.korean_name = korean_name
83
  self.job = job
 
84
 
85
  # npc 기억
86
  self.memory_store = MemoryStore()
@@ -215,7 +216,7 @@ class NPC:
215
 
216
  def remember(self, content: str, importance: int = 5, emotion: str = None,
217
  strength: float = 1.0, memory_type:str = "Event",
218
- context_tags: Optional[List[str]]=None, npc_manager: "NPCManager" = None) -> Memory:
219
  """
220
  NPC가 새로운 기억을 저장하고 감정 상태에 반영
221
  """
@@ -227,14 +228,18 @@ class NPC:
227
  context_tags=context_tags
228
  )
229
  self.memory_store.add_memory(memory)
 
 
 
 
230
  if emotion and emotion in EMOTION_LIST:
231
  self.update_emotion(emotion, strength) # strength = importance / 5.0으로도 가능
232
  # 만약 기억이 '소문'이라면, 평판을 업데이트
233
- if memory_type == "Gossip" and npc_manager:
234
  # (간단한 예시: LLM으로 소문의 대상과 긍/부정을 파악해야 더 정확함)
235
  # 긍정 소문 예시: "밥이 찰리를 도왔다"
236
  # 부정 소문 예시: "엘린이 앨리스와 다퉜다"
237
- self.process_gossip_and_update_reputation(memory, npc_manager)
238
 
239
  return memory # 생성된 기억 객체 반환
240
 
@@ -408,7 +413,7 @@ class NPC:
408
  memory_type="Summary"
409
  )
410
 
411
- def update_autonomous_behavior(self, time_context: str, npc_manager, add_log):
412
  """
413
  NPC가 스스로 판단하여 행동을 결정하는 자율 행동 로직
414
  주기적으로 호출되어 목표 설정, 계획 실행 등을 담당.
@@ -434,7 +439,7 @@ class NPC:
434
  gossip_to_spread = random.choice(gossip_memories)
435
 
436
  # 아직 대화한 적 없는 NPC를 타겟으로 선정
437
- potential_targets = [npc for npc in npc_manager.all() if npc.name != self.name]
438
  if potential_targets:
439
  target_npc = random.choice(potential_targets)
440
 
@@ -445,7 +450,7 @@ class NPC:
445
  target_npc=target_npc
446
  )
447
 
448
- add_log(f"[소문 전파] {self.korean_name} -> {target_npc.korean_name}: {gossip_dialogue}")
449
  gossip_to_spread.is_shared = True # 소문이 전파되었음을 표시 (중복 전파 방지)
450
 
451
  # 일정 확률로 새로운 목표를 생성 (매번 생성하지 않도록)
@@ -492,20 +497,20 @@ class NPC:
492
  )
493
  print(f"[{self.korean_name}]의 새로운 깨달음: {symbolic_thought}")
494
 
495
- def update_reputation(self, target_name: str, score_change: int, npc_manager: "NPCManager"):
496
  """특정 대상에 대한 평판 점수를 변경"""
497
  if self.name == target_name: return # 자기 자신에 대한 평판x (자기 자신의 평판에 대한 내용도 성격 형성에 중요할 수 있지 않나?)
498
 
499
  current_score = self.reputation.get(target_name, 0)
500
  self.reputation[target_name] = current_score + score_change
501
 
502
- target_npc = npc_manager.get_npc_by_name(target_name)
503
  target_korean_name = target_npc.korean_name if target_npc else target_name
504
 
505
  print(f"[{self.korean_name}]의 {target_korean_name}에 대한 평판: {self.reputation[target_name]} ({score_change:+.0f})")
506
 
507
 
508
- def process_gossip_and_update_reputation(self, gossip_memory: Memory, npc_manager: "NPCManager"):
509
  """LLM을 이용해 소문을 분석하고 관련 인물들의 평판을 업데이트"""
510
 
511
  analysis = analyze_gossip(gossip_memory.content)
@@ -528,11 +533,11 @@ class NPC:
528
 
529
  if score_change != 0:
530
  # LLM이 반환한 한글 이름으로 NPC 객체를 찾아 영어 ID를 가져온다.
531
- p1_npc = npc_manager.get_npc_by_korean_name(person1_korean_name)
532
- p2_npc = npc_manager.get_npc_by_korean_name(person2_korean_name)
533
 
534
  # 소문의 대상이 된 두 사람에 대한 나의 평판을 변경
535
  if p1_npc:
536
- self.update_reputation(p1_npc.name, score_change, npc_manager)
537
  if p2_npc:
538
- self.update_reputation(p2_npc.name, score_change, npc_manager)
 
12
  from .npc_relationship import RelationshipManager
13
  from ..models.llm_helper import query_llm_with_prompt, query_llm_for_emotion, summarize_memories, analyze_gossip
14
  from ..models.llm_prompt_builder import build_npc_prompt
15
+ from .npc_memory_embedder import search_similar_memories, add_memory_to_index
16
  from .npc_planner import PlannerManager
17
  from typing import TYPE_CHECKING
18
  if TYPE_CHECKING:
 
81
  self.name = name
82
  self.korean_name = korean_name
83
  self.job = job
84
+ self.manager: Optional['NPCManager'] = None
85
 
86
  # npc 기억
87
  self.memory_store = MemoryStore()
 
216
 
217
  def remember(self, content: str, importance: int = 5, emotion: str = None,
218
  strength: float = 1.0, memory_type:str = "Event",
219
+ context_tags: Optional[List[str]]=None) -> Memory:
220
  """
221
  NPC가 새로운 기억을 저장하고 감정 상태에 반영
222
  """
 
228
  context_tags=context_tags
229
  )
230
  self.memory_store.add_memory(memory)
231
+ # 중요도가 3 이상인 기억만 벡터 인덱스에 추가하여 효율성 확보
232
+ if memory.importance >= 3:
233
+ add_memory_to_index(self, memory)
234
+
235
  if emotion and emotion in EMOTION_LIST:
236
  self.update_emotion(emotion, strength) # strength = importance / 5.0으로도 가능
237
  # 만약 기억이 '소문'이라면, 평판을 업데이트
238
+ if memory_type == "Gossip":
239
  # (간단한 예시: LLM으로 소문의 대상과 긍/부정을 파악해야 더 정확함)
240
  # 긍정 소문 예시: "밥이 찰리를 도왔다"
241
  # 부정 소문 예시: "엘린이 앨리스와 다퉜다"
242
+ self.process_gossip_and_update_reputation(memory)
243
 
244
  return memory # 생성된 기억 객체 반환
245
 
 
413
  memory_type="Summary"
414
  )
415
 
416
+ def update_autonomous_behavior(self, time_context: str):
417
  """
418
  NPC가 스스로 판단하여 행동을 결정하는 자율 행동 로직
419
  주기적으로 호출되어 목표 설정, 계획 실행 등을 담당.
 
439
  gossip_to_spread = random.choice(gossip_memories)
440
 
441
  # 아직 대화한 적 없는 NPC를 타겟으로 선정
442
+ potential_targets = [npc for npc in self.manager.all() if npc.name != self.name]
443
  if potential_targets:
444
  target_npc = random.choice(potential_targets)
445
 
 
450
  target_npc=target_npc
451
  )
452
 
453
+ print(f"[소문 전파] {self.korean_name} -> {target_npc.korean_name}: {gossip_dialogue}")
454
  gossip_to_spread.is_shared = True # 소문이 전파되었음을 표시 (중복 전파 방지)
455
 
456
  # 일정 확률로 새로운 목표를 생성 (매번 생성하지 않도록)
 
497
  )
498
  print(f"[{self.korean_name}]의 새로운 깨달음: {symbolic_thought}")
499
 
500
+ def update_reputation(self, target_name: str, score_change: int):
501
  """특정 대상에 대한 평판 점수를 변경"""
502
  if self.name == target_name: return # 자기 자신에 대한 평판x (자기 자신의 평판에 대한 내용도 성격 형성에 중요할 수 있지 않나?)
503
 
504
  current_score = self.reputation.get(target_name, 0)
505
  self.reputation[target_name] = current_score + score_change
506
 
507
+ target_npc = self.manager.get_npc_by_name(target_name)
508
  target_korean_name = target_npc.korean_name if target_npc else target_name
509
 
510
  print(f"[{self.korean_name}]의 {target_korean_name}에 대한 평판: {self.reputation[target_name]} ({score_change:+.0f})")
511
 
512
 
513
+ def process_gossip_and_update_reputation(self, gossip_memory: Memory):
514
  """LLM을 이용해 소문을 분석하고 관련 인물들의 평판을 업데이트"""
515
 
516
  analysis = analyze_gossip(gossip_memory.content)
 
533
 
534
  if score_change != 0:
535
  # LLM이 반환한 한글 이름으로 NPC 객체를 찾아 영어 ID를 가져온다.
536
+ p1_npc = self.manager.get_npc_by_korean_name(person1_korean_name)
537
+ p2_npc = self.manager.get_npc_by_korean_name(person2_korean_name)
538
 
539
  # 소문의 대상이 된 두 사람에 대한 나의 평판을 변경
540
  if p1_npc:
541
+ self.update_reputation(p1_npc.name, score_change)
542
  if p2_npc:
543
+ self.update_reputation(p2_npc.name, score_change)
npc_social_network/npc/npc_manager.py CHANGED
@@ -25,6 +25,7 @@ class NPCManager:
25
  self.npcs.append(npc)
26
  self.npc_dict[npc.name] = npc
27
  self.korean_name_to_npc[npc.korean_name] = npc
 
28
 
29
  def get_npc_by_name(self, name: str) -> Optional['NPC']:
30
  """
 
25
  self.npcs.append(npc)
26
  self.npc_dict[npc.name] = npc
27
  self.korean_name_to_npc[npc.korean_name] = npc
28
+ npc.manager = self
29
 
30
  def get_npc_by_name(self, name: str) -> Optional['NPC']:
31
  """
npc_social_network/npc/npc_memory_embedder.py CHANGED
@@ -55,7 +55,7 @@ def embed_npc_memories(npc: "NPC"):
55
  texts = [memory_to_text(mem) for mem in memories]
56
  embeddings = model.encode(texts)
57
  index = faiss.IndexFlatL2(DIMENSION)
58
- index.add(np.arry(embeddings, dtype=np.float32))
59
 
60
  safe_filename = sanitize_filename(npc.name)
61
  save_path = os.path.join(VECTOR_DIR, f"{safe_filename}.faiss")
 
55
  texts = [memory_to_text(mem) for mem in memories]
56
  embeddings = model.encode(texts)
57
  index = faiss.IndexFlatL2(DIMENSION)
58
+ index.add(np.array(embeddings, dtype=np.float32))
59
 
60
  safe_filename = sanitize_filename(npc.name)
61
  save_path = os.path.join(VECTOR_DIR, f"{safe_filename}.faiss")
npc_social_network/npc/npc_relationship.py CHANGED
@@ -30,7 +30,7 @@ class RelationshipManager:
30
  return self.relationships[target_name]
31
 
32
  def update_relationship(self, target_name: str, emotion: str, strength: float=1.0,
33
- memory: Optional["Memory"]=None, npc_manager: "NPCManager"=None):
34
  """
35
  특정 감정 기반으로 관계 수치 조정
36
  - 긍정/부정만이 아니라 감정 유형에 따른 영향 차별화
@@ -40,9 +40,6 @@ class RelationshipManager:
40
 
41
  profile = self._get_or_create_profile(target_name)
42
 
43
- target_npc = npc_manager.get_npc_by_korean_name(target_name)
44
- target_korean_name = target_npc.korean_name if target_npc else target_name
45
-
46
  impact = EMOTION_RELATION_IMPACT.get(emotion, 0.0)
47
  delta = impact * strength
48
 
@@ -57,6 +54,9 @@ class RelationshipManager:
57
  if memory not in profile.key_memories:
58
  profile.key_memories.append(memory)
59
  profile.key_memories = profile.key_memories[-5:] # 최근 5개만 유지
 
 
 
60
  print(f"[{self.owner_npc.korean_name}] '{target_korean_name}'와의 새로운 핵심 기억 추가: {memory.content[:30]}...")
61
 
62
  def update_relationship_type(self, profile:SocialProfile):
@@ -82,7 +82,7 @@ class RelationshipManager:
82
  profile = self._get_or_create_profile(target_name)
83
  return profile.summary
84
 
85
- def summarize_relationship(self, target_name: str, npc_manager: "NPCManager"):
86
  """ LLM을 사용하여 특정 대상과의 관계를 주기적으로 요약하고 업데이트"""
87
  from ..models.llm_helper import query_llm_with_prompt
88
  profile = self._get_or_create_profile(target_name)
@@ -90,7 +90,7 @@ class RelationshipManager:
90
  if not profile.key_memories:
91
  return # 요약할 기억이 없으면 실행 안함
92
 
93
- target_npc = npc_manager.get_npc_by_korean_name(target_name)
94
  target_korean_name = target_npc.korean_name if target_npc else target_name
95
 
96
  memory_details = "\n".join([f"- {mem.content} (감정: {mem.emotion})" for mem in profile.key_memories])
 
30
  return self.relationships[target_name]
31
 
32
  def update_relationship(self, target_name: str, emotion: str, strength: float=1.0,
33
+ memory: Optional["Memory"]=None):
34
  """
35
  특정 감정 기반으로 관계 수치 조정
36
  - 긍정/부정만이 아니라 감정 유형에 따른 영향 차별화
 
40
 
41
  profile = self._get_or_create_profile(target_name)
42
 
 
 
 
43
  impact = EMOTION_RELATION_IMPACT.get(emotion, 0.0)
44
  delta = impact * strength
45
 
 
54
  if memory not in profile.key_memories:
55
  profile.key_memories.append(memory)
56
  profile.key_memories = profile.key_memories[-5:] # 최근 5개만 유지
57
+
58
+ target_npc = self.owner_npc.manager.get_npc_by_name(target_name)
59
+ target_korean_name = target_npc.korean_name if target_npc else target_name
60
  print(f"[{self.owner_npc.korean_name}] '{target_korean_name}'와의 새로운 핵심 기억 추가: {memory.content[:30]}...")
61
 
62
  def update_relationship_type(self, profile:SocialProfile):
 
82
  profile = self._get_or_create_profile(target_name)
83
  return profile.summary
84
 
85
+ def summarize_relationship(self, target_name: str):
86
  """ LLM을 사용하여 특정 대상과의 관계를 주기적으로 요약하고 업데이트"""
87
  from ..models.llm_helper import query_llm_with_prompt
88
  profile = self._get_or_create_profile(target_name)
 
90
  if not profile.key_memories:
91
  return # 요약할 기억이 없으면 실행 안함
92
 
93
+ target_npc = self.manager.get_npc_by_korean_name(target_name)
94
  target_korean_name = target_npc.korean_name if target_npc else target_name
95
 
96
  memory_details = "\n".join([f"- {mem.content} (감정: {mem.emotion})" for mem in profile.key_memories])
npc_social_network/simulation_core.py CHANGED
@@ -43,7 +43,7 @@ def tick_simulation():
43
  npc.decay_emotions()
44
  npc.decay_memories()
45
  if random.random() < 0.1:
46
- npc.update_autonomous_behavior("자율 행동 시간", npc_manager, add_log)
47
 
48
  if len(npc_manager.all()) >= 3: # 목격자가 있으려면 최소 3명 필요
49
  try:
@@ -66,7 +66,6 @@ def tick_simulation():
66
  importance=4,
67
  emotion="curiosity",
68
  memory_type="Gossip",
69
- npc_manager = npc_manager
70
  )
71
  add_log(f"[목격] {witness.name}이(가) {initiator.name}와 {target.name}의 대화를 목격함.")
72
 
 
43
  npc.decay_emotions()
44
  npc.decay_memories()
45
  if random.random() < 0.1:
46
+ npc.update_autonomous_behavior("자율 행동 시간")
47
 
48
  if len(npc_manager.all()) >= 3: # 목격자가 있으려면 최소 3명 필요
49
  try:
 
66
  importance=4,
67
  emotion="curiosity",
68
  memory_type="Gossip",
 
69
  )
70
  add_log(f"[목격] {witness.name}이(가) {initiator.name}와 {target.name}의 대화를 목격함.")
71