| import streamlit as st |
| from datasets import load_dataset |
| import pandas as pd |
|
|
| |
| st.set_page_config(layout="wide", page_icon="🧙", page_title="Fantasy Characters Explorer") |
|
|
| |
| @st.cache_data |
| def load_data(): |
| dataset = load_dataset("loim/ru_fantasy_characters") |
| return pd.DataFrame(dataset["train"]) |
|
|
| df = load_data() |
|
|
| |
| def generate_rpg_card(row): |
| return f""" |
| **Мир:** {row['world']} |
| |
| **Имя:** {row['name']} |
| **Внешность:** {row['description']} |
| **Характер:** {row['short_story']} |
| **Речь:** {row['style']} |
| |
| **Первая реплика:** |
| > {row['first_message']} |
| """ |
|
|
| |
| def local_css(file_name): |
| with open(file_name) as f: |
| st.markdown(f"<style>{f.read()}</style>", unsafe_allow_html=True) |
|
|
| local_css("assets/styles.css") |
|
|
| |
| with st.sidebar: |
| st.title("🔮 Фильтры") |
| search_query = st.text_input("🔍 Поиск по имени/описанию", "") |
| sort_option = st.selectbox( |
| "Сортировка", |
| ["По имени (А→Я)", "По имени (Я→А)", "По абсурдности (↑)", "По абсурдности (↓)"] |
| ) |
| absurdity_range = st.slider("Уровень абсурдности", 0, 10, (0, 10)) |
| moods = ["Все"] + sorted(df["mood"].unique().tolist()) |
| selected_mood = st.selectbox("Настроение", moods) |
| all_tags = sorted({tag for tags in df["tags"] for tag in tags.split()}) |
| selected_tags = st.multiselect("Теги", all_tags) |
|
|
| |
| filtered_df = df[ |
| (df["absurdity"] >= absurdity_range[0]) & |
| (df["absurdity"] <= absurdity_range[1]) |
| ] |
|
|
| if selected_mood != "Все": |
| filtered_df = filtered_df[filtered_df["mood"] == selected_mood] |
|
|
| if selected_tags: |
| filtered_df = filtered_df[filtered_df["tags"].str.contains("|".join(selected_tags))] |
|
|
| if search_query: |
| filtered_df = filtered_df[ |
| filtered_df["name"].str.contains(search_query, case=False) | |
| filtered_df["description"].str.contains(search_query, case=False) | |
| filtered_df["short_story"].str.contains(search_query, case=False) |
| ] |
|
|
| |
| if "А→Я" in sort_option: |
| filtered_df = filtered_df.sort_values("name") |
| elif "Я→А" in sort_option: |
| filtered_df = filtered_df.sort_values("name", ascending=False) |
| elif "↑" in sort_option: |
| filtered_df = filtered_df.sort_values("absurdity") |
| else: |
| filtered_df = filtered_df.sort_values("absurdity", ascending=False) |
|
|
| |
| st.title("🧙 Fantasy Characters Explorer") |
| st.markdown(f"**Найдено персонажей:** {len(filtered_df)}") |
|
|
| for idx, row in filtered_df.iterrows(): |
| 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 len(filtered_df) == 0: |
| st.warning("Персонажи не найдены. Попробуйте изменить фильтры.") |