bae705aa97
- Add NFC ePassport roadmap (ICAO 9303, eIDAS) - Add TensorFlow.js edge face detection (BlazeFace) - Add structured audit logger (GDPR-compliant) - Risk scoring support Part of KYC Apple Native UX v1.1.0
626 lines
23 KiB
Python
626 lines
23 KiB
Python
"""
|
|
Defect Codes - Layer 7 of IOM
|
|
Hierarchical classification system for infrastructure defects
|
|
"""
|
|
|
|
from typing import Dict, List, Optional, Tuple
|
|
from enum import Enum
|
|
|
|
|
|
class DefectCategory(str, Enum):
|
|
"""Top-level defect categories"""
|
|
SURFACE = "surface"
|
|
STRUCTURAL = "structural"
|
|
COMPONENT = "component"
|
|
BLOCKAGE = "blockage"
|
|
ENVIRONMENTAL = "environmental"
|
|
CORROSION = "corrosion"
|
|
SAFETY = "safety"
|
|
FUNCTIONAL = "functional"
|
|
|
|
|
|
class DefectSeverity(str, Enum):
|
|
"""Defect severity levels"""
|
|
COSMETIC = "cosmetic" # Purely visual
|
|
MINOR = "minor" # Minor issue, no immediate action
|
|
MODERATE = "moderate" # Requires attention within 12 months
|
|
MAJOR = "major" # Requires attention within 3 months
|
|
CRITICAL = "critical" # Immediate action required
|
|
|
|
|
|
class DefectCode:
|
|
"""Represents a defect code with metadata"""
|
|
|
|
def __init__(
|
|
self,
|
|
code: str,
|
|
name_sv: str,
|
|
name_en: str,
|
|
category: DefectCategory,
|
|
severity: DefectSeverity,
|
|
description_sv: str = "",
|
|
description_en: str = "",
|
|
parent_code: Optional[str] = None,
|
|
ai_keywords: Optional[List[str]] = None
|
|
):
|
|
self.code = code
|
|
self.name_sv = name_sv
|
|
self.name_en = name_en
|
|
self.category = category
|
|
self.severity = severity
|
|
self.description_sv = description_sv
|
|
self.description_en = description_en
|
|
self.parent_code = parent_code
|
|
self.ai_keywords = ai_keywords or []
|
|
|
|
def get_name(self, lang: str = "sv") -> str:
|
|
"""Get name in specified language"""
|
|
return self.name_en if lang == "en" else self.name_sv
|
|
|
|
def get_description(self, lang: str = "sv") -> str:
|
|
"""Get description in specified language"""
|
|
return self.description_en if lang == "en" else self.description_sv
|
|
|
|
def to_dict(self, lang: str = "sv") -> Dict:
|
|
"""Convert to dictionary"""
|
|
return {
|
|
"code": self.code,
|
|
"name": self.get_name(lang),
|
|
"description": self.get_description(lang),
|
|
"category": self.category.value,
|
|
"severity": self.severity.value,
|
|
"parent_code": self.parent_code,
|
|
"ai_keywords": self.ai_keywords
|
|
}
|
|
|
|
|
|
class DefectRegistry:
|
|
"""Registry of all defect codes"""
|
|
|
|
def __init__(self):
|
|
self._codes: Dict[str, DefectCode] = {}
|
|
self._init_codes()
|
|
|
|
def _init_codes(self):
|
|
"""Initialize all defect codes"""
|
|
|
|
# 1000 - Corrosion
|
|
self._add(DefectCode(
|
|
"1000", "Korrosion", "Corrosion",
|
|
DefectCategory.CORROSION, DefectSeverity.MODERATE,
|
|
"Korrosion på metalliska material",
|
|
"Corrosion on metallic materials",
|
|
ai_keywords=["rust", "corrosion", "oxidation", "pit"]
|
|
))
|
|
self._add(DefectCode(
|
|
"1100", "Ytrost", "Surface Rust",
|
|
DefectCategory.CORROSION, DefectSeverity.MINOR,
|
|
"Ytlig rost på yta",
|
|
"Surface rust on surface",
|
|
parent_code="1000",
|
|
ai_keywords=["surface rust", "light rust", "orange"]
|
|
))
|
|
self._add(DefectCode(
|
|
"1200", "Genomrost", "Deep Corrosion",
|
|
DefectCategory.CORROSION, DefectSeverity.MAJOR,
|
|
"Genomgående korrosion som påverkar struktur",
|
|
"Deep corrosion affecting structure",
|
|
parent_code="1000",
|
|
ai_keywords=["deep rust", "structural rust", "hole"]
|
|
))
|
|
self._add(DefectCode(
|
|
"1250", "Galvanisk korrosion", "Galvanic Corrosion",
|
|
DefectCategory.CORROSION, DefectSeverity.MODERATE,
|
|
"Korrosion mellan olika metaller",
|
|
"Corrosion between dissimilar metals",
|
|
parent_code="1000",
|
|
ai_keywords=["galvanic", "dissimilar metal"]
|
|
))
|
|
|
|
# 1300 - Concrete Cracks
|
|
self._add(DefectCode(
|
|
"1300", "Betongspricka", "Concrete Crack",
|
|
DefectCategory.STRUCTURAL, DefectSeverity.MODERATE,
|
|
"Spricka i betongkonstruktion",
|
|
"Crack in concrete structure",
|
|
ai_keywords=["crack", "fissure", "split"]
|
|
))
|
|
self._add(DefectCode(
|
|
"1310", "Plastisk krympning", "Plastic Shrinkage",
|
|
DefectCategory.STRUCTURAL, DefectSeverity.MINOR,
|
|
"Spricka från plastisk krympning",
|
|
"Crack from plastic shrinkage",
|
|
parent_code="1300",
|
|
ai_keywords=["shrinkage crack", "surface crack"]
|
|
))
|
|
self._add(DefectCode(
|
|
"1320", "Temperaturspricka", "Temperature Crack",
|
|
DefectCategory.STRUCTURAL, DefectSeverity.MINOR,
|
|
"Spricka från temperaturförändring",
|
|
"Crack from temperature change",
|
|
parent_code="1300",
|
|
ai_keywords=["temperature crack", "thermal crack"]
|
|
))
|
|
self._add(DefectCode(
|
|
"1330", "Lastspricka", "Load Crack",
|
|
DefectCategory.STRUCTURAL, DefectSeverity.MAJOR,
|
|
"Spricka från överbelastning",
|
|
"Crack from overload",
|
|
parent_code="1300",
|
|
ai_keywords=["load crack", "structural crack", "wide crack"]
|
|
))
|
|
|
|
# 1400 - Impact Damage
|
|
self._add(DefectCode(
|
|
"1400", "Påkörningsskada", "Impact Damage",
|
|
DefectCategory.STRUCTURAL, DefectSeverity.MAJOR,
|
|
"Skada från påkörning eller stöt",
|
|
"Damage from impact or collision",
|
|
ai_keywords=["impact", "collision", "dent", "damage"]
|
|
))
|
|
self._add(DefectCode(
|
|
"1410", "Ytskada", "Surface Damage",
|
|
DefectCategory.SURFACE, DefectSeverity.MINOR,
|
|
"Ytlig skada på yta",
|
|
"Superficial damage to surface",
|
|
parent_code="1400",
|
|
ai_keywords=["scratch", "scuff", "minor damage"]
|
|
))
|
|
self._add(DefectCode(
|
|
"1420", "Deformation", "Deformation",
|
|
DefectCategory.STRUCTURAL, DefectSeverity.MODERATE,
|
|
"Permanent deformation",
|
|
"Permanent deformation",
|
|
parent_code="1400",
|
|
ai_keywords=["bent", "deformed", "twisted"]
|
|
))
|
|
self._add(DefectCode(
|
|
"1430", "Genomskjutning", "Penetration",
|
|
DefectCategory.STRUCTURAL, DefectSeverity.CRITICAL,
|
|
"Genomskjutning av konstruktion",
|
|
"Penetration of structure",
|
|
parent_code="1400",
|
|
ai_keywords=["hole", "penetration", "puncture"]
|
|
))
|
|
|
|
# 1500 - Missing Component
|
|
self._add(DefectCode(
|
|
"1500", "Saknad komponent", "Missing Component",
|
|
DefectCategory.COMPONENT, DefectSeverity.MODERATE,
|
|
"Komponent saknas",
|
|
"Component is missing",
|
|
ai_keywords=["missing", "absent", "gone"]
|
|
))
|
|
self._add(DefectCode(
|
|
"1510", "Stöld", "Theft",
|
|
DefectCategory.COMPONENT, DefectSeverity.MAJOR,
|
|
"Komponent stulen",
|
|
"Component stolen",
|
|
parent_code="1500",
|
|
ai_keywords=["theft", "stolen", "removed"]
|
|
))
|
|
self._add(DefectCode(
|
|
"1520", "Ej installerad", "Not Installed",
|
|
DefectCategory.COMPONENT, DefectSeverity.MINOR,
|
|
"Komponent ej installerad",
|
|
"Component not installed",
|
|
parent_code="1500",
|
|
ai_keywords=["not installed", "missing installation"]
|
|
))
|
|
self._add(DefectCode(
|
|
"1530", "Avlägsnad", "Removed",
|
|
DefectCategory.COMPONENT, DefectSeverity.MINOR,
|
|
"Komponent avlägsnad",
|
|
"Component removed",
|
|
parent_code="1500",
|
|
ai_keywords=["removed", "taken away"]
|
|
))
|
|
|
|
# 1600 - Deformation/Settlement
|
|
self._add(DefectCode(
|
|
"1600", "Lutning / Sättning", "Tilt / Settlement",
|
|
DefectCategory.STRUCTURAL, DefectSeverity.MODERATE,
|
|
"Lutning eller sättning",
|
|
"Tilt or settlement",
|
|
ai_keywords=["tilt", "lean", "settlement", "sinking"]
|
|
))
|
|
self._add(DefectCode(
|
|
"1610", "Sättning", "Settlement",
|
|
DefectCategory.STRUCTURAL, DefectSeverity.MAJOR,
|
|
"Sättning av fundament",
|
|
"Foundation settlement",
|
|
parent_code="1600",
|
|
ai_keywords=["settlement", "sinking", "subsidence"]
|
|
))
|
|
self._add(DefectCode(
|
|
"1620", "Böjning", "Bending",
|
|
DefectCategory.STRUCTURAL, DefectSeverity.MODERATE,
|
|
"Böjning av konstruktion",
|
|
"Bending of structure",
|
|
parent_code="1600",
|
|
ai_keywords=["bending", "sagging", "deflection"]
|
|
))
|
|
self._add(DefectCode(
|
|
"1630", "Vridning", "Torsion",
|
|
DefectCategory.STRUCTURAL, DefectSeverity.MODERATE,
|
|
"Vridning av konstruktion",
|
|
"Torsion of structure",
|
|
parent_code="1600",
|
|
ai_keywords=["twist", "torsion", "warp"]
|
|
))
|
|
|
|
# 1700 - Vibration
|
|
self._add(DefectCode(
|
|
"1700", "Vibration", "Vibration",
|
|
DefectCategory.FUNCTIONAL, DefectSeverity.MODERATE,
|
|
"Oönskad vibration",
|
|
"Unwanted vibration",
|
|
ai_keywords=["vibration", "shaking", "oscillation"]
|
|
))
|
|
self._add(DefectCode(
|
|
"1710", "Mekanisk vibration", "Mechanical Vibration",
|
|
DefectCategory.FUNCTIONAL, DefectSeverity.MODERATE,
|
|
"Vibration från mekanisk källa",
|
|
"Vibration from mechanical source",
|
|
parent_code="1700",
|
|
ai_keywords=["mechanical vibration", "machinery"]
|
|
))
|
|
self._add(DefectCode(
|
|
"1720", "Aerodynamisk vibration", "Aerodynamic Vibration",
|
|
DefectCategory.FUNCTIONAL, DefectSeverity.MINOR,
|
|
"Vibration från vind",
|
|
"Vibration from wind",
|
|
parent_code="1700",
|
|
ai_keywords=["wind vibration", "aerodynamic", "flutter"]
|
|
))
|
|
|
|
# 1800 - Vegetation
|
|
self._add(DefectCode(
|
|
"1800", "Vegetation", "Vegetation",
|
|
DefectCategory.ENVIRONMENTAL, DefectSeverity.MINOR,
|
|
"Oönskad vegetation",
|
|
"Unwanted vegetation",
|
|
ai_keywords=["vegetation", "plant", "tree", "weed"]
|
|
))
|
|
self._add(DefectCode(
|
|
"1810", "Blockerande vegetation", "Blocking Vegetation",
|
|
DefectCategory.ENVIRONMENTAL, DefectSeverity.MODERATE,
|
|
"Vegetation som blockerar sikt eller tillgång",
|
|
"Vegetation blocking view or access",
|
|
parent_code="1800",
|
|
ai_keywords=["blocking", "overgrown", "obscured"]
|
|
))
|
|
self._add(DefectCode(
|
|
"1820", "Rotinträngning", "Root Intrusion",
|
|
DefectCategory.STRUCTURAL, DefectSeverity.MAJOR,
|
|
"Rötter som tränger in i struktur",
|
|
"Roots intruding into structure",
|
|
parent_code="1800",
|
|
ai_keywords=["root", "intrusion", "crack with root"]
|
|
))
|
|
self._add(DefectCode(
|
|
"1830", "Fuktbevarande vegetation", "Moisture-Retaining Vegetation",
|
|
DefectCategory.ENVIRONMENTAL, DefectSeverity.MINOR,
|
|
"Vegetation som bevarar fukt",
|
|
"Vegetation retaining moisture",
|
|
parent_code="1800",
|
|
ai_keywords=["moss", "lichen", "moisture"]
|
|
))
|
|
|
|
# 1900 - Blockage
|
|
self._add(DefectCode(
|
|
"1900", "Blockering", "Blockage",
|
|
DefectCategory.BLOCKAGE, DefectSeverity.MODERATE,
|
|
"Blockering av funktion eller tillgång",
|
|
"Blockage of function or access",
|
|
ai_keywords=["blocked", "obstructed", "clogged"]
|
|
))
|
|
self._add(DefectCode(
|
|
"1910", "Fysisk blockering", "Physical Blockage",
|
|
DefectCategory.BLOCKAGE, DefectSeverity.MODERATE,
|
|
"Fysisk blockering",
|
|
"Physical blockage",
|
|
parent_code="1900",
|
|
ai_keywords=["physical block", "debris", "trash"]
|
|
))
|
|
self._add(DefectCode(
|
|
"1920", "Digital blockering", "Digital Blockage",
|
|
DefectCategory.FUNCTIONAL, DefectSeverity.MINOR,
|
|
"Digital eller elektronisk blockering",
|
|
"Digital or electronic blockage",
|
|
parent_code="1900",
|
|
ai_keywords=["digital", "electronic", "signal"]
|
|
))
|
|
self._add(DefectCode(
|
|
"1930", "Organisk blockering", "Organic Blockage",
|
|
DefectCategory.BLOCKAGE, DefectSeverity.MODERATE,
|
|
"Organisk blockering (löv, grenar)",
|
|
"Organic blockage (leaves, branches)",
|
|
parent_code="1900",
|
|
ai_keywords=["organic", "leaves", "branches"]
|
|
))
|
|
|
|
# 2000 - Surface Issues (Phase 1 focus)
|
|
self._add(DefectCode(
|
|
"2000", "Ytskada", "Surface Issue",
|
|
DefectCategory.SURFACE, DefectSeverity.MINOR,
|
|
"Ytskada eller nedsmutsning",
|
|
"Surface damage or dirt",
|
|
ai_keywords=["surface", "dirt", "stain"]
|
|
))
|
|
self._add(DefectCode(
|
|
"2100", "Nedsmutsning", "Dirt Accumulation",
|
|
DefectCategory.SURFACE, DefectSeverity.COSMETIC,
|
|
"Nedsmutsning på yta",
|
|
"Dirt accumulation on surface",
|
|
parent_code="2000",
|
|
ai_keywords=["dirty", "dirt", "grime", "dust", "mud"]
|
|
))
|
|
self._add(DefectCode(
|
|
"2200", "Färgförändring", "Color Change",
|
|
DefectCategory.SURFACE, DefectSeverity.COSMETIC,
|
|
"Färgförändring eller blekning",
|
|
"Color change or fading",
|
|
parent_code="2000",
|
|
ai_keywords=["faded", "discoloration", "color change", "bleached"]
|
|
))
|
|
self._add(DefectCode(
|
|
"2300", "Ytskada", "Surface Damage",
|
|
DefectCategory.SURFACE, DefectSeverity.MINOR,
|
|
"Skada på yta",
|
|
"Damage to surface",
|
|
parent_code="2000",
|
|
ai_keywords=["damage", "scratch", "chip", "peel"]
|
|
))
|
|
self._add(DefectCode(
|
|
"2400", "Klotter", "Graffiti",
|
|
DefectCategory.SURFACE, DefectSeverity.COSMETIC,
|
|
"Klotter eller målning",
|
|
"Graffiti or painting",
|
|
parent_code="2000",
|
|
ai_keywords=["graffiti", "paint", "tag", "vandalism"]
|
|
))
|
|
|
|
# 3000 - Structural Issues
|
|
self._add(DefectCode(
|
|
"3000", "Strukturell skada", "Structural Damage",
|
|
DefectCategory.STRUCTURAL, DefectSeverity.MAJOR,
|
|
"Strukturell skada",
|
|
"Structural damage",
|
|
ai_keywords=["structural", "damage", "crack", "break"]
|
|
))
|
|
self._add(DefectCode(
|
|
"3100", "Spricka", "Crack",
|
|
DefectCategory.STRUCTURAL, DefectSeverity.MODERATE,
|
|
"Spricka i material",
|
|
"Crack in material",
|
|
parent_code="3000",
|
|
ai_keywords=["crack", "fissure", "fracture"]
|
|
))
|
|
self._add(DefectCode(
|
|
"3200", "Deformation", "Deformation",
|
|
DefectCategory.STRUCTURAL, DefectSeverity.MODERATE,
|
|
"Permanent deformation",
|
|
"Permanent deformation",
|
|
parent_code="3000",
|
|
ai_keywords=["deformed", "bent", "warped"]
|
|
))
|
|
self._add(DefectCode(
|
|
"3300", "Materialförlust", "Material Loss",
|
|
DefectCategory.STRUCTURAL, DefectSeverity.MAJOR,
|
|
"Förlust av material",
|
|
"Loss of material",
|
|
parent_code="3000",
|
|
ai_keywords=["missing material", "erosion", "wear"]
|
|
))
|
|
|
|
# 4000 - Component Issues
|
|
self._add(DefectCode(
|
|
"4000", "Komponentskada", "Component Issue",
|
|
DefectCategory.COMPONENT, DefectSeverity.MODERATE,
|
|
"Problem med komponent",
|
|
"Component issue",
|
|
ai_keywords=["component", "part", "piece"]
|
|
))
|
|
self._add(DefectCode(
|
|
"4100", "Saknad del", "Missing Part",
|
|
DefectCategory.COMPONENT, DefectSeverity.MODERATE,
|
|
"Del saknas",
|
|
"Part missing",
|
|
parent_code="4000",
|
|
ai_keywords=["missing", "absent", "gone"]
|
|
))
|
|
self._add(DefectCode(
|
|
"4200", "Trasig del", "Broken Part",
|
|
DefectCategory.COMPONENT, DefectSeverity.MODERATE,
|
|
"Del är trasig",
|
|
"Part broken",
|
|
parent_code="4000",
|
|
ai_keywords=["broken", "damaged", "fractured"]
|
|
))
|
|
self._add(DefectCode(
|
|
"4300", "Lossnad del", "Loose Part",
|
|
DefectCategory.COMPONENT, DefectSeverity.MINOR,
|
|
"Del är lossnad",
|
|
"Part loose",
|
|
parent_code="4000",
|
|
ai_keywords=["loose", "detached", "hanging"]
|
|
))
|
|
|
|
# 5000 - Blockage Issues
|
|
self._add(DefectCode(
|
|
"5000", "Blockering", "Blockage",
|
|
DefectCategory.BLOCKAGE, DefectSeverity.MODERATE,
|
|
"Blockering",
|
|
"Blockage",
|
|
ai_keywords=["blocked", "obstructed"]
|
|
))
|
|
self._add(DefectCode(
|
|
"5100", "Fysisk blockering", "Physical Blockage",
|
|
DefectCategory.BLOCKAGE, DefectSeverity.MODERATE,
|
|
"Fysisk blockering",
|
|
"Physical blockage",
|
|
parent_code="5000",
|
|
ai_keywords=["physical", "block", "debris"]
|
|
))
|
|
self._add(DefectCode(
|
|
"5200", "Synlig blockering", "Visible Blockage",
|
|
DefectCategory.BLOCKAGE, DefectSeverity.MINOR,
|
|
"Synlig blockering",
|
|
"Visible blockage",
|
|
parent_code="5000",
|
|
ai_keywords=["visible", "block", "obscured"]
|
|
))
|
|
|
|
# 6000 - Environmental Issues
|
|
self._add(DefectCode(
|
|
"6000", "Miljöskada", "Environmental Damage",
|
|
DefectCategory.ENVIRONMENTAL, DefectSeverity.MINOR,
|
|
"Skada från miljöfaktorer",
|
|
"Damage from environmental factors",
|
|
ai_keywords=["environmental", "weather", "water"]
|
|
))
|
|
self._add(DefectCode(
|
|
"6100", "Vegetation", "Vegetation",
|
|
DefectCategory.ENVIRONMENTAL, DefectSeverity.MINOR,
|
|
"Oönskad vegetation",
|
|
"Unwanted vegetation",
|
|
parent_code="6000",
|
|
ai_keywords=["vegetation", "plant", "tree"]
|
|
))
|
|
self._add(DefectCode(
|
|
"6200", "Vattenskada", "Water Damage",
|
|
DefectCategory.ENVIRONMENTAL, DefectSeverity.MODERATE,
|
|
"Skada från vatten",
|
|
"Water damage",
|
|
parent_code="6000",
|
|
ai_keywords=["water", "moisture", "leak", "flood"]
|
|
))
|
|
self._add(DefectCode(
|
|
"6300", "Isskada", "Ice Damage",
|
|
DefectCategory.ENVIRONMENTAL, DefectSeverity.MODERATE,
|
|
"Skada från is eller frost",
|
|
"Damage from ice or frost",
|
|
parent_code="6000",
|
|
ai_keywords=["ice", "frost", "freeze"]
|
|
))
|
|
|
|
def _add(self, code: DefectCode):
|
|
"""Add defect code to registry"""
|
|
self._codes[code.code] = code
|
|
|
|
def get(self, code: str) -> Optional[DefectCode]:
|
|
"""Get defect code by code string"""
|
|
return self._codes.get(code)
|
|
|
|
def get_by_category(self, category: DefectCategory) -> List[DefectCode]:
|
|
"""Get all codes in a category"""
|
|
return [c for c in self._codes.values() if c.category == category]
|
|
|
|
def get_by_severity(self, severity: DefectSeverity) -> List[DefectCode]:
|
|
"""Get all codes with a severity level"""
|
|
return [c for c in self._codes.values() if c.severity == severity]
|
|
|
|
def search(self, query: str, lang: str = "sv") -> List[DefectCode]:
|
|
"""Search codes by name or description"""
|
|
query = query.lower()
|
|
results = []
|
|
|
|
for code in self._codes.values():
|
|
name = code.get_name(lang).lower()
|
|
desc = code.get_description(lang).lower()
|
|
|
|
if query in name or query in desc or query in code.code:
|
|
results.append(code)
|
|
|
|
return results
|
|
|
|
def get_children(self, parent_code: str) -> List[DefectCode]:
|
|
"""Get child codes for a parent code"""
|
|
return [c for c in self._codes.values() if c.parent_code == parent_code]
|
|
|
|
def get_top_level(self) -> List[DefectCode]:
|
|
"""Get all top-level codes (no parent)"""
|
|
return [c for c in self._codes.values() if c.parent_code is None]
|
|
|
|
def get_ai_suggestions(self, keywords: List[str]) -> List[Tuple[DefectCode, float]]:
|
|
"""
|
|
Get defect code suggestions based on AI keywords
|
|
|
|
Returns:
|
|
List of (DefectCode, confidence) tuples
|
|
"""
|
|
suggestions = []
|
|
|
|
for code in self._codes.values():
|
|
matches = sum(1 for kw in keywords if kw.lower() in [k.lower() for k in code.ai_keywords])
|
|
if matches > 0:
|
|
confidence = matches / len(keywords)
|
|
suggestions.append((code, confidence))
|
|
|
|
# Sort by confidence
|
|
suggestions.sort(key=lambda x: x[1], reverse=True)
|
|
|
|
return suggestions
|
|
|
|
def list_all(self) -> List[Dict]:
|
|
"""List all defect codes"""
|
|
return [code.to_dict() for code in self._codes.values()]
|
|
|
|
def list_categories(self) -> List[Dict]:
|
|
"""List all categories with counts"""
|
|
categories = {}
|
|
|
|
for code in self._codes.values():
|
|
cat = code.category.value
|
|
if cat not in categories:
|
|
categories[cat] = 0
|
|
categories[cat] += 1
|
|
|
|
return [
|
|
{"category": cat, "count": count}
|
|
for cat, count in sorted(categories.items())
|
|
]
|
|
|
|
|
|
# Singleton instance
|
|
defect_registry = DefectRegistry()
|
|
|
|
|
|
def get_defect_code(code: str) -> Optional[DefectCode]:
|
|
"""Convenience function"""
|
|
return defect_registry.get(code)
|
|
|
|
|
|
def search_defects(query: str, lang: str = "sv") -> List[DefectCode]:
|
|
"""Convenience function"""
|
|
return defect_registry.search(query, lang)
|
|
|
|
|
|
def suggest_defect_codes(keywords: List[str]) -> List[Tuple[DefectCode, float]]:
|
|
"""Convenience function"""
|
|
return defect_registry.get_ai_suggestions(keywords)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
# Example usage
|
|
registry = DefectRegistry()
|
|
|
|
print("=== All Defect Codes ===")
|
|
for code in registry.list_all()[:5]:
|
|
print(f"{code['code']}: {code['name']} ({code['category']})")
|
|
|
|
print("\n=== Search for 'crack' ===")
|
|
results = registry.search("spricka")
|
|
for code in results[:5]:
|
|
print(f"{code.code}: {code.name_sv}")
|
|
|
|
print("\n=== AI Suggestions for ['rust', 'corrosion'] ===")
|
|
suggestions = registry.get_ai_suggestions(["rust", "corrosion"])
|
|
for code, confidence in suggestions[:5]:
|
|
print(f"{code.code}: {code.name_en} (confidence: {confidence:.2f})")
|
|
|
|
print("\n=== Categories ===")
|
|
for cat in registry.list_categories():
|
|
print(f"{cat['category']}: {cat['count']} codes")
|