Update app.py
Browse files
app.py
CHANGED
@@ -15,9 +15,6 @@ import pandas as pd
|
|
15 |
import streamlit_tags as st_tags
|
16 |
from dotenv import load_dotenv
|
17 |
|
18 |
-
# Add debug mode detection here
|
19 |
-
debug_mode = "debug" in st.query_params
|
20 |
-
|
21 |
# Load environment variables from .env file if it exists
|
22 |
load_dotenv()
|
23 |
|
@@ -193,10 +190,6 @@ def upload_to_s3(image, user_id, folder=""):
|
|
193 |
quality = 95 if folder == "raw-uploads" else 85
|
194 |
image.save(buffer, format="JPEG", quality=quality, optimize=True)
|
195 |
buffer.seek(0)
|
196 |
-
|
197 |
-
# Add debug logging
|
198 |
-
if debug_mode:
|
199 |
-
st.sidebar.info(f"S3 Upload Path: {s3_path}")
|
200 |
|
201 |
# Upload to S3
|
202 |
s3.upload_fileobj(buffer, S3_BUCKET_NAME, s3_path)
|
@@ -233,20 +226,6 @@ def save_metadata(user_id, s3_path, food_name, portion_size, portion_unit, cooki
|
|
233 |
's3_path': s3_path,
|
234 |
'tokens_awarded': tokens_awarded
|
235 |
}
|
236 |
-
|
237 |
-
# Add debug logging with more details
|
238 |
-
if debug_mode:
|
239 |
-
st.sidebar.info(f"DynamoDB Save: {image_id} - {food_name}")
|
240 |
-
if "test_debug_details" not in st.session_state:
|
241 |
-
st.session_state["test_debug_details"] = []
|
242 |
-
|
243 |
-
# Store details for debugging
|
244 |
-
st.session_state["test_debug_details"].append({
|
245 |
-
"time": datetime.now().isoformat(),
|
246 |
-
"image_id": image_id,
|
247 |
-
"food": food_name,
|
248 |
-
"s3_path": s3_path
|
249 |
-
})
|
250 |
|
251 |
# Save to DynamoDB
|
252 |
metadata_table.put_item(Item=item)
|
@@ -347,13 +326,6 @@ if auth_option == "Logout" and "user_id" in st.session_state:
|
|
347 |
del st.session_state["user_id"]
|
348 |
st.sidebar.success("✅ Logged out successfully!")
|
349 |
|
350 |
-
# Add Debug Mode Indicator to sidebar
|
351 |
-
if debug_mode:
|
352 |
-
st.sidebar.warning("⚠️ DEBUG MODE ACTIVE")
|
353 |
-
test_mode = st.sidebar.checkbox("Mark submissions as tests")
|
354 |
-
if test_mode:
|
355 |
-
st.sidebar.info("Test mode enabled - all submissions will be prefixed with 'TEST_'")
|
356 |
-
|
357 |
# Ensure user is logged in before uploading
|
358 |
if "user_id" not in st.session_state and not st.session_state.get("demo_mode", False):
|
359 |
st.warning("⚠️ Please log in to upload images.")
|
@@ -440,152 +412,6 @@ if "original_image" in st.session_state:
|
|
440 |
if size_reduction > 5: # Only show if there's a meaningful reduction
|
441 |
st.success(f"✅ Image size reduced by {size_reduction:.1f}% for faster uploads and processing")
|
442 |
|
443 |
-
# Add S3 Upload Test Panel for Debug Mode with proper subfolder structure
|
444 |
-
if debug_mode and "processed_image" in st.session_state:
|
445 |
-
with st.expander("🔍 DEBUG: S3 Upload Tests", expanded=True):
|
446 |
-
st.warning("⚠️ Debug Mode: Test S3 functionality with correct folder structure")
|
447 |
-
|
448 |
-
s3_test_col1, s3_test_col2 = st.columns(2)
|
449 |
-
|
450 |
-
with s3_test_col1:
|
451 |
-
st.subheader("Raw Image Upload")
|
452 |
-
test_raw_button = st.button("Test Raw Upload")
|
453 |
-
|
454 |
-
if test_raw_button and "original_image" in st.session_state:
|
455 |
-
# Test upload to raw-uploads folder
|
456 |
-
raw_s3_path = upload_to_s3(st.session_state["original_image"],
|
457 |
-
st.session_state["user_id"],
|
458 |
-
folder="raw-uploads")
|
459 |
-
if raw_s3_path:
|
460 |
-
st.success(f"✅ Raw upload successful!")
|
461 |
-
st.code(f"s3://{S3_BUCKET_NAME}/{raw_s3_path}", language="text")
|
462 |
-
st.session_state["test_raw_s3_path"] = raw_s3_path
|
463 |
-
else:
|
464 |
-
st.error("❌ Raw upload failed!")
|
465 |
-
|
466 |
-
with s3_test_col2:
|
467 |
-
st.subheader("Processed Image Upload")
|
468 |
-
test_processed_button = st.button("Test Processed Upload")
|
469 |
-
|
470 |
-
if test_processed_button and "processed_image" in st.session_state:
|
471 |
-
# Test upload to processed-512x512 folder
|
472 |
-
processed_s3_path = upload_to_s3(st.session_state["processed_image"],
|
473 |
-
st.session_state["user_id"],
|
474 |
-
folder="processed-512x512")
|
475 |
-
if processed_s3_path:
|
476 |
-
st.success(f"✅ Processed upload successful!")
|
477 |
-
st.code(f"s3://{S3_BUCKET_NAME}/{processed_s3_path}", language="text")
|
478 |
-
st.session_state["test_processed_s3_path"] = processed_s3_path
|
479 |
-
else:
|
480 |
-
st.error("❌ Processed upload failed!")
|
481 |
-
|
482 |
-
# Add DynamoDB Test Panel for Multiple Food Items
|
483 |
-
if debug_mode and "processed_image" in st.session_state:
|
484 |
-
with st.expander("🔍 DEBUG: Complete Food Annotation Test", expanded=True):
|
485 |
-
st.warning("⚠️ Debug Mode: Test Complete Flow with Multiple Food Items")
|
486 |
-
|
487 |
-
# Create a test session state if it doesn't exist
|
488 |
-
if "test_food_items" not in st.session_state:
|
489 |
-
st.session_state["test_food_items"] = []
|
490 |
-
|
491 |
-
# Form for adding test food items
|
492 |
-
with st.form(key="test_food_form"):
|
493 |
-
test_food = st.text_input("Food Name", "Test Pizza")
|
494 |
-
test_portion = st.number_input("Portion Size", value=1.0)
|
495 |
-
test_unit = st.selectbox("Unit", UNIT_OPTIONS)
|
496 |
-
test_cooking = st.selectbox("Cooking Method", COOKING_METHODS)
|
497 |
-
test_ingredients = st_tags.st_tags(
|
498 |
-
label="Ingredients",
|
499 |
-
text="Press enter to add",
|
500 |
-
value=["Test Ingredient"],
|
501 |
-
maxtags=5
|
502 |
-
)
|
503 |
-
|
504 |
-
test_add_button = st.form_submit_button("Add Test Food Item")
|
505 |
-
|
506 |
-
if test_add_button:
|
507 |
-
st.session_state["test_food_items"].append({
|
508 |
-
"food_name": f"TEST_{test_food}",
|
509 |
-
"portion_size": test_portion,
|
510 |
-
"portion_unit": test_unit,
|
511 |
-
"cooking_method": test_cooking,
|
512 |
-
"ingredients": test_ingredients
|
513 |
-
})
|
514 |
-
st.success(f"Added test food item: {test_food}")
|
515 |
-
st.rerun()
|
516 |
-
|
517 |
-
# Display test food items
|
518 |
-
if st.session_state["test_food_items"]:
|
519 |
-
st.subheader("Test Food Items")
|
520 |
-
for i, item in enumerate(st.session_state["test_food_items"]):
|
521 |
-
with st.expander(f"Item #{i+1}: {item['food_name']}"):
|
522 |
-
st.write(f"**Portion:** {item['portion_size']} {item['portion_unit']}")
|
523 |
-
st.write(f"**Cooking Method:** {item['cooking_method']}")
|
524 |
-
st.write(f"**Ingredients:** {', '.join(item['ingredients'])}")
|
525 |
-
if st.button(f"Remove Test Item #{i+1}", key=f"remove_test_{i}"):
|
526 |
-
st.session_state["test_food_items"].pop(i)
|
527 |
-
st.rerun()
|
528 |
-
|
529 |
-
# Button to run the full test
|
530 |
-
test_full_button = st.button("Run Complete Annotation Test")
|
531 |
-
if test_full_button and st.session_state["test_food_items"]:
|
532 |
-
with st.spinner("Testing complete annotation flow..."):
|
533 |
-
# Upload both original and processed images
|
534 |
-
raw_s3_path = upload_to_s3(original_img, st.session_state["user_id"], folder="raw-uploads")
|
535 |
-
processed_s3_path = upload_to_s3(processed_img, st.session_state["user_id"], folder="processed-512x512")
|
536 |
-
|
537 |
-
all_saved = True
|
538 |
-
saved_items = 0
|
539 |
-
|
540 |
-
if raw_s3_path and processed_s3_path:
|
541 |
-
# Set up a results area
|
542 |
-
results_area = st.empty()
|
543 |
-
|
544 |
-
# Save each food item
|
545 |
-
for item in st.session_state["test_food_items"]:
|
546 |
-
try:
|
547 |
-
# Convert to Decimal
|
548 |
-
portion_size_decimal = Decimal(str(item["portion_size"]))
|
549 |
-
|
550 |
-
# Save to DynamoDB
|
551 |
-
success = save_metadata(
|
552 |
-
st.session_state["user_id"],
|
553 |
-
processed_s3_path,
|
554 |
-
item["food_name"],
|
555 |
-
portion_size_decimal,
|
556 |
-
item["portion_unit"],
|
557 |
-
item["cooking_method"],
|
558 |
-
item["ingredients"],
|
559 |
-
1 # Test token value
|
560 |
-
)
|
561 |
-
|
562 |
-
if success:
|
563 |
-
saved_items += 1
|
564 |
-
else:
|
565 |
-
all_saved = False
|
566 |
-
break
|
567 |
-
except Exception as e:
|
568 |
-
results_area.error(f"Error saving {item['food_name']}: {e}")
|
569 |
-
all_saved = False
|
570 |
-
break
|
571 |
-
|
572 |
-
if all_saved:
|
573 |
-
st.success(f"✅ Successfully saved {saved_items} food items!")
|
574 |
-
st.json({
|
575 |
-
"user_id": st.session_state["user_id"],
|
576 |
-
"s3_paths": {
|
577 |
-
"raw": raw_s3_path,
|
578 |
-
"processed": processed_s3_path
|
579 |
-
},
|
580 |
-
"food_items": st.session_state["test_food_items"]
|
581 |
-
})
|
582 |
-
else:
|
583 |
-
st.error("❌ Failed to save all food items")
|
584 |
-
else:
|
585 |
-
st.error("❌ Failed to upload images to S3")
|
586 |
-
else:
|
587 |
-
st.info("Add test food items above to run a complete annotation test")
|
588 |
-
|
589 |
# Display existing food annotations if any
|
590 |
if st.session_state["food_items"]:
|
591 |
st.subheader("📋 Added Food Items")
|
@@ -668,14 +494,6 @@ if debug_mode and "processed_image" in st.session_state:
|
|
668 |
|
669 |
# Submit all foods button - outside the form
|
670 |
if st.button("📤 Submit All Food Items", disabled=len(st.session_state["food_items"]) == 0):
|
671 |
-
|
672 |
-
# Modify submission to handle test data
|
673 |
-
if debug_mode and test_mode:
|
674 |
-
for food_item in st.session_state["food_items"]:
|
675 |
-
# Prefix the food name to identify test data
|
676 |
-
food_item["food_name"] = f"TEST_{food_item['food_name']}"
|
677 |
-
st.info("ℹ️ Test mode: Data will be marked as test data")
|
678 |
-
|
679 |
if not st.session_state["food_items"]:
|
680 |
st.error("❌ Please add at least one food item before submitting")
|
681 |
else:
|
@@ -759,54 +577,4 @@ if st.sidebar.button("Token Rewards System"):
|
|
759 |
if st.sidebar.button("Terms of Service"):
|
760 |
with open("TERMS_OF_SERVICE.md", "r") as f:
|
761 |
terms = f.read()
|
762 |
-
st.sidebar.markdown(terms)
|
763 |
-
|
764 |
-
# Add Cleanup Tools for Debug Mode
|
765 |
-
if debug_mode and st.sidebar.checkbox("Show Cleanup Tools"):
|
766 |
-
st.sidebar.markdown("---")
|
767 |
-
st.sidebar.subheader("🧹 Debug Cleanup Tools")
|
768 |
-
|
769 |
-
with st.sidebar.expander("⚠️ Cleanup Test Data"):
|
770 |
-
st.sidebar.warning("This will delete all test records from DynamoDB and S3")
|
771 |
-
if st.sidebar.button("Delete All Test Records"):
|
772 |
-
try:
|
773 |
-
# Scan for test records in DynamoDB
|
774 |
-
from boto3.dynamodb.conditions import Attr
|
775 |
-
|
776 |
-
response = metadata_table.scan(
|
777 |
-
FilterExpression=Attr('food_name').begins_with('TEST_')
|
778 |
-
)
|
779 |
-
|
780 |
-
total_records = 0
|
781 |
-
deleted_records = 0
|
782 |
-
s3_paths = []
|
783 |
-
|
784 |
-
# Delete each record and collect S3 paths
|
785 |
-
for item in response.get('Items', []):
|
786 |
-
total_records += 1
|
787 |
-
try:
|
788 |
-
metadata_table.delete_item(Key={'image_id': item['image_id']})
|
789 |
-
deleted_records += 1
|
790 |
-
s3_paths.append(item['s3_path'])
|
791 |
-
except Exception as e:
|
792 |
-
st.sidebar.error(f"Failed to delete record {item['image_id']}: {e}")
|
793 |
-
|
794 |
-
# Delete S3 objects
|
795 |
-
for s3_path in set(s3_paths): # Use set to remove duplicates
|
796 |
-
try:
|
797 |
-
s3.delete_object(Bucket=S3_BUCKET_NAME, Key=s3_path)
|
798 |
-
except Exception as e:
|
799 |
-
st.sidebar.error(f"Failed to delete S3 object {s3_path}: {e}")
|
800 |
-
|
801 |
-
st.sidebar.success(f"Deleted {deleted_records}/{total_records} test records and their S3 objects")
|
802 |
-
except Exception as e:
|
803 |
-
st.sidebar.error(f"Cleanup error: {e}")
|
804 |
-
|
805 |
-
|
806 |
-
# Add Debug Info Panel at the end of your app
|
807 |
-
if debug_mode and "test_debug_details" in st.session_state and st.session_state["test_debug_details"]:
|
808 |
-
with st.expander("🔍 DEBUG: Last Test Results"):
|
809 |
-
st.json(st.session_state["test_debug_details"])
|
810 |
-
if st.button("Clear Debug History"):
|
811 |
-
st.session_state["test_debug_details"] = []
|
812 |
-
st.rerun()
|
|
|
15 |
import streamlit_tags as st_tags
|
16 |
from dotenv import load_dotenv
|
17 |
|
|
|
|
|
|
|
18 |
# Load environment variables from .env file if it exists
|
19 |
load_dotenv()
|
20 |
|
|
|
190 |
quality = 95 if folder == "raw-uploads" else 85
|
191 |
image.save(buffer, format="JPEG", quality=quality, optimize=True)
|
192 |
buffer.seek(0)
|
|
|
|
|
|
|
|
|
193 |
|
194 |
# Upload to S3
|
195 |
s3.upload_fileobj(buffer, S3_BUCKET_NAME, s3_path)
|
|
|
226 |
's3_path': s3_path,
|
227 |
'tokens_awarded': tokens_awarded
|
228 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
229 |
|
230 |
# Save to DynamoDB
|
231 |
metadata_table.put_item(Item=item)
|
|
|
326 |
del st.session_state["user_id"]
|
327 |
st.sidebar.success("✅ Logged out successfully!")
|
328 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
329 |
# Ensure user is logged in before uploading
|
330 |
if "user_id" not in st.session_state and not st.session_state.get("demo_mode", False):
|
331 |
st.warning("⚠️ Please log in to upload images.")
|
|
|
412 |
if size_reduction > 5: # Only show if there's a meaningful reduction
|
413 |
st.success(f"✅ Image size reduced by {size_reduction:.1f}% for faster uploads and processing")
|
414 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
415 |
# Display existing food annotations if any
|
416 |
if st.session_state["food_items"]:
|
417 |
st.subheader("📋 Added Food Items")
|
|
|
494 |
|
495 |
# Submit all foods button - outside the form
|
496 |
if st.button("📤 Submit All Food Items", disabled=len(st.session_state["food_items"]) == 0):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
497 |
if not st.session_state["food_items"]:
|
498 |
st.error("❌ Please add at least one food item before submitting")
|
499 |
else:
|
|
|
577 |
if st.sidebar.button("Terms of Service"):
|
578 |
with open("TERMS_OF_SERVICE.md", "r") as f:
|
579 |
terms = f.read()
|
580 |
+
st.sidebar.markdown(terms)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|