File size: 4,998 Bytes
ac1079c
8edd424
cd75fd1
babb405
 
fecdf12
9088634
 
859a3f4
cd75fd1
2e4bd35
cd75fd1
2e4bd35
cd75fd1
 
ac1079c
2e4bd35
9088634
 
 
 
 
 
cd75fd1
2e4bd35
 
 
ac1079c
2e4bd35
ac1079c
2e4bd35
ac1079c
2e4bd35
 
 
ac1079c
 
 
 
 
 
 
 
 
 
 
 
cd75fd1
 
8edd424
 
 
cd75fd1
 
fdcff15
8edd424
2e4bd35
 
8edd424
03f014f
cd75fd1
 
 
 
 
073c315
 
cd75fd1
 
 
 
2e4bd35
 
cd75fd1
 
 
 
 
e3c118a
babb405
 
64fd4bf
e3c118a
2e4bd35
babb405
 
16919b8
022791c
99a8b0b
ac1079c
 
2e4bd35
 
ac1079c
 
 
 
 
 
 
 
 
 
 
 
 
 
2e4bd35
ac1079c
 
2e4bd35
 
ac1079c
2e4bd35
99a8b0b
 
 
2e4bd35
ac1079c
 
 
 
 
 
 
 
022791c
99a8b0b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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
from langchain_chroma import Chroma
from langchain_community.llms import HuggingFaceHub
from langchain.prompts import ChatPromptTemplate
from dotenv import load_dotenv
import os
import shutil

# Загрузка переменных окружения
load_dotenv()

CHROMA_PATH = "/tmp/chroma"
DATA_PATH = ""  # Укажите путь к вашим данным, например "data", если файл не в корне
PROMPT_TEMPLATE = """
Ответь на вопрос, используя только следующий контекст:
{context}
---
Ответь на вопрос на основе приведенного контекста: {question}
"""

# Глобальная переменная для статуса
status_message = "Инициализация..."

def initialize_chroma():
    global status_message
    if not os.path.exists(CHROMA_PATH):
        status_message = "Создание базы данных Chroma..."
        generate_data_store()
        status_message = "База данных Chroma создана и подготовлена."
    else:
        status_message = "База данных Chroma уже существует."
    embeddings = HuggingFaceEmbeddings(
        model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
        cache_folder="/tmp/model_cache",
        model_kwargs={'device': 'cpu'},
        encode_kwargs={'normalize_embeddings': True}
    )
    db = Chroma(
        persist_directory=CHROMA_PATH,
        embedding_function=embeddings
    )
    return db

def generate_data_store():
    documents = load_documents()
    if documents:
        chunks = split_text(documents)
        save_to_chroma(chunks)

def load_documents():
    file_path = os.path.join(DATA_PATH, "pl250320252.md")
    if not os.path.exists(file_path):
        global status_message
        status_message = f"Ошибка: Файл {file_path} не найден."
        return []
    loader = UnstructuredMarkdownLoader(file_path)
    documents = loader.load()
    return documents

def split_text(documents: list[Document]):
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=900,
        chunk_overlap=300,
        length_function=len,
        add_start_index=True,
    )
    chunks = text_splitter.split_documents(documents)
    global status_message
    status_message += f"\nРазделено {len(documents)} документов на {len(chunks)} частей."
    return chunks

def save_to_chroma(chunks: list[Document]):
    if os.path.exists(CHROMA_PATH):
        shutil.rmtree(CHROMA_PATH)
    embeddings = HuggingFaceEmbeddings(
        model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
        model_kwargs={'device': 'cpu'},
        encode_kwargs={'normalize_embeddings': True}
    )
    Chroma.from_documents(
        chunks,
        embeddings,
        persist_directory=CHROMA_PATH
    )

def process_query(query_text: str, db):
    results = db.similarity_search_with_relevance_scores(query_text, k=3)
    global status_message
    status_message += f"\nНайдено {len(results)} результатов с релевантностью: {[round(score, 2) for _, score in results]}"
    if not results or results[0][1] < 0.7:
        return "Не найдено подходящих результатов.", []
    context_text = "\n\n---\n\n".join([doc.page_content for doc, _ in results])
    prompt_template = ChatPromptTemplate.from_template(PROMPT_TEMPLATE)
    prompt = prompt_template.format(context=context_text, question=query_text)
    model = HuggingFaceHub(
        repo_id="google/flan-t5-small",
        model_kwargs={"temperature": 0.5, "max_length": 512}
    )
    response_text = model.predict(prompt)
    sources = [doc.metadata.get("source", None) for doc, _ in results]
    return response_text, sources

def chat_interface(query_text):
    global status_message
    db = initialize_chroma()
    response, sources = process_query(query_text, db)
    full_response = f"{status_message}\n\nОтвет: {response}\n\nИсточники: {', '.join(sources) if sources else 'Нет источников'}"
    return full_response

# Создание папок
os.makedirs("/tmp/model_cache", exist_ok=True)
os.makedirs("/tmp/chroma", exist_ok=True)

# Интерфейс Gradio
interface = gr.Interface(
    fn=chat_interface,
    inputs=gr.Textbox(lines=2, placeholder="Введите ваш вопрос здесь..."),
    outputs="text",
    title="Чат с документами",
    description="Задайте вопрос, и я отвечу на основе загруженных документов."
)

if __name__ == "__main__":
    interface.launch()