youdie006 commited on
Commit
018295b
·
1 Parent(s): f369cb4

Fix: Data issue

Browse files
Files changed (1) hide show
  1. src/core/vector_store.py +255 -38
src/core/vector_store.py CHANGED
@@ -12,6 +12,8 @@ import uuid
12
  import time
13
  import math
14
  from datetime import datetime
 
 
15
 
16
  from ..models.vector_models import SearchResult, DocumentInput, VectorStoreStats
17
 
@@ -28,21 +30,36 @@ class ChromaVectorStore:
28
  self.cache_dir = "/app/cache"
29
 
30
  async def initialize(self):
31
- """ChromaDB 및 임베딩 모델 초기화 - 0.3.21 최종 호환"""
32
  try:
33
  logger.info("ChromaDB Vector Store 초기화 시작...")
34
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  db_path = os.getenv("CHROMADB_PATH", "/app/data/chromadb")
36
  os.makedirs(db_path, exist_ok=True)
37
 
38
- # 🔧 ChromaDB 0.3.21 호환 Settings (allow_reset 제거!)
 
 
 
 
39
  settings = Settings(
40
  chroma_db_impl="duckdb+parquet",
41
  persist_directory=db_path,
42
  anonymized_telemetry=False
43
  )
44
 
45
- # 0.3.21에서는 Client() 사용
46
  self.client = chromadb.Client(settings)
47
 
48
  # 임베딩 모델 로드
@@ -54,52 +71,252 @@ class ChromaVectorStore:
54
  )
55
  logger.info(f"임베딩 모델 로드 완료 - 차원: {self.embedding_model.get_sentence_embedding_dimension()}")
56
 
57
- # 컬렉션 생성/연결 (0.3.21 방식)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  try:
59
- self.collection = self.client.get_collection(name=self.collection_name)
60
- logger.info(f"기존 컬렉션 연결: {self.collection_name}")
61
- except Exception:
62
- # 컬렉션이 없으면 생성
63
  self.collection = self.client.create_collection(
64
  name=self.collection_name,
65
  metadata={
66
  "description": "Teen empathy conversation embeddings",
67
- "created_at": datetime.now().isoformat()
 
68
  }
69
  )
70
- logger.info(f"새 컬렉션 생성: {self.collection_name}")
 
 
 
 
 
 
 
71
 
72
  logger.info("✅ ChromaDB Vector Store 초기화 완료")
73
 
74
  except Exception as e:
75
  logger.error(f"❌ ChromaDB 초기화 실패: {e}")
76
- # 간단한 방식으로 재시도
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  try:
78
- logger.info("🔄 간단한 방식으로 재시도...")
79
- self.client = chromadb.Client()
80
-
81
- # 임베딩 모델은 이미 시도했으므로 스킵하지 않음
82
- if not self.embedding_model:
83
- logger.info(f"한국어 임베딩 모델 로드 중: {self.model_name}")
84
- self.embedding_model = SentenceTransformer(
85
- self.model_name,
86
- cache_folder=self.cache_dir,
87
- device='cpu'
88
- )
89
-
90
- # 컬렉션 생성/연결
91
- try:
92
- self.collection = self.client.get_collection(name=self.collection_name)
93
- logger.info(f"기존 컬렉션 연결: {self.collection_name}")
94
- except Exception:
95
- self.collection = self.client.create_collection(name=self.collection_name)
96
- logger.info(f"새 컬렉션 생성: {self.collection_name}")
97
-
98
- logger.info("✅ ChromaDB Vector Store 초기화 완료 (간단한 방식)")
99
-
100
- except Exception as e2:
101
- logger.error(f"❌ 간단한 방식도 실패: {e2}")
102
- raise
103
 
104
  def create_embeddings(self, texts: List[str]) -> List[List[float]]:
105
  """임베딩 생성"""
@@ -129,10 +346,10 @@ class ChromaVectorStore:
129
  document_ids = [doc.document_id or str(uuid.uuid4()) for doc in documents]
130
 
131
  # 메타데이터에 타임스탬프 추가
132
- for metadata in metadatas:
133
  metadata.update({
134
  "timestamp": datetime.now().isoformat(),
135
- "content_length": len(texts[metadatas.index(metadata)]),
136
  "indexed_at": datetime.now().isoformat()
137
  })
138
 
 
12
  import time
13
  import math
14
  from datetime import datetime
15
+ import subprocess
16
+ import glob
17
 
