Update app.py
Browse files
app.py
CHANGED
|
@@ -1006,213 +1006,6 @@ def ocr_page():
|
|
| 1006 |
else:
|
| 1007 |
st.warning("OCR not available in this deployment.")
|
| 1008 |
|
| 1009 |
-
# Locator Page (Earth Engine integration)
|
| 1010 |
-
import streamlit as st
|
| 1011 |
-
import geemap.foliumap as geemap
|
| 1012 |
-
import ee
|
| 1013 |
-
import matplotlib.pyplot as plt
|
| 1014 |
-
# ----------------------------
|
| 1015 |
-
# Authenticate Earth Engine
|
| 1016 |
-
# ----------------------------
|
| 1017 |
-
EE_JSON = os.getenv("EARTHENGINE_TOKEN")
|
| 1018 |
-
|
| 1019 |
-
if EE_JSON:
|
| 1020 |
-
try:
|
| 1021 |
-
creds = ee.ServiceAccountCredentials(
|
| 1022 |
-
email=os.getenv("SERVICE_ACCOUNT"), # <-- replace with your service account email
|
| 1023 |
-
key_data=EE_JSON # pass raw JSON string, not dict
|
| 1024 |
-
)
|
| 1025 |
-
ee.Initialize(creds)
|
| 1026 |
-
except Exception as e:
|
| 1027 |
-
st.error(f"❌ Failed to initialize Earth Engine: {e}")
|
| 1028 |
-
else:
|
| 1029 |
-
try:
|
| 1030 |
-
ee.Initialize() # fallback if running locally
|
| 1031 |
-
except Exception as e:
|
| 1032 |
-
st.error(f"❌ Local EE init failed: {e}")
|
| 1033 |
-
# Initialize Earth Engine if not already done
|
| 1034 |
-
if "ee_initialized" not in st.session_state:
|
| 1035 |
-
try:
|
| 1036 |
-
# Use service account credentials if available
|
| 1037 |
-
# ee.Initialize(credentials='persistent')
|
| 1038 |
-
ee.Initialize()
|
| 1039 |
-
except Exception:
|
| 1040 |
-
# Fallback to authentication flow
|
| 1041 |
-
ee.Authenticate()
|
| 1042 |
-
ee.Initialize()
|
| 1043 |
-
st.session_state["ee_initialized"] = True
|
| 1044 |
-
|
| 1045 |
-
def locator_page():
|
| 1046 |
-
st.title("🌍 GeoMate Interactive Earth Explorer")
|
| 1047 |
-
|
| 1048 |
-
# -------------------------------
|
| 1049 |
-
# Create Map
|
| 1050 |
-
# -------------------------------
|
| 1051 |
-
m = geemap.Map(center=[20, 78], zoom=3, draw_export=True)
|
| 1052 |
-
|
| 1053 |
-
# --- Add Multiple Basemaps ---
|
| 1054 |
-
basemaps = [
|
| 1055 |
-
"HYBRID", "ROADMAP", "TERRAIN", "SATELLITE",
|
| 1056 |
-
"Esri.WorldImagery", "Esri.WorldTopoMap", "Esri.WorldShadedRelief",
|
| 1057 |
-
"Esri.NatGeoWorldMap", "Esri.OceanBasemap",
|
| 1058 |
-
"CartoDB.Positron", "CartoDB.DarkMatter",
|
| 1059 |
-
"Stamen.Terrain", "Stamen.Watercolor",
|
| 1060 |
-
"OpenStreetMap",
|
| 1061 |
-
]
|
| 1062 |
-
for b in basemaps:
|
| 1063 |
-
try:
|
| 1064 |
-
m.add_basemap(b)
|
| 1065 |
-
except Exception:
|
| 1066 |
-
pass
|
| 1067 |
-
|
| 1068 |
-
# -------------------------------
|
| 1069 |
-
# Boundaries & Grid
|
| 1070 |
-
# -------------------------------
|
| 1071 |
-
countries = ee.FeatureCollection("USDOS/LSIB_SIMPLE/2017")
|
| 1072 |
-
m.addLayer(
|
| 1073 |
-
countries.style(**{"color": "black", "fillColor": "00000000", "width": 1}),
|
| 1074 |
-
{}, "Country Boundaries"
|
| 1075 |
-
)
|
| 1076 |
-
|
| 1077 |
-
states = ee.FeatureCollection("FAO/GAUL_SIMPLIFIED_500m/2015/level1")
|
| 1078 |
-
m.addLayer(
|
| 1079 |
-
states.style(**{"color": "purple", "fillColor": "00000000", "width": 0.5}),
|
| 1080 |
-
{}, "State/Province Boundaries"
|
| 1081 |
-
)
|
| 1082 |
-
|
| 1083 |
-
graticule = geemap.latlon_grid(5.0, region=ee.Geometry.Rectangle([-180, -90, 180, 90]))
|
| 1084 |
-
m.addLayer(graticule.style(**{"color": "gray", "width": 0.5}), {}, "Lat/Lon Grid")
|
| 1085 |
-
|
| 1086 |
-
# -------------------------------
|
| 1087 |
-
# Datasets
|
| 1088 |
-
# -------------------------------
|
| 1089 |
-
soil = ee.Image("OpenLandMap/SOL/SOL_CLAY-WFRACTION_USDA-4B1C_M/v01").select("b200")
|
| 1090 |
-
soil_vis = {"min": 0, "max": 60, "palette": ["yellow", "brown", "red"]}
|
| 1091 |
-
m.addLayer(soil, soil_vis, "Soil Clay (200cm)")
|
| 1092 |
-
|
| 1093 |
-
dem = ee.Image("USGS/SRTMGL1_003")
|
| 1094 |
-
dem_vis = {"min": 0, "max": 4000, "palette": ["blue", "green", "brown", "white"]}
|
| 1095 |
-
m.addLayer(dem, dem_vis, "Topography (SRTM DEM)")
|
| 1096 |
-
|
| 1097 |
-
seismic = ee.Image("GEM/2015/GlobalSeismicHazard").select("b0") # use band b0
|
| 1098 |
-
m.addLayer(seismic, {"min": 0, "max": 1, "palette": ["white", "red"]}, "Seismic Hazard")
|
| 1099 |
-
|
| 1100 |
-
water = ee.Image("JRC/GSW1_4/GlobalSurfaceWater").select("occurrence")
|
| 1101 |
-
flood_vis = {"min": 0, "max": 100, "palette": ["white", "blue"]}
|
| 1102 |
-
m.addLayer(water, flood_vis, "Flood Hazard")
|
| 1103 |
-
|
| 1104 |
-
landcover = ee.Image("ESA/WorldCover/v200/2021")
|
| 1105 |
-
landcover_vis = {
|
| 1106 |
-
"bands": ["Map"], "min": 10, "max": 100,
|
| 1107 |
-
"palette": [
|
| 1108 |
-
"006400", "ffbb22", "ffff4c", "f096ff", "fa0000",
|
| 1109 |
-
"b4b4b4", "f0f0f0", "0064c8", "0096a0", "00cf75"
|
| 1110 |
-
]
|
| 1111 |
-
}
|
| 1112 |
-
m.addLayer(landcover, landcover_vis, "Landcover 2021")
|
| 1113 |
-
|
| 1114 |
-
# -------------------------------
|
| 1115 |
-
# Drawing Instructions
|
| 1116 |
-
# -------------------------------
|
| 1117 |
-
st.markdown("👉 Use the **drawing tool** (polygon/rectangle) on the map to select a region.")
|
| 1118 |
-
m.add_draw_control(polyline=False, circle=False, circlemarker=False, rectangle=True, polygon=True)
|
| 1119 |
-
m.to_streamlit(height=700, responsive=True)
|
| 1120 |
-
|
| 1121 |
-
# -------------------------------
|
| 1122 |
-
# ROI Analysis
|
| 1123 |
-
# -------------------------------
|
| 1124 |
-
if m.user_roi is not None:
|
| 1125 |
-
roi = m.user_roi
|
| 1126 |
-
st.success("✅ Polygon selected!")
|
| 1127 |
-
|
| 1128 |
-
def safe_get(val):
|
| 1129 |
-
try:
|
| 1130 |
-
return round(val, 2) if val is not None else "N/A"
|
| 1131 |
-
except Exception:
|
| 1132 |
-
return "N/A"
|
| 1133 |
-
|
| 1134 |
-
# Soil
|
| 1135 |
-
soil_val = soil.reduceRegion(
|
| 1136 |
-
ee.Reducer.mean(), roi, 1000, 1e9
|
| 1137 |
-
).get("b200").getInfo()
|
| 1138 |
-
|
| 1139 |
-
# Elevation
|
| 1140 |
-
elev_val = dem.reduceRegion(
|
| 1141 |
-
ee.Reducer.mean(), roi, 1000, 1e9
|
| 1142 |
-
).get("elevation").getInfo()
|
| 1143 |
-
|
| 1144 |
-
# Seismic
|
| 1145 |
-
seismic_val = seismic.reduceRegion(
|
| 1146 |
-
ee.Reducer.mean(), roi, 5000, 1e9
|
| 1147 |
-
).get("b0").getInfo()
|
| 1148 |
-
|
| 1149 |
-
# Flood
|
| 1150 |
-
flood_val = water.reduceRegion(
|
| 1151 |
-
ee.Reducer.mean(), roi, 30, 1e9
|
| 1152 |
-
).get("occurrence").getInfo()
|
| 1153 |
-
|
| 1154 |
-
# Landcover Histogram
|
| 1155 |
-
lc_stats = landcover.reduceRegion(
|
| 1156 |
-
reducer=ee.Reducer.frequencyHistogram(),
|
| 1157 |
-
geometry=roi,
|
| 1158 |
-
scale=30,
|
| 1159 |
-
maxPixels=1e9
|
| 1160 |
-
).get("Map").getInfo()
|
| 1161 |
-
|
| 1162 |
-
# -------------------------------
|
| 1163 |
-
# UI Outputs
|
| 1164 |
-
# -------------------------------
|
| 1165 |
-
st.subheader("📊 Regional Data Summary")
|
| 1166 |
-
st.write(f"**Average Clay (200cm):** {safe_get(soil_val)} %")
|
| 1167 |
-
st.write(f"**Average Elevation:** {safe_get(elev_val)} m")
|
| 1168 |
-
st.write(f"**Seismic Hazard (PGA):** {safe_get(seismic_val)} g")
|
| 1169 |
-
st.write(f"**Flood Occurrence Probability:** {safe_get(flood_val)} %")
|
| 1170 |
-
|
| 1171 |
-
# Landcover chart
|
| 1172 |
-
if lc_stats:
|
| 1173 |
-
labels = [str(k) for k in lc_stats.keys()]
|
| 1174 |
-
values = list(lc_stats.values())
|
| 1175 |
-
fig, ax = plt.subplots(figsize=(6, 4))
|
| 1176 |
-
ax.pie(values, labels=labels, autopct="%1.1f%%", startangle=90)
|
| 1177 |
-
ax.set_title("Landcover Distribution")
|
| 1178 |
-
st.pyplot(fig)
|
| 1179 |
-
|
| 1180 |
-
# Soil histogram
|
| 1181 |
-
soil_hist = soil.reduceRegion(
|
| 1182 |
-
reducer=ee.Reducer.histogram(maxBuckets=10),
|
| 1183 |
-
geometry=roi,
|
| 1184 |
-
scale=1000,
|
| 1185 |
-
maxPixels=1e9
|
| 1186 |
-
).get("b200").getInfo()
|
| 1187 |
-
if soil_hist:
|
| 1188 |
-
fig, ax = plt.subplots(figsize=(6, 4))
|
| 1189 |
-
ax.bar(
|
| 1190 |
-
soil_hist["bucketMeans"], soil_hist["histogram"],
|
| 1191 |
-
width=2, color="brown", alpha=0.7
|
| 1192 |
-
)
|
| 1193 |
-
ax.set_xlabel("Clay fraction (%)")
|
| 1194 |
-
ax.set_ylabel("Pixel count")
|
| 1195 |
-
ax.set_title("Soil Clay Distribution")
|
| 1196 |
-
st.pyplot(fig)
|
| 1197 |
-
|
| 1198 |
-
# -------------------------------
|
| 1199 |
-
# Save to soil_json for reports
|
| 1200 |
-
# -------------------------------
|
| 1201 |
-
if "soil_json" not in st.session_state:
|
| 1202 |
-
st.session_state["soil_json"] = {}
|
| 1203 |
-
|
| 1204 |
-
st.session_state["soil_json"].update({
|
| 1205 |
-
"Soil": f"{safe_get(soil_val)} %",
|
| 1206 |
-
"Elevation": f"{safe_get(elev_val)} m",
|
| 1207 |
-
"Seismic Hazard": f"{safe_get(seismic_val)} g",
|
| 1208 |
-
"Flood Probability": f"{safe_get(flood_val)} %",
|
| 1209 |
-
"Landcover Stats": lc_stats if lc_stats else {}
|
| 1210 |
-
})
|
| 1211 |
-
st.success("📑 Data saved to soil_json for report integration!")
|
| 1212 |
-
|
| 1213 |
-
else:
|
| 1214 |
-
st.warning("⚠️ No polygon selected yet.")
|
| 1215 |
-
|
| 1216 |
|
| 1217 |
# GeoMate Ask (RAG) — simple chat with memory per site and auto-extract numeric values
|
| 1218 |
def rag_page():
|
|
|
|
| 1006 |
else:
|
| 1007 |
st.warning("OCR not available in this deployment.")
|
| 1008 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1009 |
|
| 1010 |
# GeoMate Ask (RAG) — simple chat with memory per site and auto-extract numeric values
|
| 1011 |
def rag_page():
|