Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -63,6 +63,7 @@ except Exception as e:
|
|
63 |
else:
|
64 |
st.stop()
|
65 |
|
|
|
66 |
FOOD_SUGGESTIONS = [
|
67 |
"Ajvar", "Angel Wings", "Apple", "Apple Pie", "Apfelstrudel", "Arancini", "Asparagus", "Babka", "Bagel","Baguette", "Baklava",
|
68 |
"Banana", "Banana Bread", "Banh Mi", "Banitsa", "Barbecue Ribs", "BBQ Chicken", "BBQ Chicken Pizza", "BBQ Ribs", "Bean Buritto",
|
@@ -106,9 +107,9 @@ UNIT_OPTIONS = ["grams", "ounce(s)", "teaspoon(s)", "tablespoon(s)", "cup(s)", "
|
|
106 |
|
107 |
# Cooking methods
|
108 |
COOKING_METHODS = [
|
109 |
-
"Baked", "Boiled", "Braised", "Breaded and fried", "Broiled", "Creamy", "Deep-fried", "Dried",
|
110 |
"Fried", "Grilled", "Grilled minced", "Marinated", "Microwaved", "Pan-seared", "Poached", "Raw",
|
111 |
-
"Roasted", "Sautéed", "Slow-cooked", "Smoked", "Steamed", "Stewed", "Stir-fried", "Takeout/Restaurant"
|
112 |
]
|
113 |
|
114 |
# Helper functions
|
@@ -139,8 +140,8 @@ def resize_image(image, max_size=512, quality=85):
|
|
139 |
# Resize the image
|
140 |
resized_img = image.resize((new_width, new_height), Image.LANCZOS)
|
141 |
else:
|
142 |
-
# If image is already smaller than max_size,
|
143 |
-
|
144 |
|
145 |
# Convert to RGB if image has alpha channel (for JPEG conversion)
|
146 |
if resized_img.mode == 'RGBA':
|
@@ -194,7 +195,9 @@ def upload_to_s3(image, user_id, folder="", force_quality=None):
|
|
194 |
else:
|
195 |
# Higher quality for raw uploads, compressed for processed
|
196 |
quality = 95 if folder == "raw-uploads" else 85
|
197 |
-
|
|
|
|
|
198 |
image.save(buffer, format="JPEG", quality=quality, optimize=True)
|
199 |
buffer.seek(0)
|
200 |
|
@@ -279,7 +282,11 @@ def reset_form_fields():
|
|
279 |
|
280 |
def add_food_item(food_name, portion_size, portion_unit, cooking_method, ingredients):
|
281 |
"""Add a food item to the session state"""
|
282 |
-
|
|
|
|
|
|
|
|
|
283 |
# Add the food item to the session state
|
284 |
st.session_state["food_items"].append({
|
285 |
"food_name": food_name,
|
@@ -453,7 +460,8 @@ if "original_image" in st.session_state:
|
|
453 |
with col2:
|
454 |
portion_unit = st.selectbox("Unit", options=UNIT_OPTIONS)
|
455 |
|
456 |
-
|
|
|
457 |
|
458 |
ingredients = st_tags.st_tags(
|
459 |
label="Main Ingredients (Add up to 5)",
|
@@ -472,95 +480,101 @@ if "original_image" in st.session_state:
|
|
472 |
st.session_state["custom_food_name"] = custom_food_name
|
473 |
st.rerun()
|
474 |
|
475 |
-
#
|
476 |
-
if "original_image" in st.session_state:
|
477 |
-
with st.expander("🚀 Quick Add Common Foods"):
|
478 |
-
st.info("Click to quickly add common food items with default values")
|
479 |
-
quick_add_cols = st.columns(3)
|
480 |
-
|
481 |
-
common_foods = [
|
482 |
-
{"name": "French Fries", "portion": 100, "unit": "grams", "cooking": "Fried", "ingredients": ["Potatoes", "Salt", "Oil"]},
|
483 |
-
{"name": "Hamburger", "portion": 1, "unit": "pieces", "cooking": "Grilled", "ingredients": ["Beef", "Bun", "Lettuce", "Tomato"]},
|
484 |
-
{"name": "Salad", "portion": 150, "unit": "grams", "cooking": "Raw", "ingredients": ["Lettuce", "Tomato", "Cucumber"]}
|
485 |
-
]
|
486 |
-
|
487 |
-
for i, food in enumerate(common_foods):
|
488 |
-
with quick_add_cols[i % 3]:
|
489 |
-
if st.button(f"+ {food['name']}", key=f"quick_{i}"):
|
490 |
-
add_food_item(
|
491 |
-
food['name'],
|
492 |
-
food['portion'],
|
493 |
-
food['unit'],
|
494 |
-
food['cooking'],
|
495 |
-
food['ingredients']
|
496 |
-
)
|
497 |
-
st.rerun()
|
498 |
-
|
499 |
-
# Divider before submit button
|
500 |
st.markdown("---")
|
501 |
|
502 |
-
#
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
success = save_metadata(
|
536 |
-
st.session_state["user_id"],
|
537 |
-
processed_s3_path, # Use the processed image path
|
538 |
-
food_item["food_name"],
|
539 |
-
portion_size_decimal, # Use Decimal type
|
540 |
-
food_item["portion_unit"],
|
541 |
-
food_item["cooking_method"],
|
542 |
-
food_item["ingredients"],
|
543 |
-
tokens_awarded
|
544 |
-
)
|
545 |
|
546 |
-
|
547 |
-
|
548 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
549 |
|
550 |
-
if
|
551 |
-
|
552 |
-
st.session_state["
|
553 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
554 |
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
560 |
else:
|
561 |
-
st.error("Failed to
|
562 |
-
else:
|
563 |
-
st.error("Failed to upload images. Please try again.")
|
564 |
|
565 |
# Display earned tokens
|
566 |
st.sidebar.markdown("---")
|
@@ -584,4 +598,4 @@ if st.sidebar.button("Token Rewards System"):
|
|
584 |
if st.sidebar.button("Terms of Service"):
|
585 |
with open("TERMS_OF_SERVICE.md", "r") as f:
|
586 |
terms = f.read()
|
587 |
-
st.sidebar.markdown(terms)
|
|
|
63 |
else:
|
64 |
st.stop()
|
65 |
|
66 |
+
# Food Intellisense List
|
67 |
FOOD_SUGGESTIONS = [
|
68 |
"Ajvar", "Angel Wings", "Apple", "Apple Pie", "Apfelstrudel", "Arancini", "Asparagus", "Babka", "Bagel","Baguette", "Baklava",
|
69 |
"Banana", "Banana Bread", "Banh Mi", "Banitsa", "Barbecue Ribs", "BBQ Chicken", "BBQ Chicken Pizza", "BBQ Ribs", "Bean Buritto",
|
|
|
107 |
|
108 |
# Cooking methods
|
109 |
COOKING_METHODS = [
|
110 |
+
"Unknown", "Baked", "Boiled", "Braised", "Breaded and fried", "Broiled", "Creamy", "Deep-fried", "Dried",
|
111 |
"Fried", "Grilled", "Grilled minced", "Marinated", "Microwaved", "Pan-seared", "Poached", "Raw",
|
112 |
+
"Roasted", "Sautéed", "Slow-cooked", "Smoked", "Steamed", "Stewed", "Stir-fried", "Takeout/Restaurant"
|
113 |
]
|
114 |
|
115 |
# Helper functions
|
|
|
140 |
# Resize the image
|
141 |
resized_img = image.resize((new_width, new_height), Image.LANCZOS)
|
142 |
else:
|
143 |
+
# If image is already smaller than max_size, return a copy to avoid modifying original
|
144 |
+
resized_img = image.copy()
|
145 |
|
146 |
# Convert to RGB if image has alpha channel (for JPEG conversion)
|
147 |
if resized_img.mode == 'RGBA':
|
|
|
195 |
else:
|
196 |
# Higher quality for raw uploads, compressed for processed
|
197 |
quality = 95 if folder == "raw-uploads" else 85
|
198 |
+
|
199 |
+
# Don't compress the image again if it's already been through resize_image
|
200 |
+
# Just save with the appropriate quality
|
201 |
image.save(buffer, format="JPEG", quality=quality, optimize=True)
|
202 |
buffer.seek(0)
|
203 |
|
|
|
282 |
|
283 |
def add_food_item(food_name, portion_size, portion_unit, cooking_method, ingredients):
|
284 |
"""Add a food item to the session state"""
|
285 |
+
# Set cooking method to "Unknown" if empty
|
286 |
+
if not cooking_method:
|
287 |
+
cooking_method = "Unknown"
|
288 |
+
|
289 |
+
if food_name and portion_size and portion_unit: # Cooking method no longer required
|
290 |
# Add the food item to the session state
|
291 |
st.session_state["food_items"].append({
|
292 |
"food_name": food_name,
|
|
|
460 |
with col2:
|
461 |
portion_unit = st.selectbox("Unit", options=UNIT_OPTIONS)
|
462 |
|
463 |
+
# Set Cooking Method with "Unknown" as the default (index 0)
|
464 |
+
cooking_method = st.selectbox("Cooking Method (optional)", options=COOKING_METHODS, index=0)
|
465 |
|
466 |
ingredients = st_tags.st_tags(
|
467 |
label="Main Ingredients (Add up to 5)",
|
|
|
480 |
st.session_state["custom_food_name"] = custom_food_name
|
481 |
st.rerun()
|
482 |
|
483 |
+
# Make submit button more prominent
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
484 |
st.markdown("---")
|
485 |
|
486 |
+
# More prominent submit button with instructions
|
487 |
+
st.markdown("### 📤 Submit Your Food Annotations")
|
488 |
+
st.info("⚠️ After adding all your food items, click the button below to save your submission and earn tokens.")
|
489 |
+
|
490 |
+
# Create a larger, more visible submit button
|
491 |
+
submit_col1, submit_col2, submit_col3 = st.columns([1, 2, 1])
|
492 |
+
with submit_col2:
|
493 |
+
if st.button("📤 SUBMIT ALL FOOD ITEMS",
|
494 |
+
disabled=len(st.session_state["food_items"]) == 0,
|
495 |
+
use_container_width=True,
|
496 |
+
type="primary"):
|
497 |
+
if not st.session_state["food_items"]:
|
498 |
+
st.error("❌ Please add at least one food item before submitting")
|
499 |
+
else:
|
500 |
+
with st.spinner("Processing your submission..."):
|
501 |
+
all_saved = True
|
502 |
+
total_tokens = 0
|
503 |
+
|
504 |
+
# Determine image quality (simplified version)
|
505 |
+
image_quality = "high" if original_img.width >= 1000 and original_img.height >= 1000 else "standard"
|
506 |
+
|
507 |
+
# Get original image file size for comparison
|
508 |
+
original_size = get_image_size_kb(original_img)
|
509 |
+
|
510 |
+
# Ensure we have a properly processed image with the right settings
|
511 |
+
# Force resize and compression with settings that guarantee size reduction
|
512 |
+
processed_img = resize_image(original_img, max_size=512, quality=85)
|
513 |
+
processed_size = get_image_size_kb(processed_img)
|
514 |
+
|
515 |
+
# If the processed image isn't smaller enough, reduce quality further
|
516 |
+
if processed_size > original_size * 0.8: # Ensure at least 20% reduction
|
517 |
+
processed_img = resize_image(original_img, max_size=512, quality=70)
|
518 |
+
processed_size = get_image_size_kb(processed_img)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
519 |
|
520 |
+
# If still not small enough, try more aggressive compression
|
521 |
+
if processed_size > original_size * 0.8:
|
522 |
+
processed_img = resize_image(original_img, max_size=480, quality=60)
|
523 |
+
|
524 |
+
# Upload original to raw-uploads folder
|
525 |
+
raw_s3_path = upload_to_s3(original_img, st.session_state["user_id"],
|
526 |
+
folder="raw-uploads", force_quality=95)
|
527 |
+
|
528 |
+
# Upload only one processed image to processed-512x512 folder
|
529 |
+
processed_s3_path = upload_to_s3(processed_img, st.session_state["user_id"],
|
530 |
+
folder="processed-512x512", force_quality=85)
|
531 |
|
532 |
+
if raw_s3_path and processed_s3_path:
|
533 |
+
# Save each food item with the processed image path
|
534 |
+
for food_item in st.session_state["food_items"]:
|
535 |
+
# Check if metadata is complete
|
536 |
+
has_metadata = True # Already validated
|
537 |
+
|
538 |
+
# Check if the food is in a unique category (simplified)
|
539 |
+
is_unique_category = food_item["food_name"] not in ["Pizza", "Burger", "Pasta", "Salad"]
|
540 |
+
|
541 |
+
# Calculate tokens for this item
|
542 |
+
tokens_awarded = calculate_tokens(image_quality, has_metadata, is_unique_category)
|
543 |
+
total_tokens += tokens_awarded
|
544 |
+
|
545 |
+
# Convert float to Decimal for DynamoDB
|
546 |
+
portion_size_decimal = Decimal(str(food_item["portion_size"]))
|
547 |
+
|
548 |
+
# Save metadata to DynamoDB with processed image path
|
549 |
+
success = save_metadata(
|
550 |
+
st.session_state["user_id"],
|
551 |
+
processed_s3_path, # Use the processed image path
|
552 |
+
food_item["food_name"],
|
553 |
+
portion_size_decimal, # Use Decimal type
|
554 |
+
food_item["portion_unit"],
|
555 |
+
food_item["cooking_method"],
|
556 |
+
food_item["ingredients"],
|
557 |
+
tokens_awarded
|
558 |
+
)
|
559 |
+
|
560 |
+
if not success:
|
561 |
+
all_saved = False
|
562 |
+
break
|
563 |
|
564 |
+
if all_saved:
|
565 |
+
st.session_state["tokens"] += total_tokens
|
566 |
+
st.session_state["uploads_count"] += 1
|
567 |
+
st.success(f"✅ All food items uploaded successfully! You earned {total_tokens} tokens.")
|
568 |
+
|
569 |
+
# Clear the form and image for a new submission
|
570 |
+
st.session_state.pop("original_image", None)
|
571 |
+
st.session_state.pop("processed_image", None)
|
572 |
+
st.session_state["food_items"] = []
|
573 |
+
st.rerun()
|
574 |
+
else:
|
575 |
+
st.error("Failed to save some items. Please try again.")
|
576 |
else:
|
577 |
+
st.error("Failed to upload images. Please try again.")
|
|
|
|
|
578 |
|
579 |
# Display earned tokens
|
580 |
st.sidebar.markdown("---")
|
|
|
598 |
if st.sidebar.button("Terms of Service"):
|
599 |
with open("TERMS_OF_SERVICE.md", "r") as f:
|
600 |
terms = f.read()
|
601 |
+
st.sidebar.markdown(terms)
|