Update app.py
Browse files
app.py
CHANGED
|
@@ -728,63 +728,111 @@ with st.sidebar:
|
|
| 728 |
|
| 729 |
# 7) Pages implementation
|
| 730 |
def landing_page():
|
| 731 |
-
# Background hero
|
| 732 |
-
BACKGROUND_URL = "/app/background_placeholder.jpg" #
|
|
|
|
|
|
|
| 733 |
st.markdown(f"""
|
| 734 |
<div style="
|
| 735 |
background-image: url('{BACKGROUND_URL}');
|
| 736 |
background-size: cover;
|
| 737 |
background-position: center;
|
| 738 |
-
padding:
|
| 739 |
-
border-radius:
|
| 740 |
-
margin-bottom:
|
| 741 |
position: relative;
|
|
|
|
| 742 |
">
|
| 743 |
-
<div style="background: rgba(
|
| 744 |
-
|
| 745 |
-
|
| 746 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 747 |
</p>
|
| 748 |
-
<div style='margin-top:
|
| 749 |
-
Quick: Classifier β’ GSD β’ Locator β’ RAG β’ Reports
|
| 750 |
</div>
|
| 751 |
</div>
|
| 752 |
</div>
|
| 753 |
""", unsafe_allow_html=True)
|
| 754 |
|
| 755 |
-
|
| 756 |
-
|
| 757 |
-
|
| 758 |
-
|
| 759 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 760 |
st.markdown("---")
|
|
|
|
|
|
|
| 761 |
col1, col2 = st.columns([2,1])
|
|
|
|
| 762 |
with col1:
|
| 763 |
st.markdown("<div class='gm-card'>", unsafe_allow_html=True)
|
| 764 |
-
st.write("GeoMate is built to help geotechnical engineers
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 765 |
st.markdown("</div>", unsafe_allow_html=True)
|
| 766 |
-
|
| 767 |
-
|
| 768 |
-
|
| 769 |
-
|
| 770 |
-
|
| 771 |
-
|
| 772 |
-
|
| 773 |
-
|
| 774 |
-
|
| 775 |
-
|
| 776 |
-
|
| 777 |
-
|
| 778 |
-
|
| 779 |
-
|
| 780 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 781 |
with col2:
|
| 782 |
-
st.markdown("<div class='gm-card' style='text-align:center'>", unsafe_allow_html=True)
|
| 783 |
-
st.markdown("<h3 style='color:#FF8C00'>Live Site Summary</h3>", unsafe_allow_html=True)
|
| 784 |
site = st.session_state["sites"][st.session_state["active_site"]]
|
| 785 |
-
st.
|
| 786 |
-
|
| 787 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 788 |
st.markdown("</div>", unsafe_allow_html=True)
|
| 789 |
|
| 790 |
# Soil Classifier page (conversational, step-by-step)
|
|
@@ -1280,30 +1328,39 @@ def locator_page():
|
|
| 1280 |
# Render map and capture ROI (geemap only)
|
| 1281 |
# ----------------------------
|
| 1282 |
st.markdown("π Draw a polygon/rectangle/circle using the draw tool, then press **Compute Summaries**")
|
| 1283 |
-
|
| 1284 |
# Render the map inside Streamlit
|
| 1285 |
m.to_streamlit(height=600, responsive=True)
|
| 1286 |
|
| 1287 |
-
#
|
| 1288 |
-
|
| 1289 |
-
|
| 1290 |
-
|
| 1291 |
-
|
| 1292 |
-
|
| 1293 |
-
|
| 1294 |
-
|
| 1295 |
-
|
| 1296 |
-
|
| 1297 |
-
|
| 1298 |
-
|
| 1299 |
-
|
| 1300 |
-
|
| 1301 |
-
|
| 1302 |
-
|
| 1303 |
-
|
| 1304 |
-
|
| 1305 |
-
|
| 1306 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1307 |
|
| 1308 |
|
| 1309 |
# --- Compute Summaries ---
|
|
|
|
| 728 |
|
| 729 |
# 7) Pages implementation
|
| 730 |
def landing_page():
|
| 731 |
+
# Background hero image
|
| 732 |
+
BACKGROUND_URL = "/app/background_placeholder.jpg" # Replace with your image or URL
|
| 733 |
+
|
| 734 |
+
# -------------------- HERO SECTION --------------------
|
| 735 |
st.markdown(f"""
|
| 736 |
<div style="
|
| 737 |
background-image: url('{BACKGROUND_URL}');
|
| 738 |
background-size: cover;
|
| 739 |
background-position: center;
|
| 740 |
+
padding: 64px 32px;
|
| 741 |
+
border-radius: 16px;
|
| 742 |
+
margin-bottom: 24px;
|
| 743 |
position: relative;
|
| 744 |
+
box-shadow: 0 6px 24px rgba(0,0,0,0.4);
|
| 745 |
">
|
| 746 |
+
<div style="background: rgba(15,15,15,0.65);
|
| 747 |
+
padding:32px;
|
| 748 |
+
border-radius:14px;
|
| 749 |
+
max-width:980px;">
|
| 750 |
+
<h1 style='color:#FF8C00; font-size:42px; margin:0 0 12px'>
|
| 751 |
+
π GeoMate V2
|
| 752 |
+
</h1>
|
| 753 |
+
<p style='color:#f2f4f7; font-size:17px; margin:0 0 14px; line-height:1.6'>
|
| 754 |
+
Your AI Geotechnical Copilot β soil recognition, classification, locator (Google Earth Engine),
|
| 755 |
+
RAG-powered Q&A, and dynamic professional reports.
|
| 756 |
</p>
|
| 757 |
+
<div style='margin-top:10px; color:#d6d6d6; font-size:14px'>
|
| 758 |
+
π Quick: Classifier β’ GSD β’ Locator β’ RAG β’ OCR β’ Reports
|
| 759 |
</div>
|
| 760 |
</div>
|
| 761 |
</div>
|
| 762 |
""", unsafe_allow_html=True)
|
| 763 |
|
| 764 |
+
# -------------------- BRAND HEADER --------------------
|
| 765 |
+
st.markdown("""
|
| 766 |
+
<div style="display:flex;align-items:center;gap:16px; margin-bottom:14px">
|
| 767 |
+
<div style="width:80px;height:80px;
|
| 768 |
+
border-radius:16px;
|
| 769 |
+
background:linear-gradient(135deg,#ff7a00,#ff3a3a);
|
| 770 |
+
display:flex;align-items:center;justify-content:center;
|
| 771 |
+
box-shadow:0 6px 18px rgba(0,0,0,0.55)">
|
| 772 |
+
<span style='font-size:36px'>π°οΈ</span>
|
| 773 |
+
</div>
|
| 774 |
+
<div>
|
| 775 |
+
<h1 style='margin:0;color:#FF8C00;font-size:30px'>GeoMate V2</h1>
|
| 776 |
+
<div style='color:#888; font-size:14px'>
|
| 777 |
+
AI geotechnical copilot β smarter, faster & field-ready
|
| 778 |
+
</div>
|
| 779 |
+
</div>
|
| 780 |
+
</div>
|
| 781 |
+
""", unsafe_allow_html=True)
|
| 782 |
st.markdown("---")
|
| 783 |
+
|
| 784 |
+
# -------------------- CONTENT GRID --------------------
|
| 785 |
col1, col2 = st.columns([2,1])
|
| 786 |
+
|
| 787 |
with col1:
|
| 788 |
st.markdown("<div class='gm-card'>", unsafe_allow_html=True)
|
| 789 |
+
st.write("GeoMate is built to help geotechnical engineers streamline workflows:")
|
| 790 |
+
st.markdown("""
|
| 791 |
+
- π§ͺ **Soil Recognition & Classification** (USCS, AASHTO)
|
| 792 |
+
- π **Grain Size Distribution (GSD) Curve plotting**
|
| 793 |
+
- π **Earth Engine data fetch for sites**
|
| 794 |
+
- π€ **RAG + LLM Q&A** for textbook-driven answers
|
| 795 |
+
- π **Professional report generation** (PDF-ready)
|
| 796 |
+
- π· **OCR-based input from site drawings**
|
| 797 |
+
""")
|
| 798 |
st.markdown("</div>", unsafe_allow_html=True)
|
| 799 |
+
|
| 800 |
+
# Quick Actions as styled cards
|
| 801 |
+
st.markdown("### β‘ Quick Actions")
|
| 802 |
+
qa_cols = st.columns(3)
|
| 803 |
+
quick_actions = [
|
| 804 |
+
("π§ͺ", "Classifier", "Classifier"),
|
| 805 |
+
("π", "GSD Curve", "GSD"),
|
| 806 |
+
("π", "Locator", "Locator"),
|
| 807 |
+
("π€", "GeoMate Ask", "RAG"),
|
| 808 |
+
("π·", "OCR", "OCR"),
|
| 809 |
+
("π", "Reports", "Reports"),
|
| 810 |
+
]
|
| 811 |
+
for i, (icon, label, page) in enumerate(quick_actions):
|
| 812 |
+
with qa_cols[i % 3]:
|
| 813 |
+
if st.button(f"{icon} {label}", use_container_width=True):
|
| 814 |
+
st.session_state["page"] = page
|
| 815 |
+
st.rerun()
|
| 816 |
+
|
| 817 |
+
# -------------------- SITE SUMMARY --------------------
|
| 818 |
with col2:
|
|
|
|
|
|
|
| 819 |
site = st.session_state["sites"][st.session_state["active_site"]]
|
| 820 |
+
st.markdown("""
|
| 821 |
+
<div style="
|
| 822 |
+
background: #1e1e1e;
|
| 823 |
+
border-radius:14px;
|
| 824 |
+
padding:20px;
|
| 825 |
+
text-align:center;
|
| 826 |
+
box-shadow:0 4px 14px rgba(0,0,0,0.5);
|
| 827 |
+
">
|
| 828 |
+
<h3 style='color:#FF8C00; margin:0 0 10px'>π Live Site Summary</h3>
|
| 829 |
+
""", unsafe_allow_html=True)
|
| 830 |
+
|
| 831 |
+
st.write(f"ποΈ **Site:** {site.get('Site Name')}")
|
| 832 |
+
st.write(f"π§± **USCS:** {site.get('USCS', 'β')}")
|
| 833 |
+
st.write(f"π£οΈ **AASHTO:** {site.get('AASHTO', 'β')}")
|
| 834 |
+
st.write(f"π **GSD saved:** {'β
Yes' if site.get('GSD') else 'β No'}")
|
| 835 |
+
|
| 836 |
st.markdown("</div>", unsafe_allow_html=True)
|
| 837 |
|
| 838 |
# Soil Classifier page (conversational, step-by-step)
|
|
|
|
| 1328 |
# Render map and capture ROI (geemap only)
|
| 1329 |
# ----------------------------
|
| 1330 |
st.markdown("π Draw a polygon/rectangle/circle using the draw tool, then press **Compute Summaries**")
|
| 1331 |
+
|
| 1332 |
# Render the map inside Streamlit
|
| 1333 |
m.to_streamlit(height=600, responsive=True)
|
| 1334 |
|
| 1335 |
+
# ----------------------------
|
| 1336 |
+
# ROI capture helper
|
| 1337 |
+
# ----------------------------
|
| 1338 |
+
def get_roi_from_map():
|
| 1339 |
+
"""Return ee.Geometry or None if no ROI drawn"""
|
| 1340 |
+
if m.draw_features:
|
| 1341 |
+
try:
|
| 1342 |
+
last_feature = m.draw_features[-1] # last drawn geometry
|
| 1343 |
+
if isinstance(last_feature, dict):
|
| 1344 |
+
geom = last_feature.get("geometry") or last_feature
|
| 1345 |
+
st.session_state["roi_geojson"] = json.dumps(last_feature)
|
| 1346 |
+
return ee.Geometry(geom)
|
| 1347 |
+
except Exception as e:
|
| 1348 |
+
st.warning(f"Could not parse drawn ROI: {e}")
|
| 1349 |
+
return None
|
| 1350 |
+
elif "roi_geojson" in st.session_state:
|
| 1351 |
+
# Restore ROI if already saved in session
|
| 1352 |
+
try:
|
| 1353 |
+
geom = json.loads(st.session_state["roi_geojson"]).get("geometry")
|
| 1354 |
+
return ee.Geometry(geom)
|
| 1355 |
+
except Exception:
|
| 1356 |
+
return None
|
| 1357 |
+
return None
|
| 1358 |
+
|
| 1359 |
+
# Call helper immediately to update ROI
|
| 1360 |
+
roi = get_roi_from_map()
|
| 1361 |
+
if roi:
|
| 1362 |
+
st.success("ROI captured successfully β
")
|
| 1363 |
+
|
| 1364 |
|
| 1365 |
|
| 1366 |
# --- Compute Summaries ---
|