demo_app.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import streamlit as st
  2. import requests
  3. from PIL import Image
  4. import io
  5. import base64
  6. # --- API Configuration ---
  7. API_BASE_URL = "http://localhost:8000"
  8. # --- Page Config ---
  9. st.set_page_config(page_title="Palm Oil Ripeness AI", layout="wide")
  10. st.title("🌴 Palm Oil FFB Management System")
  11. st.markdown("### Production-Ready AI Analysis & Archival")
  12. # --- Sidebar ---
  13. st.sidebar.header("Backend Controls")
  14. def update_confidence():
  15. new_conf = st.session_state.conf_slider
  16. try:
  17. requests.post(f"{API_BASE_URL}/set_confidence", json={"threshold": new_conf})
  18. st.toast(f"Threshold updated to {new_conf}")
  19. except:
  20. st.sidebar.error("Failed to update threshold")
  21. try:
  22. response = requests.get(f"{API_BASE_URL}/get_confidence")
  23. if response.status_code == 200:
  24. current_conf = response.json().get("current_confidence", 0.25)
  25. st.sidebar.success(f"Connected to API")
  26. # Synchronized Slider
  27. st.sidebar.slider(
  28. "Confidence Threshold",
  29. 0.1, 1.0,
  30. value=float(current_conf),
  31. key="conf_slider",
  32. on_change=update_confidence
  33. )
  34. else:
  35. st.sidebar.error("API Error")
  36. except:
  37. st.sidebar.error("Could not connect to Backend API. Please ensure it is running.")
  38. # --- Tabs ---
  39. tab1, tab2, tab3 = st.tabs(["Single Analysis", "Batch Processing", "Similarity Search"])
  40. # --- Tab 1: Single Analysis ---
  41. with tab1:
  42. st.subheader("Analyze Single Bunch")
  43. uploaded_file = st.file_uploader("Upload a bunch image...", type=["jpg", "jpeg", "png"], key="single")
  44. if uploaded_file:
  45. col1, col2 = st.columns(2)
  46. with col1:
  47. st.image(uploaded_file, caption="Input", use_container_width=True)
  48. with col2:
  49. if st.button("Run Full Analysis"):
  50. with st.spinner("Processing... (Detecting + Vectorizing + Archiving)"):
  51. files = {"file": (uploaded_file.name, uploaded_file.getvalue(), uploaded_file.type)}
  52. res = requests.post(f"{API_BASE_URL}/analyze", files=files)
  53. if res.status_code == 200:
  54. data = res.json()
  55. st.success(f"✅ Record Archived! ID: {data['record_id']}")
  56. for det in data['detections']:
  57. st.info(f"**{det['class']}** - {det['confidence']:.2%} confidence")
  58. else:
  59. st.error(f"Analysis Failed: {res.text}")
  60. # --- Tab 2: Batch Processing ---
  61. with tab2:
  62. st.subheader("Bulk Analysis")
  63. uploaded_files = st.file_uploader("Upload multiple images...", type=["jpg", "jpeg", "png"], accept_multiple_files=True, key="batch")
  64. if uploaded_files:
  65. if st.button(f"Process {len(uploaded_files)} Images"):
  66. with st.spinner("Batch Processing in progress..."):
  67. files = [("files", (f.name, f.getvalue(), f.type)) for f in uploaded_files]
  68. res = requests.post(f"{API_BASE_URL}/analyze_batch", files=files)
  69. if res.status_code == 200:
  70. data = res.json()
  71. st.success(f"Successfully processed {data['processed_count']} images.")
  72. st.write("Generated Record IDs:")
  73. st.code(data['record_ids'])
  74. else:
  75. st.error("Batch Failed")
  76. # --- Tab 3: Similarity Search ---
  77. with tab3:
  78. st.subheader("Atlas Vector Search")
  79. st.markdown("Upload an image to find the most similar historical records in the database.")
  80. search_file = st.file_uploader("Search Image...", type=["jpg", "jpeg", "png"], key="search")
  81. if search_file:
  82. st.image(search_file, width=300)
  83. if st.button("Find Similar Bunches"):
  84. with st.spinner("Searching Vector Index..."):
  85. files = {"file": (search_file.name, search_file.getvalue(), search_file.type)}
  86. res = requests.post(f"{API_BASE_URL}/search", files=files)
  87. if res.status_code == 200:
  88. results = res.json().get("results", [])
  89. if not results:
  90. st.warning("No similar records found.")
  91. else:
  92. for item in results:
  93. with st.container(border=True):
  94. c1, c2 = st.columns([1, 2])
  95. # Note: Actual prod app would fetch image_data by id here
  96. # For demo, we show the textual metadata
  97. with c2:
  98. st.write(f"**Class:** {item['ripeness_class']}")
  99. st.write(f"**Similarity Score:** {item['score']:.4f}")
  100. st.write(f"**Timestamp:** {item['timestamp']}")
  101. else:
  102. st.error("Search failed")