tdurzynski commited on
Commit
a6c5937
Β·
verified Β·
1 Parent(s): 6b2f10d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +80 -152
app.py CHANGED
@@ -4,168 +4,96 @@ 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
-
14
- # Load AWS credentials from secrets
15
- AWS_ACCESS_KEY = os.getenv("AWS_ACCESS_KEY_ID")
16
- AWS_SECRET_KEY = os.getenv("AWS_SECRET_ACCESS_KEY")
17
  AWS_REGION = os.getenv("AWS_REGION", "us-east-1")
18
  S3_BUCKET_NAME = os.getenv("S3_BUCKET_NAME", "food-image-crowdsourcing")
19
- DYNAMODB_TABLE = os.getenv("DYNAMODB_TABLE", "image_metadata") # βœ… Corrected Table Name
20
 
21
  # Load Firebase credentials
22
- FIREBASE_CONFIG = os.getenv("FIREBASE_CONFIG")
23
-
24
- # βœ… Initialize Firebase Admin SDK
25
- if FIREBASE_CONFIG:
26
- try:
27
- firebase_config_dict = json.loads(FIREBASE_CONFIG)
28
- if not firebase_admin._apps:
29
- cred = credentials.Certificate(firebase_config_dict)
30
- firebase_admin.initialize_app(cred)
31
- except Exception as e:
32
- st.error(f"⚠️ Firebase initialization error: {e}")
33
- else:
34
- st.error("⚠️ Firebase configuration is missing! Please check HF Secrets.")
35
-
36
- # βœ… Initialize AWS Services (S3 & DynamoDB)
37
- try:
38
- s3 = boto3.client(
39
- "s3",
40
- aws_access_key_id=AWS_ACCESS_KEY,
41
- aws_secret_access_key=AWS_SECRET_KEY,
42
- region_name=AWS_REGION
43
- )
44
-
45
- dynamodb = boto3.resource(
46
- "dynamodb",
47
- region_name=AWS_REGION,
48
- aws_access_key_id=AWS_ACCESS_KEY,
49
- aws_secret_access_key=AWS_SECRET_KEY,
50
- )
51
- metadata_table = dynamodb.Table(DYNAMODB_TABLE) # βœ… Corrected Table Name
52
- except Exception as e:
53
- st.error(f"⚠️ AWS initialization error: {e}")
54
-
55
- # πŸ”Ή Initialize Session State for Tokens
56
- if "tokens" not in st.session_state:
57
- st.session_state.tokens = 0
58
- if "user_email" not in st.session_state:
59
- st.session_state.user_email = None
60
-
61
- # πŸ”Ή UI - Page Title
62
- st.title("πŸ“· Food Crowdsourcing Research App")
63
- st.write("Help our research by uploading food images! Earn tokens for future app use.")
64
-
65
- # βœ… **User Authentication Section**
66
- st.sidebar.header("πŸ”‘ User Authentication")
67
-
68
- auth_choice = st.sidebar.radio("Select an option", ["Login", "Sign Up", "Logout"])
69
-
70
- if auth_choice == "Sign Up":
71
- with st.sidebar.form("signup_form"):
72
- email = st.text_input("Email")
73
- password = st.text_input("Password", type="password")
74
- submit_button = st.form_submit_button("Sign Up")
75
-
76
- if submit_button:
77
- try:
78
- user = auth.create_user(email=email, password=password)
79
- st.success(f"βœ… Account created! Now login with {email}.")
80
- except Exception as e:
81
- st.error(f"⚠️ {str(e)}")
82
-
83
- if auth_choice == "Login":
84
- with st.sidebar.form("login_form"):
85
- email = st.text_input("Email")
86
- password = st.text_input("Password", type="password")
87
- submit_button = st.form_submit_button("Login")
88
-
89
- if submit_button:
90
- try:
91
- user = auth.get_user_by_email(email)
92
- st.session_state.user_email = email
93
- st.success(f"βœ… Welcome back, {email}!")
94
- except Exception as e:
95
- st.error(f"⚠️ {str(e)}")
96
-
97
- if auth_choice == "Logout":
98
- if st.session_state.user_email:
99
- st.session_state.user_email = None
100
- st.success("βœ… Logged out successfully!")
101
 
