tdurzynski's picture
Update app.py
522835b verified
raw
history blame
6.31 kB
import streamlit as st
import json
import os
import io
import base64
import boto3
from PIL import Image
import firebase_admin
from firebase_admin import credentials, auth
import pandas as pd
# Load AWS credentials using correct HF Secrets
AWS_ACCESS_KEY = os.getenv("AWS_ACCESS_KEY")
AWS_SECRET_KEY = os.getenv("AWS_SECRET_KEY")
AWS_REGION = os.getenv("AWS_REGION", "us-east-1")
S3_BUCKET_NAME = os.getenv("S3_BUCKET_NAME", "food-image-crowdsourcing")
DYNAMODB_TABLE = os.getenv("DYNAMODB_TABLE", "image_metadata")
# Load Firebase credentials
FIREBASE_CONFIG = json.loads(os.getenv("FIREBASE_CONFIG", "{}"))
# Initialize Firebase Admin SDK (Prevent multiple initialization)
if not firebase_admin._apps:
cred = credentials.Certificate(FIREBASE_CONFIG)
firebase_admin.initialize_app(cred)
# Initialize AWS Services (S3 & DynamoDB)
s3 = boto3.client(
"s3",
aws_access_key_id=AWS_ACCESS_KEY,
aws_secret_access_key=AWS_SECRET_KEY,
)
dynamodb = boto3.resource(
"dynamodb",
region_name=AWS_REGION,
aws_access_key_id=AWS_ACCESS_KEY,
aws_secret_access_key=AWS_SECRET_KEY,
)
metadata_table = dynamodb.Table(DYNAMODB_TABLE)
# Food Intellisense List
FOOD_SUGGESTIONS = [
"Apple", "Banana", "Pizza", "Burger", "Pasta", "Sushi", "Tacos", "Salad",
"Chicken Curry", "Steak", "Fish & Chips", "Dumplings", "Kimchi", "Pancakes",
"Biryani", "Croissant", "Baguette", "Miso Soup", "Ramen", "Pierogi"
] # Extend this list with diverse cuisines
# Unit options for food weight/volume
UNIT_OPTIONS = ["grams", "ounces", "teaspoons", "tablespoons", "cups", "pieces"]
# Streamlit Layout - Authentication Section
st.sidebar.title("πŸ”‘ User Authentication")
auth_option = st.sidebar.radio("Select an option", ["Login", "Sign Up", "Logout"])
if auth_option == "Sign Up":
email = st.sidebar.text_input("Email")
password = st.sidebar.text_input("Password", type="password")
if st.sidebar.button("Sign Up"):
try:
user = auth.create_user(email=email, password=password)
st.sidebar.success("βœ… User created successfully! Please log in.")
except Exception as e:
st.sidebar.error(f"Error: {e}")
if auth_option == "Login":
email = st.sidebar.text_input("Email")
password = st.sidebar.text_input("Password", type="password")
if st.sidebar.button("Login"):
try:
user = auth.get_user_by_email(email)
st.session_state["user_id"] = user.uid
st.sidebar.success("βœ… Logged in successfully!")
except Exception as e:
st.sidebar.error(f"Login failed: {e}")
if auth_option == "Logout" and "user_id" in st.session_state:
del st.session_state["user_id"]
st.sidebar.success("βœ… Logged out successfully!")
# Ensure user is logged in before uploading
if "user_id" not in st.session_state:
st.warning("⚠️ Please log in to upload images.")
st.stop()
# Streamlit Layout - Three Panel Design
st.title("🍽️ Food Image Review & Annotation")
col1, col2 = st.columns([1, 1])
# Compliance & Disclaimer Section
st.markdown("### **Terms & Conditions**")
st.write(
"By uploading an image, you agree to transfer full copyright to the research team for AI training purposes."
" You are responsible for ensuring you own the image and it does not violate any copyright laws."
" We do not guarantee when tokens will be redeemable. Keep track of your user ID."
)
st.checkbox("I agree to the terms and conditions", key="terms_accepted")
# Upload Image
uploaded_file = st.file_uploader("Upload an image of your food", type=["jpg", "png", "jpeg"])
# Ensure an image is uploaded before displaying
if uploaded_file:
original_img = Image.open(uploaded_file)
st.session_state["original_image"] = original_img
# If an image has been uploaded, process and display it
if "original_image" in st.session_state:
original_img = st.session_state["original_image"]
# Resize while maintaining aspect ratio (longest side = 512)
def resize_image(image, max_size=512):
aspect_ratio = image.width / image.height
if image.width > image.height:
new_width = max_size
new_height = int(max_size / aspect_ratio)
else:
new_height = max_size
new_width = int(max_size * aspect_ratio)
return image.resize((new_width, new_height))
processed_img = resize_image(original_img)
# UI Layout: Two Columns for Images
col1, col2 = st.columns(2)
with col1:
st.subheader("πŸ“· Original Image")
st.image(original_img, caption=f"Original ({original_img.width}x{original_img.height} pixels)", use_column_width=True)
with col2:
st.subheader("πŸ–ΌοΈ Processed Image")
st.image(processed_img, caption=f"Processed ({processed_img.width}x{processed_img.height} pixels)", use_column_width=True)
# Store processed image in session state for annotations
st.session_state["processed_image"] = processed_img
else:
st.warning("⚠️ Please upload an image first.")
# Create a table-like structure for food annotation
st.subheader("πŸ“ Add Annotations")
# Define columns for table structure
col_food, col_qty, col_unit, col_ing = st.columns([2, 1, 1, 2]) # Define column widths
# Food Item Dropdown (with Intellisense)
food_item = col_food.selectbox("Food Item", options=suggested_foods, index=None, placeholder="Select or enter food")
# Quantity Input
quantity = col_qty.number_input("Qty", min_value=0, step=1)
# Unit Dropdown (Grams, Ounces, etc.)
unit = col_unit.selectbox("Unit", ["g", "oz", "tsp", "tbsp", "cup", "slice", "piece"])
# Ingredients Section with Expandable Input
with col_ing:
ingredients = []
if st.button("+ Add Ingredients"):
ingredient = st.text_input("Enter ingredient")
if ingredient:
ingredients.append(ingredient)
# Display added annotations in a structured format
if st.button("Save Annotations"):
new_entry = {
"name": food_item,
"quantity": quantity,
"unit": unit,
"ingredients": ingredients,
}
st.session_state["annotations"].append(new_entry)
st.success("βœ… Annotation saved!")
# Show existing annotations
st.write("### Current Annotations")
st.table(st.session_state["annotations"])