File size: 4,557 Bytes
e7de063
 
 
ea28818
8d81a60
e7de063
ee53246
e7de063
 
 
 
1a558e0
 
e7de063
 
 
 
 
 
 
 
 
 
 
 
 
 
1a558e0
 
e7de063
 
 
 
 
24b2edd
1a558e0
 
 
e7de063
 
 
 
 
 
ee53246
1a558e0
 
 
7885fdc
 
 
75b7371
1a558e0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ee53246
1a558e0
 
 
 
 
 
 
 
 
 
 
46b8a2b
1a558e0
 
e7de063
1a558e0
 
e7de063
1a558e0
 
7885fdc
dd9efb5
1a558e0
 
 
e7de063
1a558e0
 
 
e7de063
1a558e0
 
 
e7de063
1a558e0
 
 
 
 
 
 
 
 
 
ee53246
 
 
 
 
 
 
 
75b7371
ee53246
 
 
 
 
 
 
 
 
 
 
 
5d19c93
ee53246
 
 
 
 
 
5d19c93
ee53246
d514352
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
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()