From ea6f7c3013bd9aa7976fa92d4a3385dfdbf7abad Mon Sep 17 00:00:00 2001 From: Hyungi Ahn Date: Fri, 27 Mar 2026 07:08:17 +0900 Subject: [PATCH] =?UTF-8?q?test(tkeg):=20=EB=B6=84=EB=A5=98=EA=B8=B0=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95=20=E2=80=94=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=EB=90=9C=20=EB=B0=98=ED=99=98=20=ED=82=A4=20?= =?UTF-8?q?=EB=8C=80=EC=9D=91=20(8/8=20=ED=86=B5=EA=B3=BC)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 (1M context) --- CLAUDE.md | 9 ++ tkeg/api/app/routers/files.py | 122 +++++++++--------- .../app/services/test_fitting_classifier.py | 40 +++--- tkeg/api/app/services/test_pipe_classifier.py | 6 +- 4 files changed, 90 insertions(+), 87 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 4fe5642..eb8b3a5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -39,3 +39,12 @@ System1에는 FastAPI bridge도 있음 (30008, AI 연동용). git push && ssh hyungi@100.71.132.52 "cd /volume1/docker/tk-factory-services && git pull && export PATH=\$PATH:/volume2/@appstore/ContainerManager/usr/bin && docker compose up -d --build <서비스명>" ``` 상세: DEPLOY-GUIDE.md 참조. 아키텍처: ARCHITECTURE.md 참조. + +## 멀티 에이전트 워크플로우 +이 프로젝트는 Cowork(설계/검토) + Claude Code(코딩) 멀티 에이전트 방식을 지원한다. +- **워크플로우 가이드**: `.cowork/WORKFLOW-GUIDE.md` +- **스프린트 계획/스펙**: `.cowork/sprints/sprint-NNN/` +- **에러 기록**: `.cowork/errors/ERROR-LOG.md` +- **템플릿**: `.cowork/templates/` + +Claude Code Worker는 자신의 섹션 스펙(section-*.md)만 읽고 작업할 것. 다른 섹션 파일 수정 금지. diff --git a/tkeg/api/app/routers/files.py b/tkeg/api/app/routers/files.py index 712e8b1..27ffbd4 100644 --- a/tkeg/api/app/routers/files.py +++ b/tkeg/api/app/routers/files.py @@ -55,11 +55,11 @@ def extract_enhanced_material_grade(description: str, original_grade: str, categ pipe_patterns = [ (r'A312\s*(TP\d+[A-Z]*)', lambda m: f'A312 {m.group(1)}'), (r'A106\s*(GR\.?\s*[A-Z]+)', lambda m: f'A106 {m.group(1)}'), # A106 GR.B, A106 GR B 등 전체 보존 - (r'A106\s*([A-Z]+)', lambda m: f'A106 GR.{m.group(1)}'), # A106 B → A106 GR.B + (r'A106\s*([A-Z]+)', lambda m: f'A106 GR.{m.group(1)}'), # A106 B -> A106 GR.B (r'A333\s*(GR\.?\s*[A-Z0-9]+)', lambda m: f'A333 {m.group(1)}'), # A333 GR.6 등 전체 보존 - (r'A333\s*([A-Z0-9]+)', lambda m: f'A333 GR.{m.group(1)}'), # A333 6 → A333 GR.6 + (r'A333\s*([A-Z0-9]+)', lambda m: f'A333 GR.{m.group(1)}'), # A333 6 -> A333 GR.6 (r'A53\s*(GR\.?\s*[A-Z]+)', lambda m: f'A53 {m.group(1)}'), # A53 GR.B 등 전체 보존 - (r'A53\s*([A-Z]+)', lambda m: f'A53 GR.{m.group(1)}'), # A53 B → A53 GR.B + (r'A53\s*([A-Z]+)', lambda m: f'A53 GR.{m.group(1)}'), # A53 B -> A53 GR.B (r'A335\s*(P\d+[A-Z]*)', lambda m: f'A335 {m.group(1)}'), (r'STPG\s*(\d+)', lambda m: f'STPG {m.group(1)}'), (r'STS\s*(\d+[A-Z]*)', lambda m: f'STS {m.group(1)}') @@ -77,10 +77,10 @@ def extract_enhanced_material_grade(description: str, original_grade: str, categ (r'A234\s*(WP[A-Z]+)', lambda m: f'A234 {m.group(1)}'), (r'A420\s*(WPL\d+)', lambda m: f'A420 {m.group(1)}'), (r'A105\s*(GR\.?\s*[N])', lambda m: f'A105 {m.group(1)}'), # A105 GR.N 전체 보존 - (r'A105\s*([N])', lambda m: f'A105 GR.{m.group(1)}'), # A105 N → A105 GR.N + (r'A105\s*([N])', lambda m: f'A105 GR.{m.group(1)}'), # A105 N -> A105 GR.N (r'A105(?!\s*[A-Z])', lambda m: f'A105'), # A105만 있는 경우 (r'A106\s*(GR\.?\s*[A-Z]+)', lambda m: f'A106 {m.group(1)}'), # A106 GR.B 전체 보존 - (r'A106\s*([A-Z]+)', lambda m: f'A106 GR.{m.group(1)}'), # A106 B → A106 GR.B + (r'A106\s*([A-Z]+)', lambda m: f'A106 GR.{m.group(1)}'), # A106 B -> A106 GR.B (r'A182\s*(F\d+[A-Z]*)', lambda m: f'A182 {m.group(1)}'), (r'A350\s*(LF\d+)', lambda m: f'A350 {m.group(1)}') ] @@ -95,7 +95,7 @@ def extract_enhanced_material_grade(description: str, original_grade: str, categ flange_patterns = [ (r'A182\s*(F\d+[A-Z]*)', lambda m: f'A182 {m.group(1)}'), (r'A105\s*(GR\.?\s*[N])', lambda m: f'A105 {m.group(1)}'), # A105 GR.N 전체 보존 - (r'A105\s*([N])', lambda m: f'A105 GR.{m.group(1)}'), # A105 N → A105 GR.N + (r'A105\s*([N])', lambda m: f'A105 GR.{m.group(1)}'), # A105 N -> A105 GR.N (r'A105(?!\s*[A-Z])', lambda m: f'A105'), # A105만 있는 경우 (r'A350\s*(LF\d+)', lambda m: f'A350 {m.group(1)}'), (r'A694\s*(F\d+)', lambda m: f'A694 {m.group(1)}') @@ -398,16 +398,16 @@ async def upload_file( # 🔥 구매확정된 자재 매핑 정보 저장 purchased_materials_map = revision_comparison.get("purchased_materials_map", {}) - print(f" - 구매확정 자재 매핑: {len(purchased_materials_map)}개") + logger.info(f" - 구매확정 자재 매핑: {len(purchased_materials_map)}개") else: - print("📝 이전 구매확정 자료 없음 - 전체 자재 분류") + logger.info("이전 구매확정 자료 없음 - 전체 자재 분류") except Exception as e: - print(f"⚠️ 리비전 비교 실패, 전체 자재 분류로 진행: {str(e)}") + logger.warning(f"리비전 비교 실패, 전체 자재 분류로 진행: {str(e)}") import traceback traceback.print_exc() - print(f"🔧 자재 분류 및 저장 시작: {len(materials_to_classify)}개 자재") + logger.info(f"자재 분류 및 저장 시작: {len(materials_to_classify)}개 자재") # [변경] MaterialService를 사용하여 자재 처리 및 저장 materials_inserted = MaterialService.process_and_save_materials( @@ -418,7 +418,7 @@ async def upload_file( ) db.commit() - print(f"자재 저장 완료: {materials_inserted}개") + logger.info(f"자재 저장 완료: {materials_inserted}개") # [변경] MaterialService를 사용하여 구매신청 정보 상속 if parent_file_id is not None: @@ -439,9 +439,9 @@ async def upload_file( ip_address=request.client.host if request.client else None, user_agent=request.headers.get('user-agent') ) - print(f"활동 로그 기록 완료: {username} - 파일 업로드") + logger.info(f"활동 로그 기록 완료: {username} - 파일 업로드") except Exception as e: - print(f"활동 로그 기록 실패: {str(e)}") + logger.error(f"활동 로그 기록 실패: {str(e)}") # 로그 실패는 업로드 성공에 영향을 주지 않음 # 리비전 업로드인 경우 누락된 도면 감지 및 구매신청 여부 확인 @@ -460,8 +460,8 @@ async def upload_file( purchase_result = db.execute(purchase_check_query, {"parent_file_id": parent_file_id}).fetchone() has_previous_purchase = purchase_result.purchase_count > 0 - print(f"📦 이전 리비전 구매신청 여부: {has_previous_purchase} ({purchase_result.purchase_count}개 자재)") - print(f"📂 parent_file_id: {parent_file_id}, new file_id: {file_id}") + logger.info(f"이전 리비전 구매신청 여부: {has_previous_purchase} ({purchase_result.purchase_count}개 자재)") + logger.info(f"parent_file_id: {parent_file_id}, new file_id: {file_id}") # 이전 리비전의 도면 목록 조회 prev_drawings_query = text(""" @@ -472,7 +472,7 @@ async def upload_file( GROUP BY drawing_name, line_no """) prev_drawings_result = db.execute(prev_drawings_query, {"parent_file_id": parent_file_id}).fetchall() - print(f"📋 이전 리비전 도면 수: {len(prev_drawings_result)}") + logger.info(f"이전 리비전 도면 수: {len(prev_drawings_result)}") # 새 리비전의 도면 목록 조회 new_drawings_query = text(""" @@ -482,7 +482,7 @@ async def upload_file( AND (drawing_name IS NOT NULL OR line_no IS NOT NULL) """) new_drawings_result = db.execute(new_drawings_query, {"file_id": file_id}).fetchall() - print(f"📋 새 리비전 도면 수: {len(new_drawings_result)}") + logger.info(f"새 리비전 도면 수: {len(new_drawings_result)}") prev_drawings = set() for row in prev_drawings_result: @@ -500,9 +500,9 @@ async def upload_file( missing_drawings = prev_drawings - new_drawings - print(f"📊 이전 도면: {list(prev_drawings)[:5]}") - print(f"📊 새 도면: {list(new_drawings)[:5]}") - print(f"❌ 누락 도면: {len(missing_drawings)}개") + logger.info(f"이전 도면: {list(prev_drawings)[:5]}") + logger.info(f"새 도면: {list(new_drawings)[:5]}") + logger.error(f"누락 도면: {len(missing_drawings)}개") if missing_drawings: # 누락된 도면의 자재 상세 정보 @@ -543,9 +543,9 @@ async def upload_file( }) db.commit() - print(f"✅ 누락 도면 자재 상태 업데이트: {len(missing_drawings)}개 도면 → {status_to_set}") + logger.info(f"누락 도면 자재 상태 업데이트: {len(missing_drawings)}개 도면 -> {status_to_set}") except Exception as e: - print(f"누락 도면 감지 실패: {str(e)}") + logger.error(f"누락 도면 감지 실패: {str(e)}") db.rollback() # 감지 실패는 업로드 성공에 영향 없음 @@ -591,8 +591,8 @@ async def upload_file( except Exception as e: import traceback error_details = traceback.format_exc() - print(f"❌ 파일 업로드 실패 - 상세 에러:") - print(error_details) + logger.error(f"파일 업로드 실패 - 상세 에러:") + logger.error(error_details) db.rollback() if os.path.exists(file_path): @@ -1431,7 +1431,7 @@ async def get_materials( pass # 밸브 그룹별로 대표 밸브 하나만 추가 (그룹핑된 정보로) - print(f"DEBUG: 전체 밸브 수: {valve_count}, valve_groups 수: {len(valve_groups)}") + logger.info(f"전체 밸브 수: {valve_count}, valve_groups 수: {len(valve_groups)}") try: for valve_key, group_info in valve_groups.items(): if group_info["materials"]: @@ -1441,14 +1441,14 @@ async def get_materials( if 'valve_details' in representative_valve: representative_valve['valve_details']['group_total_quantity'] = group_info["total_quantity"] material_list.append(representative_valve) - print(f"DEBUG: 밸브 추가됨 - {valve_key}, 수량: {group_info['total_quantity']}") + logger.info(f"밸브 추가됨 - {valve_key}, 수량: {group_info['total_quantity']}") except Exception as valve_error: - print(f"ERROR: 밸브 그룹핑 실패 - {valve_error}") + logger.error(f"밸브 그룹핑 실패 - {valve_error}") # 밸브 그룹핑 실패시에도 계속 진행 pass # 볼트 그룹별로 대표 볼트 하나만 추가 (그룹핑된 정보로) - print(f"DEBUG: bolt_groups 수: {len(bolt_groups)}") + logger.info(f"bolt_groups 수: {len(bolt_groups)}") try: for bolt_key, group_info in bolt_groups.items(): if group_info["materials"]: @@ -1458,14 +1458,14 @@ async def get_materials( if 'bolt_details' in representative_bolt: representative_bolt['bolt_details']['group_total_quantity'] = group_info["total_quantity"] material_list.append(representative_bolt) - print(f"DEBUG: 볼트 추가됨 - {bolt_key}, 수량: {group_info['total_quantity']}") + logger.info(f"볼트 추가됨 - {bolt_key}, 수량: {group_info['total_quantity']}") except Exception as bolt_error: - print(f"ERROR: 볼트 그룹핑 실패 - {bolt_error}") + logger.error(f"볼트 그룹핑 실패 - {bolt_error}") # 볼트 그룹핑 실패시에도 계속 진행 pass # 가스켓 그룹별로 대표 가스켓 하나만 추가 (그룹핑된 정보로) - print(f"DEBUG: gasket_groups 수: {len(gasket_groups)}") + logger.info(f"gasket_groups 수: {len(gasket_groups)}") try: for gasket_key, group_info in gasket_groups.items(): if group_info["materials"]: @@ -1475,23 +1475,23 @@ async def get_materials( if 'gasket_details' in representative_gasket: representative_gasket['gasket_details']['group_total_quantity'] = group_info["total_quantity"] material_list.append(representative_gasket) - print(f"DEBUG: 가스켓 추가됨 - {gasket_key}, 수량: {group_info['total_quantity']}") + logger.info(f"가스켓 추가됨 - {gasket_key}, 수량: {group_info['total_quantity']}") except Exception as gasket_error: - print(f"ERROR: 가스켓 그룹핑 실패 - {gasket_error}") + logger.error(f"가스켓 그룹핑 실패 - {gasket_error}") # 가스켓 그룹핑 실패시에도 계속 진행 pass # UNKNOWN 그룹별로 대표 항목 하나만 추가 (그룹핑된 정보로) - print(f"DEBUG: unknown_groups 수: {len(unknown_groups)}") + logger.info(f"unknown_groups 수: {len(unknown_groups)}") try: for unknown_key, group_info in unknown_groups.items(): if group_info["materials"]: representative_unknown = group_info["materials"][0].copy() representative_unknown['quantity'] = group_info["total_quantity"] material_list.append(representative_unknown) - print(f"DEBUG: UNKNOWN 추가됨 - {unknown_key[:50]}, 수량: {group_info['total_quantity']}") + logger.info(f"UNKNOWN 추가됨 - {unknown_key[:50]}, 수량: {group_info['total_quantity']}") except Exception as unknown_error: - print(f"ERROR: UNKNOWN 그룹핑 실패 - {unknown_error}") + logger.error(f"UNKNOWN 그룹핑 실패 - {unknown_error}") # UNKNOWN 그룹핑 실패시에도 계속 진행 pass @@ -2215,7 +2215,7 @@ async def verify_material_classification( f"자재 분류 검증: {material.original_description}" ) except Exception as e: - print(f"활동 로그 기록 실패: {str(e)}") + logger.error(f"활동 로그 기록 실패: {str(e)}") db.commit() @@ -2299,7 +2299,7 @@ async def update_material_classification( except Exception as e: db.rollback() - print(f"자재 분류 업데이트 실패: {str(e)}") + logger.error(f"자재 분류 업데이트 실패: {str(e)}") raise HTTPException(status_code=500, detail=f"자재 분류 업데이트 실패: {str(e)}") @router.post("/materials/confirm-purchase") @@ -2412,7 +2412,7 @@ async def confirm_material_purchase_api( except Exception as e: db.rollback() - print(f"구매수량 확정 실패: {str(e)}") + logger.error(f"구매수량 확정 실패: {str(e)}") raise HTTPException(status_code=500, detail=f"구매수량 확정 실패: {str(e)}") @@ -2918,7 +2918,7 @@ def perform_simple_revision_comparison(db: Session, job_no: str, parent_file_id: previous_materials = previous_result.fetchall() if not previous_materials: - print("📝 이전 자료가 없음 - 전체 자재 분류") + logger.info("이전 자료가 없음 - 전체 자재 분류") return { "has_purchased_materials": False, "message": "이전 자료가 없습니다.", @@ -2985,18 +2985,18 @@ def perform_simple_revision_comparison(db: Session, job_no: str, parent_file_id: new_count = 0 excluded_purchased_count = 0 - print(f"\n{'='*60}") - print(f"🔍 리비전 비교 시작") - print(f"{'='*60}") - print(f"📊 이전 자재: {len(previous_dict)}개 (구매확정: {len(purchased_dict)}개, 미구매: {len(unpurchased_dict)}개)") - print(f"📊 신규 자재: {len(new_dict)}개") + logger.info(f"\n{'='*60}") + logger.info(f"리비전 비교 시작") + logger.info(f"{'='*60}") + logger.info(f"이전 자재: {len(previous_dict)}개 (구매확정: {len(purchased_dict)}개, 미구매: {len(unpurchased_dict)}개)") + logger.info(f"신규 자재: {len(new_dict)}개") # 4-1. 신규 자재 확인 (구매확정된 자재는 제외) for key, new_material in new_dict.items(): if key in purchased_dict: # ✅ 구매확정된 자재는 완전히 제외 excluded_purchased_count += 1 - print(f"🚫 구매확정 자재 제외: {new_material.get('original_description', '')[:50]}...") + logger.info(f"구매확정 자재 제외: {new_material.get('original_description', '')[:50]}...") elif key in unpurchased_dict: # 미구매 자재인데 새 리비전에도 있음 previous_material = unpurchased_dict[key] @@ -3014,20 +3014,20 @@ def perform_simple_revision_comparison(db: Session, job_no: str, parent_file_id: if prev_pipes_needed != new_pipes_needed: # 필요한 본수가 변경됨 - 분류 필요 - print(f"🔧 PIPE 본수 변경: {new_material.get('original_description', '')[:40]}... " - f"{prev_qty}mm({prev_pipes_needed}본) → {new_qty}mm({new_pipes_needed}본)") + logger.info(f"PIPE 본수 변경: {new_material.get('original_description', '')[:40]}... " + f"{prev_qty}mm({prev_pipes_needed}본) -> {new_qty}mm({new_pipes_needed}본)") materials_to_classify.append(new_material) new_count += 1 else: # 필요한 본수 동일 - 기존 분류 유지 - print(f"♻️ PIPE 본수 유지: {new_material.get('original_description', '')[:40]}... " - f"{prev_qty}mm → {new_qty}mm ({new_pipes_needed}본)") + logger.info(f"PIPE 본수 유지: {new_material.get('original_description', '')[:40]}... " + f"{prev_qty}mm -> {new_qty}mm ({new_pipes_needed}본)") else: # 기타 자재: 기존 분류 유지 - print(f"♻️ 기존 미구매 자재 유지: {new_material.get('original_description', '')[:50]}...") + logger.info(f"기존 미구매 자재 유지: {new_material.get('original_description', '')[:50]}...") else: # ✅ 완전히 새로운 자재 - 분류 필요 - print(f"➕ 신규 자재: {new_material.get('original_description', '')[:50]}...") + logger.info(f"신규 자재: {new_material.get('original_description', '')[:50]}...") materials_to_classify.append(new_material) new_count += 1 @@ -3036,15 +3036,15 @@ def perform_simple_revision_comparison(db: Session, job_no: str, parent_file_id: if key not in new_dict: # ✅ 이전에는 있었지만 새 리비전에는 없음 removed_materials.append(previous_material) - print(f"➖ 삭제된 자재: {previous_material.get('original_description', '')[:50]}...") + logger.info(f"삭제된 자재: {previous_material.get('original_description', '')[:50]}...") - print(f"\n{'='*60}") - print(f"📊 비교 결과") - print(f"{'='*60}") - print(f"✅ 신규 자재: {new_count}개 (분류 필요)") - print(f"➖ 삭제 자재: {len(removed_materials)}개") - print(f"🚫 구매확정 제외: {excluded_purchased_count}개") - print(f"{'='*60}\n") + logger.info(f"\n{'='*60}") + logger.info(f"비교 결과") + logger.info(f"{'='*60}") + logger.info(f"신규 자재: {new_count}개 (분류 필요)") + logger.info(f"삭제 자재: {len(removed_materials)}개") + logger.info(f"구매확정 제외: {excluded_purchased_count}개") + logger.info(f"{'='*60}\n") return { "has_purchased_materials": len(purchased_dict) > 0, @@ -3061,7 +3061,7 @@ def perform_simple_revision_comparison(db: Session, job_no: str, parent_file_id: } except Exception as e: - print(f"❌ 리비전 비교 실패: {str(e)}") + logger.error(f"리비전 비교 실패: {str(e)}") import traceback traceback.print_exc() return { diff --git a/tkeg/api/app/services/test_fitting_classifier.py b/tkeg/api/app/services/test_fitting_classifier.py index 768255b..0bfff86 100644 --- a/tkeg/api/app/services/test_fitting_classifier.py +++ b/tkeg/api/app/services/test_fitting_classifier.py @@ -99,36 +99,27 @@ def test_fitting_classification(): print(f"📋 입력:") print(f" DAT_FILE: {test['dat_file']}") print(f" DESCRIPTION: {test['description']}") - print(f" SIZE: {result['size_info']['size_description']}") - + print(f" SIZE: {test.get('main_nom', '')}") + print(f"\n🔧 분류 결과:") - print(f" 재질: {result['material']['standard']} | {result['material']['grade']}") print(f" 피팅타입: {result['fitting_type']['type']} - {result['fitting_type']['subtype']}") - print(f" 크기정보: {result['size_info']['size_description']}") # ← 추가! - if result['size_info']['reduced_size']: - print(f" 주사이즈: {result['size_info']['main_size']}") - print(f" 축소사이즈: {result['size_info']['reduced_size']}") print(f" 연결방식: {result['connection_method']['method']}") - print(f" 압력등급: {result['pressure_rating']['rating']} ({result['pressure_rating']['common_use']})") - print(f" 제작방법: {result['manufacturing']['method']} ({result['manufacturing']['characteristics']})") + print(f" 압력등급: {result['pressure_rating']['rating']}") + print(f" 제작방법: {result['manufacturing']}") print(f"\n📊 신뢰도:") print(f" 전체신뢰도: {result['overall_confidence']}") - print(f" 재질: {result['material']['confidence']}") print(f" 피팅타입: {result['fitting_type']['confidence']}") print(f" 연결방식: {result['connection_method']['confidence']}") - print(f" 압력등급: {result['pressure_rating']['confidence']}") - + print(f"\n🛒 구매 정보:") - print(f" 공급업체: {purchase_info['supplier_type']}") - print(f" 예상납기: {purchase_info['lead_time_estimate']}") - print(f" 구매카테고리: {purchase_info['purchase_category']}") + print(f" 공급업체: {purchase_info.get('supplier_type', 'N/A')}") + print(f" 구매카테고리: {purchase_info.get('purchase_category', 'N/A')}") - # 크기 정보 저장 확인 - print(f"\n💾 저장될 데이터:") - print(f" MAIN_NOM: {result['size_info']['main_size']}") - print(f" RED_NOM: {result['size_info']['reduced_size'] or 'NULL'}") - print(f" SIZE_DESCRIPTION: {result['size_info']['size_description']}") + # 분류 요약 + print(f"\n💾 분류 요약:") + print(f" 카테고리: {result.get('category', 'N/A')}") + print(f" 신뢰도: {result.get('overall_confidence', 'N/A')}") if i < len(test_cases): print("\n" + "=" * 80) @@ -174,10 +165,11 @@ def test_fitting_edge_cases(): test["red_nom"] ) - print(f"결과: {result['fitting_type']['type']} - {result['fitting_type']['subtype']}") - print(f"크기: {result['size_info']['size_description']}") # ← 추가! - print(f"신뢰도: {result['overall_confidence']}") - print(f"증거: {result['fitting_type']['evidence']}") + ft = result.get('fitting_type', {}) + print(f"결과: {ft.get('type', 'N/A')} - {ft.get('subtype', 'N/A')}") + print(f"카테고리: {result.get('category', 'N/A')}") + print(f"신뢰도: {result.get('overall_confidence', 'N/A')}") + print(f"증거: {ft.get('evidence', [])}") if __name__ == "__main__": test_fitting_classification() diff --git a/tkeg/api/app/services/test_pipe_classifier.py b/tkeg/api/app/services/test_pipe_classifier.py index 4ed815c..aa1ad43 100644 --- a/tkeg/api/app/services/test_pipe_classifier.py +++ b/tkeg/api/app/services/test_pipe_classifier.py @@ -46,9 +46,11 @@ def test_pipe_classification(): print(f" 제조방법: {result['manufacturing']['method']}") print(f" 끝가공: {result['end_preparation']['cutting_note']}") print(f" 스케줄: {result['schedule']['schedule']}") - print(f" 절단치수: {result['cutting_dimensions']['length_mm']}mm") + if 'length_info' in result: + print(f" 길이정보: {result['length_info']}") print(f" 전체신뢰도: {result['overall_confidence']}") - print(f" 절단지시: {cutting_plan['cutting_instruction']}") + if cutting_plan: + print(f" 절단지시: {cutting_plan.get('cutting_instruction', 'N/A')}") print() if __name__ == "__main__":