Amaanali01's picture
Update app.py
4e79e4b verified
"""
Indian/Pakistani Food Classifier
A deep learning model to identify 80+ Indian and Pakistani dishes
"""
import streamlit as st
import tensorflow as tf
import numpy as np
from PIL import Image
import json
import os
import plotly.graph_objects as go
import pandas as pd
from datetime import datetime
import random
# Page configuration
st.set_page_config(
page_title="Pakistani & Indian Food Classifier",
page_icon="๐Ÿ›",
layout="wide",
initial_sidebar_state="expanded"
)
# Custom CSS for beautiful UI
st.markdown("""
<style>
/* Main container */
.main {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
/* Header styling */
.header-container {
background: linear-gradient(135deg, #006400 0%, #008000 50%, #ffffff 100%);
padding: 2rem;
border-radius: 20px;
margin-bottom: 2rem;
text-align: center;
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
}
.header-title {
font-size: 3rem;
font-weight: bold;
color: white;
margin-bottom: 0.5rem;
}
.header-subtitle {
font-size: 1.2rem;
color: rgba(255,255,255,0.9);
}
.pakistan-flag {
font-size: 2rem;
margin-bottom: 1rem;
}
/* Card styling */
.prediction-card {
background: white;
border-radius: 15px;
padding: 1.5rem;
margin: 1rem 0;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
transition: transform 0.3s;
}
.prediction-card:hover {
transform: translateY(-5px);
box-shadow: 0 6px 12px rgba(0,0,0,0.15);
}
/* Top prediction styling */
.top-prediction {
background: linear-gradient(135deg, #006400 0%, #008000 100%);
color: white;
border-radius: 15px;
padding: 1.5rem;
margin: 1rem 0;
text-align: center;
}
.top-prediction h2 {
font-size: 2.5rem;
margin: 0;
}
.confidence-score {
font-size: 1.2rem;
margin-top: 0.5rem;
}
/* Other predictions */
.other-prediction {
background: #f8f9fa;
border-left: 5px solid #006400;
border-radius: 10px;
padding: 1rem;
margin: 0.8rem 0;
}
/* Sidebar styling */
.sidebar-content {
background: #f0f2f6;
border-radius: 10px;
padding: 1rem;
}
/* Button styling */
.stButton > button {
background: linear-gradient(135deg, #006400 0%, #008000 100%);
color: white;
border: none;
padding: 0.5rem 2rem;
border-radius: 25px;
font-weight: bold;
transition: all 0.3s;
}
.stButton > button:hover {
transform: scale(1.05);
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}
/* Footer */
.footer {
text-align: center;
padding: 2rem;
color: #666;
font-size: 0.8rem;
margin-top: 3rem;
}
/* Success/Error messages */
.success-message {
background: #d4edda;
color: #155724;
padding: 1rem;
border-radius: 10px;
margin: 1rem 0;
}
.info-message {
background: #d1ecf1;
color: #0c5460;
padding: 1rem;
border-radius: 10px;
margin: 1rem 0;
}
</style>
""", unsafe_allow_html=True)
# ============================================================
# LOAD MODEL AND CLASSES
# ============================================================
@st.cache_resource
def load_model():
"""Load the trained model"""
try:
model = tf.keras.models.load_model('indian_food_classifier.keras')
return model
except:
try:
model = tf.keras.models.load_model('/kaggle/working/indian_food_classifier.keras')
return model
except:
st.error("โš ๏ธ Model file not found. Please upload 'indian_food_classifier.keras'")
return None
@st.cache_data
def load_class_names():
"""Load class names"""
try:
with open('class_names.json', 'r') as f:
class_names = json.load(f)
return class_names
except:
try:
with open('/kaggle/working/class_names.json', 'r') as f:
class_names = json.load(f)
return class_names
except:
st.error("โš ๏ธ class_names.json not found. Please upload the file.")
return None
def preprocess_image(image, target_size=(224, 224)):
"""Preprocess image for model prediction"""
if image.mode != 'RGB':
image = image.convert('RGB')
image = image.resize(target_size)
img_array = np.array(image) / 255.0
img_array = np.expand_dims(img_array, axis=0)
return img_array
def format_food_name(name):
"""Format food name for display"""
return name.replace('_', ' ').title()
def create_confidence_chart(confidences, labels, top_n=5):
"""Create an interactive confidence chart"""
fig = go.Figure(data=[
go.Bar(
x=confidences[:top_n],
y=[format_food_name(l) for l in labels[:top_n]],
orientation='h',
marker=dict(
color=confidences[:top_n],
colorscale='Greens',
showscale=True,
colorbar=dict(title="Confidence (%)")
),
text=[f"{c:.1f}%" for c in confidences[:top_n]],
textposition='outside'
)
])
fig.update_layout(
title="Top Predictions Confidence Score",
xaxis_title="Confidence (%)",
yaxis_title="Food Item",
height=400,
margin=dict(l=0, r=0, t=40, b=0),
paper_bgcolor='rgba(0,0,0,0)',
plot_bgcolor='rgba(0,0,0,0)'
)
return fig
# ============================================================
# MAIN APP
# ============================================================
def main():
# Header
st.markdown("""
<div class="header-container">
<div class="pakistan-flag">
๐Ÿ‡ต๐Ÿ‡ฐ ๐Ÿ‡ฎ๐Ÿ‡ณ ๐Ÿ‡ต๐Ÿ‡ฐ
</div>
<div class="header-title">
๐Ÿ› Pakistani & Indian Food Classifier
</div>
<div class="header-subtitle">
AI-powered dish recognition for 80+ South Asian delicacies
</div>
</div>
""", unsafe_allow_html=True)
# Sidebar
with st.sidebar:
st.markdown("### ๐Ÿ† Model Information")
st.info("""
- **Architecture:** EfficientNetV2S
- **Classes:** 80 Indian/Pakistani Dishes
- **Accuracy:** 59.25%
- **Input Size:** 224x224 pixels
""")
st.markdown("---")
st.markdown("### ๐Ÿฝ๏ธ Popular Dishes")
# Random popular dishes
popular_dishes = [
"Biryani", "Nihari", "Butter Chicken", "Aloo Gobi",
"Samosa", "Gulab Jamun", "Naan", "Haleem",
"Karahi", "Seekh Kebab", "Dal Makhani", "Ras Malai"
]
for dish in random.sample(popular_dishes, min(6, len(popular_dishes))):
st.markdown(f"โ€ข {dish}")
st.markdown("---")
st.markdown("### ๐Ÿ“Š How It Works")
st.markdown("""
1. ๐Ÿ“ธ Upload a clear photo of food
2. ๐Ÿค– AI analyzes the image
3. ๐ŸŽฏ Get top 5 predictions with confidence scores
4. ๐Ÿ“ˆ View detailed confidence chart
""")
st.markdown("---")
st.markdown("### ๐Ÿ’ก Tips for Best Results")
st.markdown("""
- Use well-lit photos
- Focus on the main dish
- Avoid cluttered backgrounds
- Single dish per photo works best
""")
st.markdown("---")
st.markdown("Made with โค๏ธ for South Asian Cuisine")
# Main content area
col1, col2 = st.columns([1, 1])
with col1:
st.markdown("### ๐Ÿ“ค Upload Food Image")
uploaded_file = st.file_uploader(
"Choose an image...",
type=['jpg', 'jpeg', 'png', 'webp', 'gif'],
help="Upload a clear image of Pakistani or Indian food"
)
if uploaded_file is not None:
image = Image.open(uploaded_file)
# Display image with styling
st.markdown("#### Preview")
st.image(image, caption="Uploaded Image", use_container_width=True)
# Image info
st.caption(f"๐Ÿ“ Image size: {image.size[0]} x {image.size[1]} pixels")
with col2:
if uploaded_file is not None:
st.markdown("### ๐Ÿ” Analysis Results")
with st.spinner("๐Ÿ› Analyzing your food image..."):
# Load model and classes
model = load_model()
class_names = load_class_names()
if model is not None and class_names is not None:
# Preprocess and predict
processed_img = preprocess_image(image)
predictions = model.predict(processed_img, verbose=0)[0]
# Get top 5 predictions
top_5_idx = np.argsort(predictions)[-5:][::-1]
top_5_names = [class_names[idx] for idx in top_5_idx]
top_5_confidences = [predictions[idx] * 100 for idx in top_5_idx]
# Display top prediction (highlighted)
st.markdown(f"""
<div class="top-prediction">
<div style="font-size: 1.2rem;">๐Ÿฅ‡ Top Prediction</div>
<h2>{format_food_name(top_5_names[0])}</h2>
<div class="confidence-score">Confidence: {top_5_confidences[0]:.2f}%</div>
</div>
""", unsafe_allow_html=True)
# Display other predictions
st.markdown("#### Other Possibilities")
for i in range(1, min(5, len(top_5_names))):
confidence_percent = top_5_confidences[i]
# Determine emoji based on rank
if i == 1:
emoji = "๐Ÿฅˆ"
elif i == 2:
emoji = "๐Ÿฅ‰"
else:
emoji = f"{i+1}๏ธโƒฃ"
st.markdown(f"""
<div class="other-prediction">
<strong>{emoji} {format_food_name(top_5_names[i])}</strong><br>
<span style="color: #666;">Confidence: {confidence_percent:.2f}%</span>
</div>
""", unsafe_allow_html=True)
# Confidence chart
st.markdown("---")
st.markdown("### ๐Ÿ“Š Confidence Analysis")
fig = create_confidence_chart(top_5_confidences, top_5_names, top_n=5)
st.plotly_chart(fig, use_container_width=True)
# Confidence meter for top prediction
st.markdown("#### Confidence Meter")
confidence_level = top_5_confidences[0]
if confidence_level > 70:
st.success(f"๐ŸŽฏ High confidence! The AI is very sure this is {format_food_name(top_5_names[0])}")
elif confidence_level > 50:
st.warning(f"๐Ÿค” Medium confidence. The AI thinks it's {format_food_name(top_5_names[0])}")
else:
st.info(f"๐Ÿ’ก Low confidence. Try uploading a clearer photo for better results")
# Footer with additional information
st.markdown("---")
col1, col2, col3 = st.columns(3)
with col1:
st.markdown("""
### ๐ŸŽฏ Supported Cuisines
- Punjabi
- Mughlai
- South Indian
- Sindhi
- Kashmiri
- Hyderabadi
""")
with col2:
st.markdown("""
### ๐Ÿœ Dish Categories
- Curries & Gravies
- Rice Dishes (Biryani)
- Breads (Naan, Roti)
- Desserts & Sweets
- Snacks & Appetizers
- Beverages
""")
with col3:
st.markdown("""
### ๐Ÿ“ˆ Model Performance
- 59.25% Top-1 Accuracy
- 80+ Food Classes
- 3,200 Training Images
- EfficientNetV2S Backbone
- Real-time Predictions
""")
# Footer
st.markdown("""
<div class="footer">
<p>๐Ÿ‡ต๐Ÿ‡ฐ Celebrating the rich culinary heritage of Pakistan and India ๐Ÿ‡ฎ๐Ÿ‡ณ</p>
<p>โš ๏ธ Note: For best results, use clear, well-lit images of individual dishes. The model works best on traditional South Asian cuisine.</p>
<p>Made with Streamlit & TensorFlow | Model trained on 80+ dishes</p>
</div>
""", unsafe_allow_html=True)
if __name__ == "__main__":
main()