anastarlet's picture
Upload 3 files
4116e6a verified
Raw
History Blame Contribute Delete
8.76 kB
import streamlit as st
import pandas as pd
import sqlite3
import plotly.express as px
from wordcloud import WordCloud
import matplotlib.pyplot as plt
from analyzer import analyze_sentiment, calculate_priority_score, classify_theme, get_lemmas
# Конфигурация страницы
st.set_page_config(page_title="Insta Analytics Search", layout="wide", initial_sidebar_state="collapsed")
# Стили
st.markdown("""
<style>
[data-testid="collapsedControl"] { display: none; }
section[data-testid="stSidebar"] { display: none; }
.stTextInput input { border: 2px solid #E83E8C !important; border-radius: 30px !important; padding: 15px 25px !important; font-size: 18px !important; }
.stTextInput input:focus { border: 2px solid #E83E8C !important; box-shadow: 0px 0px 10px rgba(232, 62, 140, 0.3) !important; }
.stButton>button, .stButton>button p { background-color: #E83E8C !important; color: #FFFFFF !important; border-radius: 30px !important; font-weight: bold !important; border: none !important; }
.metric-card { background-color: rgba(255, 255, 255, 0.05); padding: 20px; border-radius: 15px; border-left: 5px solid #E83E8C; color: white; }
.metric-card span { font-size: 14px; opacity: 0.7; text-transform: uppercase;}
.metric-card b { color: #E83E8C !important; font-size: 28px; display: block; margin-top: 5px;}
div[role="radiogroup"] { justify-content: center; margin-top: 10px; }
</style>
""", unsafe_allow_html=True)
@st.cache_data
def load_data():
try:
conn = sqlite3.connect('instagram_data.db')
c = pd.read_sql("SELECT * FROM comments", conn)
conn.close()
c['comment_date'] = pd.to_datetime(c['comment_date'], errors='coerce')
return c
except:
return pd.DataFrame()
comments_all = load_data()
st.markdown("<h1 style='text-align: center; font-size: 48px; margin-bottom: 0;'>Insight Search</h1>", unsafe_allow_html=True)
if 'search_results' not in st.session_state:
st.session_state['search_results'] = pd.DataFrame()
col_spacer1, col_search, col_spacer2 = st.columns([1, 4, 1])
with col_search:
search_query = st.text_input("Поиск", placeholder="Введите URL, слова, никнейм или текст...", label_visibility="collapsed")
mode = st.radio("Режим", ["🔑 По словам", "🔗 По URL поста", "👤 По автору (Нику)", "✍️ Один текст"], label_visibility="collapsed", horizontal=True)
analyze_clicked = st.button("Анализировать", use_container_width=True)
st.divider()
if analyze_clicked:
if not search_query.strip():
st.warning("Пожалуйста, введите запрос!")
else:
term = search_query.strip().lower()
res = pd.DataFrame()
if mode == "🔑 По словам":
keys = [k.strip().lower() for k in search_query.split(',')]
res = comments_all[comments_all['comment_text'].apply(lambda x: any(k in str(x).lower() for k in keys))].copy()
elif mode == "🔗 По URL поста":
res = comments_all[comments_all['post_url'].astype(str).str.contains(term, na=False, case=False)].copy()
elif mode == "👤 По автору (Нику)":
res = comments_all[comments_all['comment_author'].astype(str).str.lower().str.contains(term, na=False)].copy()
elif mode == "✍️ Один текст":
res = pd.DataFrame([{'comment_text': search_query, 'comment_author': 'Вы', 'comment_date': pd.Timestamp.now()}])
if res.empty:
st.error("По вашему запросу ничего не найдено.")
st.session_state['search_results'] = pd.DataFrame()
else:
with st.spinner('ИИ анализирует данные...'):
res['sentiment'] = analyze_sentiment(res['comment_text'].tolist())
res['theme'] = res['comment_text'].apply(classify_theme)
res['priority'] = res.apply(calculate_priority_score, axis=1)
st.session_state['search_results'] = res
# ОТОБРАЖЕНИЕ
if not st.session_state['search_results'].empty:
df_result = st.session_state['search_results']
st.markdown("<h3 style='text-align:center;'>Фильтр комментариев:</h3>", unsafe_allow_html=True)
sentiment_filter = st.radio("Тональность", ["Все", "🟢 Позитив", "🔴 Негатив", "⚪ Нейтрально"], horizontal=True, label_visibility="collapsed")
df_filtered = df_result.copy()
if sentiment_filter == "🟢 Позитив":
df_filtered = df_filtered[df_filtered['sentiment'] == 'Позитив']
elif sentiment_filter == "🔴 Негатив":
df_filtered = df_filtered[df_filtered['sentiment'] == 'Негатив']
elif sentiment_filter == "⚪ Нейтрально":
df_filtered = df_filtered[df_filtered['sentiment'] == 'Нейтрально']
st.markdown(f"## Результаты ({len(df_filtered)} шт.)")
# Метрики
c1, c2, c3, c4 = st.columns(4)
with c1: st.markdown(f'<div class="metric-card"><span>Всего</span><b>{len(df_filtered)} шт.</b></div>', unsafe_allow_html=True)
with c2:
val = df_filtered["sentiment"].mode()[0] if not df_filtered.empty else "—"
st.markdown(f'<div class="metric-card"><span>Настрой</span><b>{val}</b></div>', unsafe_allow_html=True)
with c3:
val = df_filtered["theme"].mode()[0] if not df_filtered.empty else "—"
st.markdown(f'<div class="metric-card"><span>Тема</span><b>{val}</b></div>', unsafe_allow_html=True)
with c4:
val = df_filtered["priority"].mean() if not df_filtered.empty else 0
st.markdown(f'<div class="metric-card"><span>Приоритет</span><b>{val:.1f}</b></div>', unsafe_allow_html=True)
# Графики
g1, g2 = st.columns(2)
with g1:
fig = px.pie(df_filtered, names='sentiment', color='sentiment', hole=0.3,
color_discrete_map={'Позитив':'#82ca9d', 'Негатив':'#E83E8C', 'Нейтрально':'#8884d8'})
fig.update_layout(paper_bgcolor="rgba(0,0,0,0)", font_color="white")
st.plotly_chart(fig, use_container_width=True)
with g2:
if len(df_filtered) > 0:
txt = " ".join(df_filtered['comment_text'].astype(str))
wc = WordCloud(width=800, height=400, background_color=None, mode="RGBA").generate(txt)
fig_wc, ax = plt.subplots(); ax.imshow(wc); ax.axis("off")
fig_wc.patch.set_alpha(0)
st.pyplot(fig_wc)
# Таблица
st.markdown("### 📋 Детализация комментариев")
df_display = df_filtered.copy()
df_display['comment_date'] = pd.to_datetime(df_display['comment_date']).dt.strftime('%d.%m.%Y %H:%M')
df_display['Профиль'] = df_display['comment_author'].apply(lambda x: f"https://www.instagram.com/{x}/")
df_display = df_display[['priority', 'sentiment', 'theme', 'comment_text', 'comment_author', 'Профиль', 'comment_date']]
df_display.columns = ['Приоритет', 'Тональность', 'Тема', 'Текст', 'Автор', 'Instagram', 'Дата']
st.dataframe(df_display.sort_values(by='Приоритет', ascending=False), use_container_width=True, hide_index=True,
column_config={"Instagram": st.column_config.LinkColumn("Instagram")})
st.download_button("📥 Скачать отчет (CSV)", df_display.to_csv(index=False).encode('utf-8-sig'), "report.csv", "text/csv")
# ИНСАЙТЫ (ИСПРАВЛЕНО)
st.markdown("---")
st.markdown("### 💡 Инсайты разведки")
# Проверяем негатив во ВСЕЙ найденной по запросу выборке (df_result)
neg_data = df_result[df_result['sentiment'] == 'Негатив']
if not neg_data.empty:
count_bad = len(neg_data)
bad_topic = neg_data['theme'].mode()[0]
st.error(f"⚠️ **Внимание:** В результатах поиска обнаружено **{count_bad}** негативных сообщений! Основная проблемная тема: **{bad_topic}**. Требуется анализ рисков.")
else:
st.success("✅ **Положительный инсайт:** В данной выборке не обнаружено негативных проявлений. Аудитория лояльна.")