314 lines
14 KiB
Python
314 lines
14 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
DXF 파일 지원을 위한 추가 메서드들
|
||
main.py에 추가할 메서드들을 정의합니다.
|
||
"""
|
||
|
||
def handle_file_selection_update(self, e):
|
||
"""
|
||
기존 on_file_selected 메서드를 DXF 지원으로 업데이트하는 로직
|
||
이 메서드들을 main.py에 추가하거나 기존 메서드를 대체해야 합니다.
|
||
"""
|
||
|
||
def on_file_selected_updated(self, e):
|
||
"""파일 선택 결과 핸들러 - PDF/DXF 지원"""
|
||
if e.files:
|
||
file = e.files[0]
|
||
self.current_file_path = file.path
|
||
|
||
# 파일 확장자로 타입 결정
|
||
file_extension = file.path.lower().split('.')[-1]
|
||
|
||
if file_extension == 'pdf':
|
||
self.current_file_type = 'pdf'
|
||
self._handle_pdf_file_selection(file)
|
||
elif file_extension == 'dxf':
|
||
self.current_file_type = 'dxf'
|
||
self._handle_dxf_file_selection(file)
|
||
else:
|
||
self.selected_file_text.value = f"❌ 지원하지 않는 파일 형식입니다: {file_extension}"
|
||
self.selected_file_text.color = ft.Colors.RED_600
|
||
self.upload_button.disabled = True
|
||
self.pdf_preview_button.disabled = True
|
||
self._reset_file_state()
|
||
else:
|
||
self.selected_file_text.value = "선택된 파일이 없습니다"
|
||
self.selected_file_text.color = ft.Colors.GREY_600
|
||
self.upload_button.disabled = True
|
||
self.pdf_preview_button.disabled = True
|
||
self._reset_file_state()
|
||
|
||
self.page.update()
|
||
|
||
def _handle_pdf_file_selection(self, file):
|
||
"""PDF 파일 선택 처리"""
|
||
if self.pdf_processor.validate_pdf_file(self.current_file_path):
|
||
# PDF 정보 조회
|
||
self.current_pdf_info = self.pdf_processor.get_pdf_info(self.current_file_path)
|
||
|
||
# 파일 크기 정보 추가
|
||
file_size_mb = self.current_pdf_info['file_size'] / (1024 * 1024)
|
||
file_info = f"✅ {file.name} (PDF)\n📄 {self.current_pdf_info['page_count']}페이지, {file_size_mb:.1f}MB"
|
||
self.selected_file_text.value = file_info
|
||
self.selected_file_text.color = ft.Colors.GREEN_600
|
||
self.upload_button.disabled = False
|
||
self.pdf_preview_button.disabled = False
|
||
|
||
# 페이지 정보 업데이트
|
||
self.page_info_text.value = f"1 / {self.current_pdf_info['page_count']}"
|
||
self.current_page_index = 0
|
||
|
||
logger.info(f"PDF 파일 선택됨: {file.name}")
|
||
else:
|
||
self.selected_file_text.value = "❌ 유효하지 않은 PDF 파일입니다"
|
||
self.selected_file_text.color = ft.Colors.RED_600
|
||
self.upload_button.disabled = True
|
||
self.pdf_preview_button.disabled = True
|
||
self._reset_file_state()
|
||
|
||
def _handle_dxf_file_selection(self, file):
|
||
"""DXF 파일 선택 처리"""
|
||
try:
|
||
if self.dxf_processor.validate_dxf_file(self.current_file_path):
|
||
# DXF 파일 크기 계산
|
||
import os
|
||
file_size_mb = os.path.getsize(self.current_file_path) / (1024 * 1024)
|
||
|
||
file_info = f"✅ {file.name} (DXF)\n🏗️ CAD 도면 파일, {file_size_mb:.1f}MB"
|
||
self.selected_file_text.value = file_info
|
||
self.selected_file_text.color = ft.Colors.GREEN_600
|
||
self.upload_button.disabled = False
|
||
self.pdf_preview_button.disabled = True # DXF는 미리보기 비활성화
|
||
|
||
# DXF는 페이지 개념이 없으므로 기본값 설정
|
||
self.page_info_text.value = "DXF 파일"
|
||
self.current_page_index = 0
|
||
self.current_pdf_info = None # DXF는 PDF 정보 없음
|
||
|
||
logger.info(f"DXF 파일 선택됨: {file.name}")
|
||
else:
|
||
self.selected_file_text.value = "❌ 유효하지 않은 DXF 파일입니다"
|
||
self.selected_file_text.color = ft.Colors.RED_600
|
||
self.upload_button.disabled = True
|
||
self.pdf_preview_button.disabled = True
|
||
self._reset_file_state()
|
||
except Exception as e:
|
||
logger.error(f"DXF 파일 검증 오류: {e}")
|
||
self.selected_file_text.value = f"❌ DXF 파일 처리 오류: {str(e)}"
|
||
self.selected_file_text.color = ft.Colors.RED_600
|
||
self.upload_button.disabled = True
|
||
self.pdf_preview_button.disabled = True
|
||
self._reset_file_state()
|
||
|
||
def _reset_file_state(self):
|
||
"""파일 상태 초기화"""
|
||
self.current_file_path = None
|
||
self.current_file_type = None
|
||
self.current_pdf_info = None
|
||
|
||
def run_analysis_updated(self):
|
||
"""분석 실행 (백그라운드 스레드) - PDF/DXF 지원"""
|
||
try:
|
||
self.analysis_start_time = time.time()
|
||
|
||
if self.current_file_type == 'pdf':
|
||
self._run_pdf_analysis()
|
||
elif self.current_file_type == 'dxf':
|
||
self._run_dxf_analysis()
|
||
else:
|
||
raise ValueError(f"지원하지 않는 파일 타입: {self.current_file_type}")
|
||
|
||
except Exception as e:
|
||
logger.error(f"분석 중 오류 발생: {e}")
|
||
self.update_progress_ui(False, f"❌ 분석 오류: {str(e)}")
|
||
self.show_error_dialog("분석 오류", f"분석 중 오류가 발생했습니다:\n{str(e)}")
|
||
|
||
def _run_pdf_analysis(self):
|
||
"""PDF 파일 분석 실행"""
|
||
self.update_progress_ui(True, "PDF 이미지 변환 중...")
|
||
|
||
# 조직 유형 결정
|
||
organization_type = "transportation"
|
||
if self.organization_selector and self.organization_selector.value:
|
||
if self.organization_selector.value == "한국도로공사":
|
||
organization_type = "expressway"
|
||
else:
|
||
organization_type = "transportation"
|
||
|
||
logger.info(f"선택된 조직 유형: {organization_type}")
|
||
|
||
# 분석할 페이지 결정
|
||
if self.page_selector.value == "첫 번째 페이지":
|
||
pages_to_analyze = [0]
|
||
else:
|
||
pages_to_analyze = list(range(self.current_pdf_info['page_count']))
|
||
|
||
# 분석 프롬프트 결정
|
||
if self.analysis_mode.value == "custom":
|
||
prompt = self.custom_prompt.value or Config.DEFAULT_PROMPT
|
||
elif self.analysis_mode.value == "detailed":
|
||
prompt = "이 PDF 이미지를 자세히 분석하여 다음 정보를 제공해주세요: 1) 문서 유형, 2) 주요 내용, 3) 도면/도표 정보, 4) 텍스트 내용, 5) 기타 특징"
|
||
else:
|
||
prompt = Config.DEFAULT_PROMPT
|
||
|
||
# 페이지별 분석 수행
|
||
total_pages = len(pages_to_analyze)
|
||
self.analysis_results = {}
|
||
|
||
for i, page_num in enumerate(pages_to_analyze):
|
||
progress = (i + 1) / total_pages
|
||
self.update_progress_ui(
|
||
True,
|
||
f"페이지 {page_num + 1} 분석 중... ({i + 1}/{total_pages})",
|
||
progress
|
||
)
|
||
|
||
# PDF 페이지를 base64로 변환
|
||
base64_data = self.pdf_processor.pdf_page_to_base64(
|
||
self.current_file_path,
|
||
page_num
|
||
)
|
||
|
||
if base64_data:
|
||
# Gemini API로 분석
|
||
result = self.gemini_analyzer.analyze_image_from_base64(
|
||
base64_data=base64_data,
|
||
prompt=prompt,
|
||
organization_type=organization_type
|
||
)
|
||
|
||
if result:
|
||
self.analysis_results[page_num] = result
|
||
else:
|
||
self.analysis_results[page_num] = f"페이지 {page_num + 1} 분석 실패"
|
||
else:
|
||
self.analysis_results[page_num] = f"페이지 {page_num + 1} 이미지 변환 실패"
|
||
|
||
# 결과 표시
|
||
self.display_analysis_results()
|
||
|
||
# 완료 상태로 업데이트
|
||
if self.analysis_start_time:
|
||
duration = time.time() - self.analysis_start_time
|
||
duration_str = DateTimeUtils.format_duration(duration)
|
||
self.update_progress_ui(False, f"✅ PDF 분석 완료! (소요시간: {duration_str})", 1.0)
|
||
else:
|
||
self.update_progress_ui(False, "✅ PDF 분석 완료!", 1.0)
|
||
|
||
def _run_dxf_analysis(self):
|
||
"""DXF 파일 분석 실행"""
|
||
self.update_progress_ui(True, "DXF 파일 분석 중...")
|
||
|
||
try:
|
||
# DXF 파일 처리
|
||
result = self.dxf_processor.process_dxf_file(self.current_file_path)
|
||
|
||
if result['success']:
|
||
# 분석 결과 포맷팅
|
||
self.analysis_results = {'dxf': result}
|
||
|
||
# 결과 표시
|
||
self.display_dxf_analysis_results(result)
|
||
|
||
# 완료 상태로 업데이트
|
||
if self.analysis_start_time:
|
||
duration = time.time() - self.analysis_start_time
|
||
duration_str = DateTimeUtils.format_duration(duration)
|
||
self.update_progress_ui(False, f"✅ DXF 분석 완료! (소요시간: {duration_str})", 1.0)
|
||
else:
|
||
self.update_progress_ui(False, "✅ DXF 분석 완료!", 1.0)
|
||
else:
|
||
error_msg = result.get('error', '알 수 없는 오류')
|
||
self.update_progress_ui(False, f"❌ DXF 분석 실패: {error_msg}")
|
||
self.show_error_dialog("DXF 분석 오류", f"DXF 파일 분석에 실패했습니다:\n{error_msg}")
|
||
|
||
except Exception as e:
|
||
logger.error(f"DXF 분석 중 오류: {e}")
|
||
self.update_progress_ui(False, f"❌ DXF 분석 오류: {str(e)}")
|
||
self.show_error_dialog("DXF 분석 오류", f"DXF 분석 중 오류가 발생했습니다:\n{str(e)}")
|
||
|
||
def display_dxf_analysis_results(self, dxf_result):
|
||
"""DXF 분석 결과 표시"""
|
||
def update_results():
|
||
if dxf_result and dxf_result['success']:
|
||
# 결과 텍스트 구성
|
||
result_text = "🎯 DXF 분석 요약\n"
|
||
result_text += f"📊 파일: {os.path.basename(dxf_result['file_path'])}\n"
|
||
result_text += f"⏰ 완료 시간: {DateTimeUtils.get_timestamp()}\n"
|
||
result_text += "=" * 60 + "\n\n"
|
||
|
||
# 요약 정보
|
||
summary = dxf_result.get('summary', {})
|
||
result_text += "📋 분석 요약\n"
|
||
result_text += "-" * 40 + "\n"
|
||
result_text += f"전체 블록 수: {summary.get('total_blocks', 0)}\n"
|
||
result_text += f"도곽 블록 발견: {'예' if summary.get('title_block_found', False) else '아니오'}\n"
|
||
result_text += f"속성 수: {summary.get('attributes_count', 0)}\n"
|
||
|
||
if summary.get('title_block_name'):
|
||
result_text += f"도곽 블록명: {summary['title_block_name']}\n"
|
||
|
||
result_text += "\n"
|
||
|
||
# 도곽 정보
|
||
title_block = dxf_result.get('title_block')
|
||
if title_block:
|
||
result_text += "🏗️ 도곽 정보\n"
|
||
result_text += "-" * 40 + "\n"
|
||
|
||
fields = {
|
||
'drawing_name': '도면명',
|
||
'drawing_number': '도면번호',
|
||
'construction_field': '건설분야',
|
||
'construction_stage': '건설단계',
|
||
'scale': '축척',
|
||
'project_name': '프로젝트명',
|
||
'designer': '설계자',
|
||
'date': '날짜',
|
||
'revision': '리비전',
|
||
'location': '위치'
|
||
}
|
||
|
||
for field, label in fields.items():
|
||
value = title_block.get(field)
|
||
if value:
|
||
result_text += f"{label}: {value}\n"
|
||
|
||
# 바운딩 박스 정보
|
||
bbox = title_block.get('bounding_box')
|
||
if bbox:
|
||
result_text += f"\n📐 도곽 위치 정보\n"
|
||
result_text += f"좌하단: ({bbox['min_x']:.2f}, {bbox['min_y']:.2f})\n"
|
||
result_text += f"우상단: ({bbox['max_x']:.2f}, {bbox['max_y']:.2f})\n"
|
||
result_text += f"크기: {bbox['max_x'] - bbox['min_x']:.2f} × {bbox['max_y'] - bbox['min_y']:.2f}\n"
|
||
|
||
# 블록 참조 정보
|
||
block_refs = dxf_result.get('block_references', [])
|
||
if block_refs:
|
||
result_text += f"\n📦 블록 참조 목록 ({len(block_refs)}개)\n"
|
||
result_text += "-" * 40 + "\n"
|
||
|
||
for i, block_ref in enumerate(block_refs[:10]): # 최대 10개까지만 표시
|
||
result_text += f"{i+1}. {block_ref.get('name', 'Unknown')}"
|
||
if block_ref.get('attributes'):
|
||
result_text += f" (속성 {len(block_ref['attributes'])}개)"
|
||
result_text += "\n"
|
||
|
||
if len(block_refs) > 10:
|
||
result_text += f"... 외 {len(block_refs) - 10}개 블록\n"
|
||
|
||
self.results_text.value = result_text.strip()
|
||
|
||
# 저장 버튼 활성화
|
||
self.save_text_button.disabled = False
|
||
self.save_json_button.disabled = False
|
||
else:
|
||
self.results_text.value = "❌ DXF 분석 결과가 없습니다."
|
||
self.save_text_button.disabled = True
|
||
self.save_json_button.disabled = True
|
||
|
||
self.page.update()
|
||
|
||
# 메인 스레드에서 UI 업데이트
|
||
self.page.run_thread(update_results)
|