File size: 10,655 Bytes
f1b6e2e
 
 
 
 
153200d
f1b6e2e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153200d
f1b6e2e
153200d
 
 
 
f1b6e2e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
import os
import importlib.util
import torch
import streamlit as st
import pandas as pd
import time
from PIL import Image

# Формируем абсолютный путь до файла functions.py
module_path = os.path.abspath(
    os.path.join(os.path.dirname(__file__), "..", "resource", "functions.py")
)

# Загружаем модуль
spec = importlib.util.spec_from_file_location("resource.functions", module_path)
functions = importlib.util.module_from_spec(spec)
spec.loader.exec_module(functions)

# Теперь используем функции напрямую
table_maker = functions.table_maker
RecSys = functions.RecSys

poster_path = "https://resizer.mail.ru/p/"
show_path = "https://kino.mail.ru/series_"
placeholder_path = "../img/v2/nopicture/308x462.png"


@st.cache_resource(ttl=3600)  # 👈 Cache data for 1 hour (=3600 seconds)
def load_model(model_path):
    model = torch.load(model_path)
    return model


@st.cache_data(ttl=3600)  # 👈 Cache data for 1 hour (=3600 seconds)
def load_data(data_path):
    df = pd.read_pickle(data_path)
    return df


DATA_PATH = "data/data.pkl"
MODEL_PATH = "model/model.pt"

df = load_data(DATA_PATH)
model = load_model(MODEL_PATH)

image = Image.open("pages/tv_shows.png")
st.image(image, use_column_width=True)

# Заголовок приложения
st.markdown("### Поиск сериалов по запросу пользователя")

# Создание списка уникальных стран
all_countries = sorted(set(df["county"].tolist()))

# Создание списка уникальных жанров
all_genres = set()
for genres_set in df["tags"].dropna():
    all_genres.update(genres_set)
all_genres = sorted(all_genres)

# Фильтр по наличию рейтинга
has_rating = st.sidebar.checkbox("Показывать только сериалы с рейтингом?", True)

# Виджеты для боковой панели
selected_country = st.sidebar.multiselect("Страна", all_countries)
selected_genre = st.sidebar.multiselect("Жанры", all_genres)


rating = True

search_table = table_maker(
    df=df,
    country=selected_country,
    min_year=int(df["year"].min()),
    max_year=int(df["year"].max()),
    tagger=set(selected_genre),
    rating=has_rating,
)

# Проверяем, пустой ли отфильтрованный DataFrame
if search_table.empty:
    st.error(
        "После фильтрации данных не осталось. Пожалуйста, выберите другие параметры."
    )
