Spaces:
Sleeping
Sleeping
Update src/streamlit_app.py
Browse files- src/streamlit_app.py +17 -21
src/streamlit_app.py
CHANGED
@@ -39,7 +39,6 @@ def list_str_to_text(x):
|
|
39 |
|
40 |
def clean_actors_string(val):
|
41 |
v = str(val).strip().lower()
|
42 |
-
# если фраза мусорная или вообще нет букв — заменяем на "Неизвестно"
|
43 |
if any(bad in v for bad in BAD_ACTORS) or not re.search(r'[a-zа-яё]', v):
|
44 |
return "Неизвестно"
|
45 |
return val
|
@@ -58,26 +57,27 @@ def extract_intro_paragraph(text, max_sentences=4):
|
|
58 |
def clean_tvshows_data(path):
|
59 |
df = pd.read_csv(path)
|
60 |
|
61 |
-
# actors
|
62 |
df["actors"] = df["actors"].apply(list_str_to_text)
|
63 |
df["actors"] = df["actors"].apply(clean_actors_string)
|
64 |
|
65 |
-
# genres
|
66 |
df["genres"] = df["genres"].apply(list_str_to_text)
|
67 |
|
|
|
68 |
df["year"] = pd.to_numeric(df["year"], errors="coerce").fillna(0).astype(int)
|
69 |
df["num_seasons"] = pd.to_numeric(df["num_seasons"], errors="coerce").fillna(0).astype(int)
|
70 |
df["tvshow_title"] = df["tvshow_title"].fillna("Неизвестно")
|
71 |
df["description"] = df["description"].fillna("Нет описания").astype(str).str.strip()
|
72 |
|
73 |
-
#
|
74 |
df = df[df["description"].apply(lambda x: len(str(x).split())) >= 15]
|
75 |
|
76 |
-
#
|
77 |
to_drop_exact = df["description"].value_counts()[lambda x: x >= 3].index
|
78 |
df = df[~df["description"].isin(to_drop_exact)]
|
79 |
|
80 |
-
#
|
81 |
garbage_patterns = [
|
82 |
r"(всё в порядке[.!?~ ,]*){3,}",
|
83 |
r"(я не знаю[^.!?]*){2,}",
|
@@ -90,14 +90,14 @@ def clean_tvshows_data(path):
|
|
90 |
return any(re.search(p, text) for p in garbage_patterns)
|
91 |
df = df[~df["description"].apply(matches_garbage)]
|
92 |
|
93 |
-
#
|
94 |
bad_phrase_parts = [
|
95 |
"однадцатая секретаря", "тридцать третья", "оу, оу-у-у",
|
96 |
"всё в порядке?", "я не знаю, что делать"
|
97 |
]
|
98 |
df = df[~df["description"].str.lower().apply(lambda t: any(p in t for p in bad_phrase_parts))]
|
99 |
|
100 |
-
#
|
101 |
genre_onehots = [
|
102 |
c for c in df.columns
|
103 |
if c not in ['tvshow_title','year','genres','actors','rating','description',
|
@@ -106,13 +106,13 @@ def clean_tvshows_data(path):
|
|
106 |
]
|
107 |
df = df.drop(columns=genre_onehots, errors="ignore")
|
108 |
|
109 |
-
#
|
110 |
df["basic_genres"] = df["genres"].apply(filter_to_basic_genres)
|
111 |
|
112 |
-
# Колонка type (Фильм/Сериал)
|
113 |
df["type"] = df["num_seasons"].apply(lambda x: "Сериал" if pd.notna(x) and int(x) > 1 else "Фильм")
|
114 |
|
115 |
-
# Гарантия колонок
|
116 |
for col in ["image_url", "url", "rating", "language", "country"]:
|
117 |
if col not in df.columns:
|
118 |
df[col] = None
|
@@ -151,17 +151,11 @@ def semantic_search(query, embedder, index, df, genre=None, year=None, country=N
|
|
151 |
|
152 |
@st.cache_resource(ttl=3600)
|
153 |
def init_groq_llm():
|
154 |
-
|
155 |
-
key = os.environ.get("GROQ_API_KEY") \
|
156 |
-
or (st.secrets.get("GROQ_API_KEY") if hasattr(st, "secrets") else None) \
|
157 |
-
or st.text_input("Введите API-ключ Groq:", type="password")
|
158 |
-
|
159 |
if not key:
|
160 |
st.warning("Введите ваш Groq API ключ для генерации ответов.")
|
161 |
return None
|
162 |
-
|
163 |
os.environ["GROQ_API_KEY"] = key
|
164 |
-
|
165 |
try:
|
166 |
return ChatGroq(model="deepseek-r1-distill-llama-70b", temperature=0, max_tokens=2000)
|
167 |
except Exception as e:
|
@@ -191,7 +185,6 @@ def main():
|
|
191 |
|
192 |
df = load_data()
|
193 |
|
194 |
-
# Гарантия колонки type
|
195 |
if "type" not in df.columns:
|
196 |
df["type"] = df["num_seasons"].apply(lambda x: "Сериал" if pd.notna(x) and int(x) > 1 else "Фильм")
|
197 |
|
@@ -200,6 +193,7 @@ def main():
|
|
200 |
llm = init_groq_llm()
|
201 |
|
202 |
colf1, colf2, colf3, colf4 = st.columns(4)
|
|
|
203 |
with colf1:
|
204 |
genres = ["Все"] + sorted(set(sum([g.split(", ") for g in df["basic_genres"].unique()], [])))
|
205 |
genre_filter = st.selectbox("Жанр", genres)
|
@@ -259,8 +253,10 @@ def main():
|
|
259 |
f" | {row['type']} | {row['num_seasons']} сез."
|
260 |
)
|
261 |
st.write(extract_intro_paragraph(row["description"]))
|
262 |
-
if row["actors"]:
|
263 |
-
|
|
|
|
|
264 |
st.divider()
|
265 |
|
266 |
if st.button("AI: почему эти подходят и что ещё посмотреть"):
|
|
|
39 |
|
40 |
def clean_actors_string(val):
|
41 |
v = str(val).strip().lower()
|
|
|
42 |
if any(bad in v for bad in BAD_ACTORS) or not re.search(r'[a-zа-яё]', v):
|
43 |
return "Неизвестно"
|
44 |
return val
|
|
|
57 |
def clean_tvshows_data(path):
|
58 |
df = pd.read_csv(path)
|
59 |
|
60 |
+
# Преобразуем actors в строки и чистим мусор
|
61 |
df["actors"] = df["actors"].apply(list_str_to_text)
|
62 |
df["actors"] = df["actors"].apply(clean_actors_string)
|
63 |
|
64 |
+
# Преобразуем genres в строки
|
65 |
df["genres"] = df["genres"].apply(list_str_to_text)
|
66 |
|
67 |
+
# Обработка числовых колонок
|
68 |
df["year"] = pd.to_numeric(df["year"], errors="coerce").fillna(0).astype(int)
|
69 |
df["num_seasons"] = pd.to_numeric(df["num_seasons"], errors="coerce").fillna(0).astype(int)
|
70 |
df["tvshow_title"] = df["tvshow_title"].fillna("Неизвестно")
|
71 |
df["description"] = df["description"].fillna("Нет описания").astype(str).str.strip()
|
72 |
|
73 |
+
# Фильтрация описаний короче 15 слов
|
74 |
df = df[df["description"].apply(lambda x: len(str(x).split())) >= 15]
|
75 |
|
76 |
+
# Удаление часто повторяющихся описаний (3 и более)
|
77 |
to_drop_exact = df["description"].value_counts()[lambda x: x >= 3].index
|
78 |
df = df[~df["description"].isin(to_drop_exact)]
|
79 |
|
80 |
+
# Удаление мусорных шаблонов
|
81 |
garbage_patterns = [
|
82 |
r"(всё в порядке[.!?~ ,]*){3,}",
|
83 |
r"(я не знаю[^.!?]*){2,}",
|
|
|
90 |
return any(re.search(p, text) for p in garbage_patterns)
|
91 |
df = df[~df["description"].apply(matches_garbage)]
|
92 |
|
93 |
+
# Удаление строк с известными мусорными подстроками
|
94 |
bad_phrase_parts = [
|
95 |
"однадцатая секретаря", "тридцать третья", "оу, оу-у-у",
|
96 |
"всё в порядке?", "я не знаю, что делать"
|
97 |
]
|
98 |
df = df[~df["description"].str.lower().apply(lambda t: any(p in t for p in bad_phrase_parts))]
|
99 |
|
100 |
+
# Удаление бинарных one-hot колонок жанров
|
101 |
genre_onehots = [
|
102 |
c for c in df.columns
|
103 |
if c not in ['tvshow_title','year','genres','actors','rating','description',
|
|
|
106 |
]
|
107 |
df = df.drop(columns=genre_onehots, errors="ignore")
|
108 |
|
109 |
+
# Нормализация жанров
|
110 |
df["basic_genres"] = df["genres"].apply(filter_to_basic_genres)
|
111 |
|
112 |
+
# Колонка type (Фильм/Сериал) по кол-ву сезонов
|
113 |
df["type"] = df["num_seasons"].apply(lambda x: "Сериал" if pd.notna(x) and int(x) > 1 else "Фильм")
|
114 |
|
115 |
+
# Гарантия существования нужных колонок
|
116 |
for col in ["image_url", "url", "rating", "language", "country"]:
|
117 |
if col not in df.columns:
|
118 |
df[col] = None
|
|
|
151 |
|
152 |
@st.cache_resource(ttl=3600)
|
153 |
def init_groq_llm():
|
154 |
+
key = os.environ.get("GROQ_API_KEY") or (st.secrets.get("GROQ_API_KEY") if hasattr(st, "secrets") else None) or st.text_input("Введите API-ключ Groq:", type="password")
|
|
|
|
|
|
|
|
|
155 |
if not key:
|
156 |
st.warning("Введите ваш Groq API ключ для генерации ответов.")
|
157 |
return None
|
|
|
158 |
os.environ["GROQ_API_KEY"] = key
|
|
|
159 |
try:
|
160 |
return ChatGroq(model="deepseek-r1-distill-llama-70b", temperature=0, max_tokens=2000)
|
161 |
except Exception as e:
|
|
|
185 |
|
186 |
df = load_data()
|
187 |
|
|
|
188 |
if "type" not in df.columns:
|
189 |
df["type"] = df["num_seasons"].apply(lambda x: "Сериал" if pd.notna(x) and int(x) > 1 else "Фильм")
|
190 |
|
|
|
193 |
llm = init_groq_llm()
|
194 |
|
195 |
colf1, colf2, colf3, colf4 = st.columns(4)
|
196 |
+
|
197 |
with colf1:
|
198 |
genres = ["Все"] + sorted(set(sum([g.split(", ") for g in df["basic_genres"].unique()], [])))
|
199 |
genre_filter = st.selectbox("Жанр", genres)
|
|
|
253 |
f" | {row['type']} | {row['num_seasons']} сез."
|
254 |
)
|
255 |
st.write(extract_intro_paragraph(row["description"]))
|
256 |
+
if row["actors"]:
|
257 |
+
st.caption(f"Актёры: {row['actors']}")
|
258 |
+
if row["url"]:
|
259 |
+
st.markdown(f"[Подробнее]({row['url']})")
|
260 |
st.divider()
|
261 |
|
262 |
if st.button("AI: почему эти подходят и что ещё посмотреть"):
|