MSU576 commited on
Commit
a13e5e8
·
verified ·
1 Parent(s): 3b82845

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +157 -63
app.py CHANGED
@@ -164,8 +164,9 @@ def soil_recognizer_page():
164
  st.write(f"{cls}: {score:.2%}")
165
 
166
  if st.button("Save to site"):
167
- site["Soil Profile"] = predicted_class
168
- site["Soil Recognizer Confidence"] = confidence_scores[predicted_class]
 
169
  save_active_site(site)
170
  st.success("Saved prediction to active site memory.")
171
 
@@ -595,43 +596,49 @@ def build_full_geotech_pdf(site: Dict[str, Any], filename: str, include_map_imag
595
  if "sites" not in st.session_state:
596
  # initialize with a default site
597
  st.session_state["sites"] = [{
598
- "Soil Profile": None,
 
 
599
  "Soil Recognizer Confidence": None,
600
- "Site Name":"Home",
601
- "Project Name":"Demo Project",
602
- "Site ID": 0,
603
- "Coordinates":"",
604
  "lat": None,
605
  "lon": None,
606
- "Project Description":"",
607
- "Topography":"",
608
- "Drainage":"",
609
- "Current Land Use":"",
610
- "Regional Geology":"",
 
 
611
  "Field Investigation": [],
612
  "Laboratory Results": [],
613
  "GSD": None,
614
  "USCS": None,
615
  "AASHTO": None,
616
  "GI": None,
 
617
  "Load Bearing Capacity": None,
618
  "Skin Shear Strength": None,
619
  "Relative Compaction": None,
620
  "Rate of Consolidation": None,
621
- "Nature of Construction": None,
622
- "Soil Profile": None,
623
- "Flood Data": None,
624
- "Seismic Data": None,
625
- "Environmental Data": None,
626
- "Topo Data": None,
 
 
627
  "map_snapshot": None,
 
628
  "chat_history": [],
629
  "classifier_inputs": {},
630
  "classifier_decision": None,
631
  "report_convo_state": 0,
632
  "report_missing_fields": [],
633
  "report_answers": {}
634
- }]
635
 
636
  if "active_site" not in st.session_state:
637
  st.session_state["active_site"] = 0
@@ -706,31 +713,39 @@ with st.sidebar:
706
  "Site Name": new_site_name.strip(),
707
  "Project Name": "Project - " + new_site_name.strip(),
708
  "Site ID": idx,
709
- "Coordinates":"",
 
 
710
  "lat": None,
711
  "lon": None,
712
- "Project Description":"",
713
- "Topography":"",
714
- "Drainage":"",
715
- "Current Land Use":"",
716
- "Regional Geology":"",
 
 
717
  "Field Investigation": [],
718
  "Laboratory Results": [],
719
  "GSD": None,
720
  "USCS": None,
721
  "AASHTO": None,
722
  "GI": None,
 
723
  "Load Bearing Capacity": None,
724
  "Skin Shear Strength": None,
725
  "Relative Compaction": None,
726
  "Rate of Consolidation": None,
727
- "Nature of Construction": None,
728
- "Soil Profile": None,
729
- "Flood Data": None,
730
- "Seismic Data": None,
731
- "Environmental Data": None,
732
- "Topo Data": None,
 
 
733
  "map_snapshot": None,
 
734
  "chat_history": [],
735
  "classifier_inputs": {},
736
  "classifier_decision": None,
@@ -738,6 +753,7 @@ with st.sidebar:
738
  "report_missing_fields": [],
739
  "report_answers": {}
740
  })
 
741
  st.success(f"Site '{new_site_name.strip()}' created.")
742
  st.session_state["active_site"] = idx
743
  st.rerun()
@@ -993,47 +1009,125 @@ def ocr_page():
993
  def locator_page():
994
  st.header("🌍 Locator — Select Area of Interest")
995
  site = st.session_state["sites"][st.session_state["active_site"]]
 
996
  st.markdown("You can enter coordinates manually or draw/upload a GeoJSON boundary (draw-mode not available in this minimal example).")
 
