|
|
|
"""
|
|
Enhanced Series Mosaics Integration for Tag Collector Game
|
|
|
|
This module provides improved integration between series-based mosaics,
|
|
the enhanced tag storage system, and the tag collector game.
|
|
"""
|
|
|
|
import os
|
|
import json
|
|
import io
|
|
import time
|
|
import streamlit as st
|
|
from PIL import Image
|
|
from game_constants import RARITY_LEVELS, TAG_CURRENCY_NAME, ENKEPHALIN_CURRENCY_NAME, ENKEPHALIN_ICON
|
|
|
|
|
|
from tag_mosaic import RevealMosaic
|
|
|
|
|
|
DEFAULT_MOSAICS_DIR = "mosaics"
|
|
DEFAULT_TEMPLATES_DIR = "mosaics/templates"
|
|
|
|
SERIES_COMPLETION_MILESTONES = [25, 50, 75, 100]
|
|
BASE_ENKEPHALIN_REWARDS = {
|
|
25: 100,
|
|
50: 500,
|
|
75: 1000,
|
|
100: 5000
|
|
}
|
|
|
|
|
|
COLLECTION_SIZE_MULTIPLIERS = {
|
|
"small": 1.0,
|
|
"medium": 1.5,
|
|
"large": 2.0,
|
|
"huge": 3.0,
|
|
"massive": 5.0,
|
|
"all_tags": 10.0
|
|
}
|
|
|
|
def get_collection_size_tier(total_tags):
|
|
"""
|
|
Determine the size tier of a collection based on total tag count
|
|
|
|
Args:
|
|
total_tags: Total number of tags in the collection
|
|
|
|
Returns:
|
|
String representing the size tier
|
|
"""
|
|
if total_tags <= 20:
|
|
return "small"
|
|
elif total_tags <= 50:
|
|
return "medium"
|
|
elif total_tags <= 100:
|
|
return "large"
|
|
elif total_tags <= 200:
|
|
return "huge"
|
|
elif total_tags <= 1000:
|
|
return "massive"
|
|
else:
|
|
return "all_tags"
|
|
|
|
def calculate_enkephalin_reward(percentage, total_tags):
|
|
"""
|
|
Calculate the enkephalin reward for a specific milestone
|
|
|
|
Args:
|
|
percentage: Completion percentage milestone (25, 50, 75, 100)
|
|
total_tags: Total number of tags in the collection
|
|
|
|
Returns:
|
|
Integer amount of enkephalin to reward
|
|
"""
|
|
|
|
base_reward = BASE_ENKEPHALIN_REWARDS.get(percentage, 0)
|
|
|
|
|
|
size_tier = get_collection_size_tier(total_tags)
|
|
multiplier = COLLECTION_SIZE_MULTIPLIERS.get(size_tier, 1.0)
|
|
|
|
|
|
final_reward = round(base_reward * multiplier)
|
|
|
|
return max(1, final_reward)
|
|
|
|
def check_and_award_milestone_rewards(mosaic_name, filtered_tags, total_tags):
|
|
"""
|
|
Check if new milestones have been reached and award enkephalin rewards
|
|
|
|
Args:
|
|
mosaic_name: Unique identifier for this mosaic/collection
|
|
filtered_tags: Dictionary with the tags that belong to this collection
|
|
total_tags: Total number of tags in this collection
|
|
|
|
Returns:
|
|
Tuple of (awarded_milestone, reward_amount) or (None, 0) if no reward
|
|
"""
|
|
import streamlit as st
|
|
|
|
|
|
if not filtered_tags or total_tags <= 0:
|
|
return None, 0
|
|
|
|
|
|
current_tags = len(filtered_tags)
|
|
current_percentage = (current_tags / total_tags) * 100
|
|
|
|
|
|
current_percentage = int(current_percentage)
|
|
|
|
|
|
milestone_key = f"collection_milestones_{mosaic_name}"
|
|
if milestone_key not in st.session_state:
|
|
st.session_state[milestone_key] = []
|
|
|
|
awarded_milestones = st.session_state[milestone_key]
|
|
|
|
|
|
for milestone in SERIES_COMPLETION_MILESTONES:
|
|
|
|
if current_percentage >= milestone and milestone not in awarded_milestones:
|
|
|
|
reward = calculate_enkephalin_reward(milestone, total_tags)
|
|
|
|
|
|
awarded_milestones.append(milestone)
|
|
st.session_state[milestone_key] = awarded_milestones
|
|
|
|
|
|
if not hasattr(st.session_state, 'enkephalin'):
|
|
st.session_state.enkephalin = 0
|
|
|
|
|
|
st.session_state.enkephalin += reward
|
|
|
|
|
|
if hasattr(st.session_state, 'game_stats'):
|
|
if 'enkephalin_generated' in st.session_state.game_stats:
|
|
st.session_state.game_stats['enkephalin_generated'] += reward
|
|
else:
|
|
st.session_state.game_stats['enkephalin_generated'] = reward
|
|
|
|
|
|
try:
|
|
import tag_storage
|
|
tag_storage.save_game(st.session_state)
|
|
except (ImportError, Exception) as e:
|
|
print(f"Error saving game after enkephalin award: {str(e)}")
|
|
|
|
|
|
return milestone, reward
|
|
|
|
|
|
return None, 0
|
|
|
|
def ensure_directories():
|
|
"""Ensure all required directories exist"""
|
|
|
|
if not os.path.exists(DEFAULT_MOSAICS_DIR):
|
|
os.makedirs(DEFAULT_MOSAICS_DIR)
|
|
|
|
|
|
if not os.path.exists(DEFAULT_TEMPLATES_DIR):
|
|
os.makedirs(DEFAULT_TEMPLATES_DIR)
|
|
|
|
def load_series_data(regenerate=False):
|
|
"""
|
|
Load series data for mosaics from model directory
|
|
|
|
Args:
|
|
regenerate: Force regeneration of series data even if file exists
|
|
|
|
Returns:
|
|
Dictionary with series information and mosaic configs
|
|
"""
|
|
|
|
|
|
try:
|
|
with open('series_groups.json', 'r', encoding='utf-8') as f:
|
|
series_data = json.load(f)
|
|
print(f"Loaded series data from {'series_groups.json'}")
|
|
return series_data
|
|
except Exception as e:
|
|
print(f"Error loading series data: {str(e)}")
|
|
|
|
|
|
return {
|
|
"stats": {
|
|
"total_tags": 0,
|
|
"series_tags": 0,
|
|
"regular_tags": 0,
|
|
"unique_series": 0,
|
|
"total_characters": 0
|
|
},
|
|
"series": {},
|
|
"mosaic_configs": []
|
|
}
|
|
|
|
def filter_collected_tags_by_series(collected_tags, series_data, series_name):
|
|
"""
|
|
Filter collected tags to only include tags from a specific series
|
|
|
|
Args:
|
|
collected_tags: Dictionary of collected tags from session state
|
|
series_data: Series data from load_series_data()
|
|
series_name: Name of the series to filter for
|
|
|
|
Returns:
|
|
Dictionary with only the tags belonging to the specified series
|
|
"""
|
|
if 'series' not in series_data or series_name not in series_data['series']:
|
|
return {}
|
|
|
|
|
|
series_tags = set(series_data['series'][series_name]['tags'])
|
|
|
|
|
|
filtered_tags = {}
|
|
for tag, info in collected_tags.items():
|
|
if tag in series_tags:
|
|
filtered_tags[tag] = info
|
|
|
|
return filtered_tags
|
|
|
|
def create_filtered_collections(collected_tags, series_data):
|
|
"""
|
|
Create filtered tag collections for each series
|
|
|
|
Args:
|
|
collected_tags: Main collected_tags dictionary
|
|
series_data: Series data from load_series_data()
|
|
|
|
Returns:
|
|
Dictionary mapping series keys to filtered tag dictionaries
|
|
"""
|
|
filtered_collections = {}
|
|
|
|
|
|
if not series_data or 'series' not in series_data:
|
|
return filtered_collections
|
|
|
|
|
|
for series_name, series_info in series_data['series'].items():
|
|
|
|
if series_info['tag_count'] <= 1:
|
|
continue
|
|
|
|
|
|
series_key = series_name.replace(" ", "_").replace(":", "").lower()
|
|
|
|
|
|
filtered_tags = filter_collected_tags_by_series(collected_tags, series_data, series_name)
|
|
|
|
|
|
filtered_collections[series_key] = {
|
|
"series_name": series_name,
|
|
"filtered_tags": filtered_tags,
|
|
"tag_count": len(filtered_tags),
|
|
"total_tags": series_info['tag_count']
|
|
}
|
|
|
|
return filtered_collections
|
|
|
|
def render_tag_reveal_feature(st, series_name, filtered_tags, series_data, revealed_tags_key):
|
|
"""
|
|
Render a feature that allows users to pay to reveal missing tags
|
|
|
|
Args:
|
|
st: Streamlit instance
|
|
series_name: Name of the series
|
|
filtered_tags: The tags the user has already collected for this series
|
|
series_data: The full series data loaded from the JSON file
|
|
revealed_tags_key: The session key for storing revealed tags
|
|
"""
|
|
|
|
if 'series' not in series_data or series_name not in series_data['series']:
|
|
return
|
|
|
|
|
|
all_series_tags = set(series_data['series'][series_name]['tags'])
|
|
|
|
|
|
collected_tag_names = set(filtered_tags.keys())
|
|
missing_tags = all_series_tags - collected_tag_names
|
|
|
|
|
|
if not missing_tags:
|
|
st.success("Congratulations! You have collected all tags in this series!")
|
|
return
|
|
|
|
|
|
if revealed_tags_key not in st.session_state:
|
|
st.session_state[revealed_tags_key] = set()
|
|
|
|
|
|
revealed_tags = st.session_state[revealed_tags_key]
|
|
|
|
|
|
unknown_tags = missing_tags - revealed_tags
|
|
|
|
|
|
with st.expander("📋 Missing Tags Explorer", expanded=True):
|
|
|
|
st.write("""
|
|
Use this feature to explore missing tags in this collection.
|
|
You won't actually collect these tags, but you'll know what to look for in images!
|
|
""")
|
|
|
|
|
|
col1, col2, col3 = st.columns(3)
|
|
with col1:
|
|
st.metric("Tags Collected", len(collected_tag_names))
|
|
with col2:
|
|
st.metric("Tags Revealed", len(revealed_tags))
|
|
with col3:
|
|
st.metric("Tags Unknown", len(unknown_tags))
|
|
|
|
|
|
enkephalin_cost = 2
|
|
|
|
|
|
if len(unknown_tags) <= 5:
|
|
|
|
enkephalin_cost = 10
|
|
elif len(unknown_tags) <= 15:
|
|
|
|
enkephalin_cost = 5
|
|
|
|
|
|
st.write("### Reveal Missing Tags")
|
|
|
|
|
|
current_enkephalin = st.session_state.enkephalin if hasattr(st.session_state, 'enkephalin') else 0
|
|
|
|
|
|
col1, col2, col3 = st.columns([1, 2, 1])
|
|
|
|
with col2:
|
|
st.write(f"**Cost: {enkephalin_cost} {ENKEPHALIN_ICON} {ENKEPHALIN_CURRENCY_NAME}**")
|
|
can_afford_enkephalin = current_enkephalin >= enkephalin_cost
|
|
|
|
if st.button("Reveal Tag", disabled=not can_afford_enkephalin or not unknown_tags):
|
|
if can_afford_enkephalin and unknown_tags:
|
|
|
|
import random
|
|
tag_to_reveal = random.choice(list(unknown_tags))
|
|
|
|
|
|
revealed_tags.add(tag_to_reveal)
|
|
st.session_state[revealed_tags_key] = revealed_tags
|
|
|
|
|
|
st.session_state.enkephalin -= enkephalin_cost
|
|
if hasattr(st.session_state.game_stats, 'enkephalin_spent'):
|
|
st.session_state.game_stats['enkephalin_spent'] += enkephalin_cost
|
|
else:
|
|
st.session_state.game_stats['enkephalin_spent'] = enkephalin_cost
|
|
|
|
|
|
try:
|
|
import tag_storage
|
|
tag_storage.save_game(st.session_state)
|
|
except (ImportError, Exception):
|
|
pass
|
|
|
|
|
|
st.success(f"Revealed new tag: **{tag_to_reveal}**")
|
|
|
|
|
|
st.rerun()
|
|
|
|
|
|
if revealed_tags:
|
|
st.write("### Revealed Tags")
|
|
st.write("These tags are part of this collection but you haven't collected them yet:")
|
|
|
|
|
|
cols = st.columns(3)
|
|
for i, tag in enumerate(sorted(revealed_tags)):
|
|
col_idx = i % 3
|
|
with cols[col_idx]:
|
|
st.write(f"- {tag}")
|
|
|
|
|
|
if st.button("Reset Revealed Tags"):
|
|
st.session_state[revealed_tags_key] = set()
|
|
st.success("Reset successful! All revealed tags have been forgotten.")
|
|
st.rerun()
|
|
|
|
def display_series_mosaic(mosaic_name, mosaic_title, filtered_tags, total_tags=None, width=1024, height=1024):
|
|
"""
|
|
Display a mosaic for a specific tag collection or series
|
|
|
|
Args:
|
|
mosaic_name: Unique identifier for this mosaic
|
|
mosaic_title: Display title for the mosaic
|
|
filtered_tags: Dictionary with the tags that belong to this collection
|
|
total_tags: Total number of tags in this collection (if None, uses len(filtered_tags))
|
|
width: Width of the mosaic in pixels (not used in this implementation)
|
|
height: Height of the mosaic in pixels (not used in this implementation)
|
|
"""
|
|
import streamlit as st
|
|
|
|
if total_tags is None:
|
|
|
|
total_tags = max(len(filtered_tags), 20)
|
|
|
|
|
|
with st.container():
|
|
st.subheader(f"🧩 {mosaic_title} Mosaic")
|
|
|
|
|
|
mosaic_key = f"{mosaic_name}_mosaic"
|
|
if mosaic_key not in st.session_state:
|
|
|
|
st.session_state[mosaic_key] = RevealMosaic(
|
|
total_tags=total_tags,
|
|
mosaic_name=mosaic_name
|
|
)
|
|
|
|
|
|
mosaic = st.session_state[mosaic_key]
|
|
|
|
|
|
col1, col2, col3 = st.columns(3)
|
|
with col1:
|
|
st.metric("Discovered Tags", len(filtered_tags))
|
|
with col2:
|
|
st.metric("Total Tags", total_tags)
|
|
with col3:
|
|
completion = (len(filtered_tags) / total_tags) * 100 if total_tags > 0 else 0
|
|
st.metric("Completion", f"{completion:.1f}%")
|
|
|
|
|
|
display_milestone_tracker(mosaic_name, filtered_tags, total_tags)
|
|
|
|
|
|
update_requested = st.button("🔄 Update Mosaic", key=f"update_btn_{mosaic_name}")
|
|
|
|
|
|
if not update_requested:
|
|
st.info("Click the 'Update Mosaic' button to process new tag discoveries and update the image.")
|
|
|
|
|
|
newly_revealed = 0
|
|
if update_requested and filtered_tags:
|
|
|
|
with st.spinner("Processing tag discoveries and updating mosaic..."):
|
|
|
|
metadata = st.session_state.model.dataset if hasattr(st.session_state, 'model') else None
|
|
newly_revealed = mosaic.update_with_tags(filtered_tags, metadata, force_update=True)
|
|
|
|
|
|
milestone, reward = check_and_award_milestone_rewards(mosaic_name, filtered_tags, total_tags)
|
|
|
|
|
|
if milestone is not None:
|
|
|
|
st.balloons()
|
|
st.success(f"🏆 MILESTONE ACHIEVED! {milestone}% Completion of {mosaic_title}!")
|
|
st.success(f"Rewarded with {reward} {ENKEPHALIN_ICON} {ENKEPHALIN_CURRENCY_NAME}!")
|
|
|
|
|
|
st.rerun()
|
|
elif newly_revealed > 0:
|
|
st.success(f"Successfully updated! Revealed {newly_revealed} new pixels.")
|
|
else:
|
|
st.info("No new pixels to reveal.")
|
|
|
|
|
|
stats = mosaic.get_stats()
|
|
|
|
|
|
col1, col2 = st.columns(2)
|
|
with col1:
|
|
st.write(f"**Completion:** {stats['completion_percentage']:.2f}%")
|
|
st.write(f"**Pixels Revealed:** {stats['revealed_pixels']} / {stats['total_pixels']}")
|
|
with col2:
|
|
st.write(f"**Status:** {stats['completion_pattern']}")
|
|
if newly_revealed > 0:
|
|
st.write(f"**Newly Revealed:** {newly_revealed} pixels")
|
|
|
|
|
|
mosaic_img = mosaic.get_image()
|
|
|
|
|
|
img_bytes = io.BytesIO()
|
|
mosaic_img.save(img_bytes, format='PNG')
|
|
img_bytes.seek(0)
|
|
|
|
|
|
st.image(img_bytes, caption=f"Your {mosaic_title} Mosaic - Each discovery reveals more of the hidden image",
|
|
use_container_width=True)
|
|
|
|
|
|
if mosaic.highlighted_tags:
|
|
with st.expander("Recently Added Tags", expanded=False):
|
|
for tag, _, _, rarity in mosaic.highlighted_tags:
|
|
color = RARITY_LEVELS.get(rarity, {}).get("color", "#AAAAAA")
|
|
st.markdown(
|
|
f"<span style='color:{color};font-weight:bold;'>{tag}</span>",
|
|
unsafe_allow_html=True
|
|
)
|
|
|
|
def display_milestone_tracker(mosaic_name, filtered_tags, total_tags):
|
|
"""
|
|
Display a visual tracker for collection milestones
|
|
|
|
Args:
|
|
mosaic_name: Unique identifier for this mosaic/collection
|
|
filtered_tags: Dictionary with the tags that belong to this collection
|
|
total_tags: Total number of tags in this collection
|
|
"""
|
|
import streamlit as st
|
|
|
|
|
|
if not filtered_tags or total_tags <= 0:
|
|
return
|
|
|
|
|
|
milestone_key = f"collection_milestones_{mosaic_name}"
|
|
if milestone_key not in st.session_state:
|
|
st.session_state[milestone_key] = []
|
|
|
|
awarded_milestones = st.session_state[milestone_key]
|
|
|
|
|
|
current_tags = len(filtered_tags)
|
|
current_percentage = (current_tags / total_tags) * 100
|
|
|
|
|
|
milestone_data = []
|
|
for milestone in SERIES_COMPLETION_MILESTONES:
|
|
reward = calculate_enkephalin_reward(milestone, total_tags)
|
|
milestone_data.append({
|
|
"percentage": milestone,
|
|
"reward": reward,
|
|
"achieved": milestone in awarded_milestones,
|
|
"is_next": milestone not in awarded_milestones and current_percentage < milestone
|
|
})
|
|
|
|
|
|
milestone_data.sort(key=lambda x: x["percentage"])
|
|
|
|
|
|
with st.expander("Collection Milestones", expanded=len(awarded_milestones) > 0):
|
|
st.write("Complete collection milestones to earn Enkephalin rewards:")
|
|
|
|
|
|
st.progress(min(1.0, current_percentage / 100), text=f"Current Progress: {current_percentage:.1f}%")
|
|
|
|
|
|
cols = st.columns(len(milestone_data))
|
|
|
|
for i, milestone in enumerate(milestone_data):
|
|
with cols[i]:
|
|
|
|
if milestone["achieved"]:
|
|
st.markdown(f"### ✅ {milestone['percentage']}%")
|
|
st.markdown(f"Reward: **{milestone['reward']}** {ENKEPHALIN_ICON}")
|
|
st.markdown("**COMPLETED!**")
|
|
elif milestone["is_next"]:
|
|
|
|
percentage_needed = milestone["percentage"] - current_percentage
|
|
tags_needed = int((milestone["percentage"] / 100 * total_tags) - current_tags)
|
|
|
|
st.markdown(f"### 🎯 {milestone['percentage']}%")
|
|
st.markdown(f"Reward: **{milestone['reward']}** {ENKEPHALIN_ICON}")
|
|
st.markdown(f"Need: **{tags_needed}** more tags")
|
|
else:
|
|
st.markdown(f"### 🔜 {milestone['percentage']}%")
|
|
st.markdown(f"Reward: **{milestone['reward']}** {ENKEPHALIN_ICON}")
|
|
st.markdown("Coming up!")
|
|
|
|
|
|
size_tier = get_collection_size_tier(total_tags)
|
|
tier_multiplier = COLLECTION_SIZE_MULTIPLIERS.get(size_tier, 1.0)
|
|
|
|
st.markdown("---")
|
|
st.markdown(f"**Collection Size Tier:** {size_tier.capitalize()} Collection")
|
|
st.markdown(f"**Reward Multiplier:** {tier_multiplier}x")
|
|
|
|
def display_series_mosaics():
|
|
"""
|
|
Display mosaics for each series found in the metadata.
|
|
Uses the improved tag storage system for better integration.
|
|
"""
|
|
import streamlit as st
|
|
|
|
|
|
ensure_directories()
|
|
|
|
|
|
if not hasattr(st.session_state, 'collected_tags'):
|
|
st.info("Start scanning images to collect tags!")
|
|
return
|
|
|
|
|
|
series_data = load_series_data()
|
|
|
|
|
|
if not series_data or 'series' not in series_data or not series_data['series']:
|
|
st.warning("Series data not found. Make sure series_groups.json exists in the model directory.")
|
|
return
|
|
|
|
|
|
filtered_collections = create_filtered_collections(st.session_state.collected_tags, series_data)
|
|
|
|
|
|
mosaic_configs = []
|
|
|
|
|
|
for config in series_data.get("mosaic_configs", []):
|
|
|
|
if config["name"] == "main":
|
|
continue
|
|
|
|
|
|
series_key = config["name"]
|
|
config_with_session_key = config.copy()
|
|
|
|
|
|
if series_key in filtered_collections:
|
|
config_with_session_key["discovered_tags"] = filtered_collections[series_key]["tag_count"]
|
|
config_with_session_key["filtered_tags"] = filtered_collections[series_key]["filtered_tags"]
|
|
else:
|
|
|
|
config_with_session_key["discovered_tags"] = 0
|
|
config_with_session_key["filtered_tags"] = {}
|
|
|
|
mosaic_configs.append(config_with_session_key)
|
|
|
|
|
|
st.subheader("🎮 Series Collections")
|
|
|
|
|
|
|
|
collections_with_tags = [c for c in mosaic_configs if c.get("discovered_tags", 0) > 0]
|
|
collections_with_tags.sort(key=lambda x: x.get("discovered_tags", 0), reverse=True)
|
|
|
|
|
|
collections_without_tags = [c for c in mosaic_configs if c.get("discovered_tags", 0) == 0]
|
|
|
|
|
|
collection_options = []
|
|
|
|
|
|
if collections_with_tags:
|
|
collection_options.append("--- Collections with discoveries ---")
|
|
for config in collections_with_tags:
|
|
collection_options.append(f"{config['title']} ({config.get('discovered_tags', 0)}/{config['total_tags']} tags)")
|
|
|
|
|
|
if collections_without_tags:
|
|
collection_options.append("--- Collections to discover ---")
|
|
for config in collections_without_tags:
|
|
collection_options.append(f"{config['title']} (0/{config['total_tags']} tags)")
|
|
|
|
|
|
if 'selected_collection_index' not in st.session_state:
|
|
|
|
st.session_state.selected_collection_index = 1 if collections_with_tags else len(collections_with_tags) + 1
|
|
|
|
|
|
if collection_options:
|
|
selected_option = st.selectbox(
|
|
"Select Collection:",
|
|
options=collection_options,
|
|
index=min(st.session_state.selected_collection_index, len(collection_options)-1)
|
|
)
|
|
|
|
|
|
st.session_state.selected_collection_index = collection_options.index(selected_option)
|
|
|
|
|
|
if "---" in selected_option:
|
|
st.info("Please select a collection from the dropdown.")
|
|
return
|
|
|
|
|
|
selected_config = None
|
|
selected_series_name = None
|
|
for config in mosaic_configs:
|
|
option_text = f"{config['title']} ({config.get('discovered_tags', 0)}/{config['total_tags']} tags)"
|
|
if option_text == selected_option:
|
|
selected_config = config
|
|
|
|
|
|
if config['name'] == 'miku_collection':
|
|
selected_series_name = 'vocaloid'
|
|
elif 'series_name' in config:
|
|
selected_series_name = config['series_name']
|
|
else:
|
|
selected_series_name = config['name'].replace('_', ' ')
|
|
break
|
|
|
|
|
|
if selected_config:
|
|
|
|
with st.container():
|
|
|
|
filtered_tags = selected_config.get("filtered_tags", {})
|
|
|
|
|
|
mosaic_name = selected_config["name"]
|
|
total_tags = selected_config["total_tags"]
|
|
|
|
|
|
width = selected_config.get("width", 1536)
|
|
height = selected_config.get("height", 2040)
|
|
|
|
|
|
display_series_mosaic(
|
|
mosaic_name=mosaic_name,
|
|
mosaic_title=selected_config["title"],
|
|
filtered_tags=filtered_tags,
|
|
total_tags=total_tags
|
|
)
|
|
|
|
|
|
if selected_series_name:
|
|
revealed_tags_key = f"revealed_tags_{mosaic_name}"
|
|
render_tag_reveal_feature(
|
|
st,
|
|
selected_series_name,
|
|
filtered_tags,
|
|
series_data,
|
|
revealed_tags_key
|
|
)
|
|
|
|
|
|
if filtered_tags:
|
|
with st.expander(f"All Collected {selected_config['title']} Tags", expanded=False):
|
|
|
|
by_rarity = {}
|
|
for tag, info in filtered_tags.items():
|
|
rarity = info.get("rarity", "Unknown")
|
|
if rarity not in by_rarity:
|
|
by_rarity[rarity] = []
|
|
by_rarity[rarity].append(tag)
|
|
|
|
|
|
for rarity in RARITY_LEVELS.keys():
|
|
if rarity in by_rarity:
|
|
color = RARITY_LEVELS[rarity]["color"]
|
|
st.markdown(f"### <span style='color:{color};'>{rarity}</span>", unsafe_allow_html=True)
|
|
|
|
|
|
cols = st.columns(3)
|
|
for i, tag in enumerate(sorted(by_rarity[rarity])):
|
|
col_idx = i % 3
|
|
with cols[col_idx]:
|
|
st.write(f"- {tag}")
|
|
else:
|
|
st.info("No series collections found. Make sure series_groups.json exists in the model directory.") |