DIVYANSHI SINGH
feat: implement dynamic model-specific samples and resolve session stability error
e22aa39
"""
path_utils.py
-------------
Centralised path handling for the Pothole Detection Streamlit app.
"""
from pathlib import Path
# ── Root of the project ────────────────────────────────────────────────────────
ROOT = Path(__file__).resolve().parent.parent
def get_available_models() -> dict:
"""
Find and categorize trained weights in the project's local 'models' directory.
Returns
-------
dict : { "πŸ› οΈ Crack Model (run_name)": Path, "πŸ•³οΈ Pothole Model (run_name)": Path }
"""
weights_parent = ROOT / "models"
models = {}
if not weights_parent.exists():
return models
for run_dir in weights_parent.iterdir():
if run_dir.is_dir():
best_pt = run_dir / "best.pt"
if best_pt.exists():
name = run_dir.name
if "crack" in name.lower():
label = f"πŸ› οΈ Crack Model ({name})"
else:
label = f"πŸ•³οΈ Pothole Model ({name})"
models[label] = best_pt
return models
def get_model_path(variant: str) -> Path:
# This is now just returning the Path directly since get_available_models returns Paths
return Path(variant)
def get_training_artifact(model_path: Path, filename: str) -> Path:
"""Return the Path to a specific training plot/artifact, searching common synonyms."""
base_dir = model_path.parent
# Define common naming synonyms across YOLO versions
synonyms = {
"PR_curve.png": ["PR_curve.png", "BoxPR_curve.png"],
"results.png": ["results.png"],
"confusion_matrix.png": ["confusion_matrix_normalized.png", "confusion_matrix.png"],
"val_batch0_pred.jpg": ["val_batch0_pred.jpg"],
"val_batch0_labels.jpg": ["val_batch0_labels.jpg"]
}
if filename in synonyms:
for syn in synonyms[filename]:
p = base_dir / syn
if p.exists(): return p
# Fallback to exact filename
return base_dir / filename
def get_sample_path(filename: str, is_video: bool = False, is_crack: bool = False) -> Path:
"""Find a sample file, prioritizing cloud-accessible 'assets/' folder."""
if is_video:
sub = "videos"
elif is_crack:
sub = "images/cracks"
else:
sub = "images"
# Priority 1: Cloud Assets (included in Git)
p = ROOT / "assets" / "samples" / sub / filename
if p.exists(): return p
# Priority 2: Local Data Folders (Git ignored)
if is_video:
p = ROOT / "data" / "samples" / "videos" / filename
else:
p = ROOT / "data" / "combined" / "train" / "images" / filename
if not p.exists():
p = ROOT / "data" / "combined" / "test" / "images" / filename
if not p.exists() and is_crack:
p = ROOT / "data" / "bc_projekt" / "test" / "images" / filename
return p
def model_info(model_path: Path) -> dict:
# Static info based on model size (deduced from filename or parent)
name = str(model_path).lower()
if "yolo11s" in name:
return {"name": "YOLO11s", "map50": "74.1%", "speed_ms": "~8ms"}
return {"name": "YOLO11n", "map50": "66.7%", "speed_ms": "~4ms"}