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

2. 정적 인덱싱 문제 수정: step 1

Browse files
npc_social_network/npc/npc_memory_embedder.py CHANGED
@@ -8,6 +8,7 @@ import re
8
  from typing import TYPE_CHECKING
9
  if TYPE_CHECKING:
10
  from .npc_base import NPC
 
11
 
12
  # 사전 훈련된 문장 임베딩 모델
13
  model = SentenceTransformer("all-MiniLM-L6-v2")
@@ -15,8 +16,9 @@ model = SentenceTransformer("all-MiniLM-L6-v2")
15
  # 문장 임베딩 저장 장소
16
  BASE_DIR = os.path.dirname(os.path.abspath(__file__))
17
  VECTOR_DIR = os.path.join(BASE_DIR, "..", "data", "vectorstores")
 
18
 
19
- def memory_to_text(memory):
20
  """
21
  Memory 객체를 임베딩 가능한 텍스트 형태로 변환
22
  """
@@ -39,43 +41,70 @@ def embed_memory(memory):
39
 
40
  def embed_npc_memories(npc: "NPC"):
41
  """
42
- 특정 NPC의 기억 전체를 임베딩하고 FAISS index로 저장
 
43
  """
44
  if not os.path.exists(VECTOR_DIR):
45
  os.makedirs(VECTOR_DIR)
46
 
47
  memories = npc.memory_store.get_all_memories()
48
- texts = [memory_to_text(mem) for mem in memories]
49
- embeddings = model.encode(texts)
50
-
51
- index = faiss.IndexFlatL2(len(embeddings[0]))
52
- index.add(np.array(embeddings, dtype=np.float32))
 
 
 
53
 
54
  safe_filename = sanitize_filename(npc.name)
55
  save_path = os.path.join(VECTOR_DIR, f"{safe_filename}.faiss")
56
  faiss.write_index(index, save_path)
57
 
58
- print(f"[임베딩 완료] {npc.name}의 기억 {len(memories)}개를 벡터화하여 저장했습니다.")
59
- print(f"[임베딩 완료] {npc.name} → 저장 위치: {save_path}")
60
 
61
- def load_npc_faiss_index(npc_name):
62
  """
63
  저장된 FAISS 인덱스를 불러옴
 
64
  """
65
  safe_filename = sanitize_filename(npc_name)
66
- index_path = f"{VECTOR_DIR}/{safe_filename}.faiss"
67
- if not os.path.exists(index_path):
68
- raise FileNotFoundError(f"{index_path} FAISS 인덱스가 존재하지 않습니다.")
69
- index = faiss.read_index(index_path)
70
- return index
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
 
72
  def search_similar_memories(npc: "NPC", query: str, top_k=3):
73
  """
74
  질의 문장을 벡터로 변환하고 FAISS에서 유사한 기억 검색
75
  """
76
- index = load_npc_faiss_index(npc.name)
 
 
 
77
  query_vec = model.encode([query])
78
- distances, indices = index.search(np.array(query_vec, dtype=np.float32), top_k)
79
 
80
  all_memories = npc.memory_store.get_all_memories()
81
 
 
8
  from typing import TYPE_CHECKING
9
  if TYPE_CHECKING:
10
  from .npc_base import NPC
11
+ from .npc_memory import Memory
12
 
13
  # 사전 훈련된 문장 임베딩 모델
14
  model = SentenceTransformer("all-MiniLM-L6-v2")
 
16
  # 문장 임베딩 저장 장소
17
  BASE_DIR = os.path.dirname(os.path.abspath(__file__))
18
  VECTOR_DIR = os.path.join(BASE_DIR, "..", "data", "vectorstores")
19
+ DIMENSION = model.get_sentence_embedding_dimension()
20
 
21
+ def memory_to_text(memory: "Memory") -> str:
22
  """
23
  Memory 객체를 임베딩 가능한 텍스트 형태로 변환
24
  """
 
41
 
42
  def embed_npc_memories(npc: "NPC"):
43
  """
44
+ 특정 NPC의 초기 기억 전체를 임베딩하고 FAISS index로 처음 저장
45
+ - scenario_setup에서만 사용
46
  """
47
  if not os.path.exists(VECTOR_DIR):
48
  os.makedirs(VECTOR_DIR)
49
 
50
  memories = npc.memory_store.get_all_memories()
51
+ if not memories:
52
+ # 기억이 없으면 빈 인덱스 생성
53
+ index = faiss.IndexFlatL2(DIMENSION)
54
+ else:
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")
62
  faiss.write_index(index, save_path)
63
 
64
+ print(f"[초기 임베딩 완료] {npc.korean_name}의 기억 {len(memories)}개를 벡터화하여 저장했습니다.")
65
+ print(f"저장 위치: {save_path}")
66
 
67
+ def load_or_create_faiss_index(npc_name:str) -> faiss.Index:
68
  """
69
  저장된 FAISS 인덱스를 불러옴
70
+ - 없으면 새로 생성
71
  """
72
  safe_filename = sanitize_filename(npc_name)
73
+ index_path = os.path.join(VECTOR_DIR, f"{safe_filename}.faiss")
74
+
75
+ if os.path.exists(index_path):
76
+ return faiss.read_index(index_path)
77
+ else:
78
+ # 파일이 없으면 새로운 빈 인덱스를 생성하여 반환
79
+ return faiss.IndexFlatL2(DIMENSION)
80
+
81
+ def add_memory_to_index(npc: "NPC", memory: "Memory"):
82
+ """단일 기억을 기존 FAISS 인덱스에 추가하고 다시 저장"""
83
+ # 1. 기존 인덱스를 불러오거나 새로 생성
84
+ index = load_or_create_faiss_index(npc.name)
85
+
86
+ # 2. 새로운 기억을 텍스트로 변환하고 임베딩
87
+ text = memory_to_text(memory)
88
+ new_embedding = model.encode([text])
89
+
90
+ # 3. 새로운 벡터를 인덱스에 추가
91
+ index.add(np.array(new_embedding, dtype=np.float32))
92
+
93
+ # 4. 업데이트된 인덱스를 다시 저장
94
+ safe_filename = sanitize_filename(npc.name)
95
+ save_path = os.path.join(VECTOR_DIR, f"{safe_filename}.faiss")
96
+ faiss.write_index(index, save_path)
97
 
98
  def search_similar_memories(npc: "NPC", query: str, top_k=3):
99
  """
100
  질의 문장을 벡터로 변환하고 FAISS에서 유사한 기억 검색
101
  """
102
+ index = load_or_create_faiss_index(npc.name)
103
+ if index.ntotal == 0:
104
+ return [], [], []
105
+
106
  query_vec = model.encode([query])
107
+ distances, indices = index.search(np.array(query_vec, dtype=np.float32), min(top_k, index.ntotal))
108
 
109
  all_memories = npc.memory_store.get_all_memories()
110
 
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):
34
  """
35
  특정 감정 기반으로 관계 수치 조정
36
  - 긍정/부정만이 아니라 감정 유형에 따른 영향 차별화
@@ -40,6 +40,9 @@ class RelationshipManager:
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,7 +57,7 @@ class RelationshipManager:
54
  if memory not in profile.key_memories:
55
  profile.key_memories.append(memory)
56
  profile.key_memories = profile.key_memories[-5:] # 최근 5개만 유지
57
- print(f"[{self.owner_npc.name}] '{target_name}'와의 새로운 핵심 기억 추가: {memory.content[:30]}...")
58
 
59
  def update_relationship_type(self, profile:SocialProfile):
60
  """
 
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
 
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
  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):
63
  """