import streamlit as st from database import get_hash, upsert_data @st.cache_resource def load_css(): """Загрузка CSS стилей""" with open("assets/styles.css") as f: return f.read() def render_sidebar(localS, locale, all_langs, moods, all_tags): """Рендеринг боковой панели с фильтрами""" with st.sidebar: st.markdown( """ [![🤗 Open in Datasets](https://img.shields.io/badge/🤗-Download_Dataset-blue)]( https://huggingface.co/datasets/loim/ru_fantasy_characters) """ ) def on_language_change(): if st.session_state.lang_select != st.session_state.lang: localS.setItem("lang", st.session_state.lang_select) st.selectbox( locale['filter_lang'], all_langs, index=all_langs.index(st.session_state.lang), on_change=on_language_change, key="lang_select" ) st.markdown("---") st.title(locale['filter_title']) search_query = st.text_input(locale['filter_search'], "") sort_option = st.selectbox( locale['filter_sort_title'], locale['filter_sort'] ) absurdity_range = st.slider(locale['filter_absurd'], 0, 10, (0, 10)) selected_mood = st.selectbox(locale['filter_mood'], moods) selected_tags = st.multiselect(locale['filter_tags'], all_tags) return { "search_query": search_query, "sort_option": sort_option, "absurdity_range": absurdity_range, "selected_mood": selected_mood, "selected_tags": selected_tags } @st.cache_data def generate_rpg_card(locale, row): """Генерация RPG-карточки персонажа""" return f""" {locale['rpt_card_world']} {row['world']} {locale['rpt_card_name']} {row['name']} {locale['rpt_card_desc']} {row['description']} {locale['rpt_card_story']} {row['short_story']} {locale['rpt_card_style']} {row['style']} {locale['rpt_card_msg']} {row['first_message']} """ # Кэшированный рендеринг карточек @st.cache_data def render_character_card(locale, row): with st.container(): st.markdown("---") st.markdown(f"### {row['name']}") st.caption(f"*{row['short_story']}*") col1, col2 = st.columns([1, 3]) with col1: st.markdown(f"**{locale['char_world']}** {row['world']}") st.markdown(f"**{locale['char_mood']}** `{row['mood']}`") st.markdown(f"**{locale['char_absurd']}** `{row['absurdity']}/10`") st.markdown(f"**{locale['char_tags']}** `{' '.join(row['tags'].split())}`") with col2: st.markdown(f"**{locale['char_desc']}** {row['description']}") st.markdown(f"**{locale['char_style']}** *{row['style']}*") with st.expander(locale['char_rpg_card'], expanded=False): rpg_card = generate_rpg_card(locale, row) st.code(rpg_card, language="markdown") def render_character_rating(locale, database, localS, row): current_hash = row['hash'] rating_data, _ = get_hash(database, "rating", current_hash) rating_data = rating_data[1][0] if rating_data[1] else {"hash": current_hash, "likes": 0, "dislikes": 0} # Проверяем, оценивали ли уже этот хэш if current_hash in st.session_state.rated and (rating_data['likes'] != 0 or rating_data['dislikes'] != 0): # Показываем текущий рейтинг st.write(locale["rating_text"].format(rating_data['likes'], rating_data['dislikes'])) else: # Показываем кнопки для оценки if st.button(locale["rating_like"], key=f"like_{current_hash}"): rating_data["likes"] += 1 upsert_data(database, "rating", rating_data) st.session_state.rated.append(current_hash) localS.setItem("rated", st.session_state.rated) st.rerun() if st.button(locale["rating_dislike"], key=f"dislike_{current_hash}"): rating_data["dislikes"] += 1 upsert_data(database, "rating", rating_data) st.session_state.rated.append(current_hash) localS.setItem("rated", st.session_state.rated) st.rerun() def feedback_system(locale, database, localS): if 'feedback_enabled' not in st.session_state: st.session_state.feedback_enabled = False if st.session_state.feedback_enabled: st.header(locale["feedback_header"]) rating = st.slider(locale["feedback_rating"], 1, 5, 3) comment = st.text_area(locale["feedback_comment_label"], help=locale["feedback_comment_help"]) if st.button(locale["feedback_send_btn"]): if comment.strip() == "" and rating == 3: st.warning(locale["feedback_warn"]) else: upsert_data(database, "feedback", {"text": comment.strip(), "rating": rating}) st.success(locale["feedback_suc"]) else: if st.button(locale["feedback_quest"]): st.session_state.feedback_enabled = True st.rerun() def render_main_content(locale, database, localS, filtered_df): feedback_system(locale, database, localS) """Рендеринг основного контента с пагинацией""" st.title("🧙 Characters Explorer") if len(filtered_df) == 0: st.warning(locale['main_not_found']) else: # Инициализация состояния пагинации if 'page' not in st.session_state: st.session_state.page = 0 # Настройки пагинации per_page = 5 # Персонажей на странице total_pages = max(1, (len(filtered_df) // per_page) + (1 if len(filtered_df) % per_page else 0)) if st.session_state.page >= total_pages: st.session_state.page = 0 # Управление пагинацией в колонках col1, col2, _ = st.columns([2, 3, 5]) with col1: st.selectbox( locale['main_counter'], options=[5, 10, 20], index=0, key='per_page', on_change=lambda: st.session_state.update(page=0) ) with col2: st.number_input( locale['main_page'], 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(locale['main_found'].format(len(filtered_df), st.session_state.page, total_pages-1)) # Рендеринг только видимых карточек for idx in range(start_idx, end_idx): row = filtered_df.iloc[idx] render_character_card(locale, row) render_character_rating(locale, database, localS, row) st.markdown("---") # Кнопки навигации if total_pages > 1: cols = st.columns(4) with cols[0]: if st.button(locale['pages_first'], disabled=(st.session_state.page == 0)): st.session_state.page = 0 st.rerun() with cols[1]: if st.button(locale['pages_before'], disabled=(st.session_state.page == 0)): st.session_state.page -= 1 st.rerun() with cols[2]: if st.button(locale['pages_next'], disabled=(st.session_state.page >= total_pages-1)): st.session_state.page += 1 st.rerun() with cols[3]: if st.button(locale['pages_last'], disabled=(st.session_state.page == total_pages-1)): st.session_state.page = total_pages-1 st.rerun()