import pandas as pd from sentence_transformers import SentenceTransformer import faiss import numpy as np import streamlit as st import requests from PIL import Image from io import BytesIO from langchain_community.chat_models.gigachat import GigaChat from bs4 import BeautifulSoup st.title('Рекомендации сериалов по описанию пользователя с помощью асимметричного семантического поиска') st.divider() df = pd.read_csv('clean_series_data.csv') embeddings = np.load('embeddings.npy') def load_image_from_url(url): try: response = requests.get(url) response.raise_for_status() return Image.open(BytesIO(response.content)) except Exception as e: st.error(f"Не удалось загрузить изображение: {e}") return None model = SentenceTransformer('cointegrated/rubert-tiny2') model.cpu() # embeddings_desc = df['Описание'].apply(lambda x: model.encode(x)) # embeddings_gan = df['Жанры'].apply(lambda x: model.encode(x)) # embeddings = embeddings_desc + embeddings_gan metric = st.radio('Выберите метрику для поиска', [ 'Евклидово расстояние', 'Косинусное сходство']) if metric == 'Евклидово расстояние': embeddings = np.array(embeddings).astype(np.float32) faiss.normalize_L2(embeddings) dimension = embeddings.shape[1] index = faiss.IndexFlatL2(dimension) index.add(embeddings) query = [st.text_area('Введите описание сериала')] k = st.slider('Сколько сериалов рекомендовать?', min_value=1, max_value=10, value=3, step=1) button = st.button('Вывести результаты') if button: if query: query_embedding = model.encode(query).astype(np.float32) # Две строки ниже можно будет убрать # query_embedding = np.array( # query_embedding, dtype=np.float32).reshape(1, -1) # faiss.normalize_L2(query_embedding) distances, indices = index.search(query_embedding, k) st.subheader('Похожие сериалы:') for i in range(k): url = df.loc[indices[0][i]]["Изображение"] image = load_image_from_url(url) st.image(image) st.write(f'Название: {df.loc[indices[0][i]]["Название"]}') st.write(f'Рейтинг: {df.loc[indices[0][i]]["Рейтинг"]}') st.write(f'Жанр: {df.loc[indices[0][i]]["Жанры"]}') st.write(f'Страна: {df.loc[indices[0][i]]["Страна"]}') st.write( f'Длительность одной серии: {df.loc[indices[0][i]]["Длительность"]}') st.write( f'Количество серий: {df.loc[indices[0][i]]["Количество серий"]}') st.write(f'Описание: {df.loc[indices[0][i]]["Описание"]}') st.write(f'Евклидово расстояние: {distances[0][i]:.4f}') st.divider() else: embeddings = np.array(embeddings).astype(np.float32) faiss.normalize_L2(embeddings) dimension = embeddings.shape[1] index = faiss.IndexFlatIP(dimension) index.add(embeddings) query = [st.text_area('Введите описание сериала')] k = st.slider('Сколько сериалов рекомендовать?', min_value=1, max_value=10, value=3, step=1) button = st.button('Вывести результаты') if button: if query: query_embedding = model.encode(query).astype(np.float32) # Две строки ниже можно будет убрать # query_embedding = np.array( # query_embedding, dtype=np.float32).reshape(1, -1) # faiss.normalize_L2(query_embedding) distances, indices = index.search(query_embedding, k) st.subheader('Похожие сериалы:') for i in range(k): url = df.loc[indices[0][i]]["Изображение"] image = load_image_from_url(url) st.image(image) st.write(f'Название: {df.loc[indices[0][i]]["Название"]}') st.write(f'Рейтинг: {df.loc[indices[0][i]]["Рейтинг"]}') st.write(f'Жанр: {df.loc[indices[0][i]]["Жанры"]}') st.write(f'Страна: {df.loc[indices[0][i]]["Страна"]}') st.write( f'Длительность одной серии: {df.loc[indices[0][i]]["Длительность"]}') st.write( f'Количество серий: {df.loc[indices[0][i]]["Количество серий"]}') st.write(f'Описание: {df.loc[indices[0][i]]["Описание"]}') st.write(f'Косинусное сходство: {distances[0][i]:.4f}') st.divider() st.subheader( 'Генерация краткого содержания сериала с помощью SberGigaChat') name_of_series = st.text_input('Введите название сериала', key='1') gen_button = st.button('Показать краткое содержание') giga = GigaChat( credentials='MjA2MGEzNjItZjE0Mi00NWE5LTllMDItMWVjZWRlNDA2ODM0OjNhNzNlZDJmLTY4NWUtNDI1Zi1iZjg4LTkxOWFjMjkxZDg0OA==', verify_ssl_certs=False) if gen_button: with st.spinner('Генерация текста...'): st.write(giga.invoke( f"Расскажи cюжет сериала {name_of_series}").content) st.divider() st.subheader('Получение краткого содержания из Википедии') def get_wikipedia_summary(title): url = f"https://en.wikipedia.org/api/rest_v1/page/summary/{title}" response = requests.get(url) if response.status_code == 200: data = response.json() return data.get('extract', 'Сюжет не найден.') else: return f'Статья не найдена. Статус запроса: {response.status_code}' def get_english_title_from_myshows(russian_title): query = russian_title.replace(" ", "+") url = f'https://myshows.me/search/?q={query}#shows' response = requests.get(url) if response.status_code != 200: print(f"Ошибка при запросе, статус запроса: {response.status_code}") return None soup = BeautifulSoup(response.text, 'lxml') english_title = soup.find(class_='ShowCol-titleOriginal').text if english_title: return english_title else: print("Не удалось найти оригинальное название") return None name_of_series_2 = st.text_input('Введите название сериала', key='2') if 'шерлок' in name_of_series_2.lower(): st.error('За Вами выехали', icon="🚨") name_of_series_2 = None lang = st.radio('Выберите язык описания', ['Английский', 'Русский']) wiki_button = st.button('Вывести краткое содержание') if wiki_button: if name_of_series_2: english_title = get_english_title_from_myshows(name_of_series_2) st.write(english_title) if lang == 'Английский': st.write(get_wikipedia_summary(english_title)) else: text = get_wikipedia_summary(english_title) with st.spinner('Перевод...'): st.write(giga.invoke(f"Переведи этот текст: {text}").content)