Update src/streamlit_app.py
Browse files- src/streamlit_app.py +21 -12
src/streamlit_app.py
CHANGED
|
@@ -23,6 +23,8 @@ import sys
|
|
| 23 |
import time
|
| 24 |
import json
|
| 25 |
import random
|
|
|
|
|
|
|
| 26 |
import numpy as np
|
| 27 |
from PIL import Image
|
| 28 |
import streamlit as st
|
|
@@ -93,7 +95,7 @@ faiss_index = load_faiss_index()
|
|
| 93 |
metadata = load_metadata()
|
| 94 |
|
| 95 |
# ==========================================================================
|
| 96 |
-
# Preprocessing Logic
|
| 97 |
# ==========================================================================
|
| 98 |
def preprocess_image(pil_img):
|
| 99 |
"""
|
|
@@ -151,6 +153,15 @@ def perform_search(features_batch, top_k=5):
|
|
| 151 |
|
| 152 |
return results
|
| 153 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 154 |
# ==========================================================================
|
| 155 |
# Streamlit UI Configuration
|
| 156 |
# ==========================================================================
|
|
@@ -322,10 +333,10 @@ with tab1:
|
|
| 322 |
else:
|
| 323 |
st.markdown(f'<div class="glass-card"><div class="metric-value">N/A</div><div class="metric-label">Upload class unknown</div></div>', unsafe_allow_html=True)
|
| 324 |
|
| 325 |
-
# Display Results Grid (Fixed
|
| 326 |
st.markdown("#### Retrieved Nearest Neighbors")
|
| 327 |
|
| 328 |
-
# Create dynamic rows
|
| 329 |
for i in range(0, len(results), 3):
|
| 330 |
cols = st.columns(3)
|
| 331 |
for j in range(3):
|
|
@@ -349,9 +360,14 @@ with tab1:
|
|
| 349 |
bg_color = "rgba(127, 29, 29, 0.1)"
|
| 350 |
badge_html = f'<span style="background-color: #EF4444; padding: 2px 8px; border-radius: 4px; font-size: 0.8rem; font-weight: 600; color: white;">{res["class_name"]}</span>'
|
| 351 |
|
| 352 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
| 353 |
card_content = f"""
|
| 354 |
-
<div style="background: {bg_color}; border: 1px solid {border_color}; border-radius: 8px; padding: 12px; margin-bottom: 12px; text-align: center;">
|
|
|
|
| 355 |
<div style="color: #38BDF8; font-size: 1.1rem; font-weight: 700; margin-bottom: 8px;">Rank #{res["rank"]}</div>
|
| 356 |
<div style="margin-bottom: 10px;">{badge_html}</div>
|
| 357 |
<div style="color: #94A3B8; font-size: 0.9rem; margin-bottom: 4px;">Cosine Similarity:</div>
|
|
@@ -360,13 +376,6 @@ with tab1:
|
|
| 360 |
</div>
|
| 361 |
"""
|
| 362 |
|
| 363 |
-
# Render matched image and custom card
|
| 364 |
-
if os.path.exists(res["image_path"]):
|
| 365 |
-
matched_img = Image.open(res["image_path"])
|
| 366 |
-
st.image(matched_img, use_container_width=True)
|
| 367 |
-
else:
|
| 368 |
-
st.error("Image file missing.")
|
| 369 |
-
|
| 370 |
st.markdown(card_content, unsafe_allow_html=True)
|
| 371 |
|
| 372 |
else:
|
|
|
|
| 23 |
import time
|
| 24 |
import json
|
| 25 |
import random
|
| 26 |
+
import base64
|
| 27 |
+
from io import BytesIO
|
| 28 |
import numpy as np
|
| 29 |
from PIL import Image
|
| 30 |
import streamlit as st
|
|
|
|
| 95 |
metadata = load_metadata()
|
| 96 |
|
| 97 |
# ==========================================================================
|
| 98 |
+
# Preprocessing & Helper Logic
|
| 99 |
# ==========================================================================
|
| 100 |
def preprocess_image(pil_img):
|
| 101 |
"""
|
|
|
|
| 153 |
|
| 154 |
return results
|
| 155 |
|
| 156 |
+
def get_image_base64(image_path):
|
| 157 |
+
"""Converts a local image to base64 string for direct HTML rendering."""
|
| 158 |
+
if os.path.exists(image_path):
|
| 159 |
+
img = Image.open(image_path)
|
| 160 |
+
buffered = BytesIO()
|
| 161 |
+
img.save(buffered, format="PNG")
|
| 162 |
+
return base64.b64encode(buffered.getvalue()).decode()
|
| 163 |
+
return ""
|
| 164 |
+
|
| 165 |
# ==========================================================================
|
| 166 |
# Streamlit UI Configuration
|
| 167 |
# ==========================================================================
|
|
|
|
| 333 |
else:
|
| 334 |
st.markdown(f'<div class="glass-card"><div class="metric-value">N/A</div><div class="metric-label">Upload class unknown</div></div>', unsafe_allow_html=True)
|
| 335 |
|
| 336 |
+
# Display Results Grid (Fixed completely with Base64 HTML rendering)
|
| 337 |
st.markdown("#### Retrieved Nearest Neighbors")
|
| 338 |
|
| 339 |
+
# Create dynamic rows
|
| 340 |
for i in range(0, len(results), 3):
|
| 341 |
cols = st.columns(3)
|
| 342 |
for j in range(3):
|
|
|
|
| 360 |
bg_color = "rgba(127, 29, 29, 0.1)"
|
| 361 |
badge_html = f'<span style="background-color: #EF4444; padding: 2px 8px; border-radius: 4px; font-size: 0.8rem; font-weight: 600; color: white;">{res["class_name"]}</span>'
|
| 362 |
|
| 363 |
+
# Convert local image to base64
|
| 364 |
+
img_b64 = get_image_base64(res["image_path"])
|
| 365 |
+
img_html = f'<img src="data:image/png;base64,{img_b64}" style="width: 100%; border-radius: 8px; margin-bottom: 12px; display: block;">' if img_b64 else '<div style="color: #EF4444; padding: 20px; border: 1px solid #EF4444; border-radius: 8px; margin-bottom: 12px;">Image missing</div>'
|
| 366 |
+
|
| 367 |
+
# Custom card container integrating image and text as a single HTML block
|
| 368 |
card_content = f"""
|
| 369 |
+
<div style="background: {bg_color}; border: 1px solid {border_color}; border-radius: 8px; padding: 12px; margin-bottom: 12px; text-align: center; height: 100%;">
|
| 370 |
+
{img_html}
|
| 371 |
<div style="color: #38BDF8; font-size: 1.1rem; font-weight: 700; margin-bottom: 8px;">Rank #{res["rank"]}</div>
|
| 372 |
<div style="margin-bottom: 10px;">{badge_html}</div>
|
| 373 |
<div style="color: #94A3B8; font-size: 0.9rem; margin-bottom: 4px;">Cosine Similarity:</div>
|
|
|
|
| 376 |
</div>
|
| 377 |
"""
|
| 378 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 379 |
st.markdown(card_content, unsafe_allow_html=True)
|
| 380 |
|
| 381 |
else:
|