
    %<i3                        U d Z ddlZddlZddlZddlZddlZddlZddlmZm	Z	 ddl
Z
 ej                  e      Z ej                  e      j                   dz  ZdZdddd	d	d
d
d
d
d
d
d
dZeeef   ed<   e G d d             ZdedefdZdedej                  fdZdededdfdZdededz  fdZd#dZd$dededz  dee   fdZdee   dee   fdZ dddede!defd Z"ded!edefd"Z#y)%u   
doc_parser.py - 문서 파싱 모듈

PDF: opendataloader-pdf 기반 파싱
기타 포맷 (DOCX, PPTX, HTML, 이미지): docling lazy import로 처리
    N)	dataclassfieldz.parse_cachez&/home/jay/.local/jdk/jdk-11.0.25+9-jrepdfdocxpptxhtmlimage).pdfz.docxz.pptxz.htmlz.htmz.pngz.jpgz.jpegz.tiffz.bmpz.gifz.webp_EXT_TO_FORMATc                   X    e Zd ZU dZeed<   ee   ed<   ee   ed<    ee      Z	eed<   y)ParseResultu   문서 파싱 결과textpagestables)default_factorymetadataN)
__name__
__module____qualname____doc__str__annotations__listdictr   r        @/home/jay/workspace/.worktrees/task-2057-dev2/libs/doc_parser.pyr   r   *   s-    
I9J40Hd0r   r   datareturnc                 H    t        j                  |       j                         S )u   SHA-256 해시를 계산한다.)hashlibsha256	hexdigest)r   s    r   _content_hashr$   4   s    >>$))++r   content_hashc                     t         |  dz  S )u%   캐시 파일 경로를 반환한다..json)	CACHE_DIR)r%   s    r   _cache_pathr)   9   s    ,u---r   resultc                     t         j                  dd       |j                  |j                  |j                  |j
                  d}t        |       j                  t        j                  |d      d       y)	uA   ParseResult를 JSON으로 직렬화하여 캐시에 저장한다.T)parentsexist_okr   r   r   r   F)ensure_asciiutf-8encodingN)
r(   mkdirr   r   r   r   r)   
write_textjsondumps)r%   r*   r   s      r   _save_cacher7   >   s[    OOD4O0--OO	D ((Du)MX_(`r   c                 V   t        |       }|j                         sy	 t        j                  |j	                  d            }t        |d   |d   |d   |d         S # t        $ rA}t        j                  d	|       	 |j                          n# t        $ r Y nw xY wY d}~yd}~ww xY w)
uK   캐시에서 ParseResult를 로드한다. 없거나 오류 시 None 반환.Nr0   r1   r   r   r   r   r.   u/   캐시 로드 실패 (삭제 후 재파싱): %s)r)   existsr5   loads	read_textr   	ExceptionloggerwarningunlinkOSError)r%   pathr   excs       r   _load_cacherC   J   s    |$D;;=zz$..'.:;fw->*%	
 	
  H#N	KKM 		s;   ?A 	B('B#>BB#	BB#BB##B(c                      t         j                         rJt         j                         D ]3  } | j                         s| j                  dk(  s$| j                          5 t        j                  d       y)u<   캐시 디렉토리의 모든 캐시 파일을 삭제한다.r'   u"   파싱 캐시 전체 삭제 완료N)r(   r9   iterdiris_filesuffixr?   r=   info)fs    r   clear_cacherJ   `   sR    ""$ 	Ayy{qxx72
	 KK45r   nodeelementsc                     |g }d| v r|j                  |        | j                  dg       D ]  }t        ||        | j                  dg       D ]  }t        ||        |S )uP   opendataloader JSON을 재귀 순회하여 모든 element를 flat list로 수집contentkidsz
list items)appendget_collect_elements)rK   rL   kiditems       r   rR   rR   i   sn    Dxx# )#x()r* *$)*Or   c           	         g }| D ]  }|j                  d      dk(  s|j                  dg       }|rg }|D ]k  }|j                  d      dk(  s|j                  dg       D cg c](  }|j                  d      dk(  r|j                  dd      * }}|j                  |       m |s|d   }|d	d
 }	|j                  ||	d       d|v s|d   j                         j                  d      }
t	        |
      dk\  s|
d   j                  d      D cg c]#  }|j                         s|j                         % }}g }	|
d	d
 D ]S  }|j                  d      D cg c]#  }|j                         s|j                         % }}|sC|	j                  |       U |s|j                  ||	d        |S c c}w c c}w c c}w )u1   type='table' element에서 {headers, rows} 추출typetablerO   z	table rowz
