MSU576 commited on
Commit
67e53b8
·
verified ·
1 Parent(s): d18eea8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +98 -0
app.py CHANGED
@@ -74,6 +74,101 @@ if not GROQ_AVAILABLE:
74
  # 3) Global constants & helper functions
75
  MAX_SITES = 4
76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  # Pre-defined dropdown text mappings (as you requested) — exact text with mapping numbers for logic backend
78
  DILATANCY_OPTIONS = [
79
  "1. Quick to slow",
@@ -500,6 +595,7 @@ def build_full_geotech_pdf(site: Dict[str, Any], filename: str, include_map_imag
500
  if "sites" not in st.session_state:
501
  # initialize with a default site
502
  st.session_state["sites"] = [{
 
503
  "Site Name":"Home",
504
  "Project Name":"Demo Project",
505
  "Site ID": 0,
@@ -1112,6 +1208,8 @@ elif page == "RAG":
1112
  rag_page()
1113
  elif page == "Reports":
1114
  reports_page()
 
 
1115
  else:
1116
  landing_page()
1117
 
 
74
  # 3) Global constants & helper functions
75
  MAX_SITES = 4
76
 
77
+
78
+ # ----------------------------
79
+ # Soil Recognizer Page (Integrated 6-Class ResNet18)
80
+ # ----------------------------
81
+ import torch
82
+ import torch.nn as nn
83
+ import torchvision.models as models
84
+ import torchvision.transforms as T
85
+ from PIL import Image
86
+ import streamlit as st
87
+
88
+ # ----------------------------
89
+ # Load Soil Model (6 Classes)
90
+ # ----------------------------
91
+ @st.cache_resource
92
+ def load_soil_model(path="soil_best_model.pth"):
93
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
94
+ try:
95
+ model = models.resnet18(pretrained=False)
96
+ num_ftrs = model.fc.in_features
97
+ model.fc = nn.Linear(num_ftrs, 6) # 6 soil classes
98
+
99
+ # Load checkpoint
100
+ state_dict = torch.load(path, map_location=device)
101
+ model.load_state_dict(state_dict)
102
+ model = model.to(device)
103
+ model.eval()
104
+ return model, device
105
+ except Exception as e:
106
+ st.error(f"⚠️ Could not load soil model: {e}")
107
+ return None, device
108
+
109
+ soil_model, device = load_soil_model()
110
+
111
+ # ----------------------------
112
+ # Soil Classes & Transform
113
+ # ----------------------------
114
+ SOIL_CLASSES = ["Clay", "Gravel", "Loam", "Peat", "Sand", "Silt"]
115
+
116
+ transform = T.Compose([
117
+ T.Resize((224, 224)),
118
+ T.ToTensor(),
119
+ T.Normalize([0.485, 0.456, 0.406],
120
+ [0.229, 0.224, 0.225])
121
+ ])
122
+
123
+ # ----------------------------
124
+ # Prediction Function
125
+ # ----------------------------
126
+ def predict_soil(img: Image.Image):
127
+ if soil_model is None:
128
+ return "Model not loaded", {}
129
+
130
+ img = img.convert("RGB")
131
+ inp = transform(img).unsqueeze(0).to(device)
132
+
133
+ with torch.no_grad():
134
+ logits = soil_model(inp)
135
+ probs = torch.softmax(logits[0], dim=0)
136
+
137
+ top_idx = torch.argmax(probs).item()
138
+ predicted_class = SOIL_CLASSES[top_idx]
139
+
140
+ result = {SOIL_CLASSES[i]: float(probs[i]) for i in range(len(SOIL_CLASSES))}
141
+ return predicted_class, result
142
+
143
+ # ----------------------------
144
+ # Soil Recognizer Page
145
+ # ----------------------------
146
+ def soil_recognizer_page():
147
+ st.header("🖼️ Soil Recognizer (ResNet18)")
148
+
149
+ site = get_active_site() # your existing site getter
150
+ if site is None:
151
+ st.warning("⚠️ No active site selected. Please add or select a site from the sidebar.")
152
+ return
153
+
154
+ uploaded = st.file_uploader("Upload soil image", type=["jpg", "jpeg", "png"])
155
+ if uploaded is not None:
156
+ img = Image.open(uploaded)
157
+ st.image(img, caption="Uploaded soil image", use_column_width=True)
158
+
159
+ predicted_class, confidence_scores = predict_soil(img)
160
+ st.success(f"✅ Predicted: **{predicted_class}**")
161
+
162
+ st.subheader("Confidence Scores")
163
+ for cls, score in confidence_scores.items():
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
+
172
  # Pre-defined dropdown text mappings (as you requested) — exact text with mapping numbers for logic backend
173
  DILATANCY_OPTIONS = [
174
  "1. Quick to slow",
 
595
  if "sites" not in st.session_state:
596
  # initialize with a default site
597
  st.session_state["sites"] = [{
598
+ "Soil Profile": None,
599
  "Site Name":"Home",
600
  "Project Name":"Demo Project",
601
  "Site ID": 0,
 
1208
  rag_page()
1209
  elif page == "Reports":
1210
  reports_page()
1211
+ elif page == "Soil recognizer":
1212
+ soil_recognizer_page()
1213
  else:
1214
  landing_page()
1215