lanny xu commited on
Commit
116d9c5
·
1 Parent(s): 94f5b16

delete vectara

Browse files
Files changed (2) hide show
  1. document_processor.py +107 -4
  2. kaggle_simple_multimodal.py +164 -20
document_processor.py CHANGED
@@ -214,13 +214,28 @@ class DocumentProcessor:
214
  print(f"文档分割完成,共 {len(doc_splits)} 个文档块")
215
  return doc_splits
216
 
217
- def create_vectorstore(self, doc_splits):
218
- """创建向量数据库"""
 
 
 
 
 
219
  print("正在创建向量数据库...")
 
 
 
 
 
 
 
 
 
220
  self.vectorstore = Chroma.from_documents(
221
  documents=doc_splits,
222
  collection_name=COLLECTION_NAME,
223
  embedding=self.embeddings,
 
224
  )
225
  self.retriever = self.vectorstore.as_retriever()
226
 
@@ -247,7 +262,7 @@ class DocumentProcessor:
247
  print("⚠️ 将仅使用向量检索")
248
  self.ensemble_retriever = None
249
 
250
- print("向量数据库创建完成")
251
  return self.vectorstore, self.retriever
252
 
253
  def setup_knowledge_base(self, urls=None, enable_graphrag=False):
@@ -520,7 +535,95 @@ class DocumentProcessor:
520
 
521
 
522
  def initialize_document_processor():
523
- """初始化文档处理器并设置知识库"""
 
 
 
 
 
 
 
 
 
524
  processor: DocumentProcessor = DocumentProcessor()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
525
  vectorstore, retriever, doc_splits = processor.setup_knowledge_base()
 
 
 
 
 
 
 
 
 
 
526
  return processor, vectorstore, retriever, doc_splits
 
214
  print(f"文档分割完成,共 {len(doc_splits)} 个文档块")
215
  return doc_splits
216
 
217
+ def create_vectorstore(self, doc_splits, persist_directory=None):
218
+ """创建向量数据库
219
+
220
+ Args:
221
+ doc_splits: 文档块列表
222
+ persist_directory: 持久化目录(可选)
223
+ """
224
  print("正在创建向量数据库...")
225
+
226
+ # 如果没有指定持久化目录,使用默认相对路径
227
+ if persist_directory is None:
228
+ import os
229
+ current_dir = os.path.dirname(os.path.abspath(__file__))
230
+ persist_directory = os.path.join(current_dir, 'chroma_db')
231
+ os.makedirs(persist_directory, exist_ok=True)
232
+ print(f"💾 使用默认持久化目录: {persist_directory}")
233
+
234
  self.vectorstore = Chroma.from_documents(
235
  documents=doc_splits,
236
  collection_name=COLLECTION_NAME,
237
  embedding=self.embeddings,
238
+ persist_directory=persist_directory # 添加持久化目录
239
  )
240
  self.retriever = self.vectorstore.as_retriever()
241
 
 
262
  print("⚠️ 将仅使用向量检索")
263
  self.ensemble_retriever = None
264
 
265
+ print(f"✅ 向量数据库创建完成并持久化到: {persist_directory}")
266
  return self.vectorstore, self.retriever
267
 
268
  def setup_knowledge_base(self, urls=None, enable_graphrag=False):
 
535
 
536
 
537
  def initialize_document_processor():
538
+ """初始化文档处理器并设置知识库,支持持久化加载和去重"""
539
+ import os
540
+ import json
541
+ import hashlib
542
+
543
+ # 设置持久化目录(相对路径)
544
+ current_dir = os.path.dirname(os.path.abspath(__file__))
545
+ persist_dir = os.path.join(current_dir, 'chroma_db')
546
+ metadata_file = os.path.join(current_dir, 'document_metadata.json')
547
+
548
  processor: DocumentProcessor = DocumentProcessor()
