From 5eeaff565540c970f38a2d051daaad0cd12d0f0d Mon Sep 17 00:00:00 2001 From: "ki.sagidullin" Date: Wed, 1 Apr 2026 20:26:19 +0500 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=BD=D0=B0=D1=8F=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=B8=D0=BD=D0=B4=D0=B5=D0=BA=D1=81=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- local_knowledge_base.py | 87 +++++++++++++++++++++++++++++++++++------ 1 file changed, 75 insertions(+), 12 deletions(-) diff --git a/local_knowledge_base.py b/local_knowledge_base.py index b133f9c..86a145b 100644 --- a/local_knowledge_base.py +++ b/local_knowledge_base.py @@ -77,7 +77,34 @@ class LocalKnowledgeBase: print(f"Создана коллекция {self.collection_name}") def load_documents(self, directory_path: str): - """Загрузка документов из директории (рекурсивно)""" + # Кастомные разделители для C++ - в порядке приоритета + cpp_separators = [ + # Конец блока - самый важный разделитель + "\n}", + # Конец statement + ";", + # Объявления - должны быть отдельными чанками + "\nclass ", + "\nstruct ", + "\nenum ", + "\nnamespace ", + "\ntemplate<", + "\npublic:", + "\nprivate:", + "\nprotected:", + "\nvirtual ", + "\noverride ", + # Функции + "\nvoid ", "\nint ", "\nfloat ", "\ndouble ", "\nbool ", "\nauto ", "\nstd::", + "\nconst ", "\nstatic ", "\nexplicit ", + # Комментарии - тоже разделитель + "\n//", + "\n/*", + "\n*", + # Перенос строки + "\n", + ] + loaders = { ".pdf": PyPDFLoader, ".txt": lambda path: TextLoader(path, encoding="utf-8"), @@ -89,6 +116,7 @@ class LocalKnowledgeBase: } all_documents = [] + files_processed = 0 # Рекурсивный обход с фильтрацией папок for root, dirs, files in os.walk(directory_path): @@ -102,21 +130,56 @@ class LocalKnowledgeBase: try: loader = loaders[ext](full_path) documents = loader.load() + + # Добавляем метаданные о пути к файлу + for doc in documents: + doc.metadata["source"] = full_path + doc.metadata["file_name"] = file_path + doc.metadata["file_ext"] = ext + all_documents.extend(documents) - print(f"Загружен {file_path}: {len(documents)} документов") + files_processed += 1 + print(f"✓ Загружен {file_path}") except Exception as e: - print(f"Ошибка загрузки {file_path}: {e}") + print(f"✗ Ошибка загрузки {file_path}: {e}") - # Разбиваем на чанки - text_splitter = RecursiveCharacterTextSplitter.from_language( - language=Language.CPP, - chunk_size=500, - chunk_overlap=100, - length_function=len - ) + print(f"\n📁 Загружено файлов: {files_processed}") + print(f"📄 Всего документов до сплиттинга: {len(all_documents)}") - chunks = text_splitter.split_documents(all_documents) - print(f"Всего чанков: {len(chunks)}") + # Для C++ файлов используем кастомный сплиттер + cpp_files_docs = [d for d in all_documents if d.metadata.get("file_ext") in [".cpp", ".hpp", ".h", ".cc"]] + other_docs = [d for d in all_documents if d.metadata.get("file_ext") not in [".cpp", ".hpp", ".h", ".cc"]] + + chunks = [] + + # Сплиттим C++ с кастомными разделителями + if cpp_files_docs: + print("\n🔧 Сплиттинг C++ файлов...") + cpp_splitter = RecursiveCharacterTextSplitter( + separators=cpp_separators, + chunk_size=800, # Увеличил для C++ + chunk_overlap=150, # Больше overlap для контекста + length_function=len, + keep_separator=True, # Сохраняем разделители + ) + cpp_chunks = cpp_splitter.split_documents(cpp_files_docs) + chunks.extend(cpp_chunks) + print(f" C++ чанков: {len(cpp_chunks)}") + + # Для остальных файлов - стандартный сплиттер + if other_docs: + print("\n📄 Сплиттинг остальных файлов...") + text_splitter = RecursiveCharacterTextSplitter.from_language( + language=Language.CPP, + chunk_size=500, + chunk_overlap=100, + length_function=len + ) + other_chunks = text_splitter.split_documents(other_docs) + chunks.extend(other_chunks) + print(f" Остальных чанков: {len(other_chunks)}") + + print(f"\n📊 Всего чанков после сплиттинга: {len(chunks)}") # Создаем эмбеддинги и сохраняем в Qdrant self._index_documents(chunks)