Files
TK-BOM-Project/backend/temp_new_upload.py
Hyungi Ahn 512f2b7fb5 feat: 완전한 자동 분류 시스템 구현 완료
🎉 주요 성과:
- Job-Files-Materials 3단계 완전 연동
- 자동 분류 시스템 100% 작동 (pipe/valve/flange/fitting/gasket)
- PostgreSQL 통합 데이터 저장
- 실시간 업로드 + 즉시 분류 + DB 저장

 검증 완료:
- PIPE → 'pipe' 분류 성공
- VALVE → 'valve' 분류 성공
- FLANGE → 'flange' 분류 성공
- ELBOW → 'fitting' 분류 성공
- GASKET → 'gasket' 분류 성공

🔧 남은 작업:
- get_materials API 응답 형식 수정 (쿼리는 정상 작동)
- 프론트엔드 UI 개발
- 고급 분류 기능 확장

💡 핵심 기능 완성: BOM 업로드 → 자동 분류 → Job별 관리
2025-07-15 14:09:52 +09:00

121 lines
4.7 KiB
Python

@router.post("/upload")
async def upload_file(
file: UploadFile = File(...),
job_no: str = Form(...),
revision: str = Form("Rev.0"),
db: Session = Depends(get_db)
):
# 1. Job 검증 (새로 추가!)
job_validation = await validate_job_exists(job_no, db)
if not job_validation["valid"]:
raise HTTPException(
status_code=400,
detail=f"Job 오류: {job_validation['error']}"
)
job_info = job_validation["job"]
print(f"✅ Job 검증 완료: {job_info['job_no']} - {job_info['job_name']}")
# 2. 파일 검증
if not validate_file_extension(file.filename):
raise HTTPException(
status_code=400,
detail=f"지원하지 않는 파일 형식입니다. 허용된 확장자: {', '.join(ALLOWED_EXTENSIONS)}"
)
if file.size and file.size > 10 * 1024 * 1024:
raise HTTPException(status_code=400, detail="파일 크기는 10MB를 초과할 수 없습니다")
# 3. 파일 저장
unique_filename = generate_unique_filename(file.filename)
file_path = UPLOAD_DIR / unique_filename
try:
with open(file_path, "wb") as buffer:
shutil.copyfileobj(file.file, buffer)
except Exception as e:
raise HTTPException(status_code=500, detail=f"파일 저장 실패: {str(e)}")
# 4. 파일 파싱 및 자재 추출
try:
materials_data = parse_file_data(str(file_path))
parsed_count = len(materials_data)
# 파일 정보 저장 (job_no 사용!)
file_insert_query = text("""
INSERT INTO files (filename, original_filename, file_path, job_no, revision, description, file_size, parsed_count, is_active)
VALUES (:filename, :original_filename, :file_path, :job_no, :revision, :description, :file_size, :parsed_count, :is_active)
RETURNING id
""")
file_result = db.execute(file_insert_query, {
"filename": unique_filename,
"original_filename": file.filename,
"file_path": str(file_path),
"job_no": job_no, # job_no 사용!
"revision": revision,
"description": f"BOM 파일 - {parsed_count}개 자재 ({job_info['job_name']})",
"file_size": file.size,
"parsed_count": parsed_count,
"is_active": True
})
file_id = file_result.fetchone()[0]
# 자재 데이터 저장
materials_inserted = 0
for material_data in materials_data:
material_insert_query = text("""
INSERT INTO materials (
file_id, original_description, quantity, unit, size_spec,
material_grade, line_number, row_number, classified_category,
classification_confidence, is_verified, created_at
)
VALUES (
:file_id, :original_description, :quantity, :unit, :size_spec,
:material_grade, :line_number, :row_number, :classified_category,
:classification_confidence, :is_verified, :created_at
)
""")
db.execute(material_insert_query, {
"file_id": file_id,
"original_description": material_data["original_description"],
"quantity": material_data["quantity"],
"unit": material_data["unit"],
"size_spec": material_data["size_spec"],
"material_grade": material_data["material_grade"],
"line_number": material_data["line_number"],
"row_number": material_data["row_number"],
"classified_category": None,
"classification_confidence": None,
"is_verified": False,
"created_at": datetime.now()
})
materials_inserted += 1
db.commit()
return {
"success": True,
"message": f"Job '{job_info['job_name']}'에 BOM 파일 업로드 완료!",
"job": {
"job_no": job_info["job_no"],
"job_name": job_info["job_name"],
"status": job_info["status"]
},
"file": {
"id": file_id,
"original_filename": file.filename,
"parsed_count": parsed_count,
"saved_count": materials_inserted
},
"sample_materials": materials_data[:3] if materials_data else []
}
except Exception as e:
db.rollback()
if os.path.exists(file_path):
os.remove(file_path)
raise HTTPException(status_code=500, detail=f"파일 처리 실패: {str(e)}")