997
  lat = st.number_input("Latitude", value=site.get("lat") or 0.0, format="%.6f", key="locator_lat")
998
  lon = st.number_input("Longitude", value=site.get("lon") or 0.0, format="%.6f", key="locator_lon")
999
  site["lat"] = lat; site["lon"] = lon
 
1000
  if st.button("Fetch Earth Data (EE)"):
1001
  if not EE_AVAILABLE:
1002
- st.error("Earth Engine/Geemap not available in this environment. Please add geemap & earthengine-api to requirements.")
1003
  else:
1004
  try:
1005
- # Initialize EE if needed
1006
  if not ee.data._credentials:
1007
- # try to authenticate via service account string in env
1008
- ee_key_json = os.environ.get("EARTH_ENGINE_KEY")
1009
- # if provided as JSON string, write to temp file
1010
- tmp = tempfile.NamedTemporaryFile(mode="w+", delete=False, suffix=".json")
1011
- tmp.write(ee_key_json)
1012
- tmp.flush()
1013
- ee.Initialize(service_account=os.environ.get("SERVICE_ACCOUNT"), private_key_json=tmp.name)
1014
- # sample calls (very simple placeholders)
1015
- st.info("Querying Earth Engine for available layers (this may take a few seconds)...")
1016
- # NOTE: Detailed real EE reducers and datasets must be added for production.
1017
- # We'll store placeholder results and attempt to create a simple map snapshot.
1018
- site["Soil Profile"] = f"Colluvial soils over dolomite (fetched {datetime.today().date()})"
1019
- site["Flood Data"] = "No major floods in last 20 years (placeholder)"
1020
- site["Seismic Data"] = "Seismic zone: Moderate; historic events: low"
1021
- site["Environmental Data"] = "No major environmental constraints found (placeholder)"
1022
- site["Topo Data"] = "Gentle slope"
1023
- # Create a simple map via geemap and snapshot it
1024
- m = geemap.Map(center=[lat, lon], zoom=10)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1025
  m.add_basemap("SATELLITE")
1026
- # capture map to PNG (geemap has method to export html; we use to_image if available)
1027
- try:
1028
- img = m.to_image()
1029
- buf = io.BytesIO()
1030
- img.save(buf, format="PNG")
1031
- img_bytes = buf.getvalue()
1032
- site["map_snapshot"] = img_bytes
1033
- st.image(img_bytes, caption="Map snapshot", use_column_width=True)
1034
- except Exception:
1035
- st.warning("Map snapshot not available in this environment.")
1036
- st.success("Earth Engine data fetched and saved to site (placeholders).")
 
 
 
 
 
 
 
 
1037
  except Exception as e:
1038
  st.error(f"Earth Engine error: {e}")
1039
 
@@ -1182,7 +1276,7 @@ page = st.session_state["page"]
1182
  selected = option_menu(
1183
  None,
1184
  ["Home","Soil recognizer","Classifier","GSD","OCR","Locator","RAG","Reports"],
1185
- icons=["house","graph","journal-code","bar-chart","camera","geo-alt","robot","file-earmark-text"],
1186
  menu_icon="cast",
1187
  default_index=["Home","Soil recognizer","Classifier","GSD","OCR","Locator","RAG","Reports"].index(page) if page in ["Home","Soil recognizer","Classifier","GSD","OCR","Locator","RAG","Reports"] else 0,
1188
  orientation="horizontal",
 
164
  st.write(f"{cls}: {score:.2%}")
165
 
166
  if st.button("Save to site"):
167
+ # Save predicted soil class into Soil Profile field
168
+ st.session_state["sites"][st.session_state["active_site"]]["Soil Class"] = predicted_class
169
+ st.session_state["sites"][st.session_state["active_site"]]"Soil Recognizer Confidence"] = confidence_scores[predicted_class]
170
  save_active_site(site)
171
  st.success("Saved prediction to active site memory.")
172
 
 
596
  if "sites" not in st.session_state:
597
  # initialize with a default site
