dcorcoran's picture
Changed tab titles
7885fdc
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")
# --------------------------------
# ----- PAGE CONFIG --------------
# --------------------------------
st.set_page_config(
page_title="Pokemon Card Image Processor",
page_icon="🃏",
layout="wide"
)
# --------------------------------
# ----- HEADER -------------------
# --------------------------------
st.title("Pokemon Card Image Processor")
st.badge("Upload a Pokémon card image to extract its data and find similar cards.", color = "blue")
# --------------------------------
# ----- BACKEND STATUS -----------
# --------------------------------
if not health_check():
st.error("⚠️ Backend is not reachable. Make sure the FastAPI Space is running.")
st.stop()
# --------------------------------
# ----- UPLOAD -------------------
# --------------------------------
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")
# Check if file was uploaded
if uploaded_file:
# Reading Pokemon Card
image_bytes = uploaded_file.read()
image = Image.open(io.BytesIO(image_bytes))
# Separate page into two columns
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)
# Check if there was an error in the predict endpoint
if "error_type" in result:
st.error(f"Error ({result['error_type']}): {result.get('backend_response') or result.get('exception')}")
# Display the rendered card data if there is no error
else:
render_card_data(result)
# Add a divider between the uploaded card and the similar cards
st.divider()
# Add header for similar cards
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:
# Tab header and description
st.header("OCR Region Visualizer")
st.caption("Upload a card to see exactly which regions the OCR is scanning.")
# Reuse the shared upload component to accept a card image
vis_file = render_upload_section(key="upload_tab3")
if vis_file:
# Read the uploaded file bytes and decode into a Pillow Image for local display
image_bytes = vis_file.read()
image = Image.open(io.BytesIO(image_bytes)).convert("RGB")
# Split the view into two side-by-side columns: original vs. annotated
col1, col2 = st.columns(2)
# Display the unmodified card image on the left
with col1:
st.subheader("Original")
st.image(image, width="content")
# Display the modified card image on the right
with col2:
st.subheader("OCR Regions")
annotated = visualize_regions(image_bytes, vis_file.name)
if annotated:
st.image(annotated, width="content")
st.divider()