IndiScan / app /frontend.py
Wendgan's picture
Upload 9 files
2ae3f7c verified
import streamlit as st
import requests
import json
from PIL import Image
import io
import base64
from datetime import datetime
import pandas as pd
import plotly.express as px
# Configure the app
st.set_page_config(
page_title="IndiScan - Product Health Analyzer",
page_icon="πŸ”",
layout="wide"
)
# API endpoint
API_URL = "http://localhost:8000" # Change this when deploying
def main():
# Sidebar
st.sidebar.title("IndiScan πŸ”")
scan_option = st.sidebar.radio(
"Choose scan method:",
["Barcode", "Image Upload", "Manual Entry"]
)
# Main content
st.title("IndiScan - Product Health Analyzer")
st.markdown("""
Analyze food and cosmetic products for health risks and get detailed insights.
Upload an image, enter a barcode, or manually input product details.
""")
# Admin section in sidebar
with st.sidebar.expander("Admin Controls πŸ”"):
admin_username = st.text_input("Username")
admin_password = st.text_input("Password", type="password")
if st.button("Login"):
try:
auth = (admin_username, admin_password)
response = requests.get(f"{API_URL}/export", auth=auth)
if response.status_code == 200:
st.sidebar.success("Logged in as admin")
st.session_state['admin_auth'] = auth
else:
st.sidebar.error("Invalid credentials")
except Exception as e:
st.sidebar.error(f"Login failed: {str(e)}")
# Main content based on selected option
if scan_option == "Barcode":
barcode_scanner()
elif scan_option == "Image Upload":
image_scanner()
else:
manual_entry()
def barcode_scanner():
st.header("Barcode Scanner πŸ“±")
barcode = st.text_input("Enter barcode number:")
if barcode:
try:
response = requests.post(f"{API_URL}/scan/barcode", params={"barcode": barcode})
if response.status_code == 200:
display_results(response.json())
else:
st.error("Product not found")
except Exception as e:
st.error(f"Error: {str(e)}")
def image_scanner():
st.header("Image Scanner πŸ“Έ")
uploaded_file = st.file_uploader("Upload product image", type=["jpg", "jpeg", "png"])
if uploaded_file:
try:
# Display uploaded image
image = Image.open(uploaded_file)
st.image(image, caption="Uploaded Image", use_column_width=True)
# Process image
files = {"file": uploaded_file}
response = requests.post(f"{API_URL}/scan/image", files=files)
if response.status_code == 200:
display_results(response.json())
else:
st.error("Failed to process image")
except Exception as e:
st.error(f"Error: {str(e)}")
def manual_entry():
st.header("Manual Entry ✍️")
col1, col2 = st.columns(2)
with col1:
product_type = st.selectbox("Product Type", ["Food", "Cosmetic"])
ingredients_text = st.text_area("Enter ingredients list (comma-separated or as shown on package):")
with col2:
if ingredients_text:
try:
response = requests.post(
f"{API_URL}/analyze/text",
data={
"text": ingredients_text,
"product_type": product_type.lower()
}
)
if response.status_code == 200:
display_results(response.json())
else:
st.error("Failed to analyze ingredients")
except Exception as e:
st.error(f"Error: {str(e)}")
def display_results(data):
# Create three columns for different aspects of the analysis
col1, col2, col3 = st.columns([2, 2, 1])
with col1:
st.subheader("Health Score")
score = data.get('health_score', {}).get('score', 0)
# Create a gauge chart using plotly
fig = px.pie(
values=[score, 1000-score],
names=['Score', 'Remaining'],
hole=0.7,
color_discrete_sequence=['#00ff00' if score > 600 else '#ff0000', '#eee']
)
fig.update_layout(
annotations=[dict(text=f"{score}/1000", x=0.5, y=0.5, font_size=20, showarrow=False)],
showlegend=False,
width=300,
height=300
)
st.plotly_chart(fig)
# Display explanation
if 'explanation' in data.get('health_score', {}):
st.markdown(data['health_score']['explanation'])
with col2:
st.subheader("Ingredients Analysis")
if 'ingredients' in data:
ingredients = data['ingredients']
st.write(f"Found {len(ingredients)} ingredients:")
for i, ingredient in enumerate(ingredients, 1):
st.write(f"{i}. {ingredient}")
# Display risks if available
if 'risks' in data.get('health_score', {}):
st.subheader("Risk Categories")
risks = data['health_score']['risks']
for category, risk_data in risks.items():
with st.expander(f"{category.replace('_', ' ').title()}"):
st.write(f"Found in: {', '.join(risk_data['ingredients'])}")
with col3:
if 'nutrition_info' in data:
st.subheader("Nutrition Info")
nutrition = data['nutrition_info']
for nutrient, value in nutrition.items():
st.metric(nutrient.title(), f"{value}g")
if 'nutrition_analysis' in data:
analysis = data['nutrition_analysis']
if analysis['concerns']:
st.subheader("⚠️ Concerns")
for concern in analysis['concerns']:
st.write(f"- {concern}")
if analysis['positives']:
st.subheader("βœ… Positives")
for positive in analysis['positives']:
st.write(f"- {positive}")
if analysis['recommendations']:
st.subheader("πŸ’‘ Recommendations")
for rec in analysis['recommendations']:
st.write(f"- {rec}")
# Price comparison if available
if 'prices' in data:
st.subheader("Price Comparison")
prices_df = pd.DataFrame(data['prices'])
fig = px.bar(
prices_df,
x='platform',
y='price',
title="Price Comparison Across Platforms",
color='platform'
)
st.plotly_chart(fig)
# Display price table
st.dataframe(
prices_df[['platform', 'price', 'title', 'url']],
column_config={
"url": st.column_config.LinkColumn("Link")
}
)
if __name__ == "__main__":
main()