table cellrN    r      Nheadersrows
   |)rQ   rP   stripsplitlen)rL   r   elemrO   	rows_datarow_elemcellcellsr[   r\   lineshlinecrows                  r   _extract_tables_from_elementsrm   v   s   F J88Fw&88FB'D	 $ 0H||F+{: )1VR(@! $#xx/<? !HHY3! !
 "((/0 'lG$QR=DMMgt"DEd"Y--/55d;u:?27(..2ESQqwwySGSD %ab	 -26**S/OQQWWYqwwyOO KK,- '4&HI9J: M-! T Ps   "-F6F;(F;G /G T)	use_cache
file_bytesrn   c                .   | st        d      t        |       }|r(t        |      }|t        j	                  d|dd        |S t        j	                  dt        |              t        j                  j                         }t        |d<   t         d|j                  dd	       |d<   t        j                  j                  |       d}d}	 t        j                  d
d      5 }|j                  |        |j                  }ddd       t        j                          }t#        j$                  ||dd       t'        t)        j*                  |      j-                  d            }|st/        d      t1        j2                  |d   j5                  d            }	g }
|	j                  dg       D ]  }t7        ||
        i }|
D ]L  }|j                  d      }|j                  dd	      }|)|s,|j9                  |g       j;                  |       N t=        |j?                               }|D cg c]  }djA                  ||          }}djA                  |      }tC        |
      }|	j                  dt        |            }d|i}|	j                  d      r|	d   |d<   |	j                  d      r|	d   |d<   |	j                  d      r|	d   |d<   t        j	                  d|t        |      t        |             tE        ||||       }|rtG        ||       ||r	 t        jH                  |       |r	 ddl&}|jO                  |d!       S S # 1 sw Y   MxY wc c}w # tJ        $ r Y 9w xY w# tJ        $ r Y S w xY w# t         t.        f$ r  tP        $ r*}t        jS                  d"|       t/        d#|       |d}~ww xY w# |r&	 t        jH                  |       n# tJ        $ r Y nw xY w|r(	 ddl&}|jO                  |d!       w # tJ        $ r Y w w xY ww xY w)$u  
    PDF bytes를 파싱하여 ParseResult를 반환한다.

    Args:
        file_bytes: PDF 파일의 바이트 데이터
        use_cache: True이면 SHA-256 기반 캐시를 사용한다 (기본값 True)

    Returns:
        ParseResult: 파싱 결과 (text, pages, tables, metadata)

    Raises:
        ValueError: 빈 bytes가 입력된 경우
        RuntimeError: opendataloader 변환 중 오류 발생 시
    "   file_bytes가 비어 있습니다.Nu   캐시 히트: hash=%s   u   PDF 파싱 시작: %d bytes	JAVA_HOMEz/bin:PATHrX   r
   FrG   deleter5   T)
input_path
output_dirformatquietz*.jsonuL   opendataloader_pdf.convert()가 JSON 파일을 생성하지 않았습니다.r   r0   r1   rO   zpage numberrN   r]   znumber of pages
page_countauthortitlez	file namefilenameuA   PDF 파싱 완료: 페이지=%d, 테이블=%d, 텍스트길이=%dr.   )ignore_errorsu   PDF 파싱 오류: %su   PDF 파싱 실패: )*
ValueErrorr$   rC   r=   rH   rb   osenvironcopy
_JAVA_HOMErQ   updatetempfileNamedTemporaryFilewritenamemkdtempopendataloader_pdfconvertr   pathlibPathglobRuntimeErrorr5   r:   r;   rR   
setdefaultrP   sortedkeysjoinrm   r   r7   r?   r@   shutilrmtreer<   error)ro   rn   chcachedenvtmp_pathrx   tmp
json_filesraw_dataall_elementsrS   
pages_dictrc   page_norN   sorted_page_numspr   	full_textr   r{   r   r*   r   rB   s                             r   	parse_pdfr      s    =>> 
z	"BRKK0"Sb':M
KK-s:? **//
C!CLcggfb&9%:;CKJJc  H!J\((uE 	 IIj!xxH	  %%'
""!		
 ',,z277AB
mnn::jm55w5GH $&<<+ 	1Cc<0	1 ,.
  	CDhh}-Ghhy"-G"w%%gr299'B		C "*//"34>NODIIjm4OO IIe$	 /|< \\"3SZ@
*
 <<!!)(!3HX<<  ( 1HW<<$#+K#8HZ OK	N		
 	
 F# 		(# j=	 k	  	 D Pb    ! %  A,c2067S@A 		(# j=  s   M; "M C(M; )M; ,A M; ,MCM; M2M,MM; 	M)(M),	M87M8;N=%N88N==O   POP	O&#P%O&&P,PP	PPPPr~   c           
      z   | st        d      t        j                  j                  |      \  }}|j	                         }|t
        vr,t        d| dt        t
        j                                      t
        |   }t        j                  d||       |dk(  rt        |       S ddlm}m} ddlm} dd	lm}	 dd
