| import streamlit as st |
| from PIL import Image |
| import io |
| import requests |
| import os |
|
|
| from api_client import predict, health_check, get_all_cards, visualize_regions |
| from components.upload_section import render_upload_section |
| from components.display_structured_data import render_card_data |
| from components.similarity_grid import render_similarity_grid |
|
|
| BACKEND_URL = os.getenv("BACKEND_URL", "https://dcorcoran-pokemon-card-image-processor-api.hf.space") |
|
|
| |
| |
| |
|
|
| st.set_page_config( |
| page_title="Pokemon Card Image Processor", |
| page_icon="🃏", |
| layout="wide" |
| ) |
|
|
| |
| |
| |
|
|
| st.title("Pokemon Card Image Processor") |
| st.badge("Upload a Pokémon card image to extract its data and find similar cards.", color = "blue") |
|
|
|
|
| |
| |
| |
|
|
| if not health_check(): |
| st.error("⚠️ Backend is not reachable. Make sure the FastAPI Space is running.") |
| st.stop() |
|
|
|
|
| |
| |
| |
|
|
| tab1, tab2, tab3 = st.tabs(["Upload Pokemon Card", "Card Database", "OCR Card Visualizer"]) |
|
|
|
|
| with tab1: |
| st.header("Card Optical Character Recognition (OCR)") |
| st.caption("Upload a Pokémon card image.") |
|
|
| uploaded_file = render_upload_section(key="upload_tab1") |
|
|
| |
| if uploaded_file: |
| |
| image_bytes = uploaded_file.read() |
| image = Image.open(io.BytesIO(image_bytes)) |
|
|
| |
| col1, col2 = st.columns([1, 2]) |
|
|
| with col1: |
| st.image(image, width="content") |
|
|
| with col2: |
| with st.spinner("Analyzing card..."): |
| result = predict(image_bytes, uploaded_file.name) |
|
|
| |
| if "error_type" in result: |
| st.error(f"Error ({result['error_type']}): {result.get('backend_response') or result.get('exception')}") |
|
|
| |
| else: |
| render_card_data(result) |
|
|
| |
| st.divider() |
|
|
| |
| st.header("Similar Cards") |
|
|
| if "error" not in result: |
| render_similarity_grid(result.get("similar_cards", [])) |
|
|
| with tab2: |
| st.header("Card Database") |
| st.caption("Showing a sample of available cards in the database.") |
|
|
| with st.spinner("Loading cards..."): |
| try: |
| cards = get_all_cards() |
|
|
| except Exception as e: |
| st.error(f"Could not load card database: {e}") |
| cards = [] |
|
|
| if cards: |
| cols_per_row = 5 |
| rows = [cards[i:i+cols_per_row] for i in range(0, len(cards), cols_per_row)] |
|
|
| for row in rows: |
| cols = st.columns(cols_per_row) |
| for col, card in zip(cols, row): |
| with col: |
| if card.get("image_url"): |
| st.image(card["image_url"], width="content") |
| else: |
| st.markdown("🃏") |
| st.caption(card.get("name", "Unknown")) |
| else: |
| st.info("No cards to display.") |
|
|
| with tab3: |
| |
| st.header("OCR Region Visualizer") |
| st.caption("Upload a card to see exactly which regions the OCR is scanning.") |
|
|
| |
| vis_file = render_upload_section(key="upload_tab3") |
|
|
| if vis_file: |
| |
| image_bytes = vis_file.read() |
| image = Image.open(io.BytesIO(image_bytes)).convert("RGB") |
|
|
| |
| col1, col2 = st.columns(2) |
|
|
| |
| with col1: |
| st.subheader("Original") |
| st.image(image, width="content") |
|
|
| |
| with col2: |
| st.subheader("OCR Regions") |
| annotated = visualize_regions(image_bytes, vis_file.name) |
| if annotated: |
| st.image(annotated, width="content") |
|
|
| st.divider() |