import gradio as gr from langchain_community.document_loaders import UnstructuredMarkdownLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_core.documents import Document from langchain_huggingface import HuggingFaceEmbeddings, HuggingFaceEndpoint from langchain_community.vectorstores import FAISS # Обновленный импорт # from langchain_community.llms import HuggingFaceHub from langchain.prompts import ChatPromptTemplate from dotenv import load_dotenv import os # Загрузка переменных окружения load_dotenv() DATA_PATH = "" # Укажите путь к вашему файлу PROMPT_TEMPLATE = """ Ответь на вопрос, используя только следующий контекст: {context} --- Ответь на вопрос на основе приведенного контекста: {question} """ # Глобальная переменная для статуса status_message = "Инициализация..." def initialize_vectorstore(): global status_message try: status_message = "Загрузка и обработка документов..." documents = load_documents() chunks = split_text(documents) status_message = "Создание векторной базы..." vectorstore = save_to_faiss(chunks) status_message = "База данных готова к использованию." return vectorstore except Exception as e: status_message = f"Ошибка инициализации: {str(e)}" raise def load_documents(): file_path = os.path.join(DATA_PATH, "pl250320252.md") if not os.path.exists(file_path): raise FileNotFoundError(f"Файл {file_path} не найден") loader = UnstructuredMarkdownLoader(file_path) return loader.load() def split_text(documents: list[Document]): text_splitter = RecursiveCharacterTextSplitter( chunk_size=900, chunk_overlap=300, length_function=len, add_start_index=True, ) return text_splitter.split_documents(documents) def save_to_faiss(chunks: list[Document]): embeddings = HuggingFaceEmbeddings( model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2", model_kwargs={'device': 'cpu'}, encode_kwargs={'normalize_embeddings': True} ) return FAISS.from_documents(chunks, embeddings) def process_query(query_text: str, vectorstore): if vectorstore is None: return "База данных не инициализирована", [] try: results = vectorstore.similarity_search_with_relevance_scores(query_text, k=3) global status_message status_message += f"\nНайдено {len(results)} результатов" if not results: return "Не найдено результатов.", [] context_text = "\n\n---\n\n".join([ f"Релевантность: {score:.2f}\n{doc.page_content}" for doc, score in results ]) # Формируем строковый промпт для модели prompt = f"Answer the question based on the following context:\n{context_text}\n\nQuestion: {query_text}" # Используем модель t5-base для text2text-generation model = HuggingFaceEndpoint( repo_id="t5-base", task="text2text-generation", temperature=0.5, max_length=512, # huggingfacehub_api_token=os.getenv("HUGGINGFACEHUB_API_TOKEN") # Раскомментируйте, если нужен токен ) # Передаем строковый промпт response_text = model.invoke(prompt) sources = list(set([doc.metadata.get("source", "") for doc, _ in results])) return response_text, sources except Exception as e: return f"Ошибка обработки запроса: {str(e)}", [] def chat_interface(query_text): global status_message try: vectorstore = initialize_vectorstore() response, sources = process_query(query_text, vectorstore) full_response = f"{status_message}\n\nОтвет: {response}\n\nИсточники: {', '.join(sources) if sources else 'Нет источников'}" return full_response except Exception as e: return f"Критическая ошибка: {str(e)}" # Интерфейс Gradio interface = gr.Interface( fn=chat_interface, inputs=gr.Textbox(lines=2, placeholder="Введите ваш вопрос здесь..."), outputs="text", title="Чат с документами", description="Задайте вопрос, и я отвечу на основе загруженных документов." ) if __name__ == "__main__": interface.launch()