[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6FJTY5N0WKKTRH3X6XYCS5N":3,"skill-same:01M6FJTY5N0WKKTRH3X6XYCS5N":61},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":28,"linkOnly":29,"markdownContent":30,"markdownBody":31,"frontMatter":32,"refName":34,"commitSha":35,"skillDirectory":36,"forksCount":37,"repositoryHtmlUrl":38,"repositoryHomepageUrl":6,"ownerHtmlUrl":39,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":40,"install":41,"resources":54},"01M6FJTY5N0WKKTRH3X6XYCS5N","defect-detection-ai",null,"AI-powered construction defect detection using computer vision. Identify cracks, spalling, corrosion, and other defects in concrete, steel, and building components from images and video.","kbarbel640-del\u002Fskills","kbarbel640-del","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F255315490?v=4","01M6CJPPQGCCESXMG3K7BBGQ5J","01M6CJPPX2PB2BCZERFVM2C2B3",1,"MIT","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fdatadrivenconstruction\u002Fdefect-detection-ai\u002FSKILL.md",[],[18,19,20,21,22,23,24,25,26,27],"detection","defect detection ai","components","Computer Vision","Video","computer","vision","images","corrosion","steel","2026-11-10 10:12:30",false,"---\r\nslug: \"defect-detection-ai\"\r\ndisplay_name: \"Defect Detection AI\"\r\ndescription: \"AI-powered construction defect detection using computer vision. Identify cracks, spalling, corrosion, and other defects in concrete, steel, and building components from images and video.\"\r\n---\r\n\r\n# AI Defect Detection\r\n\r\n## Overview\r\n\r\nThis skill implements deep learning-based defect detection for construction quality control. Analyze images and video to automatically identify structural and surface defects, classify severity, and generate inspection reports.\r\n\r\n**Detectable Defects:**\r\n- Concrete: Cracks, spalling, honeycombing, efflorescence\r\n- Steel: Corrosion, weld defects, deformation\r\n- Masonry: Mortar deterioration, displacement\r\n- Finishes: Surface defects, coating failures\r\n- MEP: Insulation damage, pipe corrosion\r\n\r\n## Quick Start\r\n\r\n```python\r\nimport torch\r\nimport torch.nn as nn\r\nfrom torchvision import transforms, models\r\nfrom PIL import Image\r\nfrom dataclasses import dataclass\r\nfrom typing import List, Dict, Tuple\r\nfrom enum import Enum\r\n\r\nclass DefectType(Enum):\r\n    CRACK = \"crack\"\r\n    SPALLING = \"spalling\"\r\n    CORROSION = \"corrosion\"\r\n    HONEYCOMBING = \"honeycombing\"\r\n    EFFLORESCENCE = \"efflorescence\"\r\n    DEFORMATION = \"deformation\"\r\n    SURFACE_DAMAGE = \"surface_damage\"\r\n    NO_DEFECT = \"no_defect\"\r\n\r\nclass SeverityLevel(Enum):\r\n    MINOR = \"minor\"\r\n    MODERATE = \"moderate\"\r\n    SEVERE = \"severe\"\r\n    CRITICAL = \"critical\"\r\n\r\n@dataclass\r\nclass DefectDetection:\r\n    defect_type: DefectType\r\n    confidence: float\r\n    severity: SeverityLevel\r\n    bounding_box: Tuple[int, int, int, int]  # x1, y1, x2, y2\r\n    area_ratio: float  # Defect area as ratio of image\r\n\r\n# Simple classifier using pretrained model\r\nclass SimpleDefectClassifier:\r\n    def __init__(self, num_classes: int = 8):\r\n        self.model = models.resnet18(pretrained=True)\r\n        self.model.fc = nn.Linear(self.model.fc.in_features, num_classes)\r\n        self.model.eval()\r\n\r\n        self.transform = transforms.Compose([\r\n            transforms.Resize((224, 224)),\r\n            transforms.ToTensor(),\r\n            transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\r\n        ])\r\n\r\n        self.classes = list(DefectType)\r\n\r\n    def predict(self, image_path: str) -> DefectDetection:\r\n        \"\"\"Classify defect in image\"\"\"\r\n        image = Image.open(image_path).convert('RGB')\r\n        input_tensor = self.transform(image).unsqueeze(0)\r\n\r\n        with torch.no_grad():\r\n            outputs = self.model(input_tensor)\r\n            probs = torch.softmax(outputs, dim=1)\r\n            confidence, predicted = torch.max(probs, 1)\r\n\r\n        defect_type = self.classes[predicted.item()]\r\n\r\n        return DefectDetection(\r\n            defect_type=defect_type,\r\n            confidence=confidence.item(),\r\n            severity=self._estimate_severity(confidence.item()),\r\n            bounding_box=(0, 0, image.width, image.height),\r\n            area_ratio=1.0\r\n        )\r\n\r\n    def _estimate_severity(self, confidence: float) -> SeverityLevel:\r\n        if confidence > 0.9:\r\n            return SeverityLevel.CRITICAL\r\n        elif confidence > 0.7:\r\n            return SeverityLevel.SEVERE\r\n        elif confidence > 0.5:\r\n            return SeverityLevel.MODERATE\r\n        else:\r\n            return SeverityLevel.MINOR\r\n\r\n# Usage\r\nclassifier = SimpleDefectClassifier()\r\n# result = classifier.predict(\"concrete_image.jpg\")\r\n# print(f\"Defect: {result.defect_type.value}, Confidence: {result.confidence:.2%}\")\r\n```\r\n\r\n## Comprehensive Defect Detection System\r\n\r\n### Object Detection Model\r\n\r\n```python\r\nimport torch\r\nimport torch.nn as nn\r\nfrom torchvision import transforms\r\nfrom torchvision.models.detection import fasterrcnn_resnet50_fpn\r\nfrom PIL import Image\r\nimport numpy as np\r\nfrom dataclasses import dataclass, field\r\nfrom typing import List, Dict, Tuple, Optional\r\nfrom datetime import datetime\r\nimport json\r\n\r\n@dataclass\r\nclass BoundingBox:\r\n    x1: int\r\n    y1: int\r\n    x2: int\r\n    y2: int\r\n\r\n    @property\r\n    def width(self) -> int:\r\n        return self.x2 - self.x1\r\n\r\n    @property\r\n    def height(self) -> int:\r\n        return self.y2 - self.y1\r\n\r\n    @property\r\n    def area(self) -> int:\r\n        return self.width * self.height\r\n\r\n    @property\r\n    def center(self) -> Tuple[int, int]:\r\n        return ((self.x1 + self.x2) \u002F\u002F 2, (self.y1 + self.y2) \u002F\u002F 2)\r\n\r\n@dataclass\r\nclass DetectedDefect:\r\n    defect_id: str\r\n    defect_type: DefectType\r\n    confidence: float\r\n    severity: SeverityLevel\r\n    bounding_box: BoundingBox\r\n    area_sqm: Optional[float] = None\r\n    dimensions_mm: Optional[Tuple[float, float]] = None\r\n    metadata: Dict = field(default_factory=dict)\r\n\r\n@dataclass\r\nclass InspectionResult:\r\n    inspection_id: str\r\n    image_path: str\r\n    timestamp: datetime\r\n    location: str\r\n    element_type: str\r\n    defects: List[DetectedDefect]\r\n    overall_condition: str\r\n    recommended_actions: List[str]\r\n\r\nclass DefectDetectionModel:\r\n    \"\"\"Deep learning defect detection with object detection\"\"\"\r\n\r\n    DEFECT_CLASSES = {\r\n        1: DefectType.CRACK,\r\n        2: DefectType.SPALLING,\r\n        3: DefectType.CORROSION,\r\n        4: DefectType.HONEYCOMBING,\r\n        5: DefectType.EFFLORESCENCE,\r\n        6: DefectType.DEFORMATION,\r\n        7: DefectType.SURFACE_DAMAGE\r\n    }\r\n\r\n    def __init__(self, model_path: str = None, device: str = 'cpu'):\r\n        self.device = torch.device(device)\r\n\r\n        # Initialize Faster R-CNN\r\n        self.model = fasterrcnn_resnet50_fpn(pretrained=True)\r\n\r\n        # Modify for our classes\r\n        num_classes = len(self.DEFECT_CLASSES) + 1  # +1 for background\r\n        in_features = self.model.roi_heads.box_predictor.cls_score.in_features\r\n        self.model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)\r\n\r\n        if model_path:\r\n            self.model.load_state_dict(torch.load(model_path, map_location=self.device))\r\n\r\n        self.model.to(self.device)\r\n        self.model.eval()\r\n\r\n        self.transform = transforms.Compose([\r\n            transforms.ToTensor()\r\n        ])\r\n\r\n    def detect(self, image_path: str, confidence_threshold: float = 0.5,\r\n               pixels_per_mm: float = None) -> List[DetectedDefect]:\r\n        \"\"\"Detect defects in image\"\"\"\r\n        image = Image.open(image_path).convert('RGB')\r\n        image_tensor = self.transform(image).to(self.device)\r\n\r\n        with torch.no_grad():\r\n            predictions = self.model([image_tensor])\r\n\r\n        pred = predictions[0]\r\n        defects = []\r\n\r\n        for i in range(len(pred['boxes'])):\r\n            score = pred['scores'][i].item()\r\n\r\n            if score \u003C confidence_threshold:\r\n                continue\r\n\r\n            label = pred['labels'][i].item()\r\n            box = pred['boxes'][i].cpu().numpy()\r\n\r\n            defect_type = self.DEFECT_CLASSES.get(label, DefectType.SURFACE_DAMAGE)\r\n\r\n            bbox = BoundingBox(\r\n                x1=int(box[0]),\r\n                y1=int(box[1]),\r\n                x2=int(box[2]),\r\n                y2=int(box[3])\r\n            )\r\n\r\n            # Calculate dimensions if scale provided\r\n            dimensions_mm = None\r\n            if pixels_per_mm:\r\n                width_mm = bbox.width \u002F pixels_per_mm\r\n                height_mm = bbox.height \u002F pixels_per_mm\r\n                dimensions_mm = (width_mm, height_mm)\r\n\r\n            severity = self._classify_severity(defect_type, bbox, image.size)\r\n\r\n            defects.append(DetectedDefect(\r\n                defect_id=f\"DEF-{i:04d}\",\r\n                defect_type=defect_type,\r\n                confidence=score,\r\n                severity=severity,\r\n                bounding_box=bbox,\r\n                dimensions_mm=dimensions_mm\r\n            ))\r\n\r\n        return defects\r\n\r\n    def _classify_severity(self, defect_type: DefectType,\r\n                          bbox: BoundingBox,\r\n                          image_size: Tuple[int, int]) -> SeverityLevel:\r\n        \"\"\"Classify defect severity based on type and size\"\"\"\r\n        image_area = image_size[0] * image_size[1]\r\n        defect_ratio = bbox.area \u002F image_area\r\n\r\n        # Severity thresholds by defect type\r\n        thresholds = {\r\n            DefectType.CRACK: {'critical': 0.1, 'severe': 0.05, 'moderate': 0.02},\r\n            DefectType.SPALLING: {'critical': 0.15, 'severe': 0.08, 'moderate': 0.03},\r\n            DefectType.CORROSION: {'critical': 0.2, 'severe': 0.1, 'moderate': 0.05},\r\n            DefectType.HONEYCOMBING: {'critical': 0.1, 'severe': 0.05, 'moderate': 0.02},\r\n            DefectType.DEFORMATION: {'critical': 0.05, 'severe': 0.02, 'moderate': 0.01}\r\n        }\r\n\r\n        t = thresholds.get(defect_type, {'critical': 0.15, 'severe': 0.08, 'moderate': 0.03})\r\n\r\n        if defect_ratio >= t['critical']:\r\n            return SeverityLevel.CRITICAL\r\n        elif defect_ratio >= t['severe']:\r\n            return SeverityLevel.SEVERE\r\n        elif defect_ratio >= t['moderate']:\r\n            return SeverityLevel.MODERATE\r\n        else:\r\n            return SeverityLevel.MINOR\r\n\r\n\r\nclass FastRCNNPredictor(nn.Module):\r\n    \"\"\"Custom predictor for Faster R-CNN\"\"\"\r\n\r\n    def __init__(self, in_channels, num_classes):\r\n        super().__init__()\r\n        self.cls_score = nn.Linear(in_channels, num_classes)\r\n        self.bbox_pred = nn.Linear(in_channels, num_classes * 4)\r\n\r\n    def forward(self, x):\r\n        scores = self.cls_score(x)\r\n        bbox_deltas = self.bbox_pred(x)\r\n        return scores, bbox_deltas\r\n```\r\n\r\n### Crack Analysis System\r\n\r\n```python\r\nimport cv2\r\nimport numpy as np\r\nfrom typing import List, Tuple, Dict\r\n\r\nclass CrackAnalyzer:\r\n    \"\"\"Specialized crack detection and measurement\"\"\"\r\n\r\n    def __init__(self):\r\n        self.min_crack_length = 10  # pixels\r\n        self.min_crack_width = 2  # pixels\r\n\r\n    def detect_cracks(self, image_path: str,\r\n                      pixels_per_mm: float = 1.0) -> List[Dict]:\r\n        \"\"\"Detect and measure cracks in image\"\"\"\r\n        # Load image\r\n        image = cv2.imread(image_path)\r\n        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)\r\n\r\n        # Enhance contrast\r\n        clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))\r\n        enhanced = clahe.apply(gray)\r\n\r\n        # Edge detection\r\n        edges = cv2.Canny(enhanced, 50, 150)\r\n\r\n        # Morphological operations to connect crack segments\r\n        kernel = np.ones((3, 3), np.uint8)\r\n        dilated = cv2.dilate(edges, kernel, iterations=1)\r\n        closed = cv2.morphologyEx(dilated, cv2.MORPH_CLOSE, kernel)\r\n\r\n        # Find contours\r\n        contours, _ = cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\r\n\r\n        cracks = []\r\n        for i, contour in enumerate(contours):\r\n            # Filter by length\r\n            arc_length = cv2.arcLength(contour, False)\r\n            if arc_length \u003C self.min_crack_length:\r\n                continue\r\n\r\n            # Get bounding box\r\n            x, y, w, h = cv2.boundingRect(contour)\r\n\r\n            # Calculate crack properties\r\n            length_px = arc_length\r\n            width_px = self._estimate_crack_width(gray, contour)\r\n\r\n            # Convert to mm\r\n            length_mm = length_px \u002F pixels_per_mm\r\n            width_mm = width_px \u002F pixels_per_mm\r\n\r\n            # Classify crack\r\n            crack_type = self._classify_crack(length_mm, width_mm, contour)\r\n\r\n            cracks.append({\r\n                'crack_id': f\"CRACK-{i:04d}\",\r\n                'type': crack_type,\r\n                'length_mm': length_mm,\r\n                'width_mm': width_mm,\r\n                'bounding_box': (x, y, x + w, y + h),\r\n                'contour': contour.tolist(),\r\n                'severity': self._get_crack_severity(width_mm, length_mm),\r\n                'orientation': self._get_crack_orientation(contour)\r\n            })\r\n\r\n        return cracks\r\n\r\n    def _estimate_crack_width(self, gray_image: np.ndarray,\r\n                             contour: np.ndarray) -> float:\r\n        \"\"\"Estimate average crack width\"\"\"\r\n        # Create mask for contour\r\n        mask = np.zeros(gray_image.shape, dtype=np.uint8)\r\n        cv2.drawContours(mask, [contour], -1, 255, 1)\r\n\r\n        # Distance transform\r\n        dist = cv2.distanceTransform(mask, cv2.DIST_L2, 5)\r\n\r\n        # Get average distance (half-width)\r\n        nonzero = dist[dist > 0]\r\n        if len(nonzero) > 0:\r\n            return np.mean(nonzero) * 2\r\n        return 0\r\n\r\n    def _classify_crack(self, length_mm: float, width_mm: float,\r\n                       contour: np.ndarray) -> str:\r\n        \"\"\"Classify crack type\"\"\"\r\n        # Fit line to get orientation\r\n        [vx, vy, x, y] = cv2.fitLine(contour, cv2.DIST_L2, 0, 0.01, 0.01)\r\n        angle = np.arctan2(vy, vx) * 180 \u002F np.pi\r\n\r\n        if abs(angle) \u003C 20 or abs(angle) > 160:\r\n            orientation = \"horizontal\"\r\n        elif 70 \u003C abs(angle) \u003C 110:\r\n            orientation = \"vertical\"\r\n        else:\r\n            orientation = \"diagonal\"\r\n\r\n        # Check for pattern (simplified)\r\n        if width_mm > 3:\r\n            return \"structural_crack\"\r\n        elif orientation == \"horizontal\" and length_mm > 100:\r\n            return \"settlement_crack\"\r\n        elif orientation == \"diagonal\":\r\n            return \"shear_crack\"\r\n        else:\r\n            return \"shrinkage_crack\"\r\n\r\n    def _get_crack_severity(self, width_mm: float, length_mm: float) -> str:\r\n        \"\"\"Determine crack severity based on dimensions\"\"\"\r\n        # Based on ACI 224R guidelines\r\n        if width_mm > 1.0:\r\n            return \"critical\"\r\n        elif width_mm > 0.4:\r\n            return \"severe\"\r\n        elif width_mm > 0.2:\r\n            return \"moderate\"\r\n        else:\r\n            return \"minor\"\r\n\r\n    def _get_crack_orientation(self, contour: np.ndarray) -> float:\r\n        \"\"\"Get crack orientation angle\"\"\"\r\n        [vx, vy, x, y] = cv2.fitLine(contour, cv2.DIST_L2, 0, 0.01, 0.01)\r\n        return float(np.arctan2(vy, vx) * 180 \u002F np.pi)\r\n\r\n    def generate_crack_report(self, cracks: List[Dict]) -> Dict:\r\n        \"\"\"Generate summary report of detected cracks\"\"\"\r\n        if not cracks:\r\n            return {'message': 'No cracks detected'}\r\n\r\n        total_length = sum(c['length_mm'] for c in cracks)\r\n        max_width = max(c['width_mm'] for c in cracks)\r\n        severity_counts = {}\r\n\r\n        for c in cracks:\r\n            sev = c['severity']\r\n            severity_counts[sev] = severity_counts.get(sev, 0) + 1\r\n\r\n        return {\r\n            'total_cracks': len(cracks),\r\n            'total_length_mm': total_length,\r\n            'max_width_mm': max_width,\r\n            'avg_width_mm': sum(c['width_mm'] for c in cracks) \u002F len(cracks),\r\n            'by_severity': severity_counts,\r\n            'by_type': self._group_by_type(cracks),\r\n            'most_severe': max(cracks, key=lambda c: c['width_mm'])\r\n        }\r\n\r\n    def _group_by_type(self, cracks: List[Dict]) -> Dict:\r\n        \"\"\"Group cracks by type\"\"\"\r\n        grouped = {}\r\n        for c in cracks:\r\n            t = c['type']\r\n            if t not in grouped:\r\n                grouped[t] = []\r\n            grouped[t].append(c['crack_id'])\r\n        return grouped\r\n```\r\n\r\n### Inspection Report Generator\r\n\r\n```python\r\nfrom datetime import datetime\r\nimport pandas as pd\r\n\r\nclass DefectInspectionSystem:\r\n    \"\"\"Complete defect inspection and reporting system\"\"\"\r\n\r\n    def __init__(self, detection_model: DefectDetectionModel):\r\n        self.model = detection_model\r\n        self.crack_analyzer = CrackAnalyzer()\r\n        self.inspections: List[InspectionResult] = []\r\n\r\n    def perform_inspection(self, image_path: str,\r\n                          location: str,\r\n                          element_type: str,\r\n                          pixels_per_mm: float = None) -> InspectionResult:\r\n        \"\"\"Perform complete inspection on image\"\"\"\r\n        # Detect defects\r\n        defects = self.model.detect(image_path, pixels_per_mm=pixels_per_mm)\r\n\r\n        # Additional crack analysis for concrete\r\n        if element_type.lower() in ['concrete', 'slab', 'wall', 'column', 'beam']:\r\n            cracks = self.crack_analyzer.detect_cracks(image_path, pixels_per_mm or 1.0)\r\n\r\n            # Add detailed crack info to relevant defects\r\n            for defect in defects:\r\n                if defect.defect_type == DefectType.CRACK:\r\n                    for crack in cracks:\r\n                        # Check if crack overlaps with defect bbox\r\n                        if self._boxes_overlap(defect.bounding_box, crack['bounding_box']):\r\n                            defect.metadata['crack_details'] = crack\r\n                            break\r\n\r\n        # Determine overall condition\r\n        overall_condition = self._assess_overall_condition(defects)\r\n\r\n        # Generate recommendations\r\n        recommendations = self._generate_recommendations(defects, element_type)\r\n\r\n        result = InspectionResult(\r\n            inspection_id=f\"INS-{datetime.now().strftime('%Y%m%d%H%M%S')}\",\r\n            image_path=image_path,\r\n            timestamp=datetime.now(),\r\n            location=location,\r\n            element_type=element_type,\r\n            defects=defects,\r\n            overall_condition=overall_condition,\r\n            recommended_actions=recommendations\r\n        )\r\n\r\n        self.inspections.append(result)\r\n        return result\r\n\r\n    def _boxes_overlap(self, box1: BoundingBox, box2: Tuple) -> bool:\r\n        \"\"\"Check if two bounding boxes overlap\"\"\"\r\n        x1_1, y1_1, x2_1, y2_1 = box1.x1, box1.y1, box1.x2, box1.y2\r\n        x1_2, y1_2, x2_2, y2_2 = box2\r\n\r\n        return not (x2_1 \u003C x1_2 or x2_2 \u003C x1_1 or y2_1 \u003C y1_2 or y2_2 \u003C y1_1)\r\n\r\n    def _assess_overall_condition(self, defects: List[DetectedDefect]) -> str:\r\n        \"\"\"Assess overall structural condition\"\"\"\r\n        if not defects:\r\n            return \"Good\"\r\n\r\n        severity_scores = {\r\n            SeverityLevel.MINOR: 1,\r\n            SeverityLevel.MODERATE: 2,\r\n            SeverityLevel.SEVERE: 3,\r\n            SeverityLevel.CRITICAL: 4\r\n        }\r\n\r\n        max_severity = max(severity_scores[d.severity] for d in defects)\r\n        total_defects = len(defects)\r\n\r\n        if max_severity >= 4 or total_defects > 10:\r\n            return \"Critical - Immediate attention required\"\r\n        elif max_severity >= 3 or total_defects > 5:\r\n            return \"Poor - Repairs needed\"\r\n        elif max_severity >= 2 or total_defects > 2:\r\n            return \"Fair - Monitor and plan repairs\"\r\n        else:\r\n            return \"Good - Minor issues only\"\r\n\r\n    def _generate_recommendations(self, defects: List[DetectedDefect],\r\n                                 element_type: str) -> List[str]:\r\n        \"\"\"Generate repair recommendations\"\"\"\r\n        recommendations = []\r\n\r\n        # Group defects by type\r\n        defect_groups = {}\r\n        for d in defects:\r\n            t = d.defect_type\r\n            if t not in defect_groups:\r\n                defect_groups[t] = []\r\n            defect_groups[t].append(d)\r\n\r\n        # Generate recommendations by defect type\r\n        for defect_type, group in defect_groups.items():\r\n            max_severity = max(d.severity for d in group)\r\n\r\n            if defect_type == DefectType.CRACK:\r\n                if max_severity in [SeverityLevel.CRITICAL, SeverityLevel.SEVERE]:\r\n                    recommendations.append(\r\n                        f\"Structural engineer assessment required for {len(group)} crack(s). \"\r\n                        f\"Consider epoxy injection or structural repair.\"\r\n                    )\r\n                else:\r\n                    recommendations.append(\r\n                        f\"Seal {len(group)} minor crack(s) with appropriate sealant.\"\r\n                    )\r\n\r\n            elif defect_type == DefectType.SPALLING:\r\n                recommendations.append(\r\n                    f\"Remove loose concrete and apply repair mortar to {len(group)} spalling area(s). \"\r\n                    f\"Check reinforcement for corrosion.\"\r\n                )\r\n\r\n            elif defect_type == DefectType.CORROSION:\r\n                recommendations.append(\r\n                    f\"Treat {len(group)} corrosion area(s). Clean rust, apply rust converter, \"\r\n                    f\"and protective coating.\"\r\n                )\r\n\r\n            elif defect_type == DefectType.HONEYCOMBING:\r\n                recommendations.append(\r\n                    f\"Fill {len(group)} honeycomb area(s) with non-shrink grout. \"\r\n                    f\"Investigate concrete placement procedures.\"\r\n                )\r\n\r\n            elif defect_type == DefectType.EFFLORESCENCE:\r\n                recommendations.append(\r\n                    f\"Clean efflorescence from {len(group)} area(s). \"\r\n                    f\"Investigate and address moisture source.\"\r\n                )\r\n\r\n        if not recommendations:\r\n            recommendations.append(\"Continue regular inspection schedule.\")\r\n\r\n        return recommendations\r\n\r\n    def export_inspection_report(self, inspection_id: str,\r\n                                output_path: str) -> str:\r\n        \"\"\"Export inspection report to Excel\"\"\"\r\n        inspection = next(\r\n            (i for i in self.inspections if i.inspection_id == inspection_id),\r\n            None\r\n        )\r\n\r\n        if not inspection:\r\n            raise ValueError(f\"Inspection {inspection_id} not found\")\r\n\r\n        with pd.ExcelWriter(output_path, engine='openpyxl') as writer:\r\n            # Summary\r\n            summary = pd.DataFrame([{\r\n                'Inspection ID': inspection.inspection_id,\r\n                'Date': inspection.timestamp.strftime('%Y-%m-%d %H:%M'),\r\n                'Location': inspection.location,\r\n                'Element Type': inspection.element_type,\r\n                'Overall Condition': inspection.overall_condition,\r\n                'Total Defects': len(inspection.defects),\r\n                'Image': inspection.image_path\r\n            }])\r\n            summary.to_excel(writer, sheet_name='Summary', index=False)\r\n\r\n            # Defects\r\n            if inspection.defects:\r\n                defect_data = [{\r\n                    'Defect ID': d.defect_id,\r\n                    'Type': d.defect_type.value,\r\n                    'Severity': d.severity.value,\r\n                    'Confidence': f\"{d.confidence:.1%}\",\r\n                    'Location (x,y)': f\"({d.bounding_box.x1}, {d.bounding_box.y1})\",\r\n                    'Size (w×h)': f\"{d.bounding_box.width}×{d.bounding_box.height}\",\r\n                    'Dimensions (mm)': d.dimensions_mm if d.dimensions_mm else 'N\u002FA'\r\n                } for d in inspection.defects]\r\n                pd.DataFrame(defect_data).to_excel(writer, sheet_name='Defects', index=False)\r\n\r\n            # Recommendations\r\n            rec_data = [{'#': i+1, 'Recommendation': r}\r\n                       for i, r in enumerate(inspection.recommended_actions)]\r\n            pd.DataFrame(rec_data).to_excel(writer, sheet_name='Recommendations', index=False)\r\n\r\n        return output_path\r\n\r\n    def get_defect_statistics(self, start_date: datetime = None,\r\n                             end_date: datetime = None) -> Dict:\r\n        \"\"\"Get defect statistics across inspections\"\"\"\r\n        filtered = self.inspections\r\n        if start_date:\r\n            filtered = [i for i in filtered if i.timestamp >= start_date]\r\n        if end_date:\r\n            filtered = [i for i in filtered if i.timestamp \u003C= end_date]\r\n\r\n        all_defects = []\r\n        for inspection in filtered:\r\n            all_defects.extend(inspection.defects)\r\n\r\n        if not all_defects:\r\n            return {'message': 'No defects found in period'}\r\n\r\n        # Statistics\r\n        by_type = {}\r\n        by_severity = {}\r\n\r\n        for d in all_defects:\r\n            t = d.defect_type.value\r\n            s = d.severity.value\r\n\r\n            by_type[t] = by_type.get(t, 0) + 1\r\n            by_severity[s] = by_severity.get(s, 0) + 1\r\n\r\n        return {\r\n            'period': {\r\n                'start': start_date.isoformat() if start_date else 'all',\r\n                'end': end_date.isoformat() if end_date else 'all'\r\n            },\r\n            'total_inspections': len(filtered),\r\n            'total_defects': len(all_defects),\r\n            'by_type': by_type,\r\n            'by_severity': by_severity,\r\n            'avg_defects_per_inspection': len(all_defects) \u002F len(filtered) if filtered else 0\r\n        }\r\n```\r\n\r\n## Model Training\r\n\r\n```python\r\nimport torch\r\nfrom torch.utils.data import Dataset, DataLoader\r\nfrom torchvision import transforms\r\nimport os\r\nfrom PIL import Image\r\n\r\nclass DefectDataset(Dataset):\r\n    \"\"\"Dataset for training defect detection model\"\"\"\r\n\r\n    def __init__(self, root_dir: str, annotations_file: str, transform=None):\r\n        self.root_dir = root_dir\r\n        self.annotations = self._load_annotations(annotations_file)\r\n        self.transform = transform or transforms.Compose([\r\n            transforms.Resize((800, 800)),\r\n            transforms.ToTensor()\r\n        ])\r\n\r\n    def _load_annotations(self, path: str) -> List[Dict]:\r\n        \"\"\"Load COCO-format annotations\"\"\"\r\n        import json\r\n        with open(path, 'r') as f:\r\n            data = json.load(f)\r\n        return data['annotations']\r\n\r\n    def __len__(self):\r\n        return len(self.annotations)\r\n\r\n    def __getitem__(self, idx):\r\n        ann = self.annotations[idx]\r\n        image_path = os.path.join(self.root_dir, ann['image_file'])\r\n        image = Image.open(image_path).convert('RGB')\r\n\r\n        if self.transform:\r\n            image = self.transform(image)\r\n\r\n        # Prepare target\r\n        boxes = torch.tensor(ann['boxes'], dtype=torch.float32)\r\n        labels = torch.tensor(ann['labels'], dtype=torch.int64)\r\n\r\n        target = {\r\n            'boxes': boxes,\r\n            'labels': labels\r\n        }\r\n\r\n        return image, target\r\n\r\n\r\ndef train_defect_model(train_dataset: DefectDataset,\r\n                       val_dataset: DefectDataset,\r\n                       num_epochs: int = 10,\r\n                       batch_size: int = 4,\r\n                       learning_rate: float = 0.005):\r\n    \"\"\"Train defect detection model\"\"\"\r\n    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\r\n\r\n    # Initialize model\r\n    model = fasterrcnn_resnet50_fpn(pretrained=True)\r\n    num_classes = 8  # 7 defect types + background\r\n    in_features = model.roi_heads.box_predictor.cls_score.in_features\r\n    model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)\r\n    model.to(device)\r\n\r\n    # Data loaders\r\n    train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True,\r\n                              collate_fn=lambda x: tuple(zip(*x)))\r\n    val_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False,\r\n                           collate_fn=lambda x: tuple(zip(*x)))\r\n\r\n    # Optimizer\r\n    optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate,\r\n                                momentum=0.9, weight_decay=0.0005)\r\n\r\n    # Training loop\r\n    for epoch in range(num_epochs):\r\n        model.train()\r\n        total_loss = 0\r\n\r\n        for images, targets in train_loader:\r\n            images = [img.to(device) for img in images]\r\n            targets = [{k: v.to(device) for k, v in t.items()} for t in targets]\r\n\r\n            loss_dict = model(images, targets)\r\n            losses = sum(loss for loss in loss_dict.values())\r\n\r\n            optimizer.zero_grad()\r\n            losses.backward()\r\n            optimizer.step()\r\n\r\n            total_loss += losses.item()\r\n\r\n        avg_loss = total_loss \u002F len(train_loader)\r\n        print(f\"Epoch {epoch+1}\u002F{num_epochs}, Loss: {avg_loss:.4f}\")\r\n\r\n    return model\r\n```\r\n\r\n## Quick Reference\r\n\r\n| Defect Type | Detection Method | Typical Severity |\r\n|-------------|------------------|------------------|\r\n| Crack | Edge detection + CNN | Varies by width |\r\n| Spalling | Object detection | Moderate-Severe |\r\n| Corrosion | Color + texture analysis | Moderate-Critical |\r\n| Honeycombing | Object detection | Severe |\r\n| Efflorescence | Color analysis | Minor-Moderate |\r\n\r\n## ACI 224R Crack Width Guidelines\r\n\r\n| Width (mm) | Condition | Exposure |\r\n|------------|-----------|----------|\r\n| \u003C 0.1 | Acceptable | Any |\r\n| 0.1 - 0.2 | Acceptable | Dry |\r\n| 0.2 - 0.4 | Repair recommended | Humid |\r\n| > 0.4 | Repair required | Any |\r\n| > 1.0 | Structural concern | Any |\r\n\r\n## Resources\r\n\r\n- **PyTorch**: https:\u002F\u002Fpytorch.org\r\n- **OpenCV**: https:\u002F\u002Fopencv.org\r\n- **ACI 224R**: Crack control in concrete\r\n- **DDC Website**: https:\u002F\u002Fdatadrivenconstruction.io\r\n\r\n## Next Steps\r\n\r\n- See `progress-monitoring-cv` for construction progress analysis\r\n- See `safety-compliance-checker` for safety defect integration\r\n- See `bim-validation-pipeline` for model-based quality control\r\n","# AI Defect Detection\r\n\r\n## Overview\r\n\r\nThis skill implements deep learning-based defect detection for construction quality control. Analyze images and video to automatically identify structural and surface defects, classify severity, and generate inspection reports.\r\n\r\n**Detectable Defects:**\r\n- Concrete: Cracks, spalling, honeycombing, efflorescence\r\n- Steel: Corrosion, weld defects, deformation\r\n- Masonry: Mortar deterioration, displacement\r\n- Finishes: Surface defects, coating failures\r\n- MEP: Insulation damage, pipe corrosion\r\n\r\n## Quick Start\r\n\r\n```python\r\nimport torch\r\nimport torch.nn as nn\r\nfrom torchvision import transforms, models\r\nfrom PIL import Image\r\nfrom dataclasses import dataclass\r\nfrom typing import List, Dict, Tuple\r\nfrom enum import Enum\r\n\r\nclass DefectType(Enum):\r\n    CRACK = \"crack\"\r\n    SPALLING = \"spalling\"\r\n    CORROSION = \"corrosion\"\r\n    HONEYCOMBING = \"honeycombing\"\r\n    EFFLORESCENCE = \"efflorescence\"\r\n    DEFORMATION = \"deformation\"\r\n    SURFACE_DAMAGE = \"surface_damage\"\r\n    NO_DEFECT = \"no_defect\"\r\n\r\nclass SeverityLevel(Enum):\r\n    MINOR = \"minor\"\r\n    MODERATE = \"moderate\"\r\n    SEVERE = \"severe\"\r\n    CRITICAL = \"critical\"\r\n\r\n@dataclass\r\nclass DefectDetection:\r\n    defect_type: DefectType\r\n    confidence: float\r\n    severity: SeverityLevel\r\n    bounding_box: Tuple[int, int, int, int]  # x1, y1, x2, y2\r\n    area_ratio: float  # Defect area as ratio of image\r\n\r\n# Simple classifier using pretrained model\r\nclass SimpleDefectClassifier:\r\n    def __init__(self, num_classes: int = 8):\r\n        self.model = models.resnet18(pretrained=True)\r\n        self.model.fc = nn.Linear(self.model.fc.in_features, num_classes)\r\n        self.model.eval()\r\n\r\n        self.transform = transforms.Compose([\r\n            transforms.Resize((224, 224)),\r\n            transforms.ToTensor(),\r\n            transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\r\n        ])\r\n\r\n        self.classes = list(DefectType)\r\n\r\n    def predict(self, image_path: str) -> DefectDetection:\r\n        \"\"\"Classify defect in image\"\"\"\r\n        image = Image.open(image_path).convert('RGB')\r\n        input_tensor = self.transform(image).unsqueeze(0)\r\n\r\n        with torch.no_grad():\r\n            outputs = self.model(input_tensor)\r\n            probs = torch.softmax(outputs, dim=1)\r\n            confidence, predicted = torch.max(probs, 1)\r\n\r\n        defect_type = self.classes[predicted.item()]\r\n\r\n        return DefectDetection(\r\n            defect_type=defect_type,\r\n            confidence=confidence.item(),\r\n            severity=self._estimate_severity(confidence.item()),\r\n            bounding_box=(0, 0, image.width, image.height),\r\n            area_ratio=1.0\r\n        )\r\n\r\n    def _estimate_severity(self, confidence: float) -> SeverityLevel:\r\n        if confidence > 0.9:\r\n            return SeverityLevel.CRITICAL\r\n        elif confidence > 0.7:\r\n            return SeverityLevel.SEVERE\r\n        elif confidence > 0.5:\r\n            return SeverityLevel.MODERATE\r\n        else:\r\n            return SeverityLevel.MINOR\r\n\r\n# Usage\r\nclassifier = SimpleDefectClassifier()\r\n# result = classifier.predict(\"concrete_image.jpg\")\r\n# print(f\"Defect: {result.defect_type.value}, Confidence: {result.confidence:.2%}\")\r\n```\r\n\r\n## Comprehensive Defect Detection System\r\n\r\n### Object Detection Model\r\n\r\n```python\r\nimport torch\r\nimport torch.nn as nn\r\nfrom torchvision import transforms\r\nfrom torchvision.models.detection import fasterrcnn_resnet50_fpn\r\nfrom PIL import Image\r\nimport numpy as np\r\nfrom dataclasses import dataclass, field\r\nfrom typing import List, Dict, Tuple, Optional\r\nfrom datetime import datetime\r\nimport json\r\n\r\n@dataclass\r\nclass BoundingBox:\r\n    x1: int\r\n    y1: int\r\n    x2: int\r\n    y2: int\r\n\r\n    @property\r\n    def width(self) -> int:\r\n        return self.x2 - self.x1\r\n\r\n    @property\r\n    def height(self) -> int:\r\n        return self.y2 - self.y1\r\n\r\n    @property\r\n    def area(self) -> int:\r\n        return self.width * self.height\r\n\r\n    @property\r\n    def center(self) -> Tuple[int, int]:\r\n        return ((self.x1 + self.x2) \u002F\u002F 2, (self.y1 + self.y2) \u002F\u002F 2)\r\n\r\n@dataclass\r\nclass DetectedDefect:\r\n    defect_id: str\r\n    defect_type: DefectType\r\n    confidence: float\r\n    severity: SeverityLevel\r\n    bounding_box: BoundingBox\r\n    area_sqm: Optional[float] = None\r\n    dimensions_mm: Optional[Tuple[float, float]] = None\r\n    metadata: Dict = field(default_factory=dict)\r\n\r\n@dataclass\r\nclass InspectionResult:\r\n    inspection_id: str\r\n    image_path: str\r\n    timestamp: datetime\r\n    location: str\r\n    element_type: str\r\n    defects: List[DetectedDefect]\r\n    overall_condition: str\r\n    recommended_actions: List[str]\r\n\r\nclass DefectDetectionModel:\r\n    \"\"\"Deep learning defect detection with object detection\"\"\"\r\n\r\n    DEFECT_CLASSES = {\r\n        1: DefectType.CRACK,\r\n        2: DefectType.SPALLING,\r\n        3: DefectType.CORROSION,\r\n        4: DefectType.HONEYCOMBING,\r\n        5: DefectType.EFFLORESCENCE,\r\n        6: DefectType.DEFORMATION,\r\n        7: DefectType.SURFACE_DAMAGE\r\n    }\r\n\r\n    def __init__(self, model_path: str = None, device: str = 'cpu'):\r\n        self.device = torch.device(device)\r\n\r\n        # Initialize Faster R-CNN\r\n        self.model = fasterrcnn_resnet50_fpn(pretrained=True)\r\n\r\n        # Modify for our classes\r\n        num_classes = len(self.DEFECT_CLASSES) + 1  # +1 for background\r\n        in_features = self.model.roi_heads.box_predictor.cls_score.in_features\r\n        self.model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)\r\n\r\n        if model_path:\r\n            self.model.load_state_dict(torch.load(model_path, map_location=self.device))\r\n\r\n        self.model.to(self.device)\r\n        self.model.eval()\r\n\r\n        self.transform = transforms.Compose([\r\n            transforms.ToTensor()\r\n        ])\r\n\r\n    def detect(self, image_path: str, confidence_threshold: float = 0.5,\r\n               pixels_per_mm: float = None) -> List[DetectedDefect]:\r\n        \"\"\"Detect defects in image\"\"\"\r\n        image = Image.open(image_path).convert('RGB')\r\n        image_tensor = self.transform(image).to(self.device)\r\n\r\n        with torch.no_grad():\r\n            predictions = self.model([image_tensor])\r\n\r\n        pred = predictions[0]\r\n        defects = []\r\n\r\n        for i in range(len(pred['boxes'])):\r\n            score = pred['scores'][i].item()\r\n\r\n            if score \u003C confidence_threshold:\r\n                continue\r\n\r\n            label = pred['labels'][i].item()\r\n            box = pred['boxes'][i].cpu().numpy()\r\n\r\n            defect_type = self.DEFECT_CLASSES.get(label, DefectType.SURFACE_DAMAGE)\r\n\r\n            bbox = BoundingBox(\r\n                x1=int(box[0]),\r\n                y1=int(box[1]),\r\n                x2=int(box[2]),\r\n                y2=int(box[3])\r\n            )\r\n\r\n            # Calculate dimensions if scale provided\r\n            dimensions_mm = None\r\n            if pixels_per_mm:\r\n                width_mm = bbox.width \u002F pixels_per_mm\r\n                height_mm = bbox.height \u002F pixels_per_mm\r\n                dimensions_mm = (width_mm, height_mm)\r\n\r\n            severity = self._classify_severity(defect_type, bbox, image.size)\r\n\r\n            defects.append(DetectedDefect(\r\n                defect_id=f\"DEF-{i:04d}\",\r\n                defect_type=defect_type,\r\n                confidence=score,\r\n                severity=severity,\r\n                bounding_box=bbox,\r\n                dimensions_mm=dimensions_mm\r\n            ))\r\n\r\n        return defects\r\n\r\n    def _classify_severity(self, defect_type: DefectType,\r\n                          bbox: BoundingBox,\r\n                          image_size: Tuple[int, int]) -> SeverityLevel:\r\n        \"\"\"Classify defect severity based on type and size\"\"\"\r\n        image_area = image_size[0] * image_size[1]\r\n        defect_ratio = bbox.area \u002F image_area\r\n\r\n        # Severity thresholds by defect type\r\n        thresholds = {\r\n            DefectType.CRACK: {'critical': 0.1, 'severe': 0.05, 'moderate': 0.02},\r\n            DefectType.SPALLING: {'critical': 0.15, 'severe': 0.08, 'moderate': 0.03},\r\n            DefectType.CORROSION: {'critical': 0.2, 'severe': 0.1, 'moderate': 0.05},\r\n            DefectType.HONEYCOMBING: {'critical': 0.1, 'severe': 0.05, 'moderate': 0.02},\r\n            DefectType.DEFORMATION: {'critical': 0.05, 'severe': 0.02, 'moderate': 0.01}\r\n        }\r\n\r\n        t = thresholds.get(defect_type, {'critical': 0.15, 'severe': 0.08, 'moderate': 0.03})\r\n\r\n        if defect_ratio >= t['critical']:\r\n            return SeverityLevel.CRITICAL\r\n        elif defect_ratio >= t['severe']:\r\n            return SeverityLevel.SEVERE\r\n        elif defect_ratio >= t['moderate']:\r\n            return SeverityLevel.MODERATE\r\n        else:\r\n            return SeverityLevel.MINOR\r\n\r\n\r\nclass FastRCNNPredictor(nn.Module):\r\n    \"\"\"Custom predictor for Faster R-CNN\"\"\"\r\n\r\n    def __init__(self, in_channels, num_classes):\r\n        super().__init__()\r\n        self.cls_score = nn.Linear(in_channels, num_classes)\r\n        self.bbox_pred = nn.Linear(in_channels, num_classes * 4)\r\n\r\n    def forward(self, x):\r\n        scores = self.cls_score(x)\r\n        bbox_deltas = self.bbox_pred(x)\r\n        return scores, bbox_deltas\r\n```\r\n\r\n### Crack Analysis System\r\n\r\n```python\r\nimport cv2\r\nimport numpy as np\r\nfrom typing import List, Tuple, Dict\r\n\r\nclass CrackAnalyzer:\r\n    \"\"\"Specialized crack detection and measurement\"\"\"\r\n\r\n    def __init__(self):\r\n        self.min_crack_length = 10  # pixels\r\n        self.min_crack_width = 2  # pixels\r\n\r\n    def detect_cracks(self, image_path: str,\r\n                      pixels_per_mm: float = 1.0) -> List[Dict]:\r\n        \"\"\"Detect and measure cracks in image\"\"\"\r\n        # Load image\r\n        image = cv2.imread(image_path)\r\n        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)\r\n\r\n        # Enhance contrast\r\n        clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))\r\n        enhanced = clahe.apply(gray)\r\n\r\n        # Edge detection\r\n        edges = cv2.Canny(enhanced, 50, 150)\r\n\r\n        # Morphological operations to connect crack segments\r\n        kernel = np.ones((3, 3), np.uint8)\r\n        dilated = cv2.dilate(edges, kernel, iterations=1)\r\n        closed = cv2.morphologyEx(dilated, cv2.MORPH_CLOSE, kernel)\r\n\r\n        # Find contours\r\n        contours, _ = cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\r\n\r\n        cracks = []\r\n        for i, contour in enumerate(contours):\r\n            # Filter by length\r\n            arc_length = cv2.arcLength(contour, False)\r\n            if arc_length \u003C self.min_crack_length:\r\n                continue\r\n\r\n            # Get bounding box\r\n            x, y, w, h = cv2.boundingRect(contour)\r\n\r\n            # Calculate crack properties\r\n            length_px = arc_length\r\n            width_px = self._estimate_crack_width(gray, contour)\r\n\r\n            # Convert to mm\r\n            length_mm = length_px \u002F pixels_per_mm\r\n            width_mm = width_px \u002F pixels_per_mm\r\n\r\n            # Classify crack\r\n            crack_type = self._classify_crack(length_mm, width_mm, contour)\r\n\r\n            cracks.append({\r\n                'crack_id': f\"CRACK-{i:04d}\",\r\n                'type': crack_type,\r\n                'length_mm': length_mm,\r\n                'width_mm': width_mm,\r\n                'bounding_box': (x, y, x + w, y + h),\r\n                'contour': contour.tolist(),\r\n                'severity': self._get_crack_severity(width_mm, length_mm),\r\n                'orientation': self._get_crack_orientation(contour)\r\n            })\r\n\r\n        return cracks\r\n\r\n    def _estimate_crack_width(self, gray_image: np.ndarray,\r\n                             contour: np.ndarray) -> float:\r\n        \"\"\"Estimate average crack width\"\"\"\r\n        # Create mask for contour\r\n        mask = np.zeros(gray_image.shape, dtype=np.uint8)\r\n        cv2.drawContours(mask, [contour], -1, 255, 1)\r\n\r\n        # Distance transform\r\n        dist = cv2.distanceTransform(mask, cv2.DIST_L2, 5)\r\n\r\n        # Get average distance (half-width)\r\n        nonzero = dist[dist > 0]\r\n        if len(nonzero) > 0:\r\n            return np.mean(nonzero) * 2\r\n        return 0\r\n\r\n    def _classify_crack(self, length_mm: float, width_mm: float,\r\n                       contour: np.ndarray) -> str:\r\n        \"\"\"Classify crack type\"\"\"\r\n        # Fit line to get orientation\r\n        [vx, vy, x, y] = cv2.fitLine(contour, cv2.DIST_L2, 0, 0.01, 0.01)\r\n        angle = np.arctan2(vy, vx) * 180 \u002F np.pi\r\n\r\n        if abs(angle) \u003C 20 or abs(angle) > 160:\r\n            orientation = \"horizontal\"\r\n        elif 70 \u003C abs(angle) \u003C 110:\r\n            orientation = \"vertical\"\r\n        else:\r\n            orientation = \"diagonal\"\r\n\r\n        # Check for pattern (simplified)\r\n        if width_mm > 3:\r\n            return \"structural_crack\"\r\n        elif orientation == \"horizontal\" and length_mm > 100:\r\n            return \"settlement_crack\"\r\n        elif orientation == \"diagonal\":\r\n            return \"shear_crack\"\r\n        else:\r\n            return \"shrinkage_crack\"\r\n\r\n    def _get_crack_severity(self, width_mm: float, length_mm: float) -> str:\r\n        \"\"\"Determine crack severity based on dimensions\"\"\"\r\n        # Based on ACI 224R guidelines\r\n        if width_mm > 1.0:\r\n            return \"critical\"\r\n        elif width_mm > 0.4:\r\n            return \"severe\"\r\n        elif width_mm > 0.2:\r\n            return \"moderate\"\r\n        else:\r\n            return \"minor\"\r\n\r\n    def _get_crack_orientation(self, contour: np.ndarray) -> float:\r\n        \"\"\"Get crack orientation angle\"\"\"\r\n        [vx, vy, x, y] = cv2.fitLine(contour, cv2.DIST_L2, 0, 0.01, 0.01)\r\n        return float(np.arctan2(vy, vx) * 180 \u002F np.pi)\r\n\r\n    def generate_crack_report(self, cracks: List[Dict]) -> Dict:\r\n        \"\"\"Generate summary report of detected cracks\"\"\"\r\n        if not cracks:\r\n            return {'message': 'No cracks detected'}\r\n\r\n        total_length = sum(c['length_mm'] for c in cracks)\r\n        max_width = max(c['width_mm'] for c in cracks)\r\n        severity_counts = {}\r\n\r\n        for c in cracks:\r\n            sev = c['severity']\r\n            severity_counts[sev] = severity_counts.get(sev, 0) + 1\r\n\r\n        return {\r\n            'total_cracks': len(cracks),\r\n            'total_length_mm': total_length,\r\n            'max_width_mm': max_width,\r\n            'avg_width_mm': sum(c['width_mm'] for c in cracks) \u002F len(cracks),\r\n            'by_severity': severity_counts,\r\n            'by_type': self._group_by_type(cracks),\r\n            'most_severe': max(cracks, key=lambda c: c['width_mm'])\r\n        }\r\n\r\n    def _group_by_type(self, cracks: List[Dict]) -> Dict:\r\n        \"\"\"Group cracks by type\"\"\"\r\n        grouped = {}\r\n        for c in cracks:\r\n            t = c['type']\r\n            if t not in grouped:\r\n                grouped[t] = []\r\n            grouped[t].append(c['crack_id'])\r\n        return grouped\r\n```\r\n\r\n### Inspection Report Generator\r\n\r\n```python\r\nfrom datetime import datetime\r\nimport pandas as pd\r\n\r\nclass DefectInspectionSystem:\r\n    \"\"\"Complete defect inspection and reporting system\"\"\"\r\n\r\n    def __init__(self, detection_model: DefectDetectionModel):\r\n        self.model = detection_model\r\n        self.crack_analyzer = CrackAnalyzer()\r\n        self.inspections: List[InspectionResult] = []\r\n\r\n    def perform_inspection(self, image_path: str,\r\n                          location: str,\r\n                          element_type: str,\r\n                          pixels_per_mm: float = None) -> InspectionResult:\r\n        \"\"\"Perform complete inspection on image\"\"\"\r\n        # Detect defects\r\n        defects = self.model.detect(image_path, pixels_per_mm=pixels_per_mm)\r\n\r\n        # Additional crack analysis for concrete\r\n        if element_type.lower() in ['concrete', 'slab', 'wall', 'column', 'beam']:\r\n            cracks = self.crack_analyzer.detect_cracks(image_path, pixels_per_mm or 1.0)\r\n\r\n            # Add detailed crack info to relevant defects\r\n            for defect in defects:\r\n                if defect.defect_type == DefectType.CRACK:\r\n                    for crack in cracks:\r\n                        # Check if crack overlaps with defect bbox\r\n                        if self._boxes_overlap(defect.bounding_box, crack['bounding_box']):\r\n                            defect.metadata['crack_details'] = crack\r\n                            break\r\n\r\n        # Determine overall condition\r\n        overall_condition = self._assess_overall_condition(defects)\r\n\r\n        # Generate recommendations\r\n        recommendations = self._generate_recommendations(defects, element_type)\r\n\r\n        result = InspectionResult(\r\n            inspection_id=f\"INS-{datetime.now().strftime('%Y%m%d%H%M%S')}\",\r\n            image_path=image_path,\r\n            timestamp=datetime.now(),\r\n            location=location,\r\n            element_type=element_type,\r\n            defects=defects,\r\n            overall_condition=overall_condition,\r\n            recommended_actions=recommendations\r\n        )\r\n\r\n        self.inspections.append(result)\r\n        return result\r\n\r\n    def _boxes_overlap(self, box1: BoundingBox, box2: Tuple) -> bool:\r\n        \"\"\"Check if two bounding boxes overlap\"\"\"\r\n        x1_1, y1_1, x2_1, y2_1 = box1.x1, box1.y1, box1.x2, box1.y2\r\n        x1_2, y1_2, x2_2, y2_2 = box2\r\n\r\n        return not (x2_1 \u003C x1_2 or x2_2 \u003C x1_1 or y2_1 \u003C y1_2 or y2_2 \u003C y1_1)\r\n\r\n    def _assess_overall_condition(self, defects: List[DetectedDefect]) -> str:\r\n        \"\"\"Assess overall structural condition\"\"\"\r\n        if not defects:\r\n            return \"Good\"\r\n\r\n        severity_scores = {\r\n            SeverityLevel.MINOR: 1,\r\n            SeverityLevel.MODERATE: 2,\r\n            SeverityLevel.SEVERE: 3,\r\n            SeverityLevel.CRITICAL: 4\r\n        }\r\n\r\n        max_severity = max(severity_scores[d.severity] for d in defects)\r\n        total_defects = len(defects)\r\n\r\n        if max_severity >= 4 or total_defects > 10:\r\n            return \"Critical - Immediate attention required\"\r\n        elif max_severity >= 3 or total_defects > 5:\r\n            return \"Poor - Repairs needed\"\r\n        elif max_severity >= 2 or total_defects > 2:\r\n            return \"Fair - Monitor and plan repairs\"\r\n        else:\r\n            return \"Good - Minor issues only\"\r\n\r\n    def _generate_recommendations(self, defects: List[DetectedDefect],\r\n                                 element_type: str) -> List[str]:\r\n        \"\"\"Generate repair recommendations\"\"\"\r\n        recommendations = []\r\n\r\n        # Group defects by type\r\n        defect_groups = {}\r\n        for d in defects:\r\n            t = d.defect_type\r\n            if t not in defect_groups:\r\n                defect_groups[t] = []\r\n            defect_groups[t].append(d)\r\n\r\n        # Generate recommendations by defect type\r\n        for defect_type, group in defect_groups.items():\r\n            max_severity = max(d.severity for d in group)\r\n\r\n            if defect_type == DefectType.CRACK:\r\n                if max_severity in [SeverityLevel.CRITICAL, SeverityLevel.SEVERE]:\r\n                    recommendations.append(\r\n                        f\"Structural engineer assessment required for {len(group)} crack(s). \"\r\n                        f\"Consider epoxy injection or structural repair.\"\r\n                    )\r\n                else:\r\n                    recommendations.append(\r\n                        f\"Seal {len(group)} minor crack(s) with appropriate sealant.\"\r\n                    )\r\n\r\n            elif defect_type == DefectType.SPALLING:\r\n                recommendations.append(\r\n                    f\"Remove loose concrete and apply repair mortar to {len(group)} spalling area(s). \"\r\n                    f\"Check reinforcement for corrosion.\"\r\n                )\r\n\r\n            elif defect_type == DefectType.CORROSION:\r\n                recommendations.append(\r\n                    f\"Treat {len(group)} corrosion area(s). Clean rust, apply rust converter, \"\r\n                    f\"and protective coating.\"\r\n                )\r\n\r\n            elif defect_type == DefectType.HONEYCOMBING:\r\n                recommendations.append(\r\n                    f\"Fill {len(group)} honeycomb area(s) with non-shrink grout. \"\r\n                    f\"Investigate concrete placement procedures.\"\r\n                )\r\n\r\n            elif defect_type == DefectType.EFFLORESCENCE:\r\n                recommendations.append(\r\n                    f\"Clean efflorescence from {len(group)} area(s). \"\r\n                    f\"Investigate and address moisture source.\"\r\n                )\r\n\r\n        if not recommendations:\r\n            recommendations.append(\"Continue regular inspection schedule.\")\r\n\r\n        return recommendations\r\n\r\n    def export_inspection_report(self, inspection_id: str,\r\n                                output_path: str) -> str:\r\n        \"\"\"Export inspection report to Excel\"\"\"\r\n        inspection = next(\r\n            (i for i in self.inspections if i.inspection_id == inspection_id),\r\n            None\r\n        )\r\n\r\n        if not inspection:\r\n            raise ValueError(f\"Inspection {inspection_id} not found\")\r\n\r\n        with pd.ExcelWriter(output_path, engine='openpyxl') as writer:\r\n            # Summary\r\n            summary = pd.DataFrame([{\r\n                'Inspection ID': inspection.inspection_id,\r\n                'Date': inspection.timestamp.strftime('%Y-%m-%d %H:%M'),\r\n                'Location': inspection.location,\r\n                'Element Type': inspection.element_type,\r\n                'Overall Condition': inspection.overall_condition,\r\n                'Total Defects': len(inspection.defects),\r\n                'Image': inspection.image_path\r\n            }])\r\n            summary.to_excel(writer, sheet_name='Summary', index=False)\r\n\r\n            # Defects\r\n            if inspection.defects:\r\n                defect_data = [{\r\n                    'Defect ID': d.defect_id,\r\n                    'Type': d.defect_type.value,\r\n                    'Severity': d.severity.value,\r\n                    'Confidence': f\"{d.confidence:.1%}\",\r\n                    'Location (x,y)': f\"({d.bounding_box.x1}, {d.bounding_box.y1})\",\r\n                    'Size (w×h)': f\"{d.bounding_box.width}×{d.bounding_box.height}\",\r\n                    'Dimensions (mm)': d.dimensions_mm if d.dimensions_mm else 'N\u002FA'\r\n                } for d in inspection.defects]\r\n                pd.DataFrame(defect_data).to_excel(writer, sheet_name='Defects', index=False)\r\n\r\n            # Recommendations\r\n            rec_data = [{'#': i+1, 'Recommendation': r}\r\n                       for i, r in enumerate(inspection.recommended_actions)]\r\n            pd.DataFrame(rec_data).to_excel(writer, sheet_name='Recommendations', index=False)\r\n\r\n        return output_path\r\n\r\n    def get_defect_statistics(self, start_date: datetime = None,\r\n                             end_date: datetime = None) -> Dict:\r\n        \"\"\"Get defect statistics across inspections\"\"\"\r\n        filtered = self.inspections\r\n        if start_date:\r\n            filtered = [i for i in filtered if i.timestamp >= start_date]\r\n        if end_date:\r\n            filtered = [i for i in filtered if i.timestamp \u003C= end_date]\r\n\r\n        all_defects = []\r\n        for inspection in filtered:\r\n            all_defects.extend(inspection.defects)\r\n\r\n        if not all_defects:\r\n            return {'message': 'No defects found in period'}\r\n\r\n        # Statistics\r\n        by_type = {}\r\n        by_severity = {}\r\n\r\n        for d in all_defects:\r\n            t = d.defect_type.value\r\n            s = d.severity.value\r\n\r\n            by_type[t] = by_type.get(t, 0) + 1\r\n            by_severity[s] = by_severity.get(s, 0) + 1\r\n\r\n        return {\r\n            'period': {\r\n                'start': start_date.isoformat() if start_date else 'all',\r\n                'end': end_date.isoformat() if end_date else 'all'\r\n            },\r\n            'total_inspections': len(filtered),\r\n            'total_defects': len(all_defects),\r\n            'by_type': by_type,\r\n            'by_severity': by_severity,\r\n            'avg_defects_per_inspection': len(all_defects) \u002F len(filtered) if filtered else 0\r\n        }\r\n```\r\n\r\n## Model Training\r\n\r\n```python\r\nimport torch\r\nfrom torch.utils.data import Dataset, DataLoader\r\nfrom torchvision import transforms\r\nimport os\r\nfrom PIL import Image\r\n\r\nclass DefectDataset(Dataset):\r\n    \"\"\"Dataset for training defect detection model\"\"\"\r\n\r\n    def __init__(self, root_dir: str, annotations_file: str, transform=None):\r\n        self.root_dir = root_dir\r\n        self.annotations = self._load_annotations(annotations_file)\r\n        self.transform = transform or transforms.Compose([\r\n            transforms.Resize((800, 800)),\r\n            transforms.ToTensor()\r\n        ])\r\n\r\n    def _load_annotations(self, path: str) -> List[Dict]:\r\n        \"\"\"Load COCO-format annotations\"\"\"\r\n        import json\r\n        with open(path, 'r') as f:\r\n            data = json.load(f)\r\n        return data['annotations']\r\n\r\n    def __len__(self):\r\n        return len(self.annotations)\r\n\r\n    def __getitem__(self, idx):\r\n        ann = self.annotations[idx]\r\n        image_path = os.path.join(self.root_dir, ann['image_file'])\r\n        image = Image.open(image_path).convert('RGB')\r\n\r\n        if self.transform:\r\n            image = self.transform(image)\r\n\r\n        # Prepare target\r\n        boxes = torch.tensor(ann['boxes'], dtype=torch.float32)\r\n        labels = torch.tensor(ann['labels'], dtype=torch.int64)\r\n\r\n        target = {\r\n            'boxes': boxes,\r\n            'labels': labels\r\n        }\r\n\r\n        return image, target\r\n\r\n\r\ndef train_defect_model(train_dataset: DefectDataset,\r\n                       val_dataset: DefectDataset,\r\n                       num_epochs: int = 10,\r\n                       batch_size: int = 4,\r\n                       learning_rate: float = 0.005):\r\n    \"\"\"Train defect detection model\"\"\"\r\n    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\r\n\r\n    # Initialize model\r\n    model = fasterrcnn_resnet50_fpn(pretrained=True)\r\n    num_classes = 8  # 7 defect types + background\r\n    in_features = model.roi_heads.box_predictor.cls_score.in_features\r\n    model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)\r\n    model.to(device)\r\n\r\n    # Data loaders\r\n    train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True,\r\n                              collate_fn=lambda x: tuple(zip(*x)))\r\n    val_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False,\r\n                           collate_fn=lambda x: tuple(zip(*x)))\r\n\r\n    # Optimizer\r\n    optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate,\r\n                                momentum=0.9, weight_decay=0.0005)\r\n\r\n    # Training loop\r\n    for epoch in range(num_epochs):\r\n        model.train()\r\n        total_loss = 0\r\n\r\n        for images, targets in train_loader:\r\n            images = [img.to(device) for img in images]\r\n            targets = [{k: v.to(device) for k, v in t.items()} for t in targets]\r\n\r\n            loss_dict = model(images, targets)\r\n            losses = sum(loss for loss in loss_dict.values())\r\n\r\n            optimizer.zero_grad()\r\n            losses.backward()\r\n            optimizer.step()\r\n\r\n            total_loss += losses.item()\r\n\r\n        avg_loss = total_loss \u002F len(train_loader)\r\n        print(f\"Epoch {epoch+1}\u002F{num_epochs}, Loss: {avg_loss:.4f}\")\r\n\r\n    return model\r\n```\r\n\r\n## Quick Reference\r\n\r\n| Defect Type | Detection Method | Typical Severity |\r\n|-------------|------------------|------------------|\r\n| Crack | Edge detection + CNN | Varies by width |\r\n| Spalling | Object detection | Moderate-Severe |\r\n| Corrosion | Color + texture analysis | Moderate-Critical |\r\n| Honeycombing | Object detection | Severe |\r\n| Efflorescence | Color analysis | Minor-Moderate |\r\n\r\n## ACI 224R Crack Width Guidelines\r\n\r\n| Width (mm) | Condition | Exposure |\r\n|------------|-----------|----------|\r\n| \u003C 0.1 | Acceptable | Any |\r\n| 0.1 - 0.2 | Acceptable | Dry |\r\n| 0.2 - 0.4 | Repair recommended | Humid |\r\n| > 0.4 | Repair required | Any |\r\n| > 1.0 | Structural concern | Any |\r\n\r\n## Resources\r\n\r\n- **PyTorch**: https:\u002F\u002Fpytorch.org\r\n- **OpenCV**: https:\u002F\u002Fopencv.org\r\n- **ACI 224R**: Crack control in concrete\r\n- **DDC Website**: https:\u002F\u002Fdatadrivenconstruction.io\r\n\r\n## Next Steps\r\n\r\n- See `progress-monitoring-cv` for construction progress analysis\r\n- See `safety-compliance-checker` for safety defect integration\r\n- See `bim-validation-pipeline` for model-based quality control\r\n",{"slug":5,"description":7,"display_name":33},"Defect Detection AI","main","e7e336ac628c3e3bd771aff1aaa469c93778f94a","skills\u002Fdatadrivenconstruction\u002Fdefect-detection-ai",0,"https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del","2026-08-23 22:39:37",{"source":8,"skillName":5,"commands":42,"prompt":52,"zipAvailable":53},[43,46,49],{"tool":44,"command":45},"npx","npx skills add kbarbel640-del\u002Fskills --skill defect-detection-ai",{"tool":47,"command":48},"bunx","bunx skills add kbarbel640-del\u002Fskills --skill defect-detection-ai",{"tool":50,"command":51},"pnpm","pnpm dlx skills add kbarbel640-del\u002Fskills --skill defect-detection-ai","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fdatadrivenconstruction\u002Fdefect-detection-ai\u002FSKILL.md",true,[55],{"path":56,"resourceType":57,"resourceTypeDesc":58,"sizeBytes":59,"sourceHtmlUrl":60},"_meta.json","REFERENCE","参考文档",306,"https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fdatadrivenconstruction\u002Fdefect-detection-ai\u002F_meta.json",[62,93,122,143,149,169],{"skillNo":63,"name":64,"nameZh":6,"description":65,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":66,"categories":67,"keywords":73,"publishedAt":28},"01M6G8J55967D6281ACMKAKTEQ","crowd-prompting","A marketplace where AI agents improve prompts, system instructions, tool descriptions, and other text-based content with domain expertise from real-world operations — and earn tokens for valuable contributions.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzzadrian\u002Fcrowd-prompting\u002FSKILL.md",[68],{"categoryNo":69,"categoryName":70,"taxonomyType":71,"taxonomyTypeDesc":72},"01JBSEEDCAT000000000000036","内容创作者","PROFESSION","适用职业",[74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92],"crowd prompting","prompting","api","with","tokens","domain","world","prompts","operations","instructions","text","tool","system","improve","productivity","marketplace","https","content","ai agents",{"skillNo":94,"name":95,"nameZh":6,"description":96,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":97,"categories":98,"keywords":104,"publishedAt":28},"01M6G8J0PKPAYVET6BWE8W4C26","dilemm-ai","Compete in DilemmAI, the prisoner's dilemma AI arena at dilemm.ai. Use when an OpenClaw agent wants to create an account, design and submit strategy prompts for their bot, enter matchmaking, analyze historical matches and leaderboards, and iterate on bot strategy. Requires headless browser automation (no API available yet).","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzyori\u002Fdilemm-ai\u002FSKILL.md",[99],{"categoryNo":100,"categoryName":101,"taxonomyType":102,"taxonomyTypeDesc":103},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[105,76,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,81,121],"dilemm ai","arena","analyze","browser","openclaw agent","create","automation","browser automation","bot","openclaw","design","strategy","headless","compete","submit","matchmaking","use",{"skillNo":123,"name":124,"nameZh":6,"description":125,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":126,"categories":127,"keywords":131,"publishedAt":28},"01M6G8HWAF3K9SW7NP3Z83CPJ6","arxiv-paper-reviews","Interact with arXiv Crawler API to fetch papers, read reviews, and submit comments. Use when working with arXiv papers, fetching paper lists by date\u002Fcategory\u002Finterest, viewing paper details with comments, or submitting paper reviews via API at http:\u002F\u002F150.158.152.82:8000.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzxrys\u002Fweak-accept\u002FSKILL.md",[128],{"categoryNo":129,"categoryName":130,"taxonomyType":102,"taxonomyTypeDesc":103},"01JBSEEDCAT000000000000021","资料检索与研究",[132,133,134,135,136,137,138,77,139,119,121,140,76,141,142],"arxiv paper reviews","reviews","arxiv","paper","crawler","papers","comments","fetch","read","http","via",{"skillNo":144,"name":124,"nameZh":6,"description":125,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":145,"categories":146,"keywords":148,"publishedAt":28},"01M6G8HQJ7N7WMY6YV7D7SSJ16","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzxrys\u002Farxiv-paper-reviews\u002FSKILL.md",[147],{"categoryNo":129,"categoryName":130,"taxonomyType":102,"taxonomyTypeDesc":103},[135,134,133,132,142,137,138,77,136,119,121,139,140,76,141],{"skillNo":150,"name":151,"nameZh":6,"description":152,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":153,"categories":154,"keywords":155,"publishedAt":28},"01M6G8HM95Y64JNVFC2HN4E2BG","git-summary","Get a quick summary of the current Git repository including status, recent commits, branches, and contributors.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzweack\u002Fgit-summary\u002FSKILL.md",[],[156,157,158,159,160,161,162,163,164,165,166,167,168],"git","summary","git summary","commits","repository","win32","status","linux","contributors","true","quick","get","branches",{"skillNo":170,"name":171,"nameZh":6,"description":172,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":173,"categories":174,"keywords":179,"publishedAt":28},"01M6G8HGEGF05CNEJCGVYFSC4R","agent-constitution","Interact with AgentConstitution governance contracts on Base Sepolia. Check compliance, read rules, log actions, query governance state.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fztsalexey\u002Fagent-constitution\u002FSKILL.md",[175,176],{"categoryNo":100,"categoryName":101,"taxonomyType":102,"taxonomyTypeDesc":103},{"categoryNo":177,"categoryName":178,"taxonomyType":71,"taxonomyTypeDesc":72},"01JBSEEDCAT000000000000037","律师与法务",[180,181,182,183,77,184,185,34,186,140,187,188,189,190,191,90,192,193,194],"agent constitution","constitution","contracts","tree","query","base","log","check","Rules","projects","compliance","actions","state","governance","github"]