| 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
|
|
|
|
|
| st.set_page_config(
|
| page_title="IndiScan - Product Health Analyzer",
|
| page_icon="π",
|
| layout="wide"
|
| )
|
|
|
|
|
| API_URL = "http://localhost:8000"
|
|
|
| def main():
|
|
|
| st.sidebar.title("IndiScan π")
|
| scan_option = st.sidebar.radio(
|
| "Choose scan method:",
|
| ["Barcode", "Image Upload", "Manual Entry"]
|
| )
|
|
|
|
|
| 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.
|
| """)
|
|
|
|
|
| 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)}")
|
|
|
|
|
| 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:
|
|
|
| image = Image.open(uploaded_file)
|
| st.image(image, caption="Uploaded Image", use_column_width=True)
|
|
|
|
|
| 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):
|
|
|
| col1, col2, col3 = st.columns([2, 2, 1])
|
|
|
| with col1:
|
| st.subheader("Health Score")
|
| score = data.get('health_score', {}).get('score', 0)
|
|
|
|
|
| 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)
|
|
|
|
|
| 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}")
|
|
|
|
|
| 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}")
|
|
|
|
|
| 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)
|
|
|
|
|
| st.dataframe(
|
| prices_df[['platform', 'price', 'title', 'url']],
|
| column_config={
|
| "url": st.column_config.LinkColumn("Link")
|
| }
|
| )
|
|
|
| if __name__ == "__main__":
|
| main() |