Spaces:
Sleeping
Sleeping
import streamlit as st | |
import json | |
import os | |
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", "slices", "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.session_state["tokens"] = 0 # Initialize token count | |
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." | |
) | |
terms_accepted = st.checkbox("I agree to the terms and conditions", key="terms_accepted") | |
if not terms_accepted: | |
st.warning("β οΈ You must agree to the terms before proceeding.") | |
st.stop() | |
# Upload Image | |
uploaded_file = st.file_uploader("Upload an image of your food", type=["jpg", "png", "jpeg"]) | |
if uploaded_file: | |
original_img = Image.open(uploaded_file) | |
st.session_state["original_image"] = original_img | |
st.session_state["tokens"] += 1 # Earn 1 token for upload | |
# If an image has been uploaded, process and display it | |
if "original_image" in st.session_state: | |
original_img = st.session_state["original_image"] | |
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) | |
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_container_width=True) | |
with col2: | |
st.subheader("πΌοΈ Processed Image") | |
st.image(processed_img, caption=f"Processed ({processed_img.width}x{processed_img.height} pixels)", use_container_width=True) | |
st.session_state["processed_image"] = processed_img | |
# Display earned tokens | |
st.success(f"π Tokens Earned: {st.session_state['tokens']}") | |
# Annotation Table | |
st.subheader("π Add Annotations") | |
if "annotations" not in st.session_state: | |
st.session_state["annotations"] = [] | |
new_food_item = st.selectbox("Food Item", FOOD_SUGGESTIONS + ["Other..."]) | |
if new_food_item == "Other...": | |
new_food_item = st.text_input("Enter custom food item") | |
new_quantity = st.number_input("Quantity", min_value=0, step=1) | |
new_unit = st.selectbox("Unit", UNIT_OPTIONS) | |
if st.button("Add Annotation"): | |
st.session_state["annotations"].append({ | |
"name": new_food_item, | |
"quantity": new_quantity, | |
"unit": new_unit | |
}) | |
st.session_state["tokens"] += 1 # Earn 1 token per annotation | |
st.table(st.session_state["annotations"]) |