Ë
    ¢_i2  ã                   ó|   — d Z ddlZddlmZ ddlmZmZmZmZ ddlm	Z	 ddl
mZ ddlmZmZ dd	lmZ  G d
„ d«      Zy)zð
Enhanced Table Parser with Header Consolidation

Parses tables from Docling documents and consolidates consecutive headers
that immediately precede tables, following strict rules to avoid incorrect
consolidation across content boundaries.
é    N)Údatetime)ÚAnyÚListÚOptionalÚTuple)ÚInputFormat)ÚPdfPipelineOptions)ÚDocumentConverterÚPdfFormatOptioné   )ÚTableMetadatac            
       óà   — e Zd ZdZ	 	 	 	 ddedededefd„Zdedee	e
e   f   fd	„Zd
e
e	   dedee
e   e
e   f   fd„Zde
e   defd„Zdd
e
e	   dededee   fd„Zdefd„Zde
e   defd„Zy)ÚEnhancedTableParserzÙ
    Enhanced table parser with intelligent header consolidation.

    Consolidates consecutive headers of the same level that immediately
    precede tables, with strict rules to prevent incorrect consolidation.
    Ú	separatorÚmax_lookbackÚenable_consolidationÚdebugc                 ó<   — || _         || _        || _        || _        y)aL  
        Initialize the enhanced table parser.

        Args:
            separator: String to join multiple headers (e.g., " ^ " or " | ")
            max_lookback: Maximum elements to look back for headers
            enable_consolidation: Whether to consolidate consecutive headers
            debug: Enable debug output
        N)r   r   r   r   )Úselfr   r   r   r   s        ú5/home/mande/repo/quber/src/quber/core/table_parser.pyÚ__init__zEnhancedTableParser.__init__   s"   € ð  #ˆŒØ(ˆÔØ$8ˆÔ!Øˆ�
ó    Úpdf_pathÚreturnc                 óÜ  — t        «       }d|_        d|_        d|j                  _        t        t        j                  t        |¬«      i¬«      }|j                  |«      }|j                  }g }d}t        |j                  «       «      }|D �	�
cg c]  \  }	}
|	‘Œ	 }}	}
t        |«      D ��ci c]  \  }}t        |«      |“Œ }}}|j                  D �]‰  }t!        |d«      r>|j"                  r2t!        |j"                  d   d«      r|j"                  d   j$                  nd}|j'                  t        |«      d	«      }g }g }|dkD  r| j)                  ||«      \  }}d
}| j*                  r|r| j-                  |«      }d}d}d
}t!        |d«      rÐ|j.                  rÄ|j.                  j0                  }|j.                  j2                  }|dkD  r“|dkD  rŽt!        |j.                  d«      rx|j.                  j4                  rbt7        |j.                  j4                  «      dkD  r|j.                  j4                  d   ng }|r#t7        |«      dkD  r|d   rt9        |d   «      nd
}d
}t!        |d«      rl|j"                  r`t!        |j"                  d   d«      rG|j"                  d   j:                  }|j<                  |j>                  |j@                  |jB                  f}| jE                  ||d¬«      }t!        |d«      r|jG                  |«      nd
}tI        |||||r|d   nd
|||||¬«
      }|jK                  |«       |dz  }| jL                  s�Œy| jO                  |«       �ŒŒ ||fS c c}
}	w c c}}w )zÕ
        Parse document and extract all tables with enhanced metadata.

        Args:
            pdf_path: Path to PDF file

        Returns:
            Tuple of (document object, list of TableMetadata)
        FT)Úpipeline_options)Úformat_optionsr   ÚprovÚpage_nor   éÿÿÿÿNÚdataÚgridÚbboxé   )ÚlimitÚexport_to_markdown)
