AmirAziz1221 commited on
Commit
2aab4b4
·
verified ·
1 Parent(s): c3f7908

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +122 -242
app.py CHANGED
@@ -10,22 +10,29 @@ from ultralytics import YOLO
10
  from openai import OpenAI
11
 
12
  from docx import Document
13
- from docx.shared import Inches
14
 
15
 
16
  # =====================================================
17
- # MODEL
18
  # =====================================================
19
 
20
- MODEL_PATH = "best_asphalt.pt"
21
- model = YOLO(MODEL_PATH)
 
 
 
 
 
 
 
 
22
 
23
 
24
  # =====================================================
25
  # GROK / XAI API
26
  # =====================================================
27
 
28
- XAI_API_KEY = os.getenv("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")
29
 
30
  client = OpenAI(
31
  api_key=XAI_API_KEY,
@@ -47,10 +54,25 @@ def normalize_class_name(name):
47
 
48
 
49
  # =====================================================
50
- # PATHOLOGY CATALOG
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  # =====================================================
52
 
53
- PATHOLOGY_CATALOG = {
54
  "01LONGITUDINAL CRACKS": {
55
  "name": "Longitudinal Cracks",
56
  "severity": "Medium",
@@ -75,20 +97,12 @@ PATHOLOGY_CATALOG = {
75
  "risk": "Advanced structural fatigue, pothole formation, and possible pavement collapse.",
76
  "recommendation": "Mill affected layers and reconstruct pavement structure. Perform geotechnical investigation if widespread."
77
  },
78
- "04REFLECTION CRACKS": {
79
- "name": "Reflection Cracks",
80
- "severity": "Medium–High",
81
- "priority": "P2",
82
- "deadline": "Medium term: 1–3 months",
83
- "risk": "Water ingress, internal erosion, and pothole formation.",
84
- "recommendation": "Seal with elastomeric mastic. For resurfacing, use anti-crack geogrid or SAMI membrane."
85
- },
86
  "05POTHOLES": {
87
  "name": "Potholes",
88
  "severity": "High",
89
  "priority": "P1",
90
  "deadline": "Immediate: within 24–48 hours",
91
- "risk": "Direct accident risk, especially for motorcycles and bicycles; vehicle tire and suspension damage.",
92
  "recommendation": "Immediate patching with hot/cold bituminous mix. Cut edges, clean, prime, fill, and compact."
93
  },
94
  "06RUTTING": {
@@ -97,31 +111,7 @@ PATHOLOGY_CATALOG = {
97
  "priority": "P1/P2",
98
  "deadline": "Short term if rut depth exceeds 15–20 mm",
99
  "risk": "Aquaplaning, vehicle instability, and progressive lower-layer degradation.",
100
- "recommendation": "Mill affected area and replace with high-stability asphalt mix such as SMA or BBTM."
101
- },
102
- "07UNDULATIONS AND CORRUGATION": {
103
- "name": "Undulations and Corrugation",
104
- "severity": "Medium",
105
- "priority": "P2/P3",
106
- "deadline": "Medium term: 1–3 months",
107
- "risk": "Loss of driving comfort, braking instability, and possible vehicle control issues.",
108
- "recommendation": "Mill wearing course and replace with deformation-resistant asphalt mixture."
109
- },
110
- "08DEPRESSIONS AND SETTLEMENTS": {
111
- "name": "Depressions and Settlements",
112
- "severity": "High",
113
- "priority": "P1",
114
- "deadline": "Immediate if depression exceeds 3 cm",
115
- "risk": "Water accumulation, aquaplaning, and potential sudden pavement collapse.",
116
- "recommendation": "Investigate cause using GPR/load tests. Repair underlying cause before structural reconstruction."
117
- },
118
- "09SWELLING": {
119
- "name": "Swelling / Bulges",
120
- "severity": "Medium–High",
121
- "priority": "P1/P2",
122
- "deadline": "Short term; immediate if height exceeds 5 cm",
123
- "risk": "Vehicle instability and fall risk for cyclists/pedestrians.",
124
- "recommendation": "Investigate cause such as roots, frost, leakage, or expansive soil. Remove cause, mill, and level area."
125
  },
126
  "10SURFACE RAVELING": {
127
  "name": "Surface Raveling",
@@ -130,152 +120,28 @@ PATHOLOGY_CATALOG = {
130
  "deadline": "Medium term: 1–3 months",
131
  "risk": "Loose aggregate, reduced traction, water penetration, and future pothole formation.",
132
  "recommendation": "Apply slurry seal, microsurfacing, or mill and resurface if advanced."
133
- },
134
- "11PEELING AND LAYER DETACHMENT": {
135
- "name": "Peeling and Layer Detachment",
136
- "severity": "High",
137
- "priority": "P1",
138
- "deadline": "Immediate; remove loose material within 24 hours",
139
- "risk": "Loose material causing motorcyclist/cyclist falls and rapid base exposure.",
140
- "recommendation": "Remove loose material, mill affected area, clean, apply proper tack coat, and resurface."
141
- },
142
- "12BINDER BLEEDING": {
143
- "name": "Binder Bleeding / Exudation",
144
- "severity": "Medium; High on curves/intersections",
145
- "priority": "P1/P3",
146
- "deadline": "Short term; immediate on sharp curves",
147
- "risk": "Loss of skid resistance and accident risk in wet/hot conditions.",
148
- "recommendation": "Apply cover aggregate and compact lightly. In severe cases, micro-mill and replace surface layer."
149
- },
150
- "13AGGREGATE POLISHING": {
151
- "name": "Aggregate Polishing",
152
- "severity": "Medium; High in wet/slope areas",
153
- "priority": "P1",
154
- "deadline": "Short term: less than 1 month",
155
- "risk": "Loss of wet skid resistance and increased braking distance.",
156
- "recommendation": "Apply anti-skid surface treatment or overlay with high-CPA aggregate mix."
157
- },
158
- "14PAVEMENT SHOULDER LEVEL DIFFERENCE": {
159
- "name": "Pavement–Shoulder Level Difference",
160
- "severity": "High",
161
- "priority": "P1",
162
- "deadline": "Short term; immediate if level difference exceeds 8 cm",
163
- "risk": "Vehicle rollover risk and abrupt re-entry collision risk.",
164
- "recommendation": "Level shoulder to roadway or construct transition ramp with maximum slope 1:6."
165
- },
166
- "15CONSTRUCTION JOINT DETERIORATION": {
167
- "name": "Construction Joint Deterioration",
168
- "severity": "Medium",
169
- "priority": "P2/P3",
170
- "deadline": "Medium term: 1–3 months",
171
- "risk": "Water infiltration and progressive deterioration along joint line.",
172
- "recommendation": "Seal joint with elastomeric bituminous mastic. Mill and rebuild severely deteriorated joints."
173
- },
174
- "16CRESCENT CRACKS": {
175
- "name": "Crescent-Shaped / Slippage Cracks",
176
- "severity": "High",
177
- "priority": "P1",
178
- "deadline": "Short term or immediate if active detachment exists",
179
- "risk": "Layer sliding, material detachment, and direct danger to motorcycles.",
180
- "recommendation": "Mill affected area and replace with proper tack coat and compacted asphalt layer."
181
- },
182
- "17CHANNELS AND DEEP GROOVES": {
183
- "name": "Channels and Deep Grooves",
184
- "severity": "Medium; High if depth exceeds 2 cm",
185
- "priority": "P2",
186
- "deadline": "Medium term: 1–3 months",
187
- "risk": "Aquaplaning and fall risk for motorcycles/cyclists.",
188
- "recommendation": "Mill and resurface with abrasion-resistant mix. Correct surface drainage."
189
- },
190
- "18LATERAL DISPLACEMENT": {
191
- "name": "Lateral Displacement / Shoving",
192
- "severity": "Medium; High in turning areas",
193
- "priority": "P2/P3",
194
- "deadline": "Medium term: 1–3 months",
195
- "risk": "Vehicle instability on curves and cyclist risk near displaced material.",
196
- "recommendation": "Mill affected area and replace with high-stability polymer-modified mix."
197
- },
198
- "20WATER SEEPAGE": {
199
- "name": "Water Seepage / Wet Areas",
200
- "severity": "High",
201
- "priority": "P1/P2",
202
- "deadline": "Immediate investigation within 24–48 hours",
203
- "risk": "Internal erosion, loss of bearing capacity, and possible pavement collapse.",
204
- "recommendation": "Investigate drainage/leakage source, repair water source, drain retained water, and reconstruct affected pavement."
205
- },
206
- "21PERIMETER DETERIORATION OF MANHOLES": {
207
- "name": "Perimeter Deterioration of Manholes",
208
- "severity": "High",
209
- "priority": "P1",
210
- "deadline": "Short term; immediate if level difference exceeds 2 cm or loose material exists",
211
- "risk": "Cyclist/motorcyclist falls, vehicle impact damage, and water ingress.",
212
- "recommendation": "Demolish perimeter, adjust frame level, and replace pavement with compacted hot mix."
213
- },
214
- "22EDGE DETERIORATION": {
215
- "name": "Road Edge Deterioration",
216
- "severity": "Medium; High if shoulder level difference exists",
217
- "priority": "P1/P3",
218
- "deadline": "Medium term; immediate if associated with dangerous level difference",
219
- "risk": "Loss of vehicle control when moving to shoulder and progressive edge failure.",
220
- "recommendation": "Cut deteriorated edge, replace with compacted hot mix, and restore shoulder continuity."
221
- },
222
- "23PATCHES IN POOR CONDITION": {
223
- "name": "Patches in Poor Condition",
224
- "severity": "Medium; High if level difference exceeds 2 cm",
225
- "priority": "P1/P2",
226
- "deadline": "Short term; immediate if level difference exceeds 2 cm",
227
- "risk": "Uneven surface, fall risk, aggregate projection, and unresolved underlying defect.",
228
- "recommendation": "Mill and repatch correctly using straight cut, priming, hot mix, and layer compaction."
229
- },
230
- "24MARKING DAMAGE": {
231
- "name": "Horizontal Marking Damage",
232
- "severity": "Medium; High at pedestrian crossings/intersections",
233
- "priority": "P1/P3",
234
- "deadline": "Short term at intersections; long term for secondary markings",
235
- "risk": "Driver disorientation, lane invasion, and pedestrian crossing visibility loss.",
236
- "recommendation": "Clean surface and repaint/apply thermoplastic marking with glass microspheres."
237
- },
238
- "25STEP BETWEEN LANES": {
239
- "name": "Step Between Lanes",
240
- "severity": "Medium; High if step exceeds 3 cm",
241
- "priority": "P1/P2",
242
- "deadline": "Short term: less than 1 month",
243
- "risk": "Motorcycle instability during lane changes and water retention.",
244
- "recommendation": "Mill transition zone and level the step using a ramp with maximum slope 1:10."
245
- },
246
- "26THERMAL FATIGUE CRACKING": {
247
- "name": "Thermal Fatigue Cracking",
248
- "severity": "Medium",
249
- "priority": "P2",
250
- "deadline": "Medium term: 1–3 months",
251
- "risk": "Water infiltration, freeze-thaw damage, and evolution to structural cracking.",
252
- "recommendation": "Seal cracks and use polymer-modified bitumen with suitable low-temperature performance in resurfacing."
253
- },
254
- "27CHEMICAL AGENTS": {
255
- "name": "Deterioration due to Hydrocarbons / Chemical Agents",
256
- "severity": "Medium–High",
257
- "priority": "P1/P2",
258
- "deadline": "Short term: less than 1 month",
259
- "risk": "Softened asphalt, soil/groundwater contamination, and slippery surface.",
260
- "recommendation": "Apply absorbents, mill contaminated area, manage waste properly, and replace with resistant asphalt mix."
261
- },
262
- "28OXIDATION AND AGING OF BINDER": {
263
- "name": "Oxidation and Aging of Binder",
264
- "severity": "Medium",
265
- "priority": "P3",
266
- "deadline": "Long term: 3–6 months",
267
- "risk": "Reduced pavement life, brittleness, cracking, and surface disintegration.",
268
- "recommendation": "Apply rejuvenating treatment or slurry seal. Plan resurfacing before structural cracking occurs."
269
  }
270
  }
271
 
272
 
 
 
 
 
 
 
 
 
 
 
 
273
  # =====================================================
274
  # DETECTION HELPERS
275
  # =====================================================
276
 
277
- def get_detection_summary(results):
278
  detections = []
 
279
 
280
  for r in results:
281
  if r.boxes is None:
@@ -290,6 +156,7 @@ def get_detection_summary(results):
290
  key = normalize_class_name(raw_name)
291
 
292
  detections.append({
 
293
  "class": raw_name,
294
  "key": key,
295
  "confidence": round(conf, 3),
@@ -326,38 +193,41 @@ def summarize_detections(detections):
326
  # BASIC ENGINEERING REPORT
327
  # =====================================================
328
 
329
- def basic_engineering_report(detections):
330
  summary = summarize_detections(detections)
 
 
331
 
332
  if summary["total"] == 0:
333
- return """
334
- # Civil Engineering Pavement Inspection Report
335
 
336
  ## Detection Result
337
- No pavement pathology was detected with the selected confidence threshold.
338
 
339
  ## Engineering Interpretation
340
- The inspected image/video does not show a clear asphalt defect detectable by the model. This does not guarantee that the pavement is defect-free.
341
 
342
  ## Recommended Action
343
  - Repeat inspection with clearer images.
344
- - Capture the road surface perpendicular to the pavement.
345
  - Use manual visual inspection for confirmation.
346
- - Reduce the confidence threshold if the image contains small or low-contrast defects.
347
 
348
  ## Disclaimer
349
- This report is AI-assisted and must be verified by a qualified civil/pavement engineer.
350
  """
351
 
352
  lines = []
353
 
354
- lines.append("# Civil Engineering Pavement Inspection Report")
355
  lines.append("")
356
  lines.append("## 1. AI Detection Summary")
 
357
  lines.append(f"- Total detected defects: {summary['total']}")
358
 
359
  for cls, count in summary["classes"].items():
360
- info = PATHOLOGY_CATALOG.get(cls)
361
  label = info["name"] if info else cls.title()
362
  lines.append(f"- {label}: {count} detected area(s)")
363
 
@@ -365,7 +235,7 @@ This report is AI-assisted and must be verified by a qualified civil/pavement en
365
  lines.append("## 2. Engineering Diagnosis")
366
 
367
  for cls, count in summary["classes"].items():
368
- info = PATHOLOGY_CATALOG.get(cls)
369
 
370
  if info:
371
  lines.append("")
@@ -385,23 +255,22 @@ This report is AI-assisted and must be verified by a qualified civil/pavement en
385
 
386
  lines.append("")
387
  lines.append("## 3. Field Verification Checklist")
388
- lines.append("- Measure crack width, pothole depth, rut depth, or level difference where applicable.")
389
- lines.append("- Record GPS location and chainage/station of each defect.")
390
  lines.append("- Capture georeferenced photographs before repair.")
391
- lines.append("- Check drainage condition and evidence of water infiltration.")
392
- lines.append("- Confirm whether loose material creates immediate user risk.")
393
- lines.append("- Consider traffic volume, heavy vehicle loading, and vulnerable road users.")
394
 
395
  lines.append("")
396
  lines.append("## 4. Professional Notes")
397
- lines.append("- P1 defects require urgent safety management, including warning signs or cordoning if immediate repair is not possible.")
398
  lines.append("- P2 defects should be included in the structural maintenance plan.")
399
  lines.append("- P3 defects can generally be included in routine preventive maintenance.")
400
- lines.append("- Final maintenance decisions should be confirmed by an on-site civil/pavement engineer.")
401
 
402
  lines.append("")
403
  lines.append("## 5. Disclaimer")
404
- lines.append("This report is generated using AI-based image/video detection and a technical pavement pathology catalog. It is intended for preliminary engineering support only and must not replace field inspection, laboratory testing, or professional engineering judgment.")
405
 
406
  return "\n".join(lines)
407
 
@@ -410,21 +279,23 @@ This report is AI-assisted and must be verified by a qualified civil/pavement en
410
  # GROK ENGINEERING REPORT
411
  # =====================================================
412
 
413
- def grok_engineering_report(detections):
414
- base_report = basic_engineering_report(detections)
415
 
416
  if client is None:
417
  return base_report + "\n\n⚠️ Grok API key not found. Add `XAI_API_KEY` in Hugging Face Space Secrets."
418
 
419
  prompt = f"""
420
- You are a professional civil pavement engineer.
421
 
422
- Generate a formal engineering inspection report based on the following YOLO asphalt pavement detections.
 
 
423
 
424
  Use this structure:
425
  1. Project title
426
  2. AI detection summary
427
- 3. Identified asphalt pathologies
428
  4. Probable causes
429
  5. Severity and priority
430
  6. Associated civil engineering risks
@@ -433,19 +304,10 @@ Use this structure:
433
  9. Field verification checklist
434
  10. Disclaimer
435
 
436
- Use this logic:
437
- - P1 = direct third-party/user safety risk.
438
- - P2 = structural degradation risk.
439
- - P3 = superficial degradation.
440
- - High severity defects require immediate or short-term action.
441
- - Potholes, settlements, peeling, dangerous unevenness, water seepage, and loose material are urgent.
442
- - Cracking and rutting may indicate structural degradation.
443
- - Water infiltration accelerates pavement deterioration.
444
-
445
- Detected data:
446
  {json.dumps(detections, indent=2)}
447
 
448
- Local catalog interpretation:
449
  {base_report}
450
  """
451
 
@@ -453,8 +315,14 @@ Local catalog interpretation:
453
  response = client.chat.completions.create(
454
  model="grok-3-mini",
455
  messages=[
456
- {"role": "system", "content": "You are a civil engineering pavement inspection expert."},
457
- {"role": "user", "content": prompt}
 
 
 
 
 
 
458
  ],
459
  temperature=0.2
460
  )
@@ -469,10 +337,10 @@ Local catalog interpretation:
469
  # WORD REPORT
470
  # =====================================================
471
 
472
- def create_word_report(report_text):
473
  doc = Document()
474
 
475
- doc.add_heading("Civil Engineering Pavement Inspection Report", level=1)
476
 
477
  for line in report_text.split("\n"):
478
  line = line.strip()
@@ -509,10 +377,12 @@ def create_word_report(report_text):
509
  # IMAGE DETECTION
510
  # =====================================================
511
 
512
- def detect_image(image, conf):
513
  if image is None:
514
  return None, "Please upload an image.", "", None
515
 
 
 
516
  results = model.predict(
517
  source=image,
518
  imgsz=640,
@@ -524,9 +394,9 @@ def detect_image(image, conf):
524
  plotted = cv2.cvtColor(plotted, cv2.COLOR_BGR2RGB)
525
  output_img = Image.fromarray(plotted)
526
 
527
- detections = get_detection_summary(results)
528
- report = grok_engineering_report(detections)
529
- word_file = create_word_report(report)
530
 
531
  return output_img, json.dumps(detections, indent=2), report, word_file
532
 
@@ -535,10 +405,12 @@ def detect_image(image, conf):
535
  # VIDEO DETECTION
536
  # =====================================================
537
 
538
- def detect_video(video_path, conf):
539
  if video_path is None:
540
  return None, "Please upload a video.", "", None
541
 
 
 
542
  cap = cv2.VideoCapture(video_path)
543
 
544
  if not cap.isOpened():
@@ -560,8 +432,6 @@ def detect_video(video_path, conf):
560
 
561
  all_detections = []
562
  frame_count = 0
563
-
564
- # Process every 3rd frame to reduce runtime
565
  process_every_n_frames = 3
566
  last_annotated = None
567
 
@@ -580,7 +450,7 @@ def detect_video(video_path, conf):
580
  verbose=False
581
  )
582
 
583
- detections = get_detection_summary(results)
584
  all_detections.extend(detections)
585
 
586
  annotated = results[0].plot()
@@ -595,8 +465,8 @@ def detect_video(video_path, conf):
595
  cap.release()
596
  writer.release()
597
 
598
- report = grok_engineering_report(all_detections)
599
- word_file = create_word_report(report)
600
 
601
  return output_path, json.dumps(all_detections[:100], indent=2), report, word_file
602
 
@@ -605,17 +475,26 @@ def detect_video(video_path, conf):
605
  # GRADIO UI
606
  # =====================================================
607
 
608
- with gr.Blocks(title="Asphalt Pavement Defect Detection + Engineering Report") as demo:
609
 
610
  gr.Markdown("""
611
- # Asphalt Pavement Defect Detection and Civil Engineering Report
612
 
613
- Upload an asphalt pavement **image or video**.
614
- The YOLOv8 model detects pavement defects and generates a civil engineering report based on the pavement pathology catalog.
615
 
616
- The report can also be downloaded as a **Word document (.docx)**.
 
 
 
 
617
  """)
618
 
 
 
 
 
 
 
619
  conf = gr.Slider(
620
  minimum=0.10,
621
  maximum=0.90,
@@ -625,7 +504,7 @@ The report can also be downloaded as a **Word document (.docx)**.
625
  )
626
 
627
  with gr.Tab("Image Detection"):
628
- image_input = gr.Image(type="pil", label="Upload Asphalt Image")
629
  image_output = gr.Image(type="pil", label="Detection Output")
630
  image_json = gr.Textbox(label="Raw Detection Data", lines=8)
631
  image_report = gr.Markdown(label="Engineering Report")
@@ -635,12 +514,12 @@ The report can also be downloaded as a **Word document (.docx)**.
635
 
636
  image_btn.click(
637
  fn=detect_image,
638
- inputs=[image_input, conf],
639
  outputs=[image_output, image_json, image_report, image_docx]
640
  )
641
 
642
  with gr.Tab("Video Detection"):
643
- video_input = gr.Video(label="Upload Asphalt Video")
644
  video_output = gr.Video(label="Detection Output Video")
645
  video_json = gr.Textbox(label="Raw Detection Data - First 100 Detections", lines=8)
646
  video_report = gr.Markdown(label="Engineering Report")
@@ -650,22 +529,23 @@ The report can also be downloaded as a **Word document (.docx)**.
650
 
651
  video_btn.click(
652
  fn=detect_video,
653
- inputs=[video_input, conf],
654
  outputs=[video_output, video_json, video_report, video_docx]
655
  )
656
 
657
  gr.Markdown("""
658
  ## Notes
659
- - Use clear road-surface images for better detection.
660
  - For video, every 3rd frame is processed to reduce runtime.
661
- - Add `XAI_API_KEY` in Hugging Face Space Secrets to enable Grok-generated professional reporting.
662
  - If no API key is added, the app still generates a local engineering report.
663
  - The report is AI-assisted and must be verified by a qualified civil engineer.
664
  """)
665
 
 
666
  if __name__ == "__main__":
667
  demo.launch(
668
- server_name="0.0.0.0",
669
- server_port=7860,
670
- ssr_mode=False
671
- )
 
10
  from openai import OpenAI
11
 
12
  from docx import Document
 
13
 
14
 
15
  # =====================================================
16
+ # MODEL PATHS
17
  # =====================================================
18
 
19
+ MODEL_PATHS = {
20
+ "Asphalt Pathologies Detection": "best_asphalt.pt",
21
+ "Concrete Pathologies Detection": "Concreate_defect_detection.pt",
22
+ "Facades Pathologies Detection": "Facades_defect_detection.pt"
23
+ }
24
+
25
+ models = {
26
+ name: YOLO(path)
27
+ for name, path in MODEL_PATHS.items()
28
+ }
29
 
30
 
31
  # =====================================================
32
  # GROK / XAI API
33
  # =====================================================
34
 
35
+ XAI_API_KEY = os.getenv("XAI_API_KEY")
36
 
37
  client = OpenAI(
38
  api_key=XAI_API_KEY,
 
54
 
55
 
56
  # =====================================================
57
+ # REPORT TITLE
58
+ # =====================================================
59
+
60
+ def get_report_title(selected_model):
61
+ if "Asphalt" in selected_model:
62
+ return "Civil Engineering Asphalt Pavement Inspection Report"
63
+ elif "Concrete" in selected_model:
64
+ return "Civil Engineering Concrete Pathology Inspection Report"
65
+ elif "Facades" in selected_model:
66
+ return "Civil Engineering Facade Pathology Inspection Report"
67
+ else:
68
+ return "Civil Engineering Pathology Inspection Report"
69
+
70
+
71
+ # =====================================================
72
+ # ASPHALT PATHOLOGY CATALOG
73
  # =====================================================
74
 
75
+ ASPHALT_CATALOG = {
76
  "01LONGITUDINAL CRACKS": {
77
  "name": "Longitudinal Cracks",
78
  "severity": "Medium",
 
97
  "risk": "Advanced structural fatigue, pothole formation, and possible pavement collapse.",
98
  "recommendation": "Mill affected layers and reconstruct pavement structure. Perform geotechnical investigation if widespread."
99
  },
 
 
 
 
 
 
 
 
100
  "05POTHOLES": {
101
  "name": "Potholes",
102
  "severity": "High",
103
  "priority": "P1",
104
  "deadline": "Immediate: within 24–48 hours",
105
+ "risk": "Direct accident risk, especially for motorcycles and bicycles.",
106
  "recommendation": "Immediate patching with hot/cold bituminous mix. Cut edges, clean, prime, fill, and compact."
107
  },
108
  "06RUTTING": {
 
111
  "priority": "P1/P2",
112
  "deadline": "Short term if rut depth exceeds 15–20 mm",
113
  "risk": "Aquaplaning, vehicle instability, and progressive lower-layer degradation.",
114
+ "recommendation": "Mill affected area and replace with high-stability asphalt mix."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  },
116
  "10SURFACE RAVELING": {
117
  "name": "Surface Raveling",
 
120
  "deadline": "Medium term: 1–3 months",
121
  "risk": "Loose aggregate, reduced traction, water penetration, and future pothole formation.",
122
  "recommendation": "Apply slurry seal, microsurfacing, or mill and resurface if advanced."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  }
124
  }
125
 
126
 
127
+ # =====================================================
128
+ # SELECT CATALOG
129
+ # =====================================================
130
+
131
+ def get_catalog(selected_model):
132
+ if "Asphalt" in selected_model:
133
+ return ASPHALT_CATALOG
134
+ else:
135
+ return {}
136
+
137
+
138
  # =====================================================
139
  # DETECTION HELPERS
140
  # =====================================================
141
 
142
+ def get_detection_summary(results, selected_model):
143
  detections = []
144
+ model = models[selected_model]
145
 
146
  for r in results:
147
  if r.boxes is None:
 
156
  key = normalize_class_name(raw_name)
157
 
158
  detections.append({
159
+ "model": selected_model,
160
  "class": raw_name,
161
  "key": key,
162
  "confidence": round(conf, 3),
 
193
  # BASIC ENGINEERING REPORT
194
  # =====================================================
195
 
196
+ def basic_engineering_report(detections, selected_model):
197
  summary = summarize_detections(detections)
198
+ catalog = get_catalog(selected_model)
199
+ title = get_report_title(selected_model)
200
 
201
  if summary["total"] == 0:
202
+ return f"""
203
+ # {title}
204
 
205
  ## Detection Result
206
+ No pathology was detected with the selected confidence threshold.
207
 
208
  ## Engineering Interpretation
209
+ The inspected image/video does not show a clear defect detectable by the selected model. This does not guarantee that the element is defect-free.
210
 
211
  ## Recommended Action
212
  - Repeat inspection with clearer images.
213
+ - Capture the surface perpendicular to the inspected element.
214
  - Use manual visual inspection for confirmation.
215
+ - Reduce the confidence threshold if small or low-contrast defects are expected.
216
 
217
  ## Disclaimer
218
+ This report is AI-assisted and must be verified by a qualified civil engineer.
219
  """
220
 
221
  lines = []
222
 
223
+ lines.append(f"# {title}")
224
  lines.append("")
225
  lines.append("## 1. AI Detection Summary")
226
+ lines.append(f"- Selected model: {selected_model}")
227
  lines.append(f"- Total detected defects: {summary['total']}")
228
 
229
  for cls, count in summary["classes"].items():
230
+ info = catalog.get(cls)
231
  label = info["name"] if info else cls.title()
232
  lines.append(f"- {label}: {count} detected area(s)")
233
 
 
235
  lines.append("## 2. Engineering Diagnosis")
236
 
237
  for cls, count in summary["classes"].items():
238
+ info = catalog.get(cls)
239
 
240
  if info:
241
  lines.append("")
 
255
 
256
  lines.append("")
257
  lines.append("## 3. Field Verification Checklist")
258
+ lines.append("- Measure crack width, spalling depth, pothole depth, deformation, delamination, or level difference where applicable.")
259
+ lines.append("- Record GPS location and inspection area.")
260
  lines.append("- Capture georeferenced photographs before repair.")
261
+ lines.append("- Check drainage, moisture ingress, and evidence of progressive deterioration.")
262
+ lines.append("- Confirm whether loose material creates immediate public safety risk.")
 
263
 
264
  lines.append("")
265
  lines.append("## 4. Professional Notes")
266
+ lines.append("- P1 defects require urgent safety management.")
267
  lines.append("- P2 defects should be included in the structural maintenance plan.")
268
  lines.append("- P3 defects can generally be included in routine preventive maintenance.")
269
+ lines.append("- Final maintenance decisions should be confirmed by an on-site civil engineer.")
270
 
271
  lines.append("")
272
  lines.append("## 5. Disclaimer")
273
+ lines.append("This report is generated using AI-based image/video detection. It is intended for preliminary engineering support only and must not replace field inspection, testing, or professional engineering judgment.")
274
 
275
  return "\n".join(lines)
276
 
 
279
  # GROK ENGINEERING REPORT
280
  # =====================================================
281
 
282
+ def grok_engineering_report(detections, selected_model):
283
+ base_report = basic_engineering_report(detections, selected_model)
284
 
285
  if client is None:
286
  return base_report + "\n\n⚠️ Grok API key not found. Add `XAI_API_KEY` in Hugging Face Space Secrets."
287
 
288
  prompt = f"""
289
+ You are a professional civil engineering inspection expert.
290
 
291
+ Generate a formal engineering inspection report for:
292
+
293
+ {selected_model}
294
 
295
  Use this structure:
296
  1. Project title
297
  2. AI detection summary
298
+ 3. Identified pathologies
299
  4. Probable causes
300
  5. Severity and priority
301
  6. Associated civil engineering risks
 
304
  9. Field verification checklist
305
  10. Disclaimer
306
 
307
+ Detected YOLO data:
 
 
 
 
 
 
 
 
 
308
  {json.dumps(detections, indent=2)}
309
 
310
+ Local report:
311
  {base_report}
312
  """
313
 
 
315
  response = client.chat.completions.create(
316
  model="grok-3-mini",
317
  messages=[
318
+ {
319
+ "role": "system",
320
+ "content": "You are a civil engineering pathology inspection expert."
321
+ },
322
+ {
323
+ "role": "user",
324
+ "content": prompt
325
+ }
326
  ],
327
  temperature=0.2
328
  )
 
337
  # WORD REPORT
338
  # =====================================================
339
 
340
+ def create_word_report(report_text, selected_model):
341
  doc = Document()
342
 
343
+ doc.add_heading(get_report_title(selected_model), level=1)
344
 
345
  for line in report_text.split("\n"):
346
  line = line.strip()
 
377
  # IMAGE DETECTION
378
  # =====================================================
379
 
380
+ def detect_image(image, conf, selected_model):
381
  if image is None:
382
  return None, "Please upload an image.", "", None
383
 
384
+ model = models[selected_model]
385
+
386
  results = model.predict(
387
  source=image,
388
  imgsz=640,
 
394
  plotted = cv2.cvtColor(plotted, cv2.COLOR_BGR2RGB)
395
  output_img = Image.fromarray(plotted)
396
 
397
+ detections = get_detection_summary(results, selected_model)
398
+ report = grok_engineering_report(detections, selected_model)
399
+ word_file = create_word_report(report, selected_model)
400
 
401
  return output_img, json.dumps(detections, indent=2), report, word_file
402
 
 
405
  # VIDEO DETECTION
406
  # =====================================================
407
 
408
+ def detect_video(video_path, conf, selected_model):
409
  if video_path is None:
410
  return None, "Please upload a video.", "", None
411
 
412
+ model = models[selected_model]
413
+
414
  cap = cv2.VideoCapture(video_path)
415
 
416
  if not cap.isOpened():
 
432
 
433
  all_detections = []
434
  frame_count = 0
 
 
435
  process_every_n_frames = 3
436
  last_annotated = None
437
 
 
450
  verbose=False
451
  )
452
 
453
+ detections = get_detection_summary(results, selected_model)
454
  all_detections.extend(detections)
455
 
456
  annotated = results[0].plot()
 
465
  cap.release()
466
  writer.release()
467
 
468
+ report = grok_engineering_report(all_detections, selected_model)
469
+ word_file = create_word_report(report, selected_model)
470
 
471
  return output_path, json.dumps(all_detections[:100], indent=2), report, word_file
472
 
 
475
  # GRADIO UI
476
  # =====================================================
477
 
478
+ with gr.Blocks(title="Civil Infrastructure Pathology Detection + Engineering Report") as demo:
479
 
480
  gr.Markdown("""
481
+ # Civil Infrastructure Pathology Detection and Engineering Report
482
 
483
+ Upload an image or video and select one of the three trained YOLO models:
 
484
 
485
+ - Asphalt pathologies detection
486
+ - Concrete pathologies detection
487
+ - Facades pathologies detection
488
+
489
+ The app generates detection results and a downloadable Word engineering report.
490
  """)
491
 
492
+ selected_model = gr.Dropdown(
493
+ choices=list(MODEL_PATHS.keys()),
494
+ value="Asphalt Pathologies Detection",
495
+ label="Select Detection Model"
496
+ )
497
+
498
  conf = gr.Slider(
499
  minimum=0.10,
500
  maximum=0.90,
 
504
  )
505
 
506
  with gr.Tab("Image Detection"):
507
+ image_input = gr.Image(type="pil", label="Upload Image")
508
  image_output = gr.Image(type="pil", label="Detection Output")
509
  image_json = gr.Textbox(label="Raw Detection Data", lines=8)
510
  image_report = gr.Markdown(label="Engineering Report")
 
514
 
515
  image_btn.click(
516
  fn=detect_image,
517
+ inputs=[image_input, conf, selected_model],
518
  outputs=[image_output, image_json, image_report, image_docx]
519
  )
520
 
521
  with gr.Tab("Video Detection"):
522
+ video_input = gr.Video(label="Upload Video")
523
  video_output = gr.Video(label="Detection Output Video")
524
  video_json = gr.Textbox(label="Raw Detection Data - First 100 Detections", lines=8)
525
  video_report = gr.Markdown(label="Engineering Report")
 
529
 
530
  video_btn.click(
531
  fn=detect_video,
532
+ inputs=[video_input, conf, selected_model],
533
  outputs=[video_output, video_json, video_report, video_docx]
534
  )
535
 
536
  gr.Markdown("""
537
  ## Notes
538
+ - Upload the correct type of image/video for the selected model.
539
  - For video, every 3rd frame is processed to reduce runtime.
540
+ - Add `XAI_API_KEY` in Hugging Face Space Secrets to enable Grok-generated reporting.
541
  - If no API key is added, the app still generates a local engineering report.
542
  - The report is AI-assisted and must be verified by a qualified civil engineer.
543
  """)
544
 
545
+
546
  if __name__ == "__main__":
547
  demo.launch(
548
+ server_name="0.0.0.0",
549
+ server_port=7860,
550
+ ssr_mode=False
551
+ )