102
- # πŸ”Ή **Ensure User is Logged In**
103
- if not st.session_state.user_email:
104
- st.warning("⚠️ Please log in to upload images.")
105
- st.stop()
106
-
107
- # βœ… **Image Upload Section**
108
- uploaded_file = st.file_uploader("πŸ“Έ Upload a food image", type=["jpg", "png", "jpeg"])
109
-
110
- # βœ… **Terms & Conditions**
111
- st.markdown("### **Terms & Conditions**")
112
- st.write(
113
- "By uploading an image, you agree to transfer full copyright to the research team for AI training purposes. "
114
- "You are responsible for ensuring you own the image and it does not violate any copyright laws. "
115
- "We do not guarantee when tokens will be redeemable. Keep track of your user ID."
116
  )
117
- st.checkbox("I agree to the terms and conditions", key="terms_accepted")
118
-
119
- # βœ… **Process and Upload Image**
120
- if uploaded_file and st.session_state.terms_accepted:
121
- image = Image.open(uploaded_file)
122
- st.image(image, caption="Uploaded Image", use_column_width=True)
123
-
124
- # Show Original Size
125
- st.write(f"πŸ“ Original size: {image.size}")
126
-
127
- # Convert PNG to JPEG if needed
128
- if image.format == "PNG":
129
- image = image.convert("RGB")
130
-
131
- # Resize image to max 1024x1024 px
132
- MAX_SIZE = (1024, 1024)
133
- image.thumbnail(MAX_SIZE)
134
 
135
- # Convert Image to Bytes
136
- img_bytes = io.BytesIO()
137
- image.save(img_bytes, format="JPEG", quality=80) # Reduce quality to save space
138
- img_bytes.seek(0)
139
-
140
- # πŸ”Ή Generate Unique File Name
141
- file_name = f"raw-uploads/{st.session_state.user_email}_{int(time.time())}.jpg"
142
 
143
- # βœ… **Upload to S3**
144
- try:
145
- s3.put_object(
146
- Bucket=S3_BUCKET_NAME,
147
- Key=file_name,
148
- Body=img_bytes.getvalue(),
149
- ContentType="image/jpeg",
150
- )
151
- st.success("βœ… Image uploaded successfully to S3!")
152
 