18
  from ..models.vector_models import SearchResult, DocumentInput, VectorStoreStats
19
 
 
30
  self.cache_dir = "/app/cache"
31
 
32
  async def initialize(self):
33
+ """ChromaDB 및 임베딩 모델 초기화 - ChromaDB 파일 직접 사용"""
34
  try:
35
  logger.info("ChromaDB Vector Store 초기화 시작...")
36
 
37
+ # 🔍 환경 감지
38
+ is_huggingface = bool(os.getenv("SPACE_ID") or os.getenv("SPACE_AUTHOR_NAME"))
39
+ is_local_dev = bool(os.getenv("LOCAL_DEV") or os.getenv("DEVELOPMENT_MODE"))
40
+
41
+ logger.info(f"🌍 환경 감지 - HuggingFace: {is_huggingface}, Local: {is_local_dev}")
42
+
43
+ # 🤗 허깅페이스 환경에서 ChromaDB 다운로드
44
+ if is_huggingface:
45
+ logger.info("🤗 허깅페이스 환경 - ChromaDB 데이터셋 다운로드 시도")
46
+ await self._download_chromadb_dataset()
47
+
48
+ # ChromaDB 경로 설정
49
  db_path = os.getenv("CHROMADB_PATH", "/app/data/chromadb")
50
  os.makedirs(db_path, exist_ok=True)
51
 
52
+ # 📂 ChromaDB 파일 존재 확인
53
+ chroma_files = self._check_chromadb_files(db_path)
54
+ logger.info(f"📂 ChromaDB 파일 상태: {chroma_files}")
55
+
56
+ # ChromaDB 0.3.21 호환 Settings
57
  settings = Settings(
58
  chroma_db_impl="duckdb+parquet",
59
  persist_directory=db_path,
60
  anonymized_telemetry=False
61
  )
62
 
 
63
  self.client = chromadb.Client(settings)
64
 
65
  # 임베딩 모델 로드
 
71
  )
72
  logger.info(f"임베딩 모델 로드 완료 - 차원: {self.embedding_model.get_sentence_embedding_dimension()}")
73
 
74
+ # 🔍 기존 컬렉션 확인
75
+ try:
76
+ existing_collections = self.client.list_collections()
77
+ collection_names = [c.name for c in existing_collections]
78
+ logger.info(f"기존 컬렉션들: {collection_names}")
79
+
80
+ # 타겟 컬렉션 찾기
81
+ target_collection = None
82
+ possible_names = [self.collection_name, "teen_empathy_chat", "empathy_chat", "chat_data"]
83
+
84
+ for name in possible_names:
85
+ if name in collection_names:
86
+ target_collection = name
87
+ break
88
+
89
+ if target_collection:
90
+ self.collection = self.client.get_collection(name=target_collection)
91
+ existing_count = self.collection.count()
92
+ logger.info(f"✅ 기존 컬렉션 연결: {target_collection} ({existing_count}개 문서)")
93
+
94
+ if existing_count > 0:
95
+ logger.info("🎉 기존 임베딩 데이터 사용 - 초기화 완료!")
96
+ return
97
+ else:
98
+ logger.warning("⚠️ 컬렉션은 있지만 문서가 없음")
99
+
100
+ except Exception as e:
101
+ logger.warning(f"⚠️ 기존 컬렉션 확인 실패: {e}")
102
+
103
+ # 🔧 컬렉션이 없거나 빈 경우 - 새로 생성
104
+ logger.info("🔧 새 컬렉션 생성 및 기본 데이터 추가")
105
  try:
 
 
 
 
106
  self.collection = self.client.create_collection(
107
  name=self.collection_name,
108
  metadata={
109
  "description": "Teen empathy conversation embeddings",
110
+ "created_at": datetime.now().isoformat(),
111
+ "environment": "huggingface" if is_huggingface else "local"
112
  }
113
  )
114
+ logger.info(f"🆕 새 컬렉션 생성: {self.collection_name}")
115
+
116
+ # 기본 데이터 추가
117
+ await self._add_essential_data()
118
+
119
+ except Exception as e:
120
+ logger.error(f"❌ 컬렉션 생성 실패: {e}")
121
+ raise
122
 
123
  logger.info("✅ ChromaDB Vector Store 초기화 완료")
124
 
125
  except Exception as e:
126
  logger.error(f"❌ ChromaDB 초기화 실패: {e}")