598
  st.session_state["sites"] = [{
599
+ "Site Name":"home",
600
+ "Project Name": "Project ",
601
+ "Soil Class": None,
602
  "Soil Recognizer Confidence": None,
603
+ "Site ID": idx,
604
+ "Coordinates": "",
 
 
605
  "lat": None,
606
  "lon": None,
607
+ "Project Description": "",
608
+ # Site Characterization
609
+ "Topography": None, # manual / descriptive topo entry
610
+ "Drainage": None, # manual drainage notes
611
+ "Current Land Use": None, # can be linked to Environmental Data
612
+ "Regional Geology": None, # manual geology notes
613
+ # Investigations & Lab
614
  "Field Investigation": [],
615
  "Laboratory Results": [],
616
  "GSD": None,
617
  "USCS": None,
618
  "AASHTO": None,
619
  "GI": None,
620
+ # Geotechnical Parameters
621
  "Load Bearing Capacity": None,
622
  "Skin Shear Strength": None,
623
  "Relative Compaction": None,
624
  "Rate of Consolidation": None,
625
+ "Nature of Construction": None
626
+ # Earth Engine Data
627
+ "Soil Profile": None, # SoilGrids (clay/sand/silt etc.)
628
+ "Flood Data": None, # JRC Global Surface Water
629
+ "Seismic Data": None, # GSHAP Seismic hazard
630
+ "Environmental Data": None, # Landcover, forest loss, urban
631
+ "Topo Data": None, # SRTM DEM elevation
632
+ # Map & Visualization
633
  "map_snapshot": None,
634
+ # AI / Reporting
635
  "chat_history": [],
636
  "classifier_inputs": {},
637
  "classifier_decision": None,
638
  "report_convo_state": 0,
639
  "report_missing_fields": [],
640
  "report_answers": {}
641
+ })
642
 
643
  if "active_site" not in st.session_state:
644
  st.session_state["active_site"] = 0
 
713
  "Site Name": new_site_name.strip(),
714
  "Project Name": "Project - " + new_site_name.strip(),
715
  "Site ID": idx,
716
+ "Soil Class": None,
717
+ "Soil Recognizer Confidence": None,
718
+ "Coordinates": "",
719
  "lat": None,
720
  "lon": None,
721
+ "Project Description": "",
722
+ # Site Characterization
723
+ "Topography": None, # manual / descriptive topo entry
724
+ "Drainage": None, # manual drainage notes
725
+ "Current Land Use": None, # can be linked to Environmental Data
726
+ "Regional Geology": None, # manual geology notes
727
+ # Investigations & Lab
728
  "Field Investigation": [],
729
  "Laboratory Results": [],
730
  "GSD": None,
731
  "USCS": None,
732
  "AASHTO": None,
733
  "GI": None,
734
+ # Geotechnical Parameters
735
  "Load Bearing Capacity": None,
736
  "Skin Shear Strength": None,
737
  "Relative Compaction": None,
738
  "Rate of Consolidation": None,
739
+ "Nature of Construction": None
740
+ # Earth Engine Data
741
+ "Soil Profile": None, # SoilGrids (clay/sand/silt etc.)
742
+ "Flood Data": None, # JRC Global Surface Water
743
+ "Seismic Data": None, # GSHAP Seismic hazard
744
+ "Environmental Data": None, # Landcover, forest loss, urban
745
+ "Topo Data": None, # SRTM DEM elevation
746
+ # Map & Visualization
747
  "map_snapshot": None,
748
+ # AI / Reporting
749
  "chat_history": [],
750
  "classifier_inputs": {},
751
  "classifier_decision": None,
 
753
  "report_missing_fields": [],
754
  "report_answers": {}
755
  })
756
+
757
  st.success(f"Site '{new_site_name.strip()}' created.")
758
  st.session_state["active_site"] = idx
759
  st.rerun()
 
1009
  def locator_page():
1010
  st.header("🌍 Locator — Select Area of Interest")
1011
  site = st.session_state["sites"][st.session_state["active_site"]]