lm}
m} |j*                  |j,                  |j.                  |j0                  d}t3        j4                  |d      5 }|j7                  |        |j8                  }ddd       	  ||j:                        } |	       }||_        d|_         |
|j@                   ||      i      }|jC                        }|tE        d      |jF                  }|jI                         xs |jK                         }i }|jM                         D ]]  \  }}tO        |dd      }|s|D ]C  }tO        |dd      }|tO        |dd      }|s#|jQ                  |g       jS                  |       E _ |r;t        |j                               }|D cg c]  }djU                  ||          }}n|r|g}ng }g }|jV                  D ]  }	 |jY                         } | | jZ                  szt]        | j^                  ja                  tb                    }!| je                         D "cg c]#  \  }}"t]        |"ja                  tb                    % }#}}"|jS                  |!|#d        |jj                  rtm        |jj                        n
tm        |      }%|%|d}&to        ||||&      	 t        jp                  |       S # 1 sw Y   TxY wc c}w c c}"}w # tf        $ r!}$t        ji                  d|$       Y d}$~$1d}$~$ww xY w# tr        $ r Y S w xY w# t         tD        f$ r  tf        $ r.}$t        ju                  d||$       tE        d| d|$       |$d}$~$ww xY w# 	 t        jp                         w # tr        $ r Y w w xY wxY w)uz  
    파일 확장자로 포맷을 자동 감지하여 문서를 파싱한다.

    Args:
        file_bytes: 문서 파일의 바이트 데이터
        filename: 파일명 (확장자 포함)

    Returns:
        ParseResult: 파싱 결과

    Raises:
        ValueError: 지원하지 않는 파일 확장자인 경우
        RuntimeError: 변환 중 오류 발생 시
    rq   u0   지원하지 않는 파일 확장자입니다: 'u   '. 지원 목록: z&parse_document: filename=%s, format=%sr   r   )AcceleratorDeviceAcceleratorOptions)InputFormat)PdfPipelineOptions)DocumentConverterPdfFormatOption)r   r   r   r	   Fru   N)device)pipeline_options)format_optionsu'   Docling 변환 결과가 None입니다.provr   r   r]   rZ   u'   테이블 추출 실패 (건너뜀): %s)r{   r~   r.   u   문서 파싱 오류 (%s): %su   문서 파싱 실패 (z): );r   r   rA   splitextlowerr   r   r   r=   rH   r   %docling.datamodel.accelerator_optionsr   r   docling.datamodel.base_modelsr   "docling.datamodel.pipeline_optionsr   docling.document_converterr   r   DOCXPPTXHTMLIMAGEr   r   r   r   CPUaccelerator_optionsdo_ocrPDFr   r   documentexport_to_textexport_to_markdowniterate_itemsgetattrr   rP   r   r   export_to_dataframeemptyr   columnsastyper   iterrowsr<   r>   r   rb   r   r?   r@   r   )'ro   r~   _ext	ext_lowerfmtr   r   r   r   r   r   _ext_to_input_formatr   r   r   r   	converterconv_resultdocr   pages_dict_doclingrT   	prov_listr   r   text_valsorted_pages_doclingr   r   r   
table_itemdfr[   rl   r\   rB   r{   r   s'                                          r   parse_documentr     s0    =>>WWh'FAs		I&KC5Pfgmn|  oB  oB  oD  hE  gF  G  H  	H

#C
KK8(CH
e|$$ \9EM       ""	4 
	$	$Ie	D 		*88F08I8M8MN-//B,"'%'OO_N^-_`
	  ''1HII""&&(DC,B,B,D	 46((* 	XGD!fd3I% XD%dIt<G*#*4#>#.99'2FMMhWX	X #)*<*A*A*C#D ?ST!TYY1!45TETKEE  ** 	OJO335>"(("2::#4#4S#9:G@BNfaDC1NDNMMgt"DE	O (+yyS^c%j
$ 

 	
	IIhQ F U O OH#NNO.  		 %  Q4hD3H:SFGSPQ	IIh 		s   M6-B7O
 %O
 :O
 
AO
 N)O
 AN(NNAO
  N;6N O
 N	N8N3-O
 3N88O
 ;	OO
P")PPP P:P+*P:+	P74P:6P77P:)r   N)N)$r   r!   r5   loggingr   r   r   dataclassesr   r   r   	getLoggerr   r=   r   __file__parentr(   r   r   r   r   r   r   bytesr$   r)   r7   rC   rJ   r   rR   rm   boolr   r   r   r   r   <module>r      s      	   ( 			8	$GLL"))N:	 6
 "S#X   1 1 1, ,# ,
.c .gll .
	ac 	a; 	a4 	ac kD&8 ,6
D 
D4K 
4: 
 DJ  4:  F 7; B% Bt B{ BJuu u u ur   