Spaces:
Runtime error
Runtime error
youdie006
commited on
Commit
·
018295b
1
Parent(s):
f369cb4
Fix: Data issue
Browse files- 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 및 임베딩 모델 초기화 -
|
| 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 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
if
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 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[
|
| 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 |
|