Spaces:
Sleeping
Sleeping
import streamlit as st | |
from database import get_hash, upsert_data | |
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( | |
""" | |
[]( | |
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 | |
} | |
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']} | |
""" | |
# Кэшированный рендеринг карточек | |
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() |