Spaces:
Sleeping
Sleeping
Update app.py
Browse filesπΉ Features of this Implementation
β
Firebase Authentication (Email & Password)
β
AWS S3 Storage for Uploaded Images
β
DynamoDB Metadata Storage
β
Securely Fetch Secrets from HF Secrets
β
Token-based Reward System
app.py
CHANGED
@@ -1,65 +1,143 @@
|
|
1 |
import streamlit as st
|
2 |
-
import
|
3 |
-
import
|
4 |
import io
|
|
|
|
|
5 |
import time
|
6 |
from PIL import Image
|
7 |
-
import
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
|
9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
if "tokens" not in st.session_state:
|
11 |
st.session_state.tokens = 0
|
|
|
|
|
12 |
|
13 |
-
# Page
|
14 |
st.title("π· Food Crowdsourcing Research App")
|
15 |
-
|
16 |
st.write("Help our research by uploading food images! Earn tokens for future app use.")
|
17 |
|
18 |
-
#
|
19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
|
21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
st.markdown("### **Terms & Conditions**")
|
23 |
st.write(
|
24 |
"By uploading an image, you agree to transfer full copyright to the research team for AI training purposes. "
|
25 |
"You are responsible for ensuring you own the image and it does not violate any copyright laws. "
|
26 |
-
"We do not guarantee when tokens will be redeemable. Keep track of your user ID."
|
|
|
27 |
st.checkbox("I agree to the terms and conditions", key="terms_accepted")
|
28 |
|
29 |
-
# Process
|
30 |
if uploaded_file and st.session_state.terms_accepted:
|
31 |
image = Image.open(uploaded_file)
|
32 |
st.image(image, caption="Uploaded Image", use_column_width=True)
|
33 |
|
34 |
-
# Show
|
35 |
-
st.write(f"Original size: {image.size}")
|
36 |
-
|
37 |
# Convert PNG to JPEG if needed
|
38 |
if image.format == "PNG":
|
39 |
image = image.convert("RGB")
|
40 |
-
|
41 |
# Resize image to max 1024x1024 px
|
42 |
MAX_SIZE = (1024, 1024)
|
43 |
image.thumbnail(MAX_SIZE)
|
44 |
-
|
45 |
-
# Convert
|
46 |
img_bytes = io.BytesIO()
|
47 |
image.save(img_bytes, format="JPEG", quality=80) # Reduce quality to save space
|
48 |
img_bytes.seek(0)
|
49 |
-
|
50 |
-
# Show resized size
|
51 |
-
st.write(f"New size: {image.size}")
|
52 |
-
|
53 |
-
# Upload to S3 (Simulated API Call)
|
54 |
-
# response = requests.post("YOUR_BACKEND_API/upload", files={"file": img_bytes.getvalue()})
|
55 |
-
|
56 |
-
# Token rewards system
|
57 |
-
st.session_state.tokens += 1 # 1 Token for uploading
|
58 |
-
st.write("β
You earned **1 token** for uploading!")
|
59 |
-
|
60 |
-
# Future: Add annotation for an extra token
|
61 |
-
# st.session_state.tokens += 1 # If annotation is provided
|
62 |
-
|
63 |
-
st.success(f"Total tokens: {st.session_state.tokens}")
|
64 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
65 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
import streamlit as st
|
2 |
+
import json
|
3 |
+
import os
|
4 |
import io
|
5 |
+
import base64
|
6 |
+
import boto3
|
7 |
import time
|
8 |
from PIL import Image
|
9 |
+
import firebase_admin
|
10 |
+
from firebase_admin import credentials, auth, firestore
|
11 |
+
|
12 |
+
# π Load Secrets from Hugging Face Secrets
|
13 |
+
FIREBASE_CONFIG = json.loads(os.getenv("FIREBASE_CONFIG", "{}"))
|
14 |
+
AWS_ACCESS_KEY = os.getenv("AWS_ACCESS_KEY")
|
15 |
+
AWS_SECRET_KEY = os.getenv("AWS_SECRET_KEY")
|
16 |
+
S3_BUCKET_NAME = os.getenv("S3_BUCKET_NAME", "food-image-crowdsourcing")
|
17 |
+
DYNAMODB_TABLE = os.getenv("DYNAMODB_TABLE", "FoodMetadata")
|
18 |
+
|
19 |
+
# β
Initialize Firebase Admin SDK
|
20 |
+
if FIREBASE_CONFIG:
|
21 |
+
cred = credentials.Certificate(FIREBASE_CONFIG)
|
22 |
+
firebase_admin.initialize_app(cred)
|
23 |
+
else:
|
24 |
+
st.error("β οΈ Firebase configuration is missing! Please check HF Secrets.")
|
25 |
+
|
26 |
+
# β
Initialize AWS Services (S3 & DynamoDB)
|
27 |
+
s3 = boto3.client(
|
28 |
+
"s3",
|
29 |
+
aws_access_key_id=AWS_ACCESS_KEY,
|
30 |
+
aws_secret_access_key=AWS_SECRET_KEY,
|
31 |
+
)
|
32 |
|
33 |
+
dynamodb = boto3.resource(
|
34 |
+
"dynamodb",
|
35 |
+
aws_access_key_id=AWS_ACCESS_KEY,
|
36 |
+
aws_secret_access_key=AWS_SECRET_KEY,
|
37 |
+
)
|
38 |
+
metadata_table = dynamodb.Table(DYNAMODB_TABLE)
|
39 |
+
|
40 |
+
# πΉ Initialize Session State for Tokens
|
41 |
if "tokens" not in st.session_state:
|
42 |
st.session_state.tokens = 0
|
43 |
+
if "user_email" not in st.session_state:
|
44 |
+
st.session_state.user_email = None
|
45 |
|
46 |
+
# πΉ UI - Page Title
|
47 |
st.title("π· Food Crowdsourcing Research App")
|
|
|
48 |
st.write("Help our research by uploading food images! Earn tokens for future app use.")
|
49 |
|
50 |
+
# β
**User Authentication Section**
|
51 |
+
st.sidebar.header("π User Authentication")
|
52 |
+
|
53 |
+
auth_choice = st.sidebar.radio("Select an option", ["Login", "Sign Up", "Logout"])
|
54 |
+
|
55 |
+
if auth_choice == "Sign Up":
|
56 |
+
with st.sidebar.form("signup_form"):
|
57 |
+
email = st.text_input("Email")
|
58 |
+
password = st.text_input("Password", type="password")
|
59 |
+
submit_button = st.form_submit_button("Sign Up")
|
60 |
+
|
61 |
+
if submit_button:
|
62 |
+
try:
|
63 |
+
user = auth.create_user(email=email, password=password)
|
64 |
+
st.success(f"β
Account created! Now login with {email}.")
|
65 |
+
except Exception as e:
|
66 |
+
st.error(f"β οΈ {str(e)}")
|
67 |
|
68 |
+
if auth_choice == "Login":
|
69 |
+
with st.sidebar.form("login_form"):
|
70 |
+
email = st.text_input("Email")
|
71 |
+
password = st.text_input("Password", type="password")
|
72 |
+
submit_button = st.form_submit_button("Login")
|
73 |
+
|
74 |
+
if submit_button:
|
75 |
+
try:
|
76 |
+
user = auth.get_user_by_email(email)
|
77 |
+
st.session_state.user_email = email
|
78 |
+
st.success(f"β
Welcome back, {email}!")
|
79 |
+
except Exception as e:
|
80 |
+
st.error(f"β οΈ {str(e)}")
|
81 |
+
|
82 |
+
if auth_choice == "Logout":
|
83 |
+
if st.session_state.user_email:
|
84 |
+
st.session_state.user_email = None
|
85 |
+
st.success("β
Logged out successfully!")
|
86 |
+
|
87 |
+
# πΉ **Ensure User is Logged In**
|
88 |
+
if not st.session_state.user_email:
|
89 |
+
st.warning("β οΈ Please log in to upload images.")
|
90 |
+
st.stop()
|
91 |
+
|
92 |
+
# β
**Image Upload Section**
|
93 |
+
uploaded_file = st.file_uploader("πΈ Upload a food image", type=["jpg", "png", "jpeg"])
|
94 |
+
|
95 |
+
# β
**Terms & Conditions**
|
96 |
st.markdown("### **Terms & Conditions**")
|
97 |
st.write(
|
98 |
"By uploading an image, you agree to transfer full copyright to the research team for AI training purposes. "
|
99 |
"You are responsible for ensuring you own the image and it does not violate any copyright laws. "
|
100 |
+
"We do not guarantee when tokens will be redeemable. Keep track of your user ID."
|
101 |
+
)
|
102 |
st.checkbox("I agree to the terms and conditions", key="terms_accepted")
|
103 |
|
104 |
+
# β
**Process and Upload Image**
|
105 |
if uploaded_file and st.session_state.terms_accepted:
|
106 |
image = Image.open(uploaded_file)
|
107 |
st.image(image, caption="Uploaded Image", use_column_width=True)
|
108 |
|
109 |
+
# Show Original Size
|
110 |
+
st.write(f"π Original size: {image.size}")
|
111 |
+
|
112 |
# Convert PNG to JPEG if needed
|
113 |
if image.format == "PNG":
|
114 |
image = image.convert("RGB")
|
115 |
+
|
116 |
# Resize image to max 1024x1024 px
|
117 |
MAX_SIZE = (1024, 1024)
|
118 |
image.thumbnail(MAX_SIZE)
|
119 |
+
|
120 |
+
# Convert Image to Bytes
|
121 |
img_bytes = io.BytesIO()
|
122 |
image.save(img_bytes, format="JPEG", quality=80) # Reduce quality to save space
|
123 |
img_bytes.seek(0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
124 |
|
125 |
+
# πΉ Generate Unique File Name
|
126 |
+
file_name = f"raw-uploads/{st.session_state.user_email}_{int(time.time())}.jpg"
|
127 |
+
|
128 |
+
# β
**Upload to S3**
|
129 |
+
try:
|
130 |
+
s3.put_object(
|
131 |
+
Bucket=S3_BUCKET_NAME,
|
132 |
+
Key=file_name,
|
133 |
+
Body=img_bytes.getvalue(),
|
134 |
+
ContentType="image/jpeg",
|
135 |
+
)
|
136 |
+
st.success("β
Image uploaded successfully to S3!")
|
137 |
|
138 |
+
# β
**Store Metadata in DynamoDB**
|
139 |
+
metadata_table.put_item(
|
140 |
+
Item={
|
141 |
+
"user_email": st.session_state.user_email,
|
142 |
+
"file_name": file_name,
|
143 |
+
"
|