# Основные библиотеки
import os
import re
import string
import warnings
import numpy as np
import pandas as pd
import torch
# Машинное обучение и обработка текста
from transformers import AutoTokenizer, AutoModel, AutoModelForSeq2SeqLM, MarianMTModel, MarianTokenizer
from sentence_transformers import SentenceTransformer, util
from sklearn.base import BaseEstimator, TransformerMixin
# FAISS для семантического поиска
import faiss
# Лемматизация и морфология
import pymorphy3
# Streamlit для создания веб-приложений
import streamlit as st
# Кастомные модули
from EmbeddingGenerator import EmbeddingGenerator
from TextAugmentation import TextAugmentation
# LangChain для интеграции GigaChat
from langchain_community.chat_models.gigachat import GigaChat
# ======= загружаем ранее рассчитанные эмбеддинги и объявляем классы=======
# Инициализация GigaChat с ключом и отключенной проверкой SSL
giga = GigaChat(
credentials="ODk0NDE1ODEtYTJhMi00N2Y1LTk4YWItNGZlNzNkM2QwMDNiOjk5YmVjN2ZjLThmM2EtNDhjYy04OWQ2LWNkOTlhOTNkNGY3NQ==",
verify_ssl_certs=False
)
augmentor = TextAugmentation()
embedding_gen = EmbeddingGenerator()
df=pd.read_csv("movies_data_fixed.csv")
image_path = "image-2.png"
# Загружаем и отображаем картинку
st.image(image_path, use_container_width=True)
# Заголовок
st.markdown(
"""
КиноКринж
""",
unsafe_allow_html=True
)
# Добавляем окно ввода текста
user_input = st.text_area("Добавьте описание фильма", "", height=150)
# Слайдер для выбора количества фильмов
num_results = st.slider('Выберите количество фильмов', min_value=1, max_value=20, value=4)
# Выбор модели
model_option = st.selectbox('Выберите модель для обработки запроса:', ['cointegrated/rubert-tiny2','DeepPavlov/rubert-base-cased','all-MiniLM-L6-v2', 'paraphrase-MiniLM-L6-v2'])
if model_option!='DeepPavlov/rubert-base-cased':
model = SentenceTransformer(model_option)
# ======= дополнительная фильтрация для аугментаций (убираем слишком непохожие) =======
def filter_paraphrases(original, paraphrases, threshold=0.8):
original_embedding = model.encode(original)
filtered = []
for paraphrase in paraphrases:
paraphrase_embedding = model.encode(paraphrase)
similarity = util.cos_sim(original_embedding, paraphrase_embedding).item()
if similarity >= threshold:
filtered.append(paraphrase)
return filtered
#======================СЕМПЛ======= =======
# Проверка наличия рекомендованных фильмов
if 'recommended_movies' not in st.session_state:
st.session_state.recommended_movies = []
# Кнопка для поиска
if st.button('Найти фильм'):
if user_input.strip():
# Генерация эмбеддинга для запроса
if model_option != 'DeepPavlov/rubert-base-cased' and model_option != 'cointegrated/rubert-tiny2':
index = faiss.read_index('faiss_index.bin')
query_embedding = model.encode([user_input]).astype("float32")
faiss.normalize_L2(query_embedding)
elif model_option == 'DeepPavlov/rubert-base-cased':
index = faiss.read_index('pavlov3.bin')
back_translate = augmentor.back_translate(user_input)
augmented_query_pavlov = user_input + " " + back_translate
query_embedding = embedding_gen.generate_embeddings(augmented_query_pavlov, method="pavlov")
elif model_option == 'cointegrated/rubert-tiny2':
index = faiss.read_index('rubert2.bin')
paraphrase = augmentor.paraphrase(user_input, num_return_sequences=3)
filtered_rubert = filter_paraphrases(user_input, paraphrase)
augmented_query_rubert = user_input + " " + " ".join(filtered_rubert)
query_embedding = embedding_gen.generate_embeddings(augmented_query_rubert, method="rubert_tiny2").reshape(1, -1)
faiss.normalize_L2(query_embedding)
# Поиск ближайших соседей
distances, indices = index.search(query_embedding, num_results)
# Отображение результатов
st.write(f"Результаты поиска ({num_results} фильмов):")
recommended_movies = []
for idx, distance in zip(indices[0], distances[0]):
recommended_movies.append({
'title': df.iloc[idx]['movie_title'],
'description': df.iloc[idx]['description'],
'image_url': df.iloc[idx]['image_url'],
'page_url': df.iloc[idx]['page_url'],
'similarity': distance,
'short_description': None, # Содержимое краткого описания
'is_short_description_shown': False # Флаг для того, чтобы избежать повторного запроса
})
# Сохраняем результаты в session_state
st.session_state.recommended_movies = recommended_movies
# Отображение рекомендованных фильмов
for idx, movie in enumerate(st.session_state.recommended_movies):
st.write(f"### {movie['title']}")
st.write(f"Описание: {movie['description']}")
st.write(f"Схожесть: {movie['similarity']:.4f}")
# Отображаем картинку постера
if movie.get('image_url'):
st.image(movie['image_url'], width=200)
# Добавляем ссылку на страницу фильма
if movie.get('page_url'):
st.markdown(f"[Перейти на страницу фильма]({movie['page_url']})")
# Генерируем уникальный ключ с использованием индекса
button_key = f"short_description_button_{idx}" # Уникальный ключ для кнопки
if st.button(f"Получить краткое содержание для {movie['title']}", key=button_key):
if not movie.get('is_short_description_shown', False): # Проверяем состояние
try:
# Отправляем запрос в GigaChat
prompt = f"{movie['title']} краткое содержание фильма не более 100 слов"
response = giga.invoke(prompt)
# Извлекаем описание из ответа
description = response.content if response else "Описание не найдено."
movie['short_description'] = description
movie['is_short_description_shown'] = True
except Exception as e:
st.error(f"Ошибка при запросе в GigaChat: {e}")
# Показываем краткое содержание
if movie.get('short_description') and movie.get('is_short_description_shown', False):
st.write(f"Краткое содержание для {movie['title']}: {movie['short_description']}")
st.write("---")