MSU576 commited on
Commit
6c46c15
·
verified ·
1 Parent(s): b7998e7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +246 -102
app.py CHANGED
@@ -1,102 +1,246 @@
1
- """ GeoMate: Soil Engineering Toolkit 🌍
2
-
3
- A complete geotechnical engineering assistant for soil classification, analysis, and design.
4
-
5
- ===================== 🚀 Features =====================
6
-
7
- 📷 Soil Type Classifier — Upload image to identify soil type via PyTorch model
8
-
9
- 🤖 Ask GeoMate — AI-based chat powered by Groq (LLaMA 70B)
10
-
11
- 🧪 Soil Classification — USCS and AASHTO classification systems
12
-
13
- 🏗️ Engineering Calculators: • Bearing Capacity • Slope Stability • Consolidation Settlement • Seepage Flow • Compaction Density
14
-
15
- 📄 PDF Generator — Download summary reports
16
-
17
-
18
- ===================== 🔧 Tech Stack =====================
19
-
20
- Gradio (UI)
21
-
22
- PyTorch (Image Classifier)
23
-
24
- Groq API (AI Chat)
25
-
26
- ReportLab (PDF Export)
27
-
28
-
29
- ===================== Hugging Face Deployment =====================
30
-
31
- 1. Create a new Space on https://huggingface.co/spaces
32
-
33
-
34
- 2. Choose Gradio SDK
35
-
36
-
37
- 3. Upload:
38
-
39
- app.py
40
-
41
- requirements.txt
42
-
43
- README.md
44
-
45
- soil_model.pth
46
-
47
-
48
-
49
- 4. Add Secret Key: GROQ_API_KEY
50
-
51
-
52
-
53
- Use AI for smarter soil engineering 💡 """
54
-
55
- import os import gradio as gr import torch import torchvision.transforms as transforms from PIL import Image from groq import Groq from reportlab.lib.pagesizes import A4 from reportlab.pdfgen import canvas import tempfile
56
-
57
- Load model
58
-
59
- device = torch.device("cuda" if torch.cuda.is_available() else "cpu") model = torch.load("soil_model.pth", map_location=device) model.eval()
60
-
61
- transform = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), ])
62
-
63
- classes = ['Clay', 'Silt', 'Sand', 'Gravel']
64
-
65
- def classify_image(img): image = transform(img).unsqueeze(0).to(device) with torch.no_grad(): output = model(image) _, predicted = torch.max(output, 1) return classes[predicted.item()]
66
-
67
- Groq AI Chat
68
-
69
- groq_client = Groq(api_key=os.getenv("GROQ_API_KEY"))
70
-
71
- def ask_geomate(prompt): chat_completion = groq_client.chat.completions.create( messages=[{"role": "user", "content": prompt}], model="llama3-70b-8192" ) return chat_completion.choices[0].message.content
72
-
73
- Soil classification
74
-
75
- def classify_uscs(symbol, fines_percent): if symbol.startswith("G"): if fines_percent < 5: return "Well-graded Gravel (GW)" if "W" in symbol else "Poorly-graded Gravel (GP)" elif 5 <= fines_percent <= 12: return "Gravel with Fines (GW-GM or GW-GC)" else: return "Silty or Clayey Gravel (GM/GC)" elif symbol.startswith("S"): if fines_percent < 5: return "Well-graded Sand (SW)" if "W" in symbol else "Poorly-graded Sand (SP)" elif 5 <= fines_percent <= 12: return "Sand with Fines (SW-SM or SW-SC)" else: return "Silty or Clayey Sand (SM/SC)" elif symbol.startswith("M"): return "Silt (ML)" elif symbol.startswith("C"): return "Clay (CL)" return "Check symbol"
76
-
77
- def classify_aashto(percent_passing_no200): if percent_passing_no200 < 35: return "Granular Soil (A-1 to A-3)" else: return "Silty-Clay Soil (A-4 to A-7)"
78
-
79
- Calculators
80
-
81
- def bearing_capacity(q, Nq, sc, dc, ic): return q * Nq * sc * dc * ic
82
-
83
- def slope_stability(factor_safety, slope_angle): return "Stable" if factor_safety > 1.5 else "Unstable"
84
-
85
- def consolidation_settlement(H, Cv, t): return (Cv * t) / (H**2)
86
-
87
- def seepage_flow(K, H, L): return K * H / L
88
-
89
- def compaction_density(W, V): return W / V
90
-
91
- PDF Generator
92
-
93
- def generate_pdf(text): with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp: c = canvas.Canvas(tmp.name, pagesize=A4) width, height = A4 text_obj = c.beginText(40, height - 50) text_obj.setFont("Helvetica", 12) for line in text.split("\n"): text_obj.textLine(line) c.drawText(text_obj) c.showPage() c.save() return tmp.name
94
-
95
- Gradio Interface
96
-
97
- tab1 = gr.Interface(fn=classify_image, inputs=gr.Image(type="pil"), outputs="text", title="Soil Image Classifier") tab2 = gr.Interface(fn=ask_geomate, inputs=gr.Textbox(), outputs="text", title="Ask GeoMate") tab3 = gr.Interface(fn=classify_uscs, inputs=[gr.Textbox(label="USCS Symbol"), gr.Number(label="% Fines")], outputs="text", title="USCS Classification") tab4 = gr.Interface(fn=classify_aashto, inputs=gr.Number(label="% Passing No. 200"), outputs="text", title="AASHTO Classification") tab5 = gr.Interface(fn=bearing_capacity, inputs=[gr.Number(), gr.Number(), gr.Number(), gr.Number(), gr.Number()], outputs="number", title="Bearing Capacity") tab6 = gr.Interface(fn=slope_stability, inputs=[gr.Number(), gr.Number()], outputs="text", title="Slope Stability") tab7 = gr.Interface(fn=consolidation_settlement, inputs=[gr.Number(), gr.Number(), gr.Number()], outputs="number", title="Consolidation Settlement") tab8 = gr.Interface(fn=seepage_flow, inputs=[gr.Number(), gr.Number(), gr.Number()], outputs="number", title="Seepage Flow") tab9 = gr.Interface(fn=compaction_density, inputs=[gr.Number(), gr.Number()], outputs="number", title="Compaction Density") tab10 = gr.Interface(fn=generate_pdf, inputs=gr.Textbox(lines=10, placeholder="Paste your summary here"), outputs="file", title="📄 Generate PDF Report")
98
-
99
- demo = gr.TabbedInterface([tab1, tab2, tab3, tab4, tab5, tab6, tab7, tab8, tab9, tab10], tab_names=["Image Classifier", "Ask GeoMate", "USCS", "AASHTO", "Bearing", "Slope", "Consolidation", "Seepage", "Compaction", "📄 Generate PDF"])
100
-
101
- demo.launch()
102
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py
2
+
3
+ import os
4
+ import math
5
+ import torch
6
+ import torch.nn as nn
7
+ import torchvision.transforms as transforms
8
+ import torchvision.models as models
9
+ from PIL import Image
10
+ import gradio as gr
11
+ from groq import Groq
12
+ from reportlab.lib.pagesizes import A4
13
+ from reportlab.pdfgen import canvas
14
+
15
+ # Load API Key
16
+ api_key = os.environ.get("GROQ_API_KEY")
17
+ if not api_key:
18
+ raise ValueError("GROQ_API_KEY not found in environment. Please add it in HF Space Secrets.")
19
+ client = Groq(api_key=api_key)
20
+
21
+ # ------------------------------
22
+ # Model: Soil Classifier
23
+ # ------------------------------
24
+ class SoilClassifier(nn.Module):
25
+ def __init__(self):
26
+ super(SoilClassifier, self).__init__()
27
+ self.base_model = models.resnet18(weights=None)
28
+ num_features = self.base_model.fc.in_features
29
+ self.base_model.fc = nn.Linear(num_features, 1)
30
+
31
+ def forward(self, x):
32
+ return self.base_model(x)
33
+
34
+ model = SoilClassifier()
35
+ model.base_model.load_state_dict(torch.load('soil_model.pth', map_location=torch.device('cpu')))
36
+ model.eval()
37
+
38
+ transform = transforms.Compose([
39
+ transforms.Resize((224, 224)),
40
+ transforms.ToTensor(),
41
+ transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
42
+ ])
43
+
44
+ # ------------------------------
45
+ # Shared report log
46
+ # ------------------------------
47
+ report_summary = []
48
+
49
+ # ------------------------------
50
+ # Soil Prediction Function
51
+ # ------------------------------
52
+ def predict_soil_type(image):
53
+ image = image.convert("RGB")
54
+ img_tensor = transform(image).unsqueeze(0)
55
+ with torch.no_grad():
56
+ outputs = model(img_tensor)
57
+ raw_output = outputs.item()
58
+ prediction = torch.sigmoid(outputs).item()
59
+ result = f"Model Raw Output: {raw_output:.4f}"
60
+ report_summary.append(f"Soil Image Prediction: {result}")
61
+ return result
62
+
63
+
64
+ # ------------------------------
65
+ # AI Advisor
66
+ # ------------------------------
67
+ def ask_soil_region(query):
68
+ prompt = f"""You are GeoMate, a world-class geotechnical expert.
69
+ Answer the following query using global soil knowledge, latest construction practices, and foundation design standards.
70
+ Query: {query}"""
71
+ response = client.chat.completions.create(
72
+ model="llama-3.1-8b-instant",
73
+ messages=[{"role": "user", "content": prompt}]
74
+ )
75
+ return response.choices[0].message.content
76
+
77
+ # ------------------------------
78
+ # Classification System
79
+ # ------------------------------
80
+ def classify_soil(system, liquid_limit, plasticity_index, grain_size):
81
+ try:
82
+ result = ""
83
+ if system == "USCS":
84
+ if grain_size > 50:
85
+ result = "Gravel"
86
+ elif grain_size > 0.075:
87
+ result = "Sand"
88
+ else:
89
+ result = "Clay" if plasticity_index > 7 else "Silt"
90
+ elif system == "AASHTO":
91
+ if liquid_limit < 40 and plasticity_index < 10:
92
+ result = "A-1 or A-2 (Granular Soil)"
93
+ elif plasticity_index > 10:
94
+ result = "A-5 to A-7 (Silty/Clayey Soil)"
95
+ else:
96
+ result = "A-4 (Silt)"
97
+ else:
98
+ result = "Invalid system"
99
+ report_summary.append(f"Soil Classification: {result}")
100
+ return result
101
+ except Exception as e:
102
+ return f"Error: {e}"
103
+
104
+ # ------------------------------
105
+ # Engineering Calculations
106
+ # ------------------------------
107
+ def convert_pressure(val, unit):
108
+ val = float(val)
109
+ if unit == "psf":
110
+ return val * 0.04788
111
+ return val
112
+
113
+ def bearing_capacity_solver(q, Nq, S, B):
114
+ try:
115
+ q_converted = convert_pressure(q, S)
116
+ result = q_converted * float(Nq) * float(B)
117
+ report_summary.append(f"Bearing Capacity: {round(result, 2)} kN/m²")
118
+ return f"{round(result, 2)} kN/m²"
119
+ except Exception as e:
120
+ return f"Error: {e}"
121
+
122
+ def slope_stability_solver(c, phi, gamma, height):
123
+ try:
124
+ phi = math.radians(float(phi))
125
+ fs = (float(c) + float(gamma) * float(height) * math.tan(phi)) / (float(gamma) * float(height))
126
+ report_summary.append(f"Slope Stability Factor of Safety: {round(fs, 3)}")
127
+ return f"{round(fs, 3)} (Factor of Safety)"
128
+ except Exception as e:
129
+ return f"Error: {e}"
130
+
131
+ def consolidation_solver(delta_sigma, mv, H):
132
+ try:
133
+ settlement = float(mv) * float(delta_sigma) * float(H)
134
+ report_summary.append(f"Settlement: {round(settlement, 3)} m")
135
+ return f"{round(settlement, 3)} m"
136
+ except Exception as e:
137
+ return f"Error: {e}"
138
+
139
+ def seepage_solver(k, i, A):
140
+ try:
141
+ q = float(k) * float(i) * float(A)
142
+ report_summary.append(f"Seepage Discharge: {round(q, 4)} m³/s")
143
+ return f"{round(q, 4)} m³/s"
144
+ except Exception as e:
145
+ return f"Error: {e}"
146
+
147
+ def compaction_solver(W, V):
148
+ try:
149
+ dry_density = float(W) / float(V)
150
+ report_summary.append(f"Dry Density: {round(dry_density, 2)} kN/m³")
151
+ return f"{round(dry_density, 2)} kN/m³"
152
+ except Exception as e:
153
+ return f"Error: {e}"
154
+
155
+ # ------------------------------
156
+ # PDF Report Generator
157
+ # ------------------------------
158
+ def export_full_report():
159
+ try:
160
+ file_path = "/tmp/GeoMate_Report.pdf"
161
+ c = canvas.Canvas(file_path, pagesize=A4)
162
+ width, height = A4
163
+ c.setFont("Helvetica", 12)
164
+ y = height - 50
165
+ for line in report_summary:
166
+ c.drawString(40, y, line)
167
+ y -= 20
168
+ if y < 50:
169
+ c.showPage()
170
+ c.setFont("Helvetica", 12)
171
+ y = height - 50
172
+ c.save()
173
+ return file_path
174
+ except Exception as e:
175
+ return f"Error: {e}"
176
+
177
+ # ------------------------------
178
+ # Gradio Interface
179
+ # ------------------------------
180
+ with gr.Blocks(title="GeoMate 🌍 - Soil Engineering Toolkit") as demo:
181
+ gr.Markdown("""
182
+ <div style='text-align:center; font-size:26px; font-weight:bold; color:#ff6600;'>🌍 GeoMate - Soil Engineering Toolkit</div>
183
+ <p style='color:#333;'>Perform all major soil-related geotechnical calculations in one place!</p>
184
+ """)
185
+
186
+ with gr.Tab("📷 Soil Recognizer"):
187
+ img_input = gr.Image(type="pil", label="Upload Soil Image")
188
+ img_output = gr.Textbox(label="Prediction Output")
189
+ img_input.change(fn=predict_soil_type, inputs=img_input, outputs=img_output)
190
+
191
+ with gr.Tab("🤖 Ask GeoMate"):
192
+ gr.Interface(fn=ask_soil_region,
193
+ inputs=gr.Textbox(placeholder="e.g., What foundation is suitable in Karachi?", lines=2),
194
+ outputs="text").render()
195
+
196
+ with gr.Tab("🧪 Soil Classification"):
197
+ system = gr.Dropdown(["USCS", "AASHTO"], label="Classification System", value="USCS")
198
+ ll = gr.Number(label="Liquid Limit (%)")
199
+ pi = gr.Number(label="Plasticity Index (%)")
200
+ gs = gr.Number(label="Grain Size (mm)")
201
+ classify_btn = gr.Button("Classify Soil")
202
+ classification = gr.Textbox(label="Soil Type")
203
+ classify_btn.click(classify_soil, [system, ll, pi, gs], classification)
204
+
205
+ with gr.Tab("🏗️ Bearing Capacity"):
206
+ q = gr.Number(label="Overburden Pressure")
207
+ q_unit = gr.Dropdown(["kN/m²", "psf", "kPa"], label="Unit", value="kN/m²")
208
+ nq = gr.Number(label="Nq (Bearing Capacity Factor)")
209
+ B = gr.Number(label="Width of Foundation (m)")
210
+ bc_result = gr.Textbox(label="Ultimate Bearing Capacity")
211
+ gr.Button("Calculate").click(bearing_capacity_solver, [q, nq, q_unit, B], bc_result)
212
+
213
+ with gr.Tab("⛰️ Slope Stability"):
214
+ c = gr.Number(label="Cohesion (kN/m²)")
215
+ phi = gr.Number(label="Friction Angle (°)")
216
+ gamma = gr.Number(label="Unit Weight (kN/m³)")
217
+ h = gr.Number(label="Height of Slope (m)")
218
+ fs_result = gr.Textbox(label="Factor of Safety")
219
+ gr.Button("Check Stability").click(slope_stability_solver, [c, phi, gamma, h], fs_result)
220
+
221
+ with gr.Tab("📉 Consolidation Settlement"):
222
+ ds = gr.Number(label="Change in Stress (kN/m²)")
223
+ mv = gr.Number(label="Volume Compressibility (m²/kN)")
224
+ H = gr.Number(label="Soil Layer Thickness (m)")
225
+ s_result = gr.Textbox(label="Settlement")
226
+ gr.Button("Compute Settlement").click(consolidation_solver, [ds, mv, H], s_result)
227
+
228
+ with gr.Tab("💧 Seepage"):
229
+ k = gr.Number(label="Permeability (m/s)")
230
+ i = gr.Number(label="Hydraulic Gradient")
231
+ A = gr.Number(label="Flow Area (m²)")
232
+ seep_result = gr.Textbox(label="Seepage Discharge")
233
+ gr.Button("Calculate Seepage").click(seepage_solver, [k, i, A], seep_result)
234
+
235
+ with gr.Tab("🔩 Compaction Test"):
236
+ W = gr.Number(label="Dry Weight of Soil (kN)")
237
+ V = gr.Number(label="Volume of Mold (m³)")
238
+ comp_result = gr.Textbox(label="Dry Density")
239
+ gr.Button("Calculate Dry Density").click(compaction_solver, [W, V], comp_result)
240
+
241
+ with gr.Tab("📄 Generate Report"):
242
+ pdf_output = gr.File(label="Download PDF")
243
+ gr.Button("Export Full Report").click(fn=export_full_report, inputs=[], outputs=pdf_output)
244
+
245
+ # Launch App
246
+ demo.launch()