try_my_rag / app.py
fitlemon's picture
Update app.py
485cccf verified
import os
import gradio as gr
import spaces
from datasets import load_dataset, concatenate_datasets
from langchain.docstore.document import Document
from langchain.vectorstores import FAISS
from langchain_huggingface import HuggingFaceEmbeddings
from tqdm import tqdm
from dotenv import load_dotenv
import pickle
# Импорты для перевода
from langchain.chat_models import ChatOpenAI
from langchain.prompts.chat import ChatPromptTemplate
from uz_translit import to_latin
# Загружаем переменные окружения
load_dotenv()
hf_key = os.getenv("HF_KEY")
# Путь для сохранения FAISS-индекса
INDEX_PATH = "./faiss_index"
# Инициализируем эмбеддинг-модель
embeddings = HuggingFaceEmbeddings(model_name="fitlemon/bge-m3-uz-legal-matryoshka")
translations = pickle.load(open("translations.pkl", "rb"))
def update_faiss_index():
"""
Загружает датасеты, преобразует данные в документы с метаданными,
создаёт FAISS-индекс и сохраняет его локально.
"""
train_dataset = load_dataset("fitlemon/rag-labor-codex-dataset", token=hf_key)[
"train"
]
test_dataset = load_dataset("fitlemon/rag-labor-codex-dataset", token=hf_key)[
"test"
]
dataset = concatenate_datasets([train_dataset, test_dataset])
# dataset = dataset.select(range(5)) # Для тестирования на небольшом количестве данных
docs = []
unique_chunks = set()
for row in tqdm(dataset, desc="Загрузка документов..."):
chunk = row["chunk"]
if chunk in unique_chunks:
continue
unique_chunks.add(chunk)
doc = Document(
page_content=chunk,
metadata={
"section": row["section"],
"section_name": row["section_name"],
"chapter_name": row["chapter"],
},
)
docs.append(doc)
print(f"Документы успешно загружены и преобразованы. Длина документов: {len(docs)}")
db = FAISS.from_documents(docs, embeddings)
os.makedirs(INDEX_PATH, exist_ok=True)
db.save_local(INDEX_PATH)
print("FAISS индекс обновлён и сохранён в:", INDEX_PATH)
return db
if not os.path.exists(INDEX_PATH):
db = update_faiss_index()
else:
db = FAISS.load_local(INDEX_PATH, embeddings, allow_dangerous_deserialization=True)
print("Загружен существующий FAISS индекс из:", INDEX_PATH)
def translate_ru_uz(message: str) -> str:
"""
Переводит текст с русского на узбекский с использованием ChatOpenAI.
Пример: input: "отпуск" → output: "tatil".
"""
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"You are a helpful assistant that translates {input_language} to {output_language}. The subject of Text is Human Resources. Example input: отпуск. Output: tatil.",
),
("human", "{input}"),
]
)
llm = ChatOpenAI(
api_key=os.environ["OPENAI_API_KEY"], model="gpt-4o-mini-2024-07-18"
)
chain = prompt | llm
response = chain.invoke(
{
"input_language": "Russian",
"output_language": "Uzbek",
"input": message,
}
)
return response.content
@spaces.GPU
def retrieve_articles(query, language):
"""
Если выбран язык "Russian", переводит запрос с русского на узбекский.
Затем ищет в FAISS-индексе топ-3 наиболее релевантных документа и возвращает результат в Markdown.
"""
if language == "Russian":
translated_query = translate_ru_uz(query)
else:
translated_query = to_latin(query)
results = db.similarity_search(translated_query, k=3)
result_text = ""
for doc in results:
result_text += (
f"### {doc.metadata['section']}: {doc.metadata['section_name']}\n"
)
if language == "Russian":
result_text += f"**Текст статьи на русском:** {translations.get(doc.page_content, 'Не найден')}\n\n"
result_text += f"**Bo'lim:** {doc.metadata['chapter_name']}\n\n"
result_text += f"**Modda teksti:**\n{doc.page_content}\n\n"
result_text += "---\n\n"
return result_text
# return "Привет, мир!" if language == "Russian" else "Salom Dunyo!"
def toggle_language(current_language: str) -> gr.update:
"""
Переключает язык между "Russian" и "Uzbek".
"""
new_language = "Uzbek" if current_language == "Russian" else "Russian"
return gr.update(value=new_language)
# Создаём Gradio-интерфейс на основе Blocks
with gr.Blocks() as demo:
gr.Markdown("# Поиск по Трудовому Кодексу Республики Узбекистан (через Эмбеддинг Модель)")
gr.Markdown(
"Введите ваш вопрос и выберите язык запроса. Если выбран русский, запрос будет переведен на узбекский перед поиском."
)
with gr.Row():
language_radio = gr.Radio(
choices=["Russian", "Uzbek"], label="Язык запроса", value="Russian"
)
query_input = gr.Textbox(
lines=3, placeholder="Введите ваш вопрос о трудовом кодексе...", label="Запрос"
)
search_button = gr.Button("Поиск")
output_markdown = gr.Markdown()
search_button.click(
fn=retrieve_articles,
inputs=[query_input, language_radio],
outputs=output_markdown,
)
query_input.submit(
fn=retrieve_articles,
inputs=[query_input, language_radio],
outputs=output_markdown,
)
if __name__ == "__main__":
demo.launch()