import streamlit as st @st.cache_resource def load_css(): """Загрузка CSS стилей""" with open("assets/styles.css") as f: return f.read() def render_sidebar(moods, all_tags): """Рендеринг боковой панели с фильтрами""" with st.sidebar: st.title("🔮 Фильтры") search_query = st.text_input("🔍 Поиск по имени/описанию", "") sort_option = st.selectbox( "Сортировка", ["По имени (А→Я)", "По имени (Я→А)", "По абсурдности (↑)", "По абсурдности (↓)"] ) absurdity_range = st.slider("Уровень абсурдности", 0, 10, (0, 10)) selected_mood = st.selectbox("Настроение", moods) selected_tags = st.multiselect("Теги", all_tags) return { "search_query": search_query, "sort_option": sort_option, "absurdity_range": absurdity_range, "selected_mood": selected_mood, "selected_tags": selected_tags } def generate_rpg_card(row): """Генерация RPG-карточки персонажа""" return f""" **Мир:** {row['world']} **Имя:** {row['name']} **Внешность:** {row['description']} **Характер:** {row['short_story']} **Речь:** {row['style']} **Первая реплика:** > {row['first_message']} """ def render_main_content(filtered_df): """Рендеринг основного контента с пагинацией""" st.title("🧙 Fantasy Characters Explorer") if len(filtered_df) == 0: st.warning("Персонажи не найдены. Попробуйте изменить фильтры.") else: # Инициализация состояния пагинации if 'page' not in st.session_state: st.session_state.page = 0 # Настройки пагинации per_page = 10 # Персонажей на странице total_pages = max(1, (len(filtered_df) // per_page) + (1 if len(filtered_df) % per_page else 0)) # Управление пагинацией в колонках col1, col2, _ = st.columns([2, 3, 5]) with col1: st.selectbox( "Персонажей на странице", options=[5, 10, 20], index=1, key='per_page', on_change=lambda: st.session_state.update(page=0) ) with col2: st.number_input( "Страница", min_value=0, max_value=total_pages-1, value=st.session_state.page, key='page_input', format="%d", on_change=lambda: setattr(st.session_state, 'page', st.session_state.page_input) ) # Рассчет диапазона записей start_idx = st.session_state.page * st.session_state.per_page end_idx = min((st.session_state.page + 1) * st.session_state.per_page, len(filtered_df)) # Отображение статистики st.markdown(f"**Найдено персонажей:** {len(filtered_df)} (Страница {st.session_state.page + 1}/{total_pages})") # Кэшированный рендеринг карточек @st.cache_data(max_entries=100) def render_character_card(row): with st.container(): st.markdown(f"### {row['name']}") st.caption(f"*{row['short_story']}*") col1, col2 = st.columns([1, 3]) with col1: st.markdown(f"**🌍 Мир:** {row['world']}") st.markdown(f"**🎭 Настроение:** `{row['mood']}`") st.markdown(f"**🌀 Абсурдность:** `{row['absurdity']}/10`") st.markdown(f"**🏷️ Теги:** `{' '.join(row['tags'].split())}`") with col2: st.markdown(f"**📖 Описание:** {row['description']}") st.markdown(f"**💬 Стиль речи:** *{row['style']}*") with st.expander("📋 RPG-карточка", expanded=False): rpg_card = generate_rpg_card(row) st.code(rpg_card, language="markdown") st.markdown("---") # Рендеринг только видимых карточек for idx in range(start_idx, end_idx): row = filtered_df.iloc[idx] render_character_card(row) # Кнопки навигации if total_pages > 1: cols = st.columns(4) with cols[0]: if st.button("⏪ Первая страница", disabled=(st.session_state.page == 0)): st.session_state.page = 0 st.rerun() with cols[1]: if st.button("◀️ Назад", disabled=(st.session_state.page == 0)): st.session_state.page -= 1 st.rerun() with cols[2]: if st.button("Вперед ▶️", disabled=(st.session_state.page >= total_pages-1)): st.session_state.page += 1 st.rerun() with cols[3]: if st.button("Последняя ⏩", disabled=(st.session_state.page == total_pages-1)): st.session_state.page = total_pages-1 st.rerun() def render_main_content(filtered_df): """Рендеринг основного контента с пагинацией""" st.title("🧙 Fantasy Characters Explorer") # Инициализация состояния пагинации if 'page' not in st.session_state: st.session_state.page = 0 # Настройки пагинации per_page = st.session_state.get('per_page', 10) total_items = len(filtered_df) total_pages = max(1, (total_items + per_page - 1) // per_page) # Корректировка номера страницы при изменении данных if st.session_state.page >= total_pages: st.session_state.page = max(0, total_pages - 1) # Управление пагинацией в колонках col1, col2, _ = st.columns([2, 3, 5]) with col1: st.selectbox( "Персонажей на странице", options=[5, 10, 20], index=1, key='per_page', on_change=lambda: st.session_state.update(page=0) ) with col2: st.number_input( "Страница", min_value=0, max_value=max(total_pages-1, 0), # Защита от отрицательных значений value=min(st.session_state.page, total_pages-1), # Ограничение значения key='page_input', format="%d", on_change=lambda: setattr(st.session_state, 'page', st.session_state.page_input) ) # Рассчет диапазона записей start_idx = st.session_state.page * per_page end_idx = min(start_idx + per_page, total_items) # Отображение статистики st.markdown(f"**Найдено персонажей:** {total_items} (Страница {st.session_state.page if total_items > 0 else 0}/{total_pages-1})") # Кэшированный рендеринг карточек @st.cache_data def render_character_card(row): with st.container(): st.markdown(f"### {row['name']}") st.caption(f"*{row['short_story']}*") col1, col2 = st.columns([1, 3]) with col1: st.markdown(f"**🌍 Мир:** {row['world']}") st.markdown(f"**🎭 Настроение:** `{row['mood']}`") st.markdown(f"**🌀 Абсурдность:** `{row['absurdity']}/10`") st.markdown(f"**🏷️ Теги:** `{' '.join(row['tags'].split())}`") with col2: st.markdown(f"**📖 Описание:** {row['description']}") st.markdown(f"**💬 Стиль речи:** *{row['style']}*") with st.expander("📋 RPG-карточка", expanded=False): rpg_card = generate_rpg_card(row) st.code(rpg_card, language="markdown") st.markdown("---") # Рендеринг только видимых карточек if total_items > 0: for idx in range(start_idx, end_idx): row = filtered_df.iloc[idx] render_character_card(row) else: st.warning("Персонажи не найдены. Попробуйте изменить фильтры.") return # Прерываем выполнение чтобы избежать ошибок # Кнопки навигации (только если есть результаты) if total_pages > 1: cols = st.columns(4) with cols[0]: if st.button("⏪ Первая страница", disabled=(st.session_state.page == 0)): st.session_state.page = 0 st.rerun() with cols[1]: if st.button("◀️ Назад", disabled=(st.session_state.page == 0)): st.session_state.page -= 1 st.rerun() with cols[2]: if st.button("Вперед ▶️", disabled=(st.session_state.page >= total_pages-1)): st.session_state.page += 1 st.rerun() with cols[3]: if st.button("Последняя ⏩", disabled=(st.session_state.page == total_pages-1)): st.session_state.page = total_pages-1 st.rerun()