/
beeval
/
AIAssistant
Обзор
Документация
Войти
/
beeval
/
AIAssistant
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
app.py
414 строк
15 KB
beeval
upload files
11 дек 2025, 14:47
11 дек 2025, 14:47
4fd137a
Код
Авторство
О чём код?
import streamlit as st import pandas as pd import plotly.express as px import sqlite3 import time from datetime import datetime # --- Настройка страницы --- st.set_page_config( page_title="AI-Помощник HR | Сбер", page_icon="🧠", layout="wide" ) # --- CSS Стили (улучшенный Сбер-стиль) --- st.markdown( """ <style> .stApp { background-color: #f8fafc; color: #1e293b; font-family: 'Segoe UI', sans-serif; } h1, h2, h3 { color: #1E40AF; font-weight: 600; } .stMetric { background: white; padding: 16px; border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); border: 1px solid #e2e8f0; transition: all 0.2s ease; } .stMetric:hover { box-shadow: 0 4px 12px rgba(0,0,0,0.15); transform: translateY(-2px); } .dashboard-header { text-align: center; margin-bottom: 30px; padding: 20px; background: linear-gradient(135deg, #1E40AF 0%, #3B82F6 100%); color: white; border-radius: 16px; box-shadow: 0 4px 14px rgba(30, 64, 175, 0.2); } .dashboard-header h1 { margin: 0; font-size: 2.2rem; color: white; } .dashboard-header p { margin: 8px 0 0; color: #dbeafe; font-size: 1.1rem; } .streamlit-expanderHeader { font-weight: 600; color: #1E40AF; font-size: 1.05rem; } .stButton>button { background-color: #1E40AF; color: white; border: none; border-radius: 8px; padding: 10px 20px; font-weight: 500; } .stButton>button:hover { background-color: #1E3A8A; } .footer { text-align: center; margin-top: 50px; padding: 20px; color: #64748b; font-size: 0.9rem; border-top: 1px solid #e2e8f0; } /* Стиль для карточек на главной */ .feature-card { background: white; padding: 20px; border-radius: 12px; box-shadow: 0 2px 6px rgba(0,0,0,0.08); border: 1px solid #e2e8f0; margin-bottom: 16px; transition: transform 0.2s; } .feature-card:hover { transform: translateY(-4px); } .feature-card h4 { color: #1E40AF; margin: 0 0 10px; } .feature-card p { color: #475569; font-size: 0.95rem; line-height: 1.5; } /* Стиль навигации в сайдбаре */ .sidebar-nav-item { padding: 10px 15px; margin: 6px 0; background: #f1f5f9; border-radius: 8px; color: #1e293b; font-weight: 500; transition: background 0.2s; } .sidebar-nav-item:hover { background: #e2e8f0; } .sidebar-nav-item.active { background: #1E40AF; color: white; } </style> """, unsafe_allow_html=True ) # --- Загрузка данных --- @st.cache_data def load_data(): conn = sqlite3.connect("hr_analytics.db") query = "SELECT * FROM news ORDER BY timestamp DESC" df = pd.read_sql_query(query, conn) conn.close() df["datetime"] = pd.to_datetime(df["timestamp"]) return df # Эффект загрузки with st.spinner("🧠 AI-Помощник HR анализирует данные..."): time.sleep(1.2) # Имитация задержки df = load_data() # --- Боковая панель (обновлённая, без лишних деталей) --- with st.sidebar: # Логотип и название st.markdown( """ <div style="text-align: center; margin-bottom: 30px;"> <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/8/8e/Sberbank_logo.svg/200px-Sberbank_logo.svg.png" width="100" style="border-radius: 12px;"> <h3 style="color: #1E40AF; margin: 8px 0 0;">AI-Помощник HR</h3> </div> """, unsafe_allow_html=True ) # Навигация с улучшенным стилем st.markdown("### 🧭 Меню") page = st.radio( "Перейти", ["Главная", "Дашборд"], label_visibility="collapsed", format_func=lambda x: f"🏠 {x}" if x == "Главная" else f"📊 {x}" ) st.markdown("---") # Статистика total_news = len(df) high_priority = len(df[df["urgency"] == "high"]) topics_count = df["topic"].nunique() st.markdown("### 📊 Сводка") st.markdown( f""" <div style="font-size: 0.9rem; color: #475569; line-height: 1.6;"> <div>📌 Всего событий: <strong>{total_news}</strong></div> <div>🚨 Критических: <strong>{high_priority}</strong></div> <div>📚 Тем: <strong>{topics_count}</strong></div> </div> """, unsafe_allow_html=True ) st.markdown("---") # Версия st.markdown( """ <div style="text-align: center; margin-top: 20px; color: #94a3b8; font-size: 0.8rem;"> v1.2.0 • AI-аналитика </div> """, unsafe_allow_html=True ) # --- Главная страница --- if page == "Главная": st.markdown("# 🏠 Добро пожаловать в AI-Помощник HR") # Баннер st.markdown( """ <div style="text-align: center; margin: 20px 0 30px;"> <img src="https://via.placeholder.com/1000x300/1E40AF/FFFFFF?text=AI+HR+Assistant+%E2%80%94+Sber+Analytics" style="border-radius: 12px; box-shadow: 0 4px 12px rgba(0,0,0,0.1);"> </div> """, unsafe_allow_html=True ) # Описание st.markdown( """ <div style="text-align: center; max-width: 800px; margin: 0 auto 30px;"> <h3 style="color: #1E40AF;">Интеллектуальный мониторинг для HR-аналитиков</h3> <p style="color: #475569; font-size: 1.1rem; line-height: 1.6;"> Система автоматически собирает, анализирует и классифицирует информацию из множества источников, чтобы вы могли вовремя реагировать на изменения в образовании, технологиях и бизнесе. </p> </div> """, unsafe_allow_html=True ) # Карточки функций col1, col2, col3 = st.columns(3) with col1: st.markdown( """ <div class="feature-card"> <h4>📡 Мониторинг</h4> <p>Сбор данных из Telegram, VK, СМИ, научных публикаций и внутренних порталов.</p> </div> """, unsafe_allow_html=True ) with col2: st.markdown( """ <div class="feature-card"> <h4>🧠 Анализ</h4> <p>Классификация по темам, тональности и приоритету с помощью NLP-моделей.</p> </div> """, unsafe_allow_html=True ) with col3: st.markdown( """ <div class="feature-card"> <h4>📈 Визуализация</h4> <p>Интерактивные дашборды, сводки и экспорт данных для принятия решений.</p> </div> """, unsafe_allow_html=True ) # Призыв к действию st.markdown( """ <div style="text-align: center; margin: 40px 0;"> <button style=" background: #1E40AF; color: white; border: none; padding: 12px 32px; font-size: 1.1rem; border-radius: 8px; cursor: pointer; box-shadow: 0 4px 12px rgba(30, 64, 175, 0.3);"> Перейти к дашборду → </button> </div> """, unsafe_allow_html=True ) # Слоган st.markdown( """ <div style="text-align: center; margin: 20px 0; color: #64748b; font-style: italic; font-size: 1.05rem;"> «Не пропустите тренд — реагируйте раньше рынка» </div> """, unsafe_allow_html=True ) # --- Дашборд --- elif page == "Дашборд": st.markdown( """ <div class="dashboard-header"> <h1>📊 AI-Помощник HR</h1> <p>Интеллектуальный мониторинг трендов в реальном времени</p> </div> """, unsafe_allow_html=True ) # --- Сводка дня --- today = df["datetime"].max().date() today_count = len(df[df["datetime"].dt.date == today]) high_urgency_today = len(df[(df["datetime"].dt.date == today) & (df["urgency"] == "high")]) st.markdown( f""" <div style="background: #eff6ff; padding: 16px; border-radius: 12px; border-left: 4px solid #3B82F6; margin-bottom: 24px;"> 📅 Сегодня: <strong>{today}</strong> | Обнаружено: <strong>{today_count}</strong> событий, включая <strong style="color: #DC2626;">{high_urgency_today} критических</strong>. </div> """, unsafe_allow_html=True ) # --- Фильтры --- st.markdown("### 🔍 Фильтры") col1, col2 = st.columns([2, 1]) with col1: selected_topics = st.multiselect("Фильтр по темам", options=df["topic"].unique(), default=df["topic"].unique()) with col2: min_date = df["datetime"].min().date() max_date = df["datetime"].max().date() date_range = st.date_input("Период", value=(min_date, max_date), min_value=min_date, max_value=max_date) # Применение фильтров filtered_df = df[df["topic"].isin(selected_topics)] if isinstance(date_range, tuple): start_date, end_date = date_range filtered_df = filtered_df[ (filtered_df["datetime"].dt.date >= start_date) & (filtered_df["datetime"].dt.date <= end_date) ] # --- Метрики --- total = len(filtered_df) critical = len(filtered_df[filtered_df["urgency"] == "high"]) unique_topics = filtered_df["topic"].nunique() st.markdown( f""" <div style="display: flex; gap: 16px; margin: 20px 0;"> <div style="flex: 1; background: white; padding: 20px; border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); text-align: center; border: 1px solid #e2e8f0;"> <div style="font-size: 1.8rem; font-weight: bold; color: #1E40AF;">{total}</div> <div style="color: #64748b; font-size: 0.95rem;">📌 Всего событий</div> </div> <div style="flex: 1; background: white; padding: 20px; border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); text-align: center; border: 1px solid #e2e8f0;"> <div style="font-size: 1.8rem; font-weight: bold; color: #DC2626;">{critical}</div> <div style="color: #64748b; font-size: 0.95rem;">🚨 Критические события</div> </div> <div style="flex: 1; background: white; padding: 20px; border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); text-align: center; border: 1px solid #e2e8f0;"> <div style="font-size: 1.8rem; font-weight: bold; color: #059669;">{unique_topics}</div> <div style="color: #64748b; font-size: 0.95rem;">📚 Уникальных тем</div> </div> </div> """, unsafe_allow_html=True ) st.markdown("---") # --- Графики --- st.markdown("### 🎯 Распределение по темам") topic_count = filtered_df["topic"].value_counts().reset_index() topic_count.columns = ["topic", "count"] fig1 = px.pie(topic_count, names="topic", values="count", title="Доли ключевых тем", color_discrete_sequence=px.colors.sequential.Blues_r) fig1.update_traces(textinfo='percent+label') st.plotly_chart(fig1, use_container_width=True) # --- Лента новостей --- st.markdown("### 📰 Последние события") urgency_filter = st.selectbox("Приоритет", ["Все", "Критические", "Обычные"]) display_df = filtered_df.copy() if urgency_filter == "Критические": display_df = display_df[display_df["urgency"] == "high"] elif urgency_filter == "Обычные": display_df = display_df[display_df["urgency"] == "normal"] for _, row in display_df.head(10).iterrows(): sentiment_color = {"positive": "#10B981", "neutral": "#F59E0B", "negative": "#EF4444"}[row["sentiment"]] urgency_bg = "#fee2e2" if row["urgency"] == "high" else "#f0fdf4" urgency_border = "#DC2626" if row["urgency"] == "high" else "#10B981" with st.expander(f"📄 {row['title']} ({row['source']})"): st.markdown( f""" <div style="padding: 12px; background: {urgency_bg}; border-left: 4px solid {urgency_border}; border-radius: 0 8px 8px 0;"> <div style="display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 8px;"> <span style="background: {sentiment_color}; color: white; padding: 4px 10px; border-radius: 12px; font-size: 0.85rem; font-weight: 500;"> {row['sentiment'].title()} </span> <span style="background: #3B82F6; color: white; padding: 4px 10px; border-radius: 12px; font-size: 0.85rem;"> {row['topic']} </span> </div> <p style="color: #1e293b; line-height: 1.6; margin: 0;">{row['summary']}</p> <div style="color: #64748b; font-size: 0.85rem; margin-top: 8px;">🕒 {row['timestamp']}</div> </div> """, unsafe_allow_html=True ) # --- Экспорт --- st.markdown("---") @st.cache_data def convert_df_to_csv(dataframe): return dataframe[["title", "topic", "sentiment", "source", "timestamp", "urgency"]].to_csv(index=False).encode('utf-8') csv = convert_df_to_csv(display_df) st.download_button("⬇️ Экспорт данных (CSV)", data=csv, file_name=f"hr_export_{datetime.now().strftime('%Y%m%d')}.csv", mime="text/csv") # --- Подвал --- st.markdown( """<div class="footer">🧠 AI-Помощник для HR-аналитики | Хакатон 2025</div>""", unsafe_allow_html=True )