feat: 자재 분류 시스템 개선 및 상세 테이블 추가
- 모든 자재 카테고리별 상세 테이블 생성 (fitting, valve, flange, bolt, gasket, instrument) - PIPE, FITTING, VALVE 분류 결과를 각 상세 테이블에 저장하는 로직 구현 - 프론트엔드 라우팅 정리 및 BOM 현황 페이지 기능 개선 - 자재확인 페이지 에러 처리 개선 TODO: FLANGE, BOLT, GASKET, INSTRUMENT 저장 로직 추가 필요
This commit is contained in:
@@ -440,6 +440,7 @@ def parse_file(file_path: str) -> List[Dict]:
|
||||
column_mapping = {
|
||||
'description': ['DESCRIPTION', 'Description', 'description', 'DESC', 'Desc', 'desc', 'ITEM', 'Item', 'item'],
|
||||
'quantity': ['QTY', 'Quantity', 'quantity', 'QTY.', 'Qty', 'qty', 'AMOUNT', 'Amount', 'amount'],
|
||||
'length': ['LENGTH', 'Length', 'length', 'LG', 'Lg', 'lg', 'LENGTH_MM', 'Length_mm', 'length_mm'],
|
||||
'unit': ['UNIT', 'Unit', 'unit', 'UOM', 'Uom', 'uom'],
|
||||
'drawing': ['DRAWING', 'Drawing', 'drawing', 'DWG', 'Dwg', 'dwg'],
|
||||
'area': ['AREA', 'Area', 'area', 'AREA_CODE', 'Area_Code', 'area_code'],
|
||||
@@ -466,6 +467,8 @@ def parse_file(file_path: str) -> List[Dict]:
|
||||
description = str(row.get(found_columns.get('description', ''), '') or '')
|
||||
quantity_raw = row.get(found_columns.get('quantity', 1), 1)
|
||||
quantity = float(quantity_raw) if quantity_raw is not None else 1.0
|
||||
length_raw = row.get(found_columns.get('length', 0), 0)
|
||||
length = float(length_raw) if length_raw is not None else 0.0
|
||||
unit = str(row.get(found_columns.get('unit', 'EA'), 'EA') or 'EA')
|
||||
drawing = str(row.get(found_columns.get('drawing', ''), '') or '')
|
||||
area = str(row.get(found_columns.get('area', ''), '') or '')
|
||||
@@ -475,6 +478,7 @@ def parse_file(file_path: str) -> List[Dict]:
|
||||
"line_number": index + 1,
|
||||
"original_description": description,
|
||||
"quantity": quantity,
|
||||
"length": length,
|
||||
"unit": unit,
|
||||
"drawing_name": drawing,
|
||||
"area_code": area,
|
||||
@@ -505,42 +509,85 @@ def classify_material_item(material: Dict) -> Dict:
|
||||
)
|
||||
|
||||
description = material.get("original_description", "")
|
||||
size_spec = material.get("size_spec", "")
|
||||
length = material.get("length", 0.0) # 길이 정보 추가
|
||||
|
||||
# 각 분류기로 분류 시도
|
||||
classifiers = [
|
||||
("PIPE", pipe_classifier.classify_pipe),
|
||||
("FITTING", fitting_classifier.classify_fitting),
|
||||
("BOLT", bolt_classifier.classify_bolt),
|
||||
("VALVE", valve_classifier.classify_valve),
|
||||
("INSTRUMENT", instrument_classifier.classify_instrument),
|
||||
("FLANGE", flange_classifier.classify_flange),
|
||||
("GASKET", gasket_classifier.classify_gasket)
|
||||
]
|
||||
print(f"분류 시도: {description}")
|
||||
|
||||
best_result = None
|
||||
best_confidence = 0.0
|
||||
# 각 분류기로 분류 시도 (개선된 순서와 기준)
|
||||
desc_upper = description.upper()
|
||||
|
||||
for category, classifier_func in classifiers:
|
||||
try:
|
||||
result = classifier_func(description)
|
||||
if result and result.get("confidence", 0) > best_confidence:
|
||||
best_result = result
|
||||
best_confidence = result.get("confidence", 0)
|
||||
except Exception:
|
||||
continue
|
||||
# 1. 명확한 키워드 우선 확인 (높은 신뢰도)
|
||||
if any(keyword in desc_upper for keyword in ['FLG', 'FLANGE', '플랜지', 'RF', 'WN', 'SO', 'BLIND']):
|
||||
classification_result = flange_classifier.classify_flange("", description, size_spec, length)
|
||||
print(f"FLANGE 분류 결과: {classification_result.get('category', 'UNKNOWN')} (신뢰도: {classification_result.get('overall_confidence', 0)})")
|
||||
elif any(keyword in desc_upper for keyword in ['VALVE', 'GATE', 'BALL', 'GLOBE', 'CHECK', '밸브', '게이트', '볼']):
|
||||
classification_result = valve_classifier.classify_valve("", description, size_spec, length)
|
||||
print(f"VALVE 분류 결과: {classification_result.get('category', 'UNKNOWN')} (신뢰도: {classification_result.get('overall_confidence', 0)})")
|
||||
elif any(keyword in desc_upper for keyword in ['ELBOW', 'ELL', 'TEE', 'REDUCER', 'CAP', 'COUPLING', '엘보', '티', '리듀서', '캡']):
|
||||
classification_result = fitting_classifier.classify_fitting("", description, size_spec, length)
|
||||
print(f"FITTING 분류 결과: {classification_result.get('category', 'UNKNOWN')} (신뢰도: {classification_result.get('overall_confidence', 0)})")
|
||||
elif any(keyword in desc_upper for keyword in ['BOLT', 'STUD', 'NUT', 'SCREW', '볼트', '너트', '스터드']):
|
||||
classification_result = bolt_classifier.classify_bolt("", description, size_spec, length)
|
||||
print(f"BOLT 분류 결과: {classification_result.get('category', 'UNKNOWN')} (신뢰도: {classification_result.get('overall_confidence', 0)})")
|
||||
elif any(keyword in desc_upper for keyword in ['GASKET', 'GASK', '가스켓']):
|
||||
classification_result = gasket_classifier.classify_gasket("", description, size_spec, length)
|
||||
print(f"GASKET 분류 결과: {classification_result.get('category', 'UNKNOWN')} (신뢰도: {classification_result.get('overall_confidence', 0)})")
|
||||
elif any(keyword in desc_upper for keyword in ['GAUGE', 'SENSOR', 'TRANSMITTER', 'INSTRUMENT', '계기', '게이지']):
|
||||
classification_result = instrument_classifier.classify_instrument("", description, size_spec, length)
|
||||
print(f"INSTRUMENT 분류 결과: {classification_result.get('category', 'UNKNOWN')} (신뢰도: {classification_result.get('overall_confidence', 0)})")
|
||||
elif any(keyword in desc_upper for keyword in ['PIPE', 'TUBE', '파이프', '배관']):
|
||||
classification_result = pipe_classifier.classify_pipe("", description, size_spec, length)
|
||||
print(f"PIPE 분류 결과: {classification_result.get('category', 'UNKNOWN')} (신뢰도: {classification_result.get('overall_confidence', 0)})")
|
||||
else:
|
||||
# 2. 일반적인 분류 시도 (낮은 신뢰도 임계값)
|
||||
classification_result = flange_classifier.classify_flange("", description, size_spec, length)
|
||||
print(f"FLANGE 분류 결과: {classification_result.get('category', 'UNKNOWN')} (신뢰도: {classification_result.get('overall_confidence', 0)})")
|
||||
|
||||
if classification_result.get("overall_confidence", 0) < 0.3:
|
||||
classification_result = valve_classifier.classify_valve("", description, size_spec, length)
|
||||
print(f"VALVE 분류 결과: {classification_result.get('category', 'UNKNOWN')} (신뢰도: {classification_result.get('overall_confidence', 0)})")
|
||||
|
||||
if classification_result.get("overall_confidence", 0) < 0.3:
|
||||
classification_result = fitting_classifier.classify_fitting("", description, size_spec, length)
|
||||
print(f"FITTING 분류 결과: {classification_result.get('category', 'UNKNOWN')} (신뢰도: {classification_result.get('overall_confidence', 0)})")
|
||||
|
||||
if classification_result.get("overall_confidence", 0) < 0.3:
|
||||
classification_result = pipe_classifier.classify_pipe("", description, size_spec, length)
|
||||
print(f"PIPE 분류 결과: {classification_result.get('category', 'UNKNOWN')} (신뢰도: {classification_result.get('overall_confidence', 0)})")
|
||||
|
||||
if classification_result.get("overall_confidence", 0) < 0.3:
|
||||
classification_result = bolt_classifier.classify_bolt("", description, size_spec, length)
|
||||
print(f"BOLT 분류 결과: {classification_result.get('category', 'UNKNOWN')} (신뢰도: {classification_result.get('overall_confidence', 0)})")
|
||||
|
||||
if classification_result.get("overall_confidence", 0) < 0.3:
|
||||
classification_result = gasket_classifier.classify_gasket("", description, size_spec, length)
|
||||
print(f"GASKET 분류 결과: {classification_result.get('category', 'UNKNOWN')} (신뢰도: {classification_result.get('overall_confidence', 0)})")
|
||||
|
||||
if classification_result.get("overall_confidence", 0) < 0.3:
|
||||
classification_result = instrument_classifier.classify_instrument("", description, size_spec, length)
|
||||
print(f"INSTRUMENT 분류 결과: {classification_result.get('category', 'UNKNOWN')} (신뢰도: {classification_result.get('overall_confidence', 0)})")
|
||||
|
||||
print(f"최종 분류 결과: {classification_result.get('category', 'UNKNOWN')}")
|
||||
|
||||
# 재질 분류
|
||||
material_result = material_classifier.classify_material(description)
|
||||
|
||||
# 최종 결과 조합
|
||||
# schedule이 딕셔너리인 경우 문자열로 변환
|
||||
schedule_value = classification_result.get("schedule", "")
|
||||
if isinstance(schedule_value, dict):
|
||||
schedule_value = schedule_value.get("schedule", "")
|
||||
|
||||
final_result = {
|
||||
**material,
|
||||
"classified_category": best_result.get("category", "UNKNOWN") if best_result else "UNKNOWN",
|
||||
"classified_subcategory": best_result.get("subcategory", "") if best_result else "",
|
||||
"classified_category": classification_result.get("category", "UNKNOWN"),
|
||||
"classified_subcategory": classification_result.get("subcategory", ""),
|
||||
"material_grade": material_result.get("grade", "") if material_result else "",
|
||||
"schedule": best_result.get("schedule", "") if best_result else "",
|
||||
"size_spec": best_result.get("size_spec", "") if best_result else "",
|
||||
"classification_confidence": best_confidence
|
||||
"schedule": schedule_value,
|
||||
"size_spec": classification_result.get("size_spec", ""),
|
||||
"classification_confidence": classification_result.get("overall_confidence", 0.0),
|
||||
"length": length # 길이 정보 추가
|
||||
}
|
||||
|
||||
return final_result
|
||||
|
||||
Reference in New Issue
Block a user