updated the UI
Browse files- src/streamlit_app.py +77 -20
src/streamlit_app.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
import streamlit as st
|
| 2 |
-
st.set_page_config(page_title="PinoyPaws", layout="
|
| 3 |
|
| 4 |
import tensorflow as tf
|
| 5 |
from PIL import Image
|
|
@@ -8,6 +8,17 @@ import os
|
|
| 8 |
import json
|
| 9 |
from tensorflow.keras.models import load_model
|
| 10 |
from tensorflow.keras.applications.mobilenet_v2 import preprocess_input
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
|
| 12 |
# === Load model ===
|
| 13 |
@st.cache_resource
|
|
@@ -33,29 +44,75 @@ def preprocess_image(image: Image.Image) -> np.ndarray:
|
|
| 33 |
image_array = np.array(image)
|
| 34 |
if image_array.shape[-1] == 4:
|
| 35 |
image_array = image_array[..., :3]
|
| 36 |
-
image_array = preprocess_input(image_array)
|
| 37 |
return np.expand_dims(image_array, axis=0)
|
| 38 |
|
| 39 |
-
# ===
|
| 40 |
-
|
| 41 |
-
st.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
|
| 43 |
-
|
|
|
|
| 44 |
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
st.image(image, caption="Uploaded Image", use_container_width=True)
|
| 49 |
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
confidence = np.max(prediction)
|
| 56 |
|
| 57 |
-
|
| 58 |
-
|
|
|
|
| 59 |
|
| 60 |
-
|
| 61 |
-
|
|
|
|
|
|
| 1 |
import streamlit as st
|
| 2 |
+
st.set_page_config(page_title="PinoyPaws", layout="wide")
|
| 3 |
|
| 4 |
import tensorflow as tf
|
| 5 |
from PIL import Image
|
|
|
|
| 8 |
import json
|
| 9 |
from tensorflow.keras.models import load_model
|
| 10 |
from tensorflow.keras.applications.mobilenet_v2 import preprocess_input
|
| 11 |
+
from tensorflow.keras.utils import plot_model
|
| 12 |
+
import io
|
| 13 |
+
|
| 14 |
+
# === Page Configuration ===
|
| 15 |
+
st.sidebar.title("π PinoyPaws Navigation")
|
| 16 |
+
|
| 17 |
+
# === Sidebar Navigation ===
|
| 18 |
+
page = st.sidebar.selectbox("Navigate to", ["Overview", "Predict Breed", "Model Insights"])
|
| 19 |
+
|
| 20 |
+
with st.sidebar.expander("βΉοΈ About this App"):
|
| 21 |
+
st.markdown("Built with π TensorFlow and π§ MobileNetV2")
|
| 22 |
|
| 23 |
# === Load model ===
|
| 24 |
@st.cache_resource
|
|
|
|
| 44 |
image_array = np.array(image)
|
| 45 |
if image_array.shape[-1] == 4:
|
| 46 |
image_array = image_array[..., :3]
|
| 47 |
+
image_array = preprocess_input(image_array)
|
| 48 |
return np.expand_dims(image_array, axis=0)
|
| 49 |
|
| 50 |
+
# === Page: Overview ===
|
| 51 |
+
if page == "Overview":
|
| 52 |
+
st.title("πΎ PinoyPaws: Dog Breed Classifier")
|
| 53 |
+
st.markdown("""
|
| 54 |
+
Welcome to **PinoyPaws**, a dog breed classifier tailored to recognize common dog breeds found in the Philippines ππ΅π.
|
| 55 |
+
|
| 56 |
+
### π Features:
|
| 57 |
+
- π· Upload a dog image and let our AI guess the breed!
|
| 58 |
+
- π§ Built using **MobileNetV2** for fast and lightweight inference
|
| 59 |
+
- π Confidence score included
|
| 60 |
+
- π Trained on 5 local and common breeds:
|
| 61 |
+
- **Beagle**
|
| 62 |
+
- **Chihuahua**
|
| 63 |
+
- **Golden Retriever**
|
| 64 |
+
- **Shih Tzu**
|
| 65 |
+
- **Siberian Husky**
|
| 66 |
+
|
| 67 |
+
### π Input:
|
| 68 |
+
- Accepts `.jpg`, `.jpeg`, `.png` images
|
| 69 |
+
- Optimized for images where the dog is clearly visible
|
| 70 |
+
|
| 71 |
+
You can get started by choosing **Predict Breed** in the sidebar.
|
| 72 |
+
""")
|
| 73 |
+
|
| 74 |
+
# === Page: Predict Breed ===
|
| 75 |
+
elif page == "Predict Breed":
|
| 76 |
+
st.title("ππΆ Predict Dog Breed")
|
| 77 |
+
st.write(f"Upload an image of a dog and let the model predict its breed from {len(class_names)} common dog breeds.")
|
| 78 |
+
|
| 79 |
+
uploaded_file = st.file_uploader("π· Choose a dog image...", type=["jpg", "jpeg", "png"])
|
| 80 |
+
|
| 81 |
+
if uploaded_file is not None:
|
| 82 |
+
image = Image.open(uploaded_file).convert("RGB")
|
| 83 |
+
st.image(image, caption="Uploaded Image", use_container_width=True)
|
| 84 |
+
|
| 85 |
+
if st.button("πΌοΈ Predict"):
|
| 86 |
+
|
| 87 |
+
with st.spinner("Classifying..."):
|
| 88 |
+
try:
|
| 89 |
+
|
| 90 |
+
input_tensor = preprocess_image(image)
|
| 91 |
+
prediction = model.predict(input_tensor)
|
| 92 |
+
predicted_index = int(np.argmax(prediction))
|
| 93 |
+
predicted_class = class_names[predicted_index]
|
| 94 |
+
confidence = np.max(prediction)
|
| 95 |
+
|
| 96 |
+
st.success(f"πΆ Predicted Breed: **{predicted_class}**")
|
| 97 |
+
st.info(f"π Confidence: {confidence * 100:.2f}%")
|
| 98 |
|
| 99 |
+
except Exception as e:
|
| 100 |
+
st.error(f"An error occurred: {e}")
|
| 101 |
|
| 102 |
+
# === Page: Model Insights ===
|
| 103 |
+
elif page == "Model Insights":
|
| 104 |
+
st.title("π Model Insights & Architecture")
|
|
|
|
| 105 |
|
| 106 |
+
st.markdown("### π§ Model Summary")
|
| 107 |
+
string_io = io.StringIO()
|
| 108 |
+
model.summary(print_fn=lambda x: string_io.write(x + "\n"))
|
| 109 |
+
summary_str = string_io.getvalue()
|
| 110 |
+
st.text(summary_str)
|
|
|
|
| 111 |
|
| 112 |
+
st.markdown("### 𧬠Model Details")
|
| 113 |
+
st.write(f"β’ Total parameters: `{model.count_params():,}`")
|
| 114 |
+
st.write("β’ Architecture: **MobileNetV2** base with custom dense layers")
|
| 115 |
|
| 116 |
+
st.markdown("### π Classes Detected")
|
| 117 |
+
st.write(f"The model can classify the following {len(class_names)} breeds:")
|
| 118 |
+
st.markdown(" - " + "\n - ".join(class_names))
|