else:
    # Преобразование year в числовой формат, если возможно, и обработка NaN значений
    search_table["year"] = pd.to_numeric(search_table["year"], errors="coerce").dropna()

    if search_table.empty:
        st.error(
            "После фильтрации и обработки годов в данных не осталось записей. Пожалуйста, выберите другие параметры."
        )
    else:
        # Теперь безопасно ищем min и max
        min_year = int(search_table["year"].min())
        max_year = int(search_table["year"].max())

        # Если есть хотя бы два разных года, отображаем слайдер
        if min_year < max_year:
            selected_year_range = st.sidebar.slider(
                "Выберите диапазон лет выпуска",
                min_value=min_year,
                max_value=max_year,
                value=(min_year, max_year),
            )
            # Применяем фильтр по годам
            search_table = search_table[
                (search_table["year"] >= selected_year_range[0])
                & (search_table["year"] <= selected_year_range[1])
            ]

        st.sidebar.markdown("---")
        st.sidebar.markdown("### Дополнительные настройки")

        # Позволяет пользователю выбрать количество сериалов для отображения, от 1 до 10
        top_n = st.sidebar.number_input(
            "Сколько сериалов показывать?", min_value=1, max_value=10, value=5
        )

        # Создание текстового поля для ввода пользовательского запроса
        user_request = st.text_input("Введите ваш запрос:", "звездные войны")

        if st.button("Найти сериалы по запросу") and len(df) > 0:

            start_time = time.time()
            output = RecSys(search_table, user_request, model)
            end_time = time.time()
            elapsed_time = end_time - start_time

            st.info(f"Время поиска составило: {elapsed_time:.4f} sec.")

            # top_n = 5  # мин 1 макс 10
            res = output().head(top_n)

            (
                poster,
                title,
                description,
                rating,
                genre,
                cast,
                score,
                year,
                links,
                country,
            ) = (
                {},
                {},
                {},
                {},
                {},
                {},
                {},
                {},
                {},
                {},
            )

            for i, con in enumerate(res["poster"]):
                # Проверяем, является ли значение в con ссылкой или путем к файлу
                if "nopicture" in con:
                    poster[i] = placeholder_path
                else:
                    poster[i] = poster_path + con

            for i, con in enumerate(res["year"]):
                year[i] = con

            for i, con in enumerate(res["title"]):
                title[i] = con

            for i, con in enumerate(res["description"]):
                description[i] = con

            for i, con in enumerate(res["rating"]):
                rating[i] = con

            for i, con in enumerate(res["tags"]):
                genre[i] = ", ".join(con)

            for i, con in enumerate(res["cast"]):
                cast[i] = con

            for i, con in enumerate(res["score"]):
                score[i] = con

            for i, con in enumerate(res["url"]):
                links[i] = show_path + con

            for i, con in enumerate(res["county"]):
                country[i] = con

            st.markdown("---")

            # Проверяем, пустой ли набор результатов
            if len(res) == 0:
                st.error(
                    "Сериалы по выбранным параметрам не найдены. Попробуйте изменить критерии поиска."
                )
            else:
                # Если результаты есть, выводим их
                iterations = min(len(res), top_n)

                for i in range(iterations):

                    col1, col2 = st.columns([1, 3])
                    with col1:
                        st.image(poster[i])
                        # Добавляем ссылку под картинкой
                        st.markdown(
                            f"<a href='{links[i]}' target='_blank' style='display: block; text-align: center; color: grey; font-size: small; font-style: italic;'>Смотреть сериал</a>",
                            unsafe_allow_html=True,
                        )

                    with col2:

                        st.markdown(
                            f"<span style='font-weight:bold; font-size:22px;'>Название сериала:</span> <span style='font-size:20px;'>«{title[i]}»</span>",
                            unsafe_allow_html=True,
                        )

                        st.markdown(
                            f"<span style='font-weight:bold; font-size:16px;'>Страна:</span> <span style='font-size:16px;'>{country[i]}</span>",
                            unsafe_allow_html=True,
                        )

                        st.markdown(
                            f"<span style='font-weight:bold; font-size:16px;'>Год выпуска:</span> <span style='font-size:16px;'>{year[i]}</span>",
                            unsafe_allow_html=True,
                        )

                        st.markdown(
                            f"<span style='font-weight:bold; font-size:16px;'>Жанр:</span> <span style='font-size:16px;'>{genre[i]}</span>",
                            unsafe_allow_html=True,
                        )

                        rating_display = (
                            "Нет информации" if pd.isna(rating[i]) else rating[i]
                        )

                        st.markdown(
                            f"<span style='font-weight:bold; font-size:16px;'>Рейтинг:</span> <span style='font-size:16px;'>{rating_display}</span>",
                            unsafe_allow_html=True,
                        )

                        st.markdown(
                            "<h6 style='font-weight:bold;'>В ролях:</h6>",
                            unsafe_allow_html=True,
                        )

                        st.markdown(
                            f"<div style='text-align: justify; margin-bottom: 18px;'>{cast[i]}</div>",
                            unsafe_allow_html=True,
                        )

                        st.markdown(
                            "<h6 style='font-weight:bold;'>Описание:</h6>",
                            unsafe_allow_html=True,
                        )

                        st.markdown(
                            f"<div style='text-align: justify;'>{description[i]}</div>",
                            unsafe_allow_html=True,
                        )
                        score_display = round(score[i], 3)
                        st.markdown(
                            f"<div style='color: grey;'><hr style='margin: 2px 0;'/><span style='font-weight:bold; font-size:13px; font-style: italic;'>Коэффициент сходимости (косинусное сходство):</span> <span style='font-size:13px; font-style: italic;'>{score_display}</span><hr style='margin: 2px 0;'/></div>",
                            unsafe_allow_html=True,
                        )

                    st.markdown("---")