Spaces:
Runtime error
Runtime error
| import re | |
| # --------------------------------------------------------------------------- | |
| # Reconstructed from master.ipynb (cells 182-189). | |
| # extract_attributes(desc) -> dict of parsed spec fields | |
| # attribute_score(attrs1, attrs2) -> weighted similarity in [0, 1] | |
| # --------------------------------------------------------------------------- | |
| PATTERNS = { | |
| # Item Type | |
| "ITEM": r"^([A-Z]+,[A-Z]+)", | |
| # Application | |
| "TYPE": r"TYPE(?:/APPLICATION)?[:=]\s*(.+?)(?=\s+[A-Z][A-Z /-]*:|$)", | |
| # Sizes | |
| "SIZE": r"SIZE[:=]\s*([^:]+?)(?=\s+[A-Z][A-Z /-]*:|$)", | |
| "RUN SIZE": r"RUN SIZE[:=]\s*([^:]+?)(?=\s+[A-Z][A-Z /-]*:|$)", | |
| "BRANCH SIZE": r"BRANCH SIZE[:=]\s*([^:]+?)(?=\s+[A-Z][A-Z /-]*:|$)", | |
| # Pressure | |
| "RATING": r"RATING(?:/SCHEDULE)?[:=]\s*([^:]+?)(?=\s+[A-Z][A-Z /-]*:|$)", | |
| "PRESSURE CLASS": r"CLASS[:=]\s*([^:]+?)(?=\s+[A-Z][A-Z /-]*:|$)", | |
| # Schedule | |
| "SCHEDULE": r"SCH(?:EDULE)?\.?\s*([0-9A-Z\-]+)", | |
| # Material | |
| "MATERIAL": r"MATERIAL[:=]\s*([^:]+?)(?=\s+[A-Z][A-Z /-]*:|$)", | |
| # Grade | |
| "GRADE": r"GRADE[:=]\s*([^:]+?)(?=\s+[A-Z][A-Z /-]*:|$)", | |
| # Specification | |
| "SPECIFICATION": r"SPECIFICATION[:=]\s*([^:]+?)(?=\s+[A-Z][A-Z /-]*:|$)", | |
| # Standards | |
| "STANDARD": r"(ASME\s*B[0-9.\-]+|ASTM\s*A[0-9A-Z\-]+|API\s*[0-9A-Z\-]+|ANSI\s*B[0-9.\-]+|USAS\s*B[0-9.\-]+)", | |
| # Connection | |
| "CONNECTION": r"CONNECTION[:=]\s*([^:]+?)(?=\s+[A-Z][A-Z /-]*:|$)", | |
| # End Connection | |
| "END CONNECTION": r"END CONNECTION[:=]\s*([^:]+?)(?=\s+[A-Z][A-Z /-]*:|$)", | |
| # Radius | |
| "RADIUS": r"RADIUS[:=]\s*([^:]+?)(?=\s+[A-Z][A-Z /-]*:|$)", | |
| # Degree | |
| "DEGREE": r"DEGREE[:=]\s*([0-9]+)", | |
| # Face | |
| "FACE": r"FACE[:=]\s*([^:]+?)(?=\s+[A-Z][A-Z /-]*:|$)", | |
| # Ends | |
| "ENDS": r"ENDS[:=]\s*([^:]+?)(?=\s+[A-Z][A-Z /-]*:|$)", | |
| # Bore | |
| "BORE": r"BORE[:=]\s*([^:]+?)(?=\s+[A-Z][A-Z /-]*:|$)", | |
| # Thickness | |
| "THICKNESS": r"THICKNESS[:=]\s*([^:]+?)(?=\s+[A-Z][A-Z /-]*:|$)", | |
| # Length | |
| "LENGTH": r"LENGTH[:=]\s*([^:]+?)(?=\s+[A-Z][A-Z /-]*:|$)", | |
| # Diameter | |
| "DIAMETER": r"DIAMETER[:=]\s*([^:]+?)(?=\s+[A-Z][A-Z /-]*:|$)", | |
| # Manufacturer | |
| "MANUFACTURER": r"MANUFACTURER(?: CODE)?[:=]\s*([^:]+?)(?=\s+[A-Z][A-Z /-]*:|$)", | |
| # Thread | |
| "THREAD": r"THREAD(?: TYPE)?[:=]\s*([^:]+?)(?=\s+[A-Z][A-Z /-]*:|$)", | |
| # Seal | |
| "SEAL": r"SEAL[:=]\s*([^:]+?)(?=\s+[A-Z][A-Z /-]*:|$)", | |
| # Seat | |
| "SEAT": r"SEAT[:=]\s*([^:]+?)(?=\s+[A-Z][A-Z /-]*:|$)", | |
| # Disc | |
| "DISC": r"DISC[:=]\s*([^:]+?)(?=\s+[A-Z][A-Z /-]*:|$)", | |
| # Stem | |
| "STEM": r"STEM[:=]\s*([^:]+?)(?=\s+[A-Z][A-Z /-]*:|$)", | |
| # Body | |
| "BODY": r"BODY[:=]\s*([^:]+?)(?=\s+[A-Z][A-Z /-]*:|$)", | |
| # Trim | |
| "TRIM": r"TRIM[:=]\s*([^:]+?)(?=\s+[A-Z][A-Z /-]*:|$)", | |
| } | |
| WEIGHTS = { | |
| "ITEM": 0.05, | |
| "TYPE": 0.05, | |
| "SIZE": 0.15, | |
| "RUN SIZE": 0.08, | |
| "BRANCH SIZE": 0.08, | |
| "RATING": 0.12, | |
| "PRESSURE CLASS": 0.06, | |
| "SCHEDULE": 0.05, | |
| "MATERIAL": 0.08, | |
| "GRADE": 0.06, | |
| "SPECIFICATION": 0.05, | |
| "STANDARD": 0.04, | |
| "CONNECTION": 0.04, | |
| "END CONNECTION": 0.03, | |
| "RADIUS": 0.03, | |
| "DEGREE": 0.02, | |
| "FACE": 0.02, | |
| "ENDS": 0.02, | |
| "BORE": 0.02, | |
| "THICKNESS": 0.02, | |
| "LENGTH": 0.02, | |
| "DIAMETER": 0.02, | |
| "MANUFACTURER": 0.02, | |
| "THREAD": 0.02, | |
| "SEAL": 0.01, | |
| "SEAT": 0.01, | |
| "DISC": 0.01, | |
| "STEM": 0.01, | |
| "BODY": 0.01, | |
| "TRIM": 0.01, | |
| } | |
| NORMALIZATION = { | |
| # ---------- MATERIAL ---------- | |
| "SS": "STAINLESS STEEL", | |
| "S.S": "STAINLESS STEEL", | |
| "STAINLESS STEEL": "STAINLESS STEEL", | |
| "CS": "CARBON STEEL", | |
| "C.S": "CARBON STEEL", | |
| "CARBON STEEL": "CARBON STEEL", | |
| "MS": "MILD STEEL", | |
| "M.S": "MILD STEEL", | |
| "GI": "GALVANIZED IRON", | |
| # ---------- CONNECTION ---------- | |
| "BW": "BUTT WELD", | |
| "BUTT WELD": "BUTT WELD", | |
| "SW": "SOCKET WELD", | |
| "SOCKET WELD": "SOCKET WELD", | |
| "THD": "THREADED", | |
| "NPT": "THREADED", | |
| "BSP": "THREADED", | |
| "RF": "RAISED FACE", | |
| "FF": "FLAT FACE", | |
| "RTJ": "RING TYPE JOINT", | |
| # ---------- RADIUS ---------- | |
| "SR": "SHORT", | |
| "SHORT RADIUS": "SHORT", | |
| "SHORT": "SHORT", | |
| "LR": "LONG", | |
| "LONG RADIUS": "LONG", | |
| "LONG": "LONG", | |
| # ---------- PRESSURE ---------- | |
| "150#": "150 LB", | |
| "300#": "300 LB", | |
| "600#": "600 LB", | |
| "900#": "900 LB", | |
| "1500#": "1500 LB", | |
| "2500#": "2500 LB", | |
| # ---------- GRADE ---------- | |
| "304 SS": "F304", | |
| "SS304": "F304", | |
| "304": "F304", | |
| "316 SS": "F316", | |
| "SS316": "F316", | |
| "316": "F316", | |
| # ---------- SCHEDULE ---------- | |
| "SCH40": "SCH 40", | |
| "SCH80": "SCH 80", | |
| "SCH160": "SCH 160", | |
| # ---------- DEGREE ---------- | |
| "90 DEG": "90", | |
| "45 DEG": "45", | |
| } | |
| def extract_attributes(desc): | |
| desc = str(desc).upper() | |
| attrs = {} | |
| for key, pattern in PATTERNS.items(): | |
| m = re.search(pattern, desc) | |
| attrs[key] = m.group(1).strip() if m else "" | |
| return attrs | |
| def normalize_value(value): | |
| value = str(value).upper().strip() | |
| value = re.sub(r"\s+", " ", value) | |
| value = value.replace('"', " IN") | |
| value = value.replace("''", " IN") | |
| value = value.replace("INCH", "IN") | |
| value = value.replace("IN.", "IN") | |
| value = value.strip() | |
| if value in NORMALIZATION: | |
| value = NORMALIZATION[value] | |
| return value | |
| def normalize_attributes(attrs): | |
| return {key: normalize_value(value) for key, value in attrs.items()} | |
| def attribute_score(a, b): | |
| a = normalize_attributes(a) | |
| b = normalize_attributes(b) | |
| score = 0 | |
| total = 0 | |
| for key, weight in WEIGHTS.items(): | |
| total += weight | |
| if a.get(key, "") == b.get(key, "") and a.get(key, "") != "": | |
| score += weight | |
| return score / total | |