549
+
550
+ # 加载已处理文档的元数据
551
+ processed_sources = set()
552
+ if os.path.exists(metadata_file):
553
+ try:
554
+ with open(metadata_file, 'r', encoding='utf-8') as f:
555
+ metadata = json.load(f)
556
+ processed_sources = set(metadata.get('processed_sources', []))
557
+ print(f"📊 已加载元数据,发现 {len(processed_sources)} 个已处理的数据源")
558
+ except Exception as e:
559
+ print(f"⚠️ 加载元数据失败: {e}")
560
+
561
+ # 检查是否已存在持久化的向量数据库
562
+ if os.path.exists(persist_dir) and os.listdir(persist_dir):
563
+ print(f"✅ 检测到已存在的向量数据库: {persist_dir}")
564
+ print("📂 正在加载持久化的向量数据库...")
565
+ try:
566
+ # 加载已有的向量数据库
567
+ vectorstore = Chroma(
568
+ persist_directory=persist_dir,
569
+ embedding_function=processor.embeddings,
570
+ collection_name=COLLECTION_NAME
571
+ )
572
+ retriever = vectorstore.as_retriever()
573
+
574
+ # 获取文档数量
575
+ doc_count = vectorstore._collection.count()
576
+ print(f"✅ 已加载持久化的向量数据库,共 {doc_count} 个文档块")
577
+
578
+ # 设置processor的vectorstore和retriever
579
+ processor.vectorstore = vectorstore
580
+ processor.retriever = retriever
581
+
582
+ # 检查是否需要添加新数据源
583
+ default_urls = set(KNOWLEDGE_BASE_URLS)
584
+ new_urls = default_urls - processed_sources
585
+
586
+ if new_urls:
587
+ print(f"🆕 检测到 {len(new_urls)} 个新的数据源,正在添加...")
588
+ try:
589
+ # 加载新数据源
590
+ new_docs = processor.load_documents(list(new_urls))
591
+ new_doc_splits = processor.split_documents(new_docs)
592
+
593
+ # 添加到现有向量数据库
594
+ vectorstore.add_documents(new_doc_splits)
595
+ print(f"✅ 已添加 {len(new_doc_splits)} 个新文档块")
596
+
597
+ # 更新元数据
598
+ processed_sources.update(new_urls)
599
+ with open(metadata_file, 'w', encoding='utf-8') as f:
600
+ json.dump({'processed_sources': list(processed_sources)}, f, ensure_ascii=False, indent=2)
601
+
602
+ except Exception as e:
603
+ print(f"⚠️ 添加新数据源失败: {e}")
604
+ else:
605
+ print("✅ 所有默认数据源已处理,无需重复加载")
606
+
607
+ # doc_splits 设置为 None,因为已经持久化了
608
+ doc_splits = None
609
+
610
+ return processor, vectorstore, retriever, doc_splits
611
+
612
+ except Exception as e:
613
+ print(f"⚠️ 加载持久化向量数据库失败: {e}")
614
+ print("🔧 将重新创建向量数据库...")
615
+
616
+ # 如果没有持久化数据或加载失败,创建新的
617
+ print("🔧 正在创建新的向量数据库...")
618
  vectorstore, retriever, doc_splits = processor.setup_knowledge_base()
619
+
620
+ # 保存元数据
621
+ try:
622
+ processed_sources.update(KNOWLEDGE_BASE_URLS)
623
+ with open(metadata_file, 'w', encoding='utf-8') as f:
624
+ json.dump({'processed_sources': list(processed_sources)}, f, ensure_ascii=False, indent=2)
625
+ print(f"✅ 元数据已保存到: {metadata_file}")
626
+ except Exception as e:
627
+ print(f"⚠️ 保存元数据失败: {e}")
628
+
629
  return processor, vectorstore, retriever, doc_splits
kaggle_simple_multimodal.py CHANGED
@@ -29,38 +29,182 @@ def setup_kaggle_environment():
29
 
30
  def process_uploaded_files(pdf_path: str = None, image_paths: List[str] = None):
31
  """
32
- 处理已上传的文件
 
33
 
34
  Args:
35
  pdf_path: PDF文件路径
36
  image_paths: 图片路径列表
37
  """
38
- # 初始化文档处理器
39
- print("🔧 正在初始化文档处理器...")
40
- doc_processor = DocumentProcessor()
41
 
