🎯 주요 성과: - 8개 주요 자재군 완전 분류 시스템 구축 - 재질 분류 엔진 + 개별 자재별 특화 분류 - 스풀 관리 시스템 (파이프 절단 계획용) - 실제 BOM 데이터 기반 설계 및 테스트 📁 새로 추가된 자재 분류 시스템: - app/services/pipe_classifier.py (파이프 + 스풀 관리) - app/services/fitting_classifier.py (피팅 10가지 타입) - app/services/flange_classifier.py (플랜지 SPECIAL/STANDARD) - app/services/valve_classifier.py (밸브 단조/주조 구분) - app/services/gasket_classifier.py (가스켓 8가지 타입) - app/services/bolt_classifier.py (볼트/너트/와셔 통합) - app/services/instrument_classifier.py (계기류 기본) 🔧 분류 성능: - PIPE: 제조방법, 끝가공, 스케줄, 절단계획 - FITTING: 타입, 연결방식, 압력등급, 제작방법 - FLANGE: SPECIAL(10종)/STANDARD(6종), 면가공 - VALVE: 9가지 타입, 단조/주조 구분, 작동방식 - GASKET: 8가지 타입, 재질별, 온도/압력 범위 - BOLT: 체결재 3종, 나사규격, 강도등급 📊 기술적 특징: - 정규표현식 기반 패턴 매칭 엔진 - 신뢰도 점수 시스템 (0.0-1.0) - 증거 기반 분류 추적 (evidence tracking) - 모듈화 구조로 재사용성 극대화 - 실제 DAT_FILE + DESCRIPTION 패턴 분석 🎯 분류 커버리지: - 재질: ASTM/ASME 표준 + 특수합금 (INCONEL, TITANIUM) - 제작방법: FORGED, CAST, SEAMLESS, WELDED 자동 판단 - 압력등급: 150LB ~ 9000LB 전 범위 - 연결방식: BW, SW, THD, FL 등 모든 방식 - 사이즈: 1/8" ~ 48" 전 범위 💾 데이터 통합: - 기존 materials 테이블과 완전 호환 - 프로젝트/도면 정보 자동 연결 - 스풀 정보 사용자 입력 대기 (파이프만) - 구매 정보 자동 생성 (공급업체, 납기) 🧪 테스트 완료: - 각 시스템별 10+ 테스트 케이스 - 실제 BOM 데이터 기반 검증 - 예외 상황 처리 테스트 - 신뢰도 검증 완료 Version: v2.0 (Major Release) Date: 2024-07-15 Author: hyungiahn Breaking Changes: 새로운 분류 시스템 추가 (기존 호환성 유지) Next Phase: files.py 통합 및 웹 인터페이스 연동
553 lines
20 KiB
Python
553 lines
20 KiB
Python
"""
|
|
GASKET 분류 시스템
|
|
플랜지용 가스켓 및 씰링 제품 분류
|
|
"""
|
|
|
|
import re
|
|
from typing import Dict, List, Optional
|
|
from .material_classifier import classify_material
|
|
|
|
# ========== 가스켓 타입별 분류 ==========
|
|
GASKET_TYPES = {
|
|
"SPIRAL_WOUND": {
|
|
"dat_file_patterns": ["SWG_", "SPIRAL_"],
|
|
"description_keywords": ["SPIRAL WOUND", "SPIRAL", "스파이럴", "SWG"],
|
|
"characteristics": "금속 스트립과 필러의 나선형 조합",
|
|
"pressure_range": "150LB ~ 2500LB",
|
|
"temperature_range": "-200°C ~ 800°C",
|
|
"applications": "고온고압, 일반 산업용"
|
|
},
|
|
|
|
"RING_JOINT": {
|
|
"dat_file_patterns": ["RTJ_", "RJ_", "RING_"],
|
|
"description_keywords": ["RING JOINT", "RTJ", "RING TYPE JOINT", "링조인트"],
|
|
"characteristics": "금속 링 형태의 고압용 가스켓",
|
|
"pressure_range": "600LB ~ 2500LB",
|
|
"temperature_range": "-100°C ~ 650°C",
|
|
"applications": "고압 플랜지 전용"
|
|
},
|
|
|
|
"FULL_FACE": {
|
|
"dat_file_patterns": ["FF_", "FULL_"],
|
|
"description_keywords": ["FULL FACE", "FF", "풀페이스"],
|
|
"characteristics": "플랜지 전면 커버 가스켓",
|
|
"pressure_range": "150LB ~ 300LB",
|
|
"temperature_range": "-50°C ~ 400°C",
|
|
"applications": "평면 플랜지용"
|
|
},
|
|
|
|
"RAISED_FACE": {
|
|
"dat_file_patterns": ["RF_", "RAISED_"],
|
|
"description_keywords": ["RAISED FACE", "RF", "레이즈드"],
|
|
"characteristics": "볼록한 면 전용 가스켓",
|
|
"pressure_range": "150LB ~ 600LB",
|
|
"temperature_range": "-50°C ~ 450°C",
|
|
"applications": "일반 볼록면 플랜지용"
|
|
},
|
|
|
|
"O_RING": {
|
|
"dat_file_patterns": ["OR_", "ORING_"],
|
|
"description_keywords": ["O-RING", "O RING", "ORING", "오링"],
|
|
"characteristics": "원형 단면의 씰링 링",
|
|
"pressure_range": "저압 ~ 고압 (재질별)",
|
|
"temperature_range": "-60°C ~ 300°C (재질별)",
|
|
"applications": "홈 씰링, 회전축 씰링"
|
|
},
|
|
|
|
"SHEET_GASKET": {
|
|
"dat_file_patterns": ["SHEET_", "SHT_"],
|
|
"description_keywords": ["SHEET GASKET", "SHEET", "시트"],
|
|
"characteristics": "판 형태의 가스켓",
|
|
"pressure_range": "150LB ~ 600LB",
|
|
"temperature_range": "-50°C ~ 500°C",
|
|
"applications": "일반 플랜지, 맨홀"
|
|
},
|
|
|
|
"KAMMPROFILE": {
|
|
"dat_file_patterns": ["KAMM_", "KP_"],
|
|
"description_keywords": ["KAMMPROFILE", "KAMM", "캄프로파일"],
|
|
"characteristics": "파형 금속에 소프트 코팅",
|
|
"pressure_range": "150LB ~ 1500LB",
|
|
"temperature_range": "-200°C ~ 700°C",
|
|
"applications": "고온고압, 화학공정"
|
|
},
|
|
|
|
"CUSTOM_GASKET": {
|
|
"dat_file_patterns": ["CUSTOM_", "SPEC_"],
|
|
"description_keywords": ["CUSTOM", "SPECIAL", "특주", "맞춤"],
|
|
"characteristics": "특수 제작 가스켓",
|
|
"pressure_range": "요구사항별",
|
|
"temperature_range": "요구사항별",
|
|
"applications": "특수 형상, 특수 조건"
|
|
}
|
|
}
|
|
|
|
# ========== 가스켓 재질별 분류 ==========
|
|
GASKET_MATERIALS = {
|
|
"GRAPHITE": {
|
|
"keywords": ["GRAPHITE", "그라파이트", "흑연"],
|
|
"characteristics": "고온 내성, 화학 안정성",
|
|
"temperature_range": "-200°C ~ 650°C",
|
|
"applications": "고온 스팀, 화학공정"
|
|
},
|
|
|
|
"PTFE": {
|
|
"keywords": ["PTFE", "TEFLON", "테프론"],
|
|
"characteristics": "화학 내성, 낮은 마찰",
|
|
"temperature_range": "-200°C ~ 260°C",
|
|
"applications": "화학공정, 식품용"
|
|
},
|
|
|
|
"VITON": {
|
|
"keywords": ["VITON", "FKM", "바이톤"],
|
|
"characteristics": "유류 내성, 고온 내성",
|
|
"temperature_range": "-20°C ~ 200°C",
|
|
"applications": "유류, 고온 가스"
|
|
},
|
|
|
|
"EPDM": {
|
|
"keywords": ["EPDM", "이피디엠"],
|
|
"characteristics": "일반 고무, 스팀 내성",
|
|
"temperature_range": "-50°C ~ 150°C",
|
|
"applications": "스팀, 일반용"
|
|
},
|
|
|
|
"NBR": {
|
|
"keywords": ["NBR", "NITRILE", "니트릴"],
|
|
"characteristics": "유류 내성",
|
|
"temperature_range": "-30°C ~ 100°C",
|
|
"applications": "유압, 윤활유"
|
|
},
|
|
|
|
"METAL": {
|
|
"keywords": ["METAL", "SS", "STAINLESS", "금속"],
|
|
"characteristics": "고온고압 내성",
|
|
"temperature_range": "-200°C ~ 800°C",
|
|
"applications": "극한 조건"
|
|
},
|
|
|
|
"COMPOSITE": {
|
|
"keywords": ["COMPOSITE", "복합재", "FIBER"],
|
|
"characteristics": "다층 구조",
|
|
"temperature_range": "재질별 상이",
|
|
"applications": "특수 조건"
|
|
}
|
|
}
|
|
|
|
# ========== 압력 등급별 분류 ==========
|
|
GASKET_PRESSURE_RATINGS = {
|
|
"patterns": [
|
|
r"(\d+)LB",
|
|
r"CLASS\s*(\d+)",
|
|
r"CL\s*(\d+)",
|
|
r"(\d+)#"
|
|
],
|
|
"standard_ratings": {
|
|
"150LB": {"max_pressure": "285 PSI", "typical_gasket": "SHEET, SPIRAL_WOUND"},
|
|
"300LB": {"max_pressure": "740 PSI", "typical_gasket": "SPIRAL_WOUND, SHEET"},
|
|
"600LB": {"max_pressure": "1480 PSI", "typical_gasket": "SPIRAL_WOUND, RTJ"},
|
|
"900LB": {"max_pressure": "2220 PSI", "typical_gasket": "SPIRAL_WOUND, RTJ"},
|
|
"1500LB": {"max_pressure": "3705 PSI", "typical_gasket": "RTJ, SPIRAL_WOUND"},
|
|
"2500LB": {"max_pressure": "6170 PSI", "typical_gasket": "RTJ"}
|
|
}
|
|
}
|
|
|
|
# ========== 사이즈 표기법 ==========
|
|
GASKET_SIZE_PATTERNS = {
|
|
"flange_size": r"(\d+(?:\.\d+)?)\s*[\"\'']?\s*(?:INCH|IN|인치)?",
|
|
"inner_diameter": r"ID\s*(\d+(?:\.\d+)?)",
|
|
"outer_diameter": r"OD\s*(\d+(?:\.\d+)?)",
|
|
"thickness": r"THK?\s*(\d+(?:\.\d+)?)\s*MM"
|
|
}
|
|
|
|
def classify_gasket(dat_file: str, description: str, main_nom: str) -> Dict:
|
|
"""
|
|
완전한 GASKET 분류
|
|
|
|
Args:
|
|
dat_file: DAT_FILE 필드
|
|
description: DESCRIPTION 필드
|
|
main_nom: MAIN_NOM 필드 (플랜지 사이즈)
|
|
|
|
Returns:
|
|
완전한 가스켓 분류 결과
|
|
"""
|
|
|
|
# 1. 재질 분류 (공통 모듈 + 가스켓 전용)
|
|
material_result = classify_material(description)
|
|
gasket_material_result = classify_gasket_material(description)
|
|
|
|
# 2. 가스켓 타입 분류
|
|
gasket_type_result = classify_gasket_type(dat_file, description)
|
|
|
|
# 3. 압력 등급 분류
|
|
pressure_result = classify_gasket_pressure_rating(dat_file, description)
|
|
|
|
# 4. 사이즈 정보 추출
|
|
size_result = extract_gasket_size_info(main_nom, description)
|
|
|
|
# 5. 온도 범위 추출
|
|
temperature_result = extract_temperature_range(description, gasket_type_result, gasket_material_result)
|
|
|
|
# 6. 최종 결과 조합
|
|
return {
|
|
"category": "GASKET",
|
|
|
|
# 재질 정보 (공통 + 가스켓 전용)
|
|
"material": {
|
|
"standard": material_result.get('standard', 'UNKNOWN'),
|
|
"grade": material_result.get('grade', 'UNKNOWN'),
|
|
"material_type": material_result.get('material_type', 'UNKNOWN'),
|
|
"confidence": material_result.get('confidence', 0.0)
|
|
},
|
|
|
|
"gasket_material": {
|
|
"material": gasket_material_result.get('material', 'UNKNOWN'),
|
|
"characteristics": gasket_material_result.get('characteristics', ''),
|
|
"temperature_range": gasket_material_result.get('temperature_range', ''),
|
|
"confidence": gasket_material_result.get('confidence', 0.0)
|
|
},
|
|
|
|
# 가스켓 분류 정보
|
|
"gasket_type": {
|
|
"type": gasket_type_result.get('type', 'UNKNOWN'),
|
|
"characteristics": gasket_type_result.get('characteristics', ''),
|
|
"confidence": gasket_type_result.get('confidence', 0.0),
|
|
"evidence": gasket_type_result.get('evidence', []),
|
|
"pressure_range": gasket_type_result.get('pressure_range', ''),
|
|
"applications": gasket_type_result.get('applications', '')
|
|
},
|
|
|
|
"pressure_rating": {
|
|
"rating": pressure_result.get('rating', 'UNKNOWN'),
|
|
"confidence": pressure_result.get('confidence', 0.0),
|
|
"max_pressure": pressure_result.get('max_pressure', ''),
|
|
"typical_gasket": pressure_result.get('typical_gasket', '')
|
|
},
|
|
|
|
"size_info": {
|
|
"flange_size": size_result.get('flange_size', main_nom),
|
|
"inner_diameter": size_result.get('inner_diameter', ''),
|
|
"outer_diameter": size_result.get('outer_diameter', ''),
|
|
"thickness": size_result.get('thickness', ''),
|
|
"size_description": size_result.get('size_description', main_nom)
|
|
},
|
|
|
|
"temperature_info": {
|
|
"range": temperature_result.get('range', ''),
|
|
"max_temp": temperature_result.get('max_temp', ''),
|
|
"min_temp": temperature_result.get('min_temp', ''),
|
|
"confidence": temperature_result.get('confidence', 0.0)
|
|
},
|
|
|
|
# 전체 신뢰도
|
|
"overall_confidence": calculate_gasket_confidence({
|
|
"gasket_type": gasket_type_result.get('confidence', 0),
|
|
"gasket_material": gasket_material_result.get('confidence', 0),
|
|
"pressure": pressure_result.get('confidence', 0),
|
|
"size": size_result.get('confidence', 0.8) # 기본 신뢰도
|
|
})
|
|
}
|
|
|
|
def classify_gasket_type(dat_file: str, description: str) -> Dict:
|
|
"""가스켓 타입 분류"""
|
|
|
|
dat_upper = dat_file.upper()
|
|
desc_upper = description.upper()
|
|
|
|
# 1. DAT_FILE 패턴으로 1차 분류
|
|
for gasket_type, type_data in GASKET_TYPES.items():
|
|
for pattern in type_data["dat_file_patterns"]:
|
|
if pattern in dat_upper:
|
|
return {
|
|
"type": gasket_type,
|
|
"characteristics": type_data["characteristics"],
|
|
"confidence": 0.95,
|
|
"evidence": [f"DAT_FILE_PATTERN: {pattern}"],
|
|
"pressure_range": type_data["pressure_range"],
|
|
"temperature_range": type_data["temperature_range"],
|
|
"applications": type_data["applications"]
|
|
}
|
|
|
|
# 2. DESCRIPTION 키워드로 2차 분류
|
|
for gasket_type, type_data in GASKET_TYPES.items():
|
|
for keyword in type_data["description_keywords"]:
|
|
if keyword in desc_upper:
|
|
return {
|
|
"type": gasket_type,
|
|
"characteristics": type_data["characteristics"],
|
|
"confidence": 0.85,
|
|
"evidence": [f"DESCRIPTION_KEYWORD: {keyword}"],
|
|
"pressure_range": type_data["pressure_range"],
|
|
"temperature_range": type_data["temperature_range"],
|
|
"applications": type_data["applications"]
|
|
}
|
|
|
|
# 3. 분류 실패
|
|
return {
|
|
"type": "UNKNOWN",
|
|
"characteristics": "",
|
|
"confidence": 0.0,
|
|
"evidence": ["NO_GASKET_TYPE_IDENTIFIED"],
|
|
"pressure_range": "",
|
|
"temperature_range": "",
|
|
"applications": ""
|
|
}
|
|
|
|
def classify_gasket_material(description: str) -> Dict:
|
|
"""가스켓 전용 재질 분류"""
|
|
|
|
desc_upper = description.upper()
|
|
|
|
# 가스켓 전용 재질 확인
|
|
for material_type, material_data in GASKET_MATERIALS.items():
|
|
for keyword in material_data["keywords"]:
|
|
if keyword in desc_upper:
|
|
return {
|
|
"material": material_type,
|
|
"characteristics": material_data["characteristics"],
|
|
"temperature_range": material_data["temperature_range"],
|
|
"confidence": 0.9,
|
|
"matched_keyword": keyword,
|
|
"applications": material_data["applications"]
|
|
}
|
|
|
|
# 일반 재질 키워드 확인
|
|
if any(keyword in desc_upper for keyword in ["RUBBER", "고무"]):
|
|
return {
|
|
"material": "RUBBER",
|
|
"characteristics": "일반 고무계",
|
|
"temperature_range": "-50°C ~ 100°C",
|
|
"confidence": 0.7,
|
|
"matched_keyword": "RUBBER",
|
|
"applications": "일반용"
|
|
}
|
|
|
|
return {
|
|
"material": "UNKNOWN",
|
|
"characteristics": "",
|
|
"temperature_range": "",
|
|
"confidence": 0.0,
|
|
"matched_keyword": "",
|
|
"applications": ""
|
|
}
|
|
|
|
def classify_gasket_pressure_rating(dat_file: str, description: str) -> Dict:
|
|
"""가스켓 압력 등급 분류"""
|
|
|
|
combined_text = f"{dat_file} {description}".upper()
|
|
|
|
# 패턴 매칭으로 압력 등급 추출
|
|
for pattern in GASKET_PRESSURE_RATINGS["patterns"]:
|
|
match = re.search(pattern, combined_text)
|
|
if match:
|
|
rating_num = match.group(1)
|
|
rating = f"{rating_num}LB"
|
|
|
|
# 표준 등급 정보 확인
|
|
rating_info = GASKET_PRESSURE_RATINGS["standard_ratings"].get(rating, {})
|
|
|
|
if rating_info:
|
|
confidence = 0.95
|
|
else:
|
|
confidence = 0.8
|
|
rating_info = {
|
|
"max_pressure": "확인 필요",
|
|
"typical_gasket": "확인 필요"
|
|
}
|
|
|
|
return {
|
|
"rating": rating,
|
|
"confidence": confidence,
|
|
"matched_pattern": pattern,
|
|
"matched_value": rating_num,
|
|
"max_pressure": rating_info.get("max_pressure", ""),
|
|
"typical_gasket": rating_info.get("typical_gasket", "")
|
|
}
|
|
|
|
return {
|
|
"rating": "UNKNOWN",
|
|
"confidence": 0.0,
|
|
"matched_pattern": "",
|
|
"max_pressure": "",
|
|
"typical_gasket": ""
|
|
}
|
|
|
|
def extract_gasket_size_info(main_nom: str, description: str) -> Dict:
|
|
"""가스켓 사이즈 정보 추출"""
|
|
|
|
desc_upper = description.upper()
|
|
size_info = {
|
|
"flange_size": main_nom,
|
|
"inner_diameter": "",
|
|
"outer_diameter": "",
|
|
"thickness": "",
|
|
"size_description": main_nom,
|
|
"confidence": 0.8
|
|
}
|
|
|
|
# 내경(ID) 추출
|
|
id_match = re.search(GASKET_SIZE_PATTERNS["inner_diameter"], desc_upper)
|
|
if id_match:
|
|
size_info["inner_diameter"] = f"{id_match.group(1)}mm"
|
|
|
|
# 외경(OD) 추출
|
|
od_match = re.search(GASKET_SIZE_PATTERNS["outer_diameter"], desc_upper)
|
|
if od_match:
|
|
size_info["outer_diameter"] = f"{od_match.group(1)}mm"
|
|
|
|
# 두께(THK) 추출
|
|
thk_match = re.search(GASKET_SIZE_PATTERNS["thickness"], desc_upper)
|
|
if thk_match:
|
|
size_info["thickness"] = f"{thk_match.group(1)}mm"
|
|
|
|
# 사이즈 설명 조합
|
|
size_parts = [main_nom]
|
|
if size_info["inner_diameter"] and size_info["outer_diameter"]:
|
|
size_parts.append(f"ID{size_info['inner_diameter']}")
|
|
size_parts.append(f"OD{size_info['outer_diameter']}")
|
|
if size_info["thickness"]:
|
|
size_parts.append(f"THK{size_info['thickness']}")
|
|
|
|
size_info["size_description"] = " ".join(size_parts)
|
|
|
|
return size_info
|
|
|
|
def extract_temperature_range(description: str, gasket_type_result: Dict,
|
|
gasket_material_result: Dict) -> Dict:
|
|
"""온도 범위 정보 추출"""
|
|
|
|
desc_upper = description.upper()
|
|
|
|
# DESCRIPTION에서 직접 온도 추출
|
|
temp_patterns = [
|
|
r'(\-?\d+(?:\.\d+)?)\s*°?C\s*~\s*(\-?\d+(?:\.\d+)?)\s*°?C',
|
|
r'(\-?\d+(?:\.\d+)?)\s*TO\s*(\-?\d+(?:\.\d+)?)\s*°?C',
|
|
r'MAX\s*(\-?\d+(?:\.\d+)?)\s*°?C',
|
|
r'MIN\s*(\-?\d+(?:\.\d+)?)\s*°?C'
|
|
]
|
|
|
|
for pattern in temp_patterns:
|
|
match = re.search(pattern, desc_upper)
|
|
if match:
|
|
if len(match.groups()) == 2: # 범위
|
|
return {
|
|
"range": f"{match.group(1)}°C ~ {match.group(2)}°C",
|
|
"min_temp": f"{match.group(1)}°C",
|
|
"max_temp": f"{match.group(2)}°C",
|
|
"confidence": 0.95,
|
|
"source": "DESCRIPTION_RANGE"
|
|
}
|
|
else: # 단일 온도
|
|
temp_value = match.group(1)
|
|
if "MAX" in pattern:
|
|
return {
|
|
"range": f"~ {temp_value}°C",
|
|
"max_temp": f"{temp_value}°C",
|
|
"confidence": 0.9,
|
|
"source": "DESCRIPTION_MAX"
|
|
}
|
|
|
|
# 가스켓 재질 기반 온도 범위
|
|
material_temp = gasket_material_result.get('temperature_range', '')
|
|
if material_temp:
|
|
return {
|
|
"range": material_temp,
|
|
"confidence": 0.8,
|
|
"source": "MATERIAL_BASED"
|
|
}
|
|
|
|
# 가스켓 타입 기반 온도 범위
|
|
type_temp = gasket_type_result.get('temperature_range', '')
|
|
if type_temp:
|
|
return {
|
|
"range": type_temp,
|
|
"confidence": 0.7,
|
|
"source": "TYPE_BASED"
|
|
}
|
|
|
|
return {
|
|
"range": "",
|
|
"confidence": 0.0,
|
|
"source": "NO_TEMPERATURE_INFO"
|
|
}
|
|
|
|
def calculate_gasket_confidence(confidence_scores: Dict) -> float:
|
|
"""가스켓 분류 전체 신뢰도 계산"""
|
|
|
|
scores = [score for score in confidence_scores.values() if score > 0]
|
|
|
|
if not scores:
|
|
return 0.0
|
|
|
|
# 가중 평균
|
|
weights = {
|
|
"gasket_type": 0.4,
|
|
"gasket_material": 0.3,
|
|
"pressure": 0.2,
|
|
"size": 0.1
|
|
}
|
|
|
|
weighted_sum = sum(
|
|
confidence_scores.get(key, 0) * weight
|
|
for key, weight in weights.items()
|
|
)
|
|
|
|
return round(weighted_sum, 2)
|
|
|
|
# ========== 특수 기능들 ==========
|
|
|
|
def get_gasket_purchase_info(gasket_result: Dict) -> Dict:
|
|
"""가스켓 구매 정보 생성"""
|
|
|
|
gasket_type = gasket_result["gasket_type"]["type"]
|
|
gasket_material = gasket_result["gasket_material"]["material"]
|
|
pressure = gasket_result["pressure_rating"]["rating"]
|
|
|
|
# 공급업체 타입 결정
|
|
if gasket_type == "CUSTOM_GASKET":
|
|
supplier_type = "특수 가스켓 제작업체"
|
|
elif gasket_material in ["GRAPHITE", "PTFE"]:
|
|
supplier_type = "고급 씰링 전문업체"
|
|
elif gasket_type in ["SPIRAL_WOUND", "RING_JOINT"]:
|
|
supplier_type = "산업용 가스켓 전문업체"
|
|
else:
|
|
supplier_type = "일반 가스켓 업체"
|
|
|
|
# 납기 추정
|
|
if gasket_type == "CUSTOM_GASKET":
|
|
lead_time = "4-8주 (특수 제작)"
|
|
elif gasket_type in ["SPIRAL_WOUND", "KAMMPROFILE"]:
|
|
lead_time = "2-4주 (제작품)"
|
|
else:
|
|
lead_time = "1-2주 (재고품)"
|
|
|
|
# 구매 단위
|
|
if gasket_type == "O_RING":
|
|
purchase_unit = "EA (개별)"
|
|
elif gasket_type == "SHEET_GASKET":
|
|
purchase_unit = "SHEET (시트)"
|
|
else:
|
|
purchase_unit = "SET (세트)"
|
|
|
|
return {
|
|
"supplier_type": supplier_type,
|
|
"lead_time_estimate": lead_time,
|
|
"purchase_category": f"{gasket_type} {pressure}",
|
|
"purchase_unit": purchase_unit,
|
|
"material_note": gasket_result["gasket_material"]["characteristics"],
|
|
"temperature_note": gasket_result["temperature_info"]["range"],
|
|
"applications": gasket_result["gasket_type"]["applications"]
|
|
}
|
|
|
|
def is_high_temperature_gasket(gasket_result: Dict) -> bool:
|
|
"""고온용 가스켓 여부 판단"""
|
|
temp_range = gasket_result.get("temperature_info", {}).get("range", "")
|
|
return any(indicator in temp_range for indicator in ["500°C", "600°C", "700°C", "800°C"])
|
|
|
|
def is_high_pressure_gasket(gasket_result: Dict) -> bool:
|
|
"""고압용 가스켓 여부 판단"""
|
|
pressure_rating = gasket_result.get("pressure_rating", {}).get("rating", "")
|
|
high_pressure_ratings = ["600LB", "900LB", "1500LB", "2500LB"]
|
|
return any(pressure in pressure_rating for pressure in high_pressure_ratings)
|