Útable_indexÚpage_numberÚheadersÚconsolidated_headerÚdescriptive_textÚtable_markdownÚpreceding_textÚrowsÚcolsÚfirst_cell_content)(r	   Údo_ocrÚdo_table_structureÚtable_structure_optionsÚdo_cell_matchingr
   r   ÚPDFr   ÚconvertÚdocumentÚlistÚiterate_itemsÚ	enumerateÚidÚtablesÚhasattrr   r   ÚgetÚ_find_preceding_headersr   Ú_consolidate_headersr!   Únum_rowsÚnum_colsr"   ÚlenÚstrr#   ÚlÚtÚrÚbÚ_get_preceding_textr&   r   Úappendr   Ú_print_debug_info)r   r   r   Ú	converterÚresultr7   Útables_metadatar'   Úelements_with_depthÚitemÚdepthÚelements_listÚiÚelemÚelement_to_indexÚtableÚpage_numÚ	table_idxr)   Údescriptive_textsr*   r.   r/   Ú
first_cellÚ	first_rowr#   rH   r-   Útable_mdÚmetadatas                                 r   Úparse_documentz"EnhancedTableParser.parse_document1   sH  € ô .Ó/ÐØ"'ÐÔØ.2ÐÔ+ØDHÐ×0Ñ0ÔAô &Ü'ŸO™O¬_ÐN^Ô-_Ð`ô
ˆ	ð ×"Ñ" 8Ó,ˆØ—?‘?ˆð ˆØˆô # 8×#9Ñ#9Ó#;Ó<ÐÙ1DÔEÑ1D¡+ $¨šÐ1DˆÑEÜ7@ÀÔ7OÔPÑ7O©G¨A¨tœB˜t›H a™KÐ7OÐÑPà—_•_ˆEô ˜E 6Ô*¨u¯zªz¼gÀeÇjÁjÐQRÁmÐU^Ô>_ð —
‘
˜1‘×%Ò%àð ð )×,Ñ,¬R°«Y¸Ó;ˆIð ˆGØ "ÐØ˜1Š}Ø-1×-IÑ-IÈ-ÐYbÓ-cÑ*�Ð*ð #'ÐØ×(Ò(©WØ&*×&?Ñ&?ÀÓ&HÐ#ð ˆDØˆDØˆJä�u˜fÔ%¨%¯*ª*à—z‘z×*Ñ*�Ø—z‘z×*Ñ*�ð ˜!’8  q¢ä˜uŸz™z¨6Ô2°u·z±z·²Ü:=¸e¿j¹j¿o¹oÓ:NÐQRÒ:R E§J¡J§O¡O°AÒ$6ÐXZ˜	Ù$¬¨Y«¸!Ò);Ø>GÈºl¬¨Y°q©\Ô):ÐPT˜Jð ˆDÜ�u˜fÔ%¨%¯*ª*¼ÀÇÁÈAÁÐPVÔ9WØ—J‘J˜q‘M×&Ñ&�ØŸ™˜QŸS™S !§#¡# q§s¡sÐ+�ð "×5Ñ5°mÀYÐVWÐ5ÓXˆNô >EÀUÐL`Ô=a�u×/Ñ/°Ô9ÐgkˆHô %Ø'Ø$ØØ$7Ù9JÐ!2°1Ò!5ÐPTØ'Ø-ØØØ#-ôˆHð ×"Ñ" 8Ô,Ø˜1ÑˆKà�zŒzØ×&Ñ& xÖ0ðM %ðP ˜Ð(Ð(ùóW FùÛPs   ÂM"Â,M(ÚelementsrX   c           	      óÂ  — g }g }d}d}t        t        | j                  |«      «      D �]±  }||z
  dz
  }||   }	t        |	«      j                  }
|
dv r | j
                  rt        d|
› d�«        ||fS |
dk(  r|r| j
                  rt        d«        ||fS t        |	d	«      r|	j                  sŒ†|	j                  j                  «       }|sŒ£t        |	d
«      xr |	j                  du}|r§|	j                  }|€8|}|j                  d|«       | j
                  sŒðt        d|› d|dd › d�«       �Œ||k(  r9|r7|j                  d|«       | j
                  s�Œ.t        d|› d|dd › d�«       �ŒE| j
                  rt        d|› d|› d�«        ||fS |sBt        |«      dk(  r4|j                  d|«       | j
                  s�Œ˜t        d|dd › d�«       �Œ¬|s�Œ°d}�Œ´ ||fS )aÿ  
        Find headers that immediately precede a table.

        Only consolidates headers that are:
        1. Consecutive (no non-header content between them)
        2. Of the same level
        3. Immediately before the table
        4. Not separated by boundary elements (tables, images, etc.)

        Args:
            elements: List of document elements
            table_idx: Index of the table in the elements list

        Returns:
            Tuple of (headers list, descriptive texts list)
        NTr   )Ú	TableItemÚPictureItemz  Hit boundary element (z), stopping header searchÚListItemz/  Hit list item after finding headers, stoppingÚtextÚlevelr   z  Found first header at level z: é2   ú...z$  Found consecutive header at level z   Found different level header (z vs z), stoppingz  Found descriptive text: F)ÚrangeÚminr   ÚtypeÚ__name__r   Úprintr=   rd   Ústripre   ÚinsertrC   )r   r_   rX   r)   rY   Úcurrent_levelÚconsecutiverS   ÚidxrT   Ú	elem_typerd   Ú	is_headerre   s                 r   r?   z+EnhancedTableParser._find_preceding_headers�   s*  € ð" ˆØÐØˆØˆô ”s˜4×,Ñ,¨iÓ8×9ˆAØ˜a‘- !Ñ#ˆCØ˜C‘=ˆDô ˜T›
×+Ñ+ˆIð Ð8Ñ8Ø—:’:ÜÐ4°Y°KÐ?XÐYÔZØðn Ð)Ð)Ð)ði ˜JÒ&©7Ø—:’:ÜÐKÔLØðb Ð)Ð)Ð)ô] ˜4 Ô(°·	²	Øà—9‘9—?‘?Ó$ˆDÙØô    gÓ.ÒI°4·:±:ÀTÐ3IˆIáØŸ
™
�ð !Ð(Ø$)�MØ—N‘N 1 dÔ+Ø—z“zÜÐ >¸u¸gÀRÈÈSÈbÈ	À{ÐRUÐVÖWð ˜mÒ+±Ø—N‘N 1 dÔ+Ø—z”zÜÐ DÀUÀGÈ2ÈdÐSVÐTVÈiÈ[ÐX[Ð\Ö]ð —z’zÜÐ @ÀÀÀtÈMÈ?ÐZeÐfÔgØð  Ð)Ð)Ð)ñ ¤3Ð'8Ó#9¸QÒ#>Ø%×,Ñ,¨Q°Ô5Ø—z”zÜÐ :¸4ÀÀ¸9¸+ÀSÐIÖJó Ø"'’Kð} :ðD Ð)Ð)Ð)r   r)   c                 ód   — |syt        |«      dk(  r|d   S | j                  j                  |«      S )zÅ
        Consolidate multiple headers into a single string.

        Args:
            headers: List of header texts to consolidate

        Returns:
            Consolidated header string
        Nr   r   )rC   r   Újoin)r   r)   s     r   r@   z(EnhancedTableParser._consolidate_headersø   s5   € ñ ØÜˆw‹<˜1ÒØ˜1‘:ÐØ�~‰~×"Ñ" 7Ó+Ð+r   r%   c                 óš  — g }d}t        t        | j                  |«      «      D ]‘  }||z
  dz
  }||   }t        |«      j                  }	|	dk(  r|j                  dd«       Œ=t        |d«      sŒJ|j                  sŒW|j                  j                  «       }
|
sŒt|j                  d|
«       |dz  }||k\  sŒ‘ n |rdj                  |«      S dS )aY  
        Get text content immediately preceding the table.

        Args:
            elements: List of document elements
            table_idx: Index of the table
            limit: Maximum number of text elements to include

        Returns:
            Preceding text context or None, with [Table] placeholders for intervening tables
        r   r   ra   z[Table]rd   Ú
N)
rh   ri   r   rj   rk   rn   r=   rd   rm   ru   )r   r_   rX   r%   ÚtextsÚcountrS   rq   rT   rr   rd   s              r   rI   z'EnhancedTableParser._get_preceding_text  sÇ   € ð ˆØˆä”s˜4×,Ñ,¨iÓ8Ö9ˆAØ˜a‘- !Ñ#ˆCØ˜C‘=ˆDÜ˜T›
×+Ñ+ˆIð ˜KÒ'Ø—‘˜Q 	Ô*Øä�t˜VÕ$¨¯«Ø—y‘y—‘Ó(�ÚØ—L‘L  DÔ)Ø˜Q‘J�EØ “~Ùð! :ñ$ $)ˆt�y‰y˜ÓÐ2¨dÐ2r   r]   c                 óÔ  — t        d|j                  dz   › d|j                  › d�«       |j                  rt        d|j                  › �«       |j                  rt        d|j                  › �«       |j
                  rt        d|j
                  dd	 › d
�«       t        d|j                  › d|j                  › d�«       |j                  rt        d|j                  dd › d
�«       yy)z$Print debug information for a table.z
=== Table r   z (Page z) ===zConsolidated Header: zIndividual Headers: zDescriptive Text: Néd   rg   zSize: u	    rows Ã— z colszFirst Cell: rf   )	rl   r'   r(   r*   r)   r+   r.   r/   r0   )r   r]   s     r   rK   z%EnhancedTableParser._print_debug_info+  sâ   € ä�˜X×1Ñ1°AÑ5Ð6°g¸h×>RÑ>RÐ=SÐSXÐYÔZØ×'Ò'ÜÐ)¨(×*FÑ*FÐ)GÐHÔIØ×ÒÜÐ(¨×)9Ñ)9Ð(:Ð;Ô<Ø×$Ò$ÜÐ& x×'@Ñ'@ÀÀ#Ð'FÐ&GÀsÐKÔLÜ��x—}‘}�o Y¨x¯}©}¨o¸UÐCÔDØ×&Ò&Ü�L ×!<Ñ!<¸S¸bÐ!AÐ BÀ#ÐFÕGð 'r   Úmetadata_listÚoutput_pathc           
      óü  — t        j                  «       j                  «       t        |«      g dœ}|D ]~  }|j                  |j
                  |j                  |j                  |j                  |j                  |j                  |j                  dœ|j                  dœ}|d   j                  |«       Œ€ t        |dd¬«      5 }t        j                   ||dd	¬
«       ddd«       t#        d|› �«       y# 1 sw Y   ŒxY w)z®
        Save table metadata to JSON file.

        Args:
            metadata_list: List of TableMetadata objects
            output_path: Path for output JSON file
        )Úextraction_dateÚtotal_tablesr<   )r.   r/   )r'   r(   r*   r)   r+   r-   Ú
dimensionsrZ   r<   Úwzutf-8)Úencodingé   F)ÚindentÚensure_asciiNzMetadata saved to: )r   ÚnowÚ	isoformatrC   r'   r(   r*   r)   r+   r-   r.   r/   r0   rJ   ÚopenÚjsonÚdumprl   )r   r|   r}   r!   ÚmetaÚ
table_dictÚfs          r   Úsave_metadataz!EnhancedTableParser.save_metadata8  sÞ   € ô  (Ÿ|™|›~×7Ñ7Ó9Ü Ó.Øñ
ˆó "ˆDà#×/Ñ/Ø#×/Ñ/Ø'+×'?Ñ'?ØŸ<™<Ø$(×$9Ñ$9Ø"&×"5Ñ"5Ø'+§y¡y¸$¿)¹)ÑDØ"×5Ñ5ñ	ˆJð �‰N×!Ñ! *Õ-ð "ô �+˜s¨WÕ5¸Ü�I‰I�d˜A a°eÕ<÷ 6ô 	Ð# K =Ð1Õ2÷ 6Ð5ús   ÃC2Ã2C;N)z ^ é
   TF)r$   )rk   Ú
__module__Ú__qualname__Ú__doc__rD   ÚintÚboolr   r   r   r   r   r^   r?   r@   r   rI   rK   r�   © r   r   r   r      s  „ ñð ØØ%)Øñàðð ðð #ð	ð
 óð*j) sð j)¨u°S¸$¸}Ñ:MÐ5MÑ/Nó j)ðXY*°°S±	ð Y*Àcð Y*ÈeÐTXÐY\ÑT]Ð_cÐdgÑ_hÐThÑNió Y*ðv,¨D°©Ið ,¸#ó ,ñ !3¨D°©Ið !3À#ð !3Ècð !3ÐZbÐcfÑZgó !3ðFH¨-ó Hð 3¨4°Ñ+>ð  3ÈSô  3r   r   )r“   rŠ   r   Útypingr   r   r   r   Údocling.datamodel.base_modelsr   Ú"docling.datamodel.pipeline_optionsr	   Údocling.document_converterr
   r   Úmodelsr   r   r–   r   r   Ú<module>rœ      s0   ðñó Ý ß -Ó -å 5Ý Aß Iå !÷D3ò D3r   