42
- # 处理PDF文件
43
- if pdf_path and os.path.exists(pdf_path):
44
- print(f"📄 处理PDF文件: {pdf_path}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  try:
46
- from langchain_community.document_loaders import PyPDFLoader
47
- loader = PyPDFLoader(pdf_path)
48
- docs = loader.load()
 
 
 
 
 
 
 
 
 
 
 
 
49
 
50
- # 分割文档
51
- doc_splits = doc_processor.split_documents(docs)
52
 
53
- # 创建向量数据库
54
- vectorstore, retriever = doc_processor.create_vectorstore(doc_splits)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
- print(f"✅ PDF处理完成,共 {len(doc_splits)} 个文档块")
57
  except Exception as e:
58
- print(f" PDF处理失败: {e}")
59
- return None
60
  else:
61
- # 使用默认知识库
62
- print("📄 使用默认知识库...")
63
- vectorstore, retriever, doc_splits = doc_processor.setup_knowledge_base()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
  # 初始化RAG系统
66
  print("🤖 正在初始化自适应RAG系统...")
 
29
 
30
  def process_uploaded_files(pdf_path: str = None, image_paths: List[str] = None):
31
  """
32
+ 处理已上传的文件,向量化并持久化到项目目录
33
+ 支持文件去重,避免重复处理
34
 
35
  Args:
36
  pdf_path: PDF文件路径
37
  image_paths: 图片路径列表
38
  """
39
+ import hashlib
40
+ import json
 
41
 
42
+ # 设置向量数据库持久化目录(相对路径)
43
+ # 获取当前脚本所在目录
44
+ current_dir = os.path.dirname(os.path.abspath(__file__))
45
+ persist_dir = os.path.join(current_dir, 'chroma_db')
46
+ metadata_file = os.path.join(current_dir, 'document_metadata.json')
47
+ os.makedirs(persist_dir, exist_ok=True)
48
+
49
+ print(f"💾 向量数据库持久化目录: {persist_dir}")
50
+
51
+ # 加载已处理文件的元数据(用于去重)
52
+ processed_files = {}
53
+ if os.path.exists(metadata_file):
54
+ try:
55
+ with open(metadata_file, 'r', encoding='utf-8') as f:
56
+ metadata = json.load(f)
57
+ processed_files = metadata.get('processed_files', {})
58
+ print(f"📊 已加载元数据,发现 {len(processed_files)} 个已处理的文件")
59
+ except Exception as e:
60
+ print(f"⚠️ 加载元数据失败: {e}")
61
+
62
+ # 计算文件哈希值(用于去重检测)
63
+ def get_file_hash(file_path: str) -> str:
64
+ """计算文件的MD5哈希值"""
65
+ if not os.path.exists(file_path):
66
+ return None
67
+ try:
68
+ with open(file_path, 'rb') as f:
69
+ file_hash = hashlib.md5(f.read()).hexdigest()
70
+ return file_hash
71
+ except Exception as e:
72
+ print(f"⚠️ 计算文件哈希失败: {e}")
73
+ return None
74
+
75
+ # 检查是否已存在向量数据库
76
+ if os.path.exists(persist_dir) and os.listdir(persist_dir):
77
+ print("✅ 检测到已存在的向量数据库,加载中...")
78
  try:
79
+ # 加载已存在的向量数据库
80
+ from langchain_community.embeddings import HuggingFaceEmbeddings
81
+ from langchain_community.vectorstores import Chroma
82
+ from config import EMBEDDING_MODEL, COLLECTION_NAME
83
+
84
+ embeddings = HuggingFaceEmbeddings(
85
+ model_name=EMBEDDING_MODEL,
86
+ model_kwargs={'device': 'cpu'}
87
+ )
88
+
89
+ vectorstore = Chroma(
90
+ persist_directory=persist_dir,
91
+ embedding_function=embeddings,
92
+ collection_name=COLLECTION_NAME
93
+ )
94
 
95
+ retriever = vectorstore.as_retriever()
96
+ print(f"✅ 已加载持久化的向量数据库,共 {vectorstore._collection.count()} 个文档块")
97
 
98
+ # 初始化文档处理器
99
+ doc_processor = DocumentProcessor()
100
+
101
+ # 检查PDF文件是否需要处理
102
+ if pdf_path and os.path.exists(pdf_path):
103
+ file_hash = get_file_hash(pdf_path)
104
+ if file_hash and file_hash in processed_files:
105
+ print(f"⏭️ PDF文件已处理过({pdf_path}),跳过")
106
+ else:
107
+ print(f"🆕 检测到新PDF文件,正在添加: {pdf_path}")
108
+ try:
109
+ from langchain_community.document_loaders import PyPDFLoader
110
+ loader = PyPDFLoader(pdf_path)
111
+ docs = loader.load()
112
+ doc_splits = doc_processor.split_documents(docs)
113
+
114
+ # 添加到现有向量数据库
115
+ vectorstore.add_documents(doc_splits)
116
+ print(f"✅ 已添加 {len(doc_splits)} 个新文档块")
117
+
118
+ # 更新元数据
119
+ if file_hash:
120
+ processed_files[file_hash] = {
121
+ 'path': pdf_path,
122
+ 'type': 'pdf',
123
+ 'chunks': len(doc_splits),
124
+ 'processed_at': time.time()
125
+ }
126
+ with open(metadata_file, 'w', encoding='utf-8') as f:
127
+ json.dump({'processed_files': processed_files}, f, ensure_ascii=False, indent=2)
128
+ print(f"💾 元数据已更新")
129
+ except Exception as e:
130
+ print(f"⚠️ 添加新PDF失败: {e}")
131
 
 
132
  except Exception as e:
133
+ print(f"⚠️ 加载向量数据库失败: {e},将重新创建")
134
+ vectorstore, retriever, doc_processor = None, None, None
135
  else:
136
+ vectorstore, retriever, doc_processor = None, None, None
137
+
138
+ # 如果没有加载成功,则创建新的向量数据库
139
+ if vectorstore is None:
140
+ print("🔧 正在创建新的向量数据库...")
141
+
142
+ # 初始化文档处理器
143
+ doc_processor = DocumentProcessor()
144
+
145
+ # 处理PDF文件
146
+ if pdf_path and os.path.exists(pdf_path):
147
+ print(f"📄 处理PDF文件: {pdf_path}")
148
+ try:
149
+ from langchain_community.document_loaders import PyPDFLoader
150
+ loader = PyPDFLoader(pdf_path)
151
+ docs = loader.load()
152
+
153
+ # 分割文档
154
+ doc_splits = doc_processor.split_documents(docs)
155
+
156
+ # 创建向量数据库(带持久化)
157
+ from langchain_community.embeddings import HuggingFaceEmbeddings
158
+ from langchain_community.vectorstores import Chroma
159
+ from config import EMBEDDING_MODEL, COLLECTION_NAME
160
+
161
+ embeddings = HuggingFaceEmbeddings(
162
+ model_name=EMBEDDING_MODEL,
163
+ model_kwargs={'device': 'cpu'}
164
+ )
165
+
166
+ vectorstore = Chroma.from_documents(
167
+ documents=doc_splits,
168
+ embedding=embeddings,
169
+ collection_name=COLLECTION_NAME,
170
+ persist_directory=persist_dir # 持久化目录
171
+ )
172
+
173
+ retriever = vectorstore.as_retriever()
174
+
175
+ print(f"✅ PDF处理完成,共 {len(doc_splits)} 个文档块")
176
+ print(f"💾 向量数据库已持久化到: {persist_dir}")
177
+
178
+ # 保存元数据
179
+ file_hash = get_file_hash(pdf_path)
180
+ if file_hash:
181
+ processed_files[file_hash] = {
182
+ 'path': pdf_path,
183
+ 'type': 'pdf',
184
+ 'chunks': len(doc_splits),
185
+ 'processed_at': time.time()
186
+ }
187
+ with open(metadata_file, 'w', encoding='utf-8') as f:
188
+ json.dump({'processed_files': processed_files}, f, ensure_ascii=False, indent=2)
189
+ print(f"💾 元数据已保存")
190
+
191
+ except Exception as e:
192
+ print(f"❌ PDF处理失败: {e}")
193
+ return None, None
194
+ else:
195
+ # 使用默认知识库
196
+ print("📄 使用默认知识库...")
197
+ try:
198
+ vectorstore, retriever, doc_splits = doc_processor.setup_knowledge_base()
199
+
200
+ # 将默认知识库也持久化
201
+ if vectorstore and hasattr(vectorstore, '_persist_directory'):
202
+ vectorstore._persist_directory = persist_dir
203
+ print(f"💾 默认知识库已持久化到: {persist_dir}")
204
+
205
+ except Exception as e:
206
+ print(f"❌ 默认知识库加载失败: {e}")
207
+ return None, None
208
 
209
  # 初始化RAG系统
210
  print("🤖 正在初始化自适应RAG系统...")