127
+ # 간단한 방식으로 재시도
128
+ await self._fallback_initialize()
129
+
130
+ async def _download_chromadb_dataset(self):
131
+ """허깅페이스에서 ChromaDB 데이터셋 다운로드"""
132
+ try:
133
+ logger.info("📥 ChromaDB 데이터셋 다운로드 시작...")
134
+
135
+ # 다운로드 디렉토리 준비
136
+ download_dir = "/app/data"
137
+ os.makedirs(download_dir, exist_ok=True)
138
+
139
+ # huggingface-cli를 사용해서 ChromaDB 파일들 다운로드
140
+ cmd = [
141
+ "huggingface-cli", "download",
142
+ "youdie006/simsimi-ai-agent-data",
143
+ "--repo-type", "dataset",
144
+ "--local-dir", download_dir,
145
+ "--local-dir-use-symlinks", "False"
146
+ ]
147
+
148
+ logger.info(f"📥 실행 명령: {' '.join(cmd)}")
149
+
150
+ result = subprocess.run(
151
+ cmd,
152
+ capture_output=True,
153
+ text=True,
154
+ timeout=600, # 10분 타임아웃
155
+ cwd="/app"
156
+ )
157
+
158
+ if result.returncode == 0:
159
+ logger.info("✅ ChromaDB 데이터셋 다운로드 완료")
160
+ logger.info(f"📁 다운로드 내용: {result.stdout}")
161
+
162
+ # 다운로드된 파일 확인
163
+ downloaded_files = []
164
+ for root, dirs, files in os.walk(download_dir):
165
+ for file in files:
166
+ file_path = os.path.join(root, file)
167
+ downloaded_files.append(file_path)
168
+
169
+ logger.info(f"📂 다운로드된 파일들: {downloaded_files}")
170
+
171
+ # ChromaDB 관련 파일 확인
172
+ chromadb_files = [f for f in downloaded_files if any(ext in f.lower() for ext in ['.duckdb', '.parquet', 'chroma'])]
173
+ logger.info(f"🗄️ ChromaDB 관련 파일들: {chromadb_files}")
174
+
175
+ else:
176
+ logger.warning(f"⚠️ 다운로드 실패: {result.stderr}")
177
+ logger.warning(f"📤 출력: {result.stdout}")
178
+
179
+ except subprocess.TimeoutExpired:
180
+ logger.warning("⚠️ 다운로드 타임아웃 (10분 초과)")
181
+ except Exception as e:
182
+ logger.warning(f"⚠️ 다운로드 실패: {e}")
183
+
184
+ def _check_chromadb_files(self, db_path: str) -> dict:
185
+ """ChromaDB 파일 존재 확인"""
186
+ try:
187
+ files_info = {}
188
+
189
+ # 일반적인 ChromaDB 파일 패턴
190
+ patterns = [
191
+ "*.duckdb",
192
+ "*.parquet",
193
+ "chroma.sqlite3",
194
+ "index/*",
195
+ "*.bin"
196
+ ]
197
+
198
+ for pattern in patterns:
199
+ files = glob.glob(os.path.join(db_path, "**", pattern), recursive=True)
200
+ if files:
201
+ files_info[pattern] = files
202
+
203
+ # 전체 파일 목록
204
+ all_files = []
205
+ if os.path.exists(db_path):
206
+ for root, dirs, files in os.walk(db_path):
207
+ for file in files:
208
+ all_files.append(os.path.join(root, file))
209
+
210
+ files_info["all_files"] = all_files
211
+ files_info["total_count"] = len(all_files)
212
+
213
+ return files_info
214
+
215
+ except Exception as e:
216
+ logger.warning(f"파일 확인 실패: {e}")
217
+ return {"error": str(e)}
218
+
219
+ async def _add_essential_data(self):
220
+ """필수 데이터 추가 (ChromaDB 파일이 없는 경우)"""
221
+ try:
222
+ logger.info("🔧 필수 데이터 추가 중...")
223
+
224
+ essential_docs = [
225
+ DocumentInput(
226
+ content="엄마가 계속 잔소리해서 화가 나요",
227
+ metadata={
228
+ "user_utterance": "엄마가 계속 잔소리해서 화가 나요",
229
+ "system_response": "부모님과의 갈등은 정말 힘들지. 엄마도 너를 걱정해서 그러는 건 알지만, 잔소리가 계속되면 스트레스받을 만해.",
230
+ "emotion": "분노",
231
+ "relationship": "부모님",
232
+ "data_source": "essential"
233
+ },
234
+ document_id="essential_parent_conflict"
235
+ ),
236
+ DocumentInput(
237
+ content="친구가 나를 무시하는 것 같아서 속상해",
238
+ metadata={
239
+ "user_utterance": "친구가 나를 무시하는 것 같아서 속상해",
240
+ "system_response": "친구가 너를 무시한다고 느끼는 구체적인 상황이 있었나? 그런 기분이 들면 정말 속상할 것 같아.",
241
+ "emotion": "상처",
242
+ "relationship": "친구",
243
+ "data_source": "essential"
244
+ },
245
+ document_id="essential_friend_hurt"
246
+ ),
247
+ DocumentInput(
248
+ content="시험이 걱정돼서 잠이 안 와요",
249
+ metadata={
250
+ "user_utterance": "시험이 걱정돼서 잠이 안 와요",
251
+ "system_response": "시험 스트레스는 정말 힘들어. 불안한 마음이 드는 건 당연해. 깊게 숨을 쉬고 차근차근 준비해보자.",
252
+ "emotion": "불안",
253
+ "relationship": "기타",
254
+ "data_source": "essential"
255
+ },
256
+ document_id="essential_exam_anxiety"
257
+ ),
258
+ DocumentInput(
259
+ content="요즘 우울해서 아무것도 하기 싫어",
260
+ metadata={
261
+ "user_utterance": "요즘 우울해서 아무것도 하기 싫어",
262
+ "system_response": "우울한 기분이 드는 건 정말 힘들어. 혼자 견디지 말고 주변 사람들과 이야기해보는 것도 좋을 것 같아.",
263
+ "emotion": "슬픔",
264
+ "relationship": "기타",
265
+ "data_source": "essential"
266
+ },
267
+ document_id="essential_depression"
268
+ ),
269
+ DocumentInput(
270
+ content="선생님이 나만 미워하는 것 같아",
271
+ metadata={
272
+ "user_utterance": "선생님이 나만 미워하는 것 같아",
273
+ "system_response": "선생님이 너를 미워한다고 느끼는 구체적인 상황이 있었나? 오해일 수도 있으니까 차근차근 생각해보자.",
274
+ "emotion": "당황",
275
+ "relationship": "선생님",
276
+ "data_source": "essential"
277
+ },
278
+ document_id="essential_teacher_conflict"
279
+ )
280
+ ]
281
+
282
+ await self.add_documents(essential_docs)
283
+ logger.info(f"✅ 필수 데이터 {len(essential_docs)}개 추가 완료")
284
+
285
+ except Exception as e:
286
+ logger.error(f"❌ 필수 데이터 추가 실패: {e}")
287
+
288
+ async def _fallback_initialize(self):
289
+ """폴백 초기화"""
290
+ try:
291
+ logger.info("🔄 폴백 초기화 시작...")
292
+
293
+ self.client = chromadb.Client()
294
+
295
+ if not self.embedding_model:
296
+ self.embedding_model = SentenceTransformer(
297
+ self.model_name,
298
+ cache_folder=self.cache_dir,
299
+ device='cpu'
300
+ )
301
+
302
  try:
303
+ self.collection = self.client.get_collection(name=self.collection_name)
304
+ count = self.collection.count()
305
+ logger.info(f"기존 컬렉션 연결: {self.collection_name} ({count}개)")
306
+
307
+ if count == 0:
308
+ await self._add_essential_data()
309
+
310
+ except Exception:
311
+ self.collection = self.client.create_collection(name=self.collection_name)
312
+ logger.info(f"새 컬렉션 생성: {self.collection_name}")
313
+ await self._add_essential_data()
314
+
315
+ logger.info("✅ 폴백 초기화 완료")
316
+
317
+ except Exception as e:
318
+ logger.error(f" 폴백 초기화도 실패: {e}")
319
+ raise
 
 
 
 
 
 
 
 
320
 
321
  def create_embeddings(self, texts: List[str]) -> List[List[float]]:
322
  """임베딩 생성"""
 
346
  document_ids = [doc.document_id or str(uuid.uuid4()) for doc in documents]
347
 
348
  # 메타데이터에 타임스탬프 추가
349
+ for i, metadata in enumerate(metadatas):
350
  metadata.update({
351
  "timestamp": datetime.now().isoformat(),
352
+ "content_length": len(texts[i]),
353
  "indexed_at": datetime.now().isoformat()
354
  })
355