153
- # βœ… **Store Metadata in DynamoDB**
154
- metadata_table.put_item(
155
- Item={
156
- "user_email": st.session_state.user_email,
157
- "file_name": file_name,
158
- "upload_time": int(time.time()),
159
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  )
161
 
162
- # πŸŽ‰ **Reward Tokens**
163
- st.session_state.tokens += 1
164
- st.write("πŸŽ‰ You earned **1 token** for uploading!")
165
- st.success(f"πŸ”’ Total tokens: {st.session_state.tokens}")
166
-
167
- except Exception as e:
168
- st.error(f"⚠️ Failed to upload image: {str(e)}")
169
-
170
- # βœ… **Future: Annotation for Additional Token**
171
- # If annotation is provided, reward another token
 
 
 
4
  import io
5
  import base64
6
  import boto3
 
7
  from PIL import Image
8
+ from streamlit_tags import st_tags
 
9
 
10
+ # Load AWS credentials using correct HF Secrets
11
+ AWS_ACCESS_KEY = os.getenv("AWS_ACCESS_KEY")
12
+ AWS_SECRET_KEY = os.getenv("AWS_SECRET_KEY")
 
 
13
  AWS_REGION = os.getenv("AWS_REGION", "us-east-1")
14
  S3_BUCKET_NAME = os.getenv("S3_BUCKET_NAME", "food-image-crowdsourcing")
15
+ DYNAMODB_TABLE = os.getenv("DYNAMODB_TABLE", "image_metadata")
16
 
17
  # Load Firebase credentials
18
+ FIREBASE_CONFIG = json.loads(os.getenv("FIREBASE_CONFIG", "{}"))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
+ # Initialize AWS Services (S3 & DynamoDB)
21
+ s3 = boto3.client(
22
+ "s3",
23
+ aws_access_key_id=AWS_ACCESS_KEY,
24
+ aws_secret_access_key=AWS_SECRET_KEY,
 
 
 
 
 
 
 
 
 
25
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
+ dynamodb = boto3.resource(
28
+ "dynamodb",
29
+ region_name=AWS_REGION,
30
+ aws_access_key_id=AWS_ACCESS_KEY,
31
+ aws_secret_access_key=AWS_SECRET_KEY,
32
+ )
33
+ metadata_table = dynamodb.Table(DYNAMODB_TABLE)
34
 
35
+ # Streamlit Layout - Three Panel Design
36
+ st.title("🍽️ Food Image Review & Annotation")
37
+ col1, col2, col3 = st.columns([1, 1, 1]) # Equal size columns
 
 
 
 
 
 
38
 
39
+ # Upload Image
40
+ uploaded_file = st.file_uploader("Upload an image of your food", type=["jpg", "png", "jpeg"])
41
+ if uploaded_file:
42
+ image = Image.open(uploaded_file)
43
+ st.session_state["original_image"] = image
44
+
45
+ # Resize image in Streamlit before sending to S3
46
+ def resize_image(image):
47
+ aspect_ratio = image.width / image.height
48
+ new_width = 512
49
+ new_height = int(new_width / aspect_ratio)
50
+ resized_image = image.resize((new_width, new_height))
51
+ return resized_image
52
+
53
+ if "original_image" in st.session_state:
54
+ original_img = st.session_state["original_image"]
55
+ processed_img = resize_image(original_img)
56
+
57
+ # πŸ–ΌοΈ Panel 1: Original Image
58
+ with col1:
59
+ st.subheader("πŸ“· Original Image")
60
+ st.image(original_img, caption="Uploaded", use_container_width=True)
61
+
62
+ # πŸ–ΌοΈ Panel 2: Resized Image (512x512 Maintaining Aspect Ratio)
63
+ with col2:
64
+ st.subheader("πŸ–ΌοΈ Processed Image")
65
+ st.image(processed_img, caption="512x512 Maintained Aspect", use_container_width=True)
66
+
67
+ # ✏️ Panel 3: Food Annotations with Intellisense
68
+ with col3:
69
+ st.subheader("πŸ“ Add Annotations")
70
+
71
+ # Expanded food suggestions
72
+ suggested_foods = [
73
+ "Pizza", "Pasta", "Tacos", "Sushi", "Ramen", "Kimchi", "Bratwurst", "Jambalaya",
74
+ "Chicken", "Rice", "Steak", "Bread", "Cheese", "Salmon", "Avocado", "Eggs",
75
+ "Carrots", "Tomatoes", "Cucumber", "Yogurt", "Peanuts", "Lettuce", "Pierogies", "Mongolian Beef", "Spaghetti Bolognese",
76
+ "Bigos", "Stuffed Cabbage", "Zurek", "Schnitzel", "Tomato Soup", "Potato Pancakes", "Blintzes", "Broccoli Chicken"
77
+ ]
78
+
79
+ # User selects food items from suggestions
80
+ food_items = st_tags(
81
+ label="Enter food items",
82
+ text="Add items...",
83
+ value=[],
84
+ suggestions=suggested_foods,
85
+ maxtags=10,
86
  )
87
 
88
+ if st.button("Save Annotations"):
89
+ metadata_table.update_item(
90
+ Key={"image_id": uploaded_file.name},
91
+ UpdateExpression="SET annotations = :a, processing_status = :p, s3_url = :s, tokens_earned = :t",
92
+ ExpressionAttributeValues={
93
+ ":a": food_items,
94
+ ":p": "processed",
95
+ ":s": f"s3://{S3_BUCKET_NAME}/raw-uploads/{uploaded_file.name}",
96
+ ":t": 1 if food_items else 0
97
+ },
98
+ )
99
+ st.success("βœ… Annotations saved successfully!")