File size: 31,548 Bytes
29b445b |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 |
#!/usr/bin/env python3
"""
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
# Import the improved tag mosaic implementation
from tag_mosaic import RevealMosaic
# Default paths
DEFAULT_MOSAICS_DIR = "mosaics"
DEFAULT_TEMPLATES_DIR = "mosaics/templates"
SERIES_COMPLETION_MILESTONES = [25, 50, 75, 100] # Percentage milestones
BASE_ENKEPHALIN_REWARDS = { # Base rewards for each milestone
25: 100, # 25% completion
50: 500, # 50% completion
75: 1000, # 75% completion
100: 5000 # 100% completion
}
# Define collection size tiers
COLLECTION_SIZE_MULTIPLIERS = {
"small": 1.0, # 1-20 tags
"medium": 1.5, # 21-50 tags
"large": 2.0, # 51-100 tags
"huge": 3.0, # 101-200 tags
"massive": 5.0, # 201+ tags
"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
"""
# Get the base reward for this percentage
base_reward = BASE_ENKEPHALIN_REWARDS.get(percentage, 0)
# Get the collection size multiplier
size_tier = get_collection_size_tier(total_tags)
multiplier = COLLECTION_SIZE_MULTIPLIERS.get(size_tier, 1.0)
# Calculate the final reward (round to nearest integer)
final_reward = round(base_reward * multiplier)
return max(1, final_reward) # Ensure at least 1 enkephalin is rewarded
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
# Skip if no tags or invalid total
if not filtered_tags or total_tags <= 0:
return None, 0
# Calculate current completion percentage
current_tags = len(filtered_tags)
current_percentage = (current_tags / total_tags) * 100
# Round down to the nearest whole percentage
current_percentage = int(current_percentage)
# Get the milestones already awarded for this collection
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]
# Check each milestone
for milestone in SERIES_COMPLETION_MILESTONES:
# If we've reached this milestone and haven't awarded it yet
if current_percentage >= milestone and milestone not in awarded_milestones:
# Calculate reward
reward = calculate_enkephalin_reward(milestone, total_tags)
# Add to awarded milestones
awarded_milestones.append(milestone)
st.session_state[milestone_key] = awarded_milestones
# Give the reward
if not hasattr(st.session_state, 'enkephalin'):
st.session_state.enkephalin = 0
# Update enkephalin - using direct assignment to ensure it changes
st.session_state.enkephalin += reward
# Track in game stats if available
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
# Save game state after awarding 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 the awarded milestone and reward
return milestone, reward
# No new milestone reached
return None, 0
def ensure_directories():
"""Ensure all required directories exist"""
# Create mosaics directory if it doesn't exist
if not os.path.exists(DEFAULT_MOSAICS_DIR):
os.makedirs(DEFAULT_MOSAICS_DIR)
# Create templates directory if it doesn't exist
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
"""
# Load existing series data
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 a default empty structure instead of None
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 {}
# Get tags for this series
series_tags = set(series_data['series'][series_name]['tags'])
# Filter collected tags to only include this series
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 = {}
# Handle case where series_data is None or doesn't have 'series' key
if not series_data or 'series' not in series_data:
return filtered_collections
# Create a filtered collection for each series
for series_name, series_info in series_data['series'].items():
# Skip series with too few tags
if series_info['tag_count'] <= 1: # Skip series with just 1 tag
continue
# Create a series key (safe for filenames)
series_key = series_name.replace(" ", "_").replace(":", "").lower()
# Filter tags for this series
filtered_tags = filter_collected_tags_by_series(collected_tags, series_data, series_name)
# Add to return dictionary
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
"""
# Skip if series data is invalid
if 'series' not in series_data or series_name not in series_data['series']:
return
# Get all tags for this series
all_series_tags = set(series_data['series'][series_name]['tags'])
# Calculate missing tags
collected_tag_names = set(filtered_tags.keys())
missing_tags = all_series_tags - collected_tag_names
# If no missing tags, don't show the feature
if not missing_tags:
st.success("Congratulations! You have collected all tags in this series!")
return
# Check if we already have a revealed tags session state for this series
if revealed_tags_key not in st.session_state:
st.session_state[revealed_tags_key] = set()
# Get previously revealed tags
revealed_tags = st.session_state[revealed_tags_key]
# Calculate truly unknown tags (not collected and not revealed)
unknown_tags = missing_tags - revealed_tags
# Show tag reveal section
with st.expander("๐ Missing Tags Explorer", expanded=True):
# Explain the feature
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!
""")
# Show stats
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))
# Cost calculation - only use enkephalin
enkephalin_cost = 2 # Base cost in Enkephalin
# Adjust cost based on rarity
if len(unknown_tags) <= 5:
# Very few tags remaining - more expensive
enkephalin_cost = 10
elif len(unknown_tags) <= 15:
# Getting close to completion
enkephalin_cost = 5
# Show reveal option
st.write("### Reveal Missing Tags")
# Get current resources
current_enkephalin = st.session_state.enkephalin if hasattr(st.session_state, 'enkephalin') else 0
# Create centered column for the payment option
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:
# Pick a random tag to reveal
import random
tag_to_reveal = random.choice(list(unknown_tags))
# Add to revealed tags
revealed_tags.add(tag_to_reveal)
st.session_state[revealed_tags_key] = revealed_tags
# Deduct enkephalin
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
# Save game state after purchase
try:
import tag_storage
tag_storage.save_game(st.session_state)
except (ImportError, Exception):
pass
# Show success message
st.success(f"Revealed new tag: **{tag_to_reveal}**")
# Force a rerun to update the UI
st.rerun()
# Show revealed tags
if revealed_tags:
st.write("### Revealed Tags")
st.write("These tags are part of this collection but you haven't collected them yet:")
# Create columns for tags
cols = st.columns(3)
for i, tag in enumerate(sorted(revealed_tags)):
col_idx = i % 3
with cols[col_idx]:
st.write(f"- {tag}")
# Add a button to reset revealed tags
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:
# Use the number of filtered tags as the total or set minimum
total_tags = max(len(filtered_tags), 20) # At least 20 tags
# Create a container for the mosaic
with st.container():
st.subheader(f"๐งฉ {mosaic_title} Mosaic")
# Initialize the mosaic if not already in session state
mosaic_key = f"{mosaic_name}_mosaic"
if mosaic_key not in st.session_state:
# Create the reveal mosaic
st.session_state[mosaic_key] = RevealMosaic(
total_tags=total_tags,
mosaic_name=mosaic_name
)
# Get the mosaic
mosaic = st.session_state[mosaic_key]
# Show collection stats and progress
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}%")
# Always display milestone tracker at the top
display_milestone_tracker(mosaic_name, filtered_tags, total_tags)
# Add update button
update_requested = st.button("๐ Update Mosaic", key=f"update_btn_{mosaic_name}")
# Display the manually update message
if not update_requested:
st.info("Click the 'Update Mosaic' button to process new tag discoveries and update the image.")
# Update the mosaic with the filtered tags only if requested
newly_revealed = 0
if update_requested and filtered_tags:
# Show processing spinner
with st.spinner("Processing tag discoveries and updating mosaic..."):
# Get optional metadata if available
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)
# Check for milestone rewards after updating
milestone, reward = check_and_award_milestone_rewards(mosaic_name, filtered_tags, total_tags)
# Show appropriate messages based on update results
if milestone is not None:
# Show milestone achievement message with celebration
st.balloons()
st.success(f"๐ MILESTONE ACHIEVED! {milestone}% Completion of {mosaic_title}!")
st.success(f"Rewarded with {reward} {ENKEPHALIN_ICON} {ENKEPHALIN_CURRENCY_NAME}!")
# Force update of UI to show new enkephalin amount
st.rerun()
elif newly_revealed > 0:
st.success(f"Successfully updated! Revealed {newly_revealed} new pixels.")
else:
st.info("No new pixels to reveal.")
# Get mosaic stats
stats = mosaic.get_stats()
# Show completion 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")
# Display the mosaic image
mosaic_img = mosaic.get_image()
# Convert to bytes for display
img_bytes = io.BytesIO()
mosaic_img.save(img_bytes, format='PNG')
img_bytes.seek(0)
# Show the mosaic image
st.image(img_bytes, caption=f"Your {mosaic_title} Mosaic - Each discovery reveals more of the hidden image",
use_container_width=True)
# Only show newly added tags
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
# Skip if no tags or invalid total
if not filtered_tags or total_tags <= 0:
return
# Get the milestones already awarded for this collection
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]
# Calculate current completion percentage
current_tags = len(filtered_tags)
current_percentage = (current_tags / total_tags) * 100
# Prepare milestone data with rewards
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
})
# Sort by percentage
milestone_data.sort(key=lambda x: x["percentage"])
# Display milestone expander
with st.expander("Collection Milestones", expanded=len(awarded_milestones) > 0):
st.write("Complete collection milestones to earn Enkephalin rewards:")
# Display progress bar
st.progress(min(1.0, current_percentage / 100), text=f"Current Progress: {current_percentage:.1f}%")
# Display milestone columns
cols = st.columns(len(milestone_data))
for i, milestone in enumerate(milestone_data):
with cols[i]:
# Format with emoji based on status
if milestone["achieved"]:
st.markdown(f"### โ
{milestone['percentage']}%")
st.markdown(f"Reward: **{milestone['reward']}** {ENKEPHALIN_ICON}")
st.markdown("**COMPLETED!**")
elif milestone["is_next"]:
# This is the next milestone to achieve
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!")
# Display collection size tier info
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 all directories exist
ensure_directories()
# Check if we have collected tags
if not hasattr(st.session_state, 'collected_tags'):
st.info("Start scanning images to collect tags!")
return
# Load series data from model directory
series_data = load_series_data()
# Handle case where no series were found
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
# Create filtered collections for each series
filtered_collections = create_filtered_collections(st.session_state.collected_tags, series_data)
# Create the mosaic configs with additional data
mosaic_configs = []
# Add all series configurations
for config in series_data.get("mosaic_configs", []):
# Skip the main collection - it's handled by the main game
if config["name"] == "main":
continue
# Add the session state key to the config
series_key = config["name"]
config_with_session_key = config.copy()
# Add discovered tags info if this series is in our filtered collections
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:
# For series not in filtered collections, set discovered tags to 0
config_with_session_key["discovered_tags"] = 0
config_with_session_key["filtered_tags"] = {}
mosaic_configs.append(config_with_session_key)
# Display the collection dropdown and selected mosaic
st.subheader("๐ฎ Series Collections")
# Organize collection options in two ways:
# 1. Collections with discovered tags, sorted by most discovered first
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)
# 2. Collections with no tags yet
collections_without_tags = [c for c in mosaic_configs if c.get("discovered_tags", 0) == 0]
# Create a selection menu
collection_options = []
# First add collections with tags
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)")
# Then add collections without 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)")
# Get the index of the currently selected collection
if 'selected_collection_index' not in st.session_state:
# Default to first real collection (index 1 if there are collections with tags)
st.session_state.selected_collection_index = 1 if collections_with_tags else len(collections_with_tags) + 1
# Create the collection dropdown
if collection_options: # Only create dropdown if we have options
selected_option = st.selectbox(
"Select Collection:",
options=collection_options,
index=min(st.session_state.selected_collection_index, len(collection_options)-1)
)
# Update the selected collection index
st.session_state.selected_collection_index = collection_options.index(selected_option)
# Skip displaying if a separator is selected
if "---" in selected_option:
st.info("Please select a collection from the dropdown.")
return
# Find the corresponding config for the selected collection
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
# Extract series name from config title
if config['name'] == 'miku_collection':
selected_series_name = 'vocaloid' # Special case for Miku
elif 'series_name' in config:
selected_series_name = config['series_name']
else:
selected_series_name = config['name'].replace('_', ' ')
break
# Display the selected collection
if selected_config:
# Create a container for this collection
with st.container():
# Get the filtered tags for this collection
filtered_tags = selected_config.get("filtered_tags", {})
# Get mosaic name and total tags
mosaic_name = selected_config["name"]
total_tags = selected_config["total_tags"]
# Get dimensions from config or use defaults
width = selected_config.get("width", 1536)
height = selected_config.get("height", 2040)
# Display the mosaic
display_series_mosaic(
mosaic_name=mosaic_name,
mosaic_title=selected_config["title"],
filtered_tags=filtered_tags,
total_tags=total_tags
)
# Show tag reveal feature if we have series_data
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
)
# Show all collected tags for this series
if filtered_tags:
with st.expander(f"All Collected {selected_config['title']} Tags", expanded=False):
# Group by rarity
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)
# Display by rarity
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)
# Create columns for tags
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.") |