1012
+
1013
  st.markdown("You can enter coordinates manually or draw/upload a GeoJSON boundary (draw-mode not available in this minimal example).")
1014
+
1015
  lat = st.number_input("Latitude", value=site.get("lat") or 0.0, format="%.6f", key="locator_lat")
1016
  lon = st.number_input("Longitude", value=site.get("lon") or 0.0, format="%.6f", key="locator_lon")
1017
  site["lat"] = lat; site["lon"] = lon
1018
+
1019
  if st.button("Fetch Earth Data (EE)"):
1020
  if not EE_AVAILABLE:
1021
+ st.error("Earth Engine/Geemap not available in this environment. Please add `geemap` & `earthengine-api` to requirements.txt.")
1022
  else:
1023
  try:
1024
+ # Initialize Earth Engine with service account if not already
1025
  if not ee.data._credentials:
1026
+ ee_key_json = os.environ.get("EARTHENGINE_TOKEN")
1027
+ if ee_key_json:
1028
+ token_dict = json.loads(ee_key_json)
1029
+ ee.Initialize(credentials=ee.ServiceAccountCredentials(
1030
+ email=token_dict["client_email"],
1031
+ key_data=json.dumps(token_dict)
1032
+ ))
1033
+ else:
1034
+ st.error("No Earth Engine credentials found.")
1035
+ return
1036
+
1037
+ st.info("Querying Earth Engine datasets... (this may take a few seconds)")
1038
+
1039
+ # ----------------------------
1040
+ # DEM / Topography (SRTM)
1041
+ # ----------------------------
1042
+ dem = ee.Image("USGS/SRTMGL1_003")
1043
+ elevation = dem.sample(region=ee.Geometry.Point([lon, lat]), scale=30).first().get("elevation").getInfo()
1044
+ site["Topo Data"] = f"Elevation: {elevation:.1f} m (from SRTM DEM)"
1045
+
1046
+ # ----------------------------
1047
+ # Flood (JRC Global Surface Water)
1048
+ # ----------------------------
1049
+ gsw = ee.Image("JRC/GSW1_4/GlobalSurfaceWater").select("occurrence")
1050
+ flood_val = gsw.sample(region=ee.Geometry.Point([lon, lat]), scale=30).first().get("occurrence").getInfo()
1051
+ site["Flood Data"] = f"Flood occurrence probability: {flood_val:.1f}%"
1052
+
1053
+ # ----------------------------
1054
+ # Soil (SoilGrids250m from ISRIC)
1055
+ # ----------------------------
1056
+ soil = ee.Image("ISRIC/SoilGrids/2017/original").select("clay_0-5cm_mean")
1057
+ soil_val = soil.sample(region=ee.Geometry.Point([lon, lat]), scale=250).first().get("clay_0-5cm_mean").getInfo()
1058
+ site["Soil Profile"] = f"Surface clay content: {soil_val:.1f} g/kg (SoilGrids)"
1059
+
1060
+ # ----------------------------
1061
+ # Seismic (GSHAP Global Seismic Hazard)
1062
+ # ----------------------------
1063
+ seismic = ee.Image("SEDAC/GSHAPSeismicHazard")
1064
+ seis_val = seismic.sample(region=ee.Geometry.Point([lon, lat]), scale=1000).first().get("gshap").getInfo()
1065
+ site["Seismic Data"] = f"Seismic hazard (PGA, g): {seis_val:.3f}"
1066
+
1067
+ # ----------------------------
1068
+ # Environmental (Landcover, Deforestation, Urbanization)
1069
+ # ----------------------------
1070
+
1071
+ # 1. ESA WorldCover 2020 landcover class
1072
+ landcover = ee.ImageCollection("ESA/WorldCover/v200").first()
1073
+ lc_val = landcover.sample(region=ee.Geometry.Point([lon, lat]), scale=10).first().get("Map").getInfo()
1074
+ landcover_dict = {
1075
+ 10: "Tree Cover",
1076
+ 20: "Shrubland",
1077
+ 30: "Grassland",
1078
+ 40: "Cropland",
1079
+ 50: "Built-up",
1080
+ 60: "Bare / Sparse vegetation",
1081
+ 70: "Snow and Ice",
1082
+ 80: "Permanent Water",
1083
+ 90: "Herbaceous Wetland",
1084
+ 95: "Mangroves",
1085
+ 100: "Moss & Lichen"
1086
+ }
1087
+ lc_class = landcover_dict.get(lc_val, "Unknown")
1088
+
1089
+ # 2. Hansen Forest Loss (2001–2021)
1090
+ forest = ee.Image("UMD/hansen/global_forest_change_2021_v1_9").select("loss")
1091
+ forest_loss = forest.sample(region=ee.Geometry.Point([lon, lat]), scale=30).first().get("loss").getInfo()
1092
+ forest_status = "Recent forest loss detected" if forest_loss == 1 else "No forest loss detected"
1093
+
1094
+ # 3. Urban footprint (GHSL built-up)
1095
+ urban = ee.Image("JRC/GHSL/P2016/BUILT_LDSMT_GLOBE_V1").select("built")
1096
+ urban_val = urban.sample(region=ee.Geometry.Point([lon, lat]), scale=250).first().get("built").getInfo()
1097
+ urban_status = "Urban area" if urban_val == 1 else "Non-urban area"
1098
+
1099
+ # Combine environmental info
1100
+ site["Environmental Data"] = (
1101
+ f"Landcover: {lc_class}; "
1102
+ f"{forest_status};
1103
+ f"{urban_status}."
1104
+ )
1105
+
1106
+
1107
+ # ----------------------------
1108
+ # Map Display
1109
+ # ----------------------------
1110
+ m = geemap.Map(center=[lat, lon], zoom=8)
1111
  m.add_basemap("SATELLITE")
1112
+
1113
+ # Add layers with visualization params
1114
+ m.addLayer(dem, {"min": 0, "max": 3000, "palette": ["blue", "green", "brown", "white"]}, "DEM")
1115
+ m.addLayer(gsw, {"min": 0, "max": 100, "palette": ["white", "blue"]}, "Flood Occurrence")
1116
+ m.addLayer(soil, {"min": 0, "max": 600, "palette": ["yellow", "brown", "red"]}, "Soil Clay (0-5cm)")
1117
+ m.addLayer(seismic, {"min": 0, "max": 1, "palette": ["green", "yellow", "red"]}, "Seismic Hazard")
1118
+ m.addLayer(landcover, {"min": 10, "max": 100, "palette": ["006400","ffbb22","ffff4c","f096ff","fa0000","b4b4b4","f0f0f0","0064c8","0096a0","00cf75","fae6a0"]}, "Landcover")
1119
+ m.addLayer(forest, {"palette":["white","green"]}, "Forest Loss")
1120
+ m.addLayer(urban, {"min":0,"max":1,"palette":["white","black"]}, "Urban Footprint")
1121
+
1122
+ m.addLayerControl()
1123
+
1124
+ # Save to /tmp and embed in Streamlit
1125
+ map_file = "/tmp/locator_map.html"
1126
+ m.to_html(map_file)
1127
+ st.components.v1.html(open(map_file, "r").read(), height=600)
1128
+
1129
+ st.success("✅ Earth Engine data fetched and saved to site!")
1130
+
1131
  except Exception as e:
1132
  st.error(f"Earth Engine error: {e}")
1133
 
 
1276
  selected = option_menu(
1277
  None,
1278
  ["Home","Soil recognizer","Classifier","GSD","OCR","Locator","RAG","Reports"],
1279
+ icons=["house","chart","journal-code","bar-chart","camera","geo-alt","robot","file-earmark-text"],
1280
  menu_icon="cast",
1281
  default_index=["Home","Soil recognizer","Classifier","GSD","OCR","Locator","RAG","Reports"].index(page) if page in ["Home","Soil recognizer","Classifier","GSD","OCR","Locator","RAG","Reports"] else 0,
1282
  orientation="horizontal",