§
    �Øj×Y  ã                   óÞ   — d Z ddlmZmZmZmZmZmZ  eh d£¦  «        Z	 G d„ d¦  «        Z
dee         fd„Zdee         fd„Zd	ee         dee         fd
„Zd	ee         dee         fd„ZdS )a  Steps C+D: Assemble initial chunks and refine via split/merge.

Token budgeting works on per-unit token counts precomputed once by the
pipeline and summed here (D12 error contract: the sum of unit counts may
differ from tokenizing the joined text by up to the number of joins).
Assembly never re-tokenizes or re-joins chunk text; ``ProtoChunk.text``
stays empty until serialization.
é   )ÚSentenceUnitÚ
ProtoChunkÚ
union_bboxÚgroup_bboxesÚhorizontal_overlap_ratioÚcaption_matches_element>   ÚlistÚtableÚfigurec                   ó¨  — e Zd ZdZ	 	 	 	 	 	 d1deded	ed
ededefd„Zde	e
         de	e         de	e         fd„Zde	e         de	e         fd„Zde
de
defd„Zede
de
defd„¦   «         Zede
de
defd„¦   «         Zdede	e         fd„Zde	e         de	e         fd„Zdededefd„Zeded edefd!„¦   «         Zde	e         de	e         fd"„Zdededefd#„Zed2d%ed&ed'edefd(„¦   «         Zed2d)e	d*e	d'edefd+„¦   «         Zd,ede	e
         defd-„Zede	e
         deee	e         f         fd.„¦   «         Zede	e         de	e         fd/„¦   «         Zd0S )3ÚChunkAssemblerzŽAssembles SentenceUnits into ProtoChunks based on boundary scores,
    then refines by splitting oversized and merging undersized chunks.
    é�  éx   ç      à?ÚpreserveTÚ
max_tokensÚ
min_tokensÚ	thresholdÚ
table_modeÚmerge_small_chunksÚrespect_section_startsc                 óZ   — || _         || _        || _        || _        || _        || _        d S ©N)r   r   r   r   Úmerge_smallr   )Úselfr   r   r   r   r   r   s          ú¡/Users/tedpeters/Documents/Projects/Claude Projects/Misc Tools/notename-sheets/.venv/lib/python3.11/site-packages/pymupdf4llm/helpers/chunking/chunk_assembler.pyÚ__init__zChunkAssembler.__init__   s6   € ð %ˆŒØ$ˆŒØ"ˆŒØ$ˆŒØ-ˆÔØ&<ˆÔ#Ð#Ð#ó    ÚsentsÚscoresÚreturnc                 óŽ  — |sg S g }|d         g}|d         j         }t          |¦  «        D ]à\  }}||dz            }|| j        k    }	|	s|                      |d         |¦  «        }	|	s||j         z   | j        k    }	|	r.|j        |d         j        k    r|j        |d         j        k    rd}	|	rA|                     |                      t          |¦  «        |¦  «        ¦  «         |g}|j         }ŒÁ|                     |¦  «         ||j         z  }Œá|r6|                     |                      t          |¦  «        |¦  «        ¦  «         |S )zûForm initial chunks from sentences + boundary scores.

        A new chunk starts when:
        - break_score > threshold, OR
        - structural break (heading, type transition), OR
        - adding the next sentence would exceed max_tokens
        é    r   éÿÿÿÿF)
Útoken_countÚ	enumerater   Ú_is_structural_breakr   Ú	box_indexÚpage_noÚappendÚ_make_proto_chunkÚlen)
r   r   r    ÚchunksÚcurrent_sentsÚcurrent_tokensÚiÚscoreÚ	next_sentÚdo_breaks
             r   ÚassemblezChunkAssembler.assemble&   sy  € ð ð 	ØˆIàˆØ˜qœ˜
ˆØ˜qœÔ-ˆå! &Ñ)Ô)ð 	8ð 	8‰HˆAˆuØ˜a !™eœˆIð ˜tœ~Ò-ˆHØð SØ×4Ò4°]À2Ô5FÈ	ÑRÔR�Øð TØ)¨IÔ,AÑAÀDÄOÒS�ð ð !˜YÔ0°MÀ"Ô4EÔ4OÒOÐOØ!*Ô!2°mÀBÔ6GÔ6OÒ!OÐ!OØ �àð 8Ø—’˜d×4Ò4µS¸±[´[À-ÑPÔPÑQÔQÐQØ!* �Ø!*Ô!6��à×$Ò$ YÑ/Ô/Ð/Ø )Ô"7Ñ7��ð ð 	NØ�MŠM˜$×0Ò0µ°V±´¸mÑLÔLÑMÔMÐMàˆr   r-   c                 ób  — g }|D ]P}|j         | j        k    r)|                     |                      |¦  «        ¦  «         Œ;|                     |¦  «         ŒQ| j        s|                      |¦  «        S |                      |¦  «        }|                      |¦  «        }|                      |¦  «        S )uN  Refine chunks via split and multi-depth merge.

        1. Split  â€” break oversized chunks at sentence boundaries
        2. Semantic merge â€” heading+content, caption+element
        3. Budget merge  â€” combine undersized neighbours within max_tokens
           (a pair is merged only while one side is below min_tokens)
        )	r%   r   ÚextendÚ_split_chunkr*   r   Ú	_renumberÚ_merge_semanticÚ_merge_budget)r   r-   ÚsplitÚchunkÚsemanticÚmergeds         r   ÚrefinezChunkAssembler.refineT   s¹   € ð #%ˆØð 	$ð 	$ˆEØÔ  4¤?Ò2Ð2Ø—’˜T×.Ò.¨uÑ5Ô5Ñ6Ô6Ð6Ð6à—’˜UÑ#Ô#Ð#Ð#àÔð 	)Ø—>’> %Ñ(Ô(Ð(ð ×'Ò'¨Ñ.Ô.ˆð ×#Ò# HÑ-Ô-ˆØ�~Š~˜fÑ%Ô%Ð%r   Úprevr2   c                 óä   — |                       ||¦  «        rdS |                      ||¦  «        rdS |j        |j        k    rdS |j        |j        k    rdS |j        |j        k    rdS |j        rdS dS )z9Check if there's a forced structural break between units.FT)Ú_is_caption_element_pairÚ_is_heading_element_pairÚis_header_footerÚis_table_contentÚis_figure_relatedÚis_heading_hint)r   r@   r2   s      r   r'   z#ChunkAssembler._is_structural_breakp   s•   € ð ×(Ò(¨¨yÑ9Ô9ð 	Ø�5à×(Ò(¨¨yÑ9Ô9ð 	Ø�5ØÔ%¨Ô)>Ò>Ð>Ø�4ØÔ%¨Ô)>Ò>Ð>Ø�4ØÔ&¨$Ô*@Ò@Ð@Ø�4ØÔ$ð 	Ø�4Øˆur   c                 ó¢   — | j         sdS | j        |j        k    rdS |j        s	|j        sdS t                               | j        |j        ¦  «        S )z>Check if prev is a heading and next is its associated element.F)rG   r)   rE   rF   r   Ú_has_horizontal_overlapÚbbox)r@   r2   s     r   rC   z'ChunkAssembler._is_heading_element_pair‚   s]   € ð Ô#ð 	Ø�5ØŒ<˜9Ô,Ò,Ð,Ø�5ØÔ*ð 	¨iÔ.Ið 	Ø�5Ý×5Ò5°d´iÀÄÑPÔPÐPr   ÚaÚbc                 ó´   — | j         |j         k    rdS t                               | j        |j        ¦  «        sdS t	          | |¦  «        pt	          || ¦  «        S )z>Check if a and b form a caption-element pair on the same page.F)r)   r   rI   rJ   r   )rK   rL   s     r   rB   z'ChunkAssembler._is_caption_element_pair�   sY   € ð Œ9˜œ	Ò!Ð!Ø�5Ý×5Ò5°a´f¸a¼fÑEÔEð 	Ø�5Ý& q¨!Ñ,Ô,ÐMÕ0GÈÈ1Ñ0MÔ0MÐMr   r<   c                 ó¤  — |j         }|s|gS |j        dk    r| j        dk    r|gS g }g }d}|D �]õ}|j        | j        k    rZ|r-|                     |                      d|¦  «        ¦  «         g }d}|                     |                      d|g¦  «        ¦  «         Œm||j        z   | j        k    �rU|�rRt          |¦  «        }|j        |d         j        k    rÍ|j	        |d         j	        k    r·|j        }|j	        }	t          |¦  «        dz
  }
|
dk    rO||
         j        |k    r>||
         j	        |	k    r-|
dz  }
|
dk    r"||
         j        |k    r||
         j	        |	k    °-|
dk    r<t          d„ ||
dz   d…         D ¦   «         ¦  «        }||j        z   | j        k    r|
dz   }|d|…         }||d…         }|r)|                     |                      d|¦  «        ¦  «         ||gz   }t          d„ |D ¦   «         ¦  «        }�ŒÖ|                     |¦  «         ||j        z  }�Œ÷|r)|                     |                      d|¦  «        ¦  «         |S )	uv  Split an oversized chunk at sentence boundaries.

        Prefers splitting at box boundaries (where box_index changes) to
        avoid the same box's bbox appearing in two chunks â€” but only when
        carrying the whole shared-box run forward still fits the budget.
        Otherwise the box is split at a sentence boundary instead: a
        cosmetic bbox split is cheaper than a chunk over max_tokens.

        With every unit within the budget, every chunk this returns is
        within the budget too.  Units larger than max_tokens (and, in
        table_mode="preserve", tables) are the documented exceptions.
        r
   r   r#   r$   r   c              3   ó$   K  — | ]}|j         V — Œd S r   ©r%   ©Ú.0Úss     r   ú	<genexpr>z.ChunkAssembler._split_chunk.<locals>.<genexpr>È   s$   è è € Ð*RÐ*R¸Q¨1¬=Ð*RÐ*RÐ*RÐ*RÐ*RÐ*Rr   Nc              3   ó$   K  — | ]}|j         V — Œd S r   rP   rQ   s     r   rT   z.ChunkAssembler._split_chunk.<locals>.<genexpr>Ñ   s$   è è € Ð$DÐ$D°q Q¤]Ð$DÐ$DÐ$DÐ$DÐ$DÐ$Dr   )Ú
_sentencesÚprimary_typer   r%   r   r*   r+   r,   r(   r)   Úsum)r   r<   r   ÚresultÚcurrentr/   ÚsentÚsplit_pointÚbiÚpgÚjÚcarry_tokensÚkeepÚcarrys                 r   r7   zChunkAssembler._split_chunk˜   s¤  € ð Ô ˆØð 	Ø�7ˆNàÔ Ò(Ð(¨T¬_À
Ò-JÐ-JØ�7ˆNàˆØˆØˆàð $	3ñ $	3ˆDØÔ $¤/Ò1Ð1Øð 'Ø—M’M $×"8Ò"8¸¸GÑ"DÔ"DÑEÔEÐEØ �GØ%&�NØ—’˜d×4Ò4°Q¸¸Ñ?Ô?Ñ@Ô@Ð@Øà Ô 0Ñ0°4´?ÒBÑBÀwÑBõ
 " '™lœl�Ø”N g¨b¤kÔ&;Ò;Ð;Ø œL¨G°B¬KÔ,?Ò?Ð?àœ�BØœ�BÝ˜G™œ qÑ(�AØ˜aš%˜% G¨A¤JÔ$8¸BÒ$>Ð$>À7È1Ä:ÔCUÐY[ÒC[ÐC[Ø˜Q™˜ð ˜aš%˜% G¨A¤JÔ$8¸BÒ$>Ð$>À7È1Ä:ÔCUÐY[ÒC[ÐC[à˜1’u�uÝ'*Ð*RÐ*RÀ'È!ÈaÉ%È&È&Ä/Ð*RÑ*RÔ*RÑ'RÔ'R˜Ø'¨$Ô*:Ñ:¸d¼oÒMÐMØ*+¨a©%˜Kà˜| ˜|Ô,�Ø   Ô-�Øð CØ—M’M $×"8Ò"8¸¸DÑ"AÔ"AÑBÔBÐBØ 4 &™.�Ý!$Ð$DÐ$D¸GÐ$DÑ$DÔ$DÑ!DÔ!D�‘à—’˜tÑ$Ô$Ð$Ø $Ô"2Ñ2�‘àð 	>Ø�MŠM˜$×0Ò0°°GÑ<Ô<Ñ=Ô=Ð=àˆr   c                 ó€  — t          |¦  «        dk    r|S g }d}|t          |¦  «        k     �r�||         }|dz   t          |¦  «        k     �rC|                      |||dz            ¦  «        �r#t          |j        ¦  «        }|dz   }|t          |¦  «        k     r˜|                      |                      d|¦  «        ||         ¦  «        rh|                     ||         j        ¦  «         |dz  }|t          |¦  «        k     r0|                      |                      d|¦  «        ||         ¦  «        °h|                      d|¦  «        }t          |j        ¦  «        dk    rt          |j        ¦  «        |_        |                     |¦  «         |}n|                     |¦  «         |dz  }|t          |¦  «        k     �°�|S )zÈMerge semantic pairs in a single forward pass.

        Pairs: heading + following content, caption + adjacent element.
        Semantic pairs always produce a single union bbox (not a list).
        r   r#   )	r,   Ú_is_semantic_pairr	   rV   r+   r6   ÚbboxesÚ_union_per_pager*   )r   r-   rY   r0   r<   Úcombinedr_   Úpcs           r   r9   zChunkAssembler._merge_semanticÝ   s­  € õ ˆv‰;Œ;˜!ÒÐØˆMà#%ˆØˆØ•#�f‘+”+Šo‰oØ˜1”IˆEà�1‰u•s˜6‘{”{Ò"Ñ" t×'=Ò'=¸eÀVÈAÐPQÉEÄ]Ñ'SÔ'SÑ"å Ô 0Ñ1Ô1�Ø˜‘E�Ø�#˜f™+œ+’o�o¨$×*@Ò*@Ø×*Ò*¨1¨hÑ7Ô7¸À¼ñ+ô +�oð —O’O F¨1¤IÔ$8Ñ9Ô9Ð9Ø˜‘F�Að	 �#˜f™+œ+’o�o¨$×*@Ò*@Ø×*Ò*¨1¨hÑ7Ô7¸À¼ñ+ô +�oð
 ×+Ò+¨A¨xÑ8Ô8�å�r”y‘>”> AÒ%Ð%Ý /°´	Ñ :Ô :�B”IØ—’˜bÑ!Ô!Ð!Ø��à—’˜eÑ$Ô$Ð$Ø�Q‘�ð) •#�f‘+”+Šo‰oð, ˆr   c                 ó
  — |j         dk    s|j         dk    rdS | j        r|j        r|j        d         j        rdS |j        |j        z   | j        k    rdS t          |j        |j        z
  ¦  «        dk    rdS |  	                    |j
        |j
        ¦  «        sdS |j         dk    r|j         dk    rdS |j         dk    r|j         dk    rdS t          |j        ¦  «        ot          d„ |j        D ¦   «         ¦  «        }|r)|j         t          v r|                      ||j         ¦  «        S t          |j        ¦  «        ot          d	„ |j        D ¦   «         ¦  «        }|j         t          v r|r|                      ||j         ¦  «        S dS )
z?Check if (a, b) form a semantic pair that should stay together.Úheader_footerFr#   r   ÚheadingTr	   c              3   ó$   K  — | ]}|j         V — Œd S r   ©Ú
is_captionrQ   s     r   rT   z3ChunkAssembler._is_semantic_pair.<locals>.<genexpr>  ó$   è è € Ð1UÐ1UÀ1°!´,Ð1UÐ1UÐ1UÐ1UÐ1UÐ1Ur   c              3   ó$   K  — | ]}|j         V — Œd S r   rm   rQ   s     r   rT   z3ChunkAssembler._is_semantic_pair.<locals>.<genexpr>   ro   r   )rW   r   rV   rG   r%   r   ÚabsÚpage_endÚ
page_startÚ_any_bbox_overlapre   ÚboolÚallÚ_ELEMENT_TYPESÚ_caption_target_matches)r   rK   rL   Úa_is_captionÚb_is_captions        r   rd   z ChunkAssembler._is_semantic_pair   s£  € àŒ>˜_Ò,Ð,°´À/Ò0QÐ0QØ�5ð
 Ô'ð 	¨A¬Lð 	Ø”L ”OÔ3ð	à�5ØŒ=˜1œ=Ñ(¨4¬?Ò:Ð:Ø�5ÝˆqŒz˜AœLÑ(Ñ)Ô)¨AÒ-Ð-Ø�5Ø×%Ò% a¤h°´Ñ9Ô9ð 	Ø�5ð Œ>˜YÒ&Ð&¨1¬>¸YÒ+FÐ+FØ�4ð Œ>˜VÒ#Ð#¨¬¸&Ò(@Ð(@Ø�4õ ˜AœLÑ)Ô)ÐU­cÐ1UÐ1UÈÌÐ1UÑ1UÔ1UÑ.UÔ.UˆØð 	C˜AœN­nÐ<Ð<Ø×/Ò/°°1´>ÑBÔBÐBõ ˜AœLÑ)Ô)ÐU­cÐ1UÐ1UÈÌÐ1UÑ1UÔ1UÑ.UÔ.UˆØŒ>�^Ð+Ð+°Ð+Ø×/Ò/°°1´>ÑBÔBÐBàˆur   Úcaption_chunkÚelement_typec                 ó4   — d„ | j         D ¦   «         }|sdS ||v S )z8Check if caption's target type matches the element type.c                 ó*   — h | ]}|j         ¯	|j         ’ŒS © )Úcaption_target_typerQ   s     r   ú	<setcomp>z9ChunkAssembler._caption_target_matches.<locals>.<setcomp>)  s4   € ð 
ð 
ð 
Ø&'ØÔ$ð
ØÔ!ð
ð 
ð 
r   T)rV   )r{   r|   Útarget_typess      r   rx   z&ChunkAssembler._caption_target_matches&  s=   € ð
ð 
Ø+8Ô+Cð
ñ 
ô 
ˆð ð 	Ø�4Ø˜|Ð+Ð+r   c                 ó�  — t          |¦  «        dk    r|S |d         g}t          dt          |¦  «        ¦  «        D ]‰}|d         }||         }|                      ||¦  «        rL|j        |j        z   }|                      d|¦  «        }t          |j        |j        z   ¦  «        |_        ||d<   Œt|                     |¦  «         ŒŠ|S )a  Merge adjacent undersized chunks that fit within max_tokens.

        Preserves bbox structure from earlier phases: instead of rebuilding
        bboxes from scratch, concatenates the bbox lists of both chunks.
        This keeps semantic-merge union bboxes intact.
        r   r#   r$   )r,   ÚrangeÚ_can_budget_mergerV   r+   Ú_regroup_page_bboxesre   r*   )r   r-   r>   r0   r@   ÚcurrÚcombined_sentsrh   s           r   r:   zChunkAssembler._merge_budget3  sÐ   € õ ˆv‰;Œ;˜!ÒÐØˆMà˜”)�ˆÝ�q�#˜f™+œ+Ñ&Ô&ð 	$ð 	$ˆAØ˜"”:ˆDØ˜!”9ˆDà×%Ò% d¨DÑ1Ô1ð 	$Ø!%¤°4´?Ñ!B�Ø×+Ò+¨A¨~Ñ>Ô>�õ 1°´¸t¼{Ñ1JÑKÔK�”	Ø��r‘
�
à—’˜dÑ#Ô#Ð#Ð#àˆr   c                 óh  — |j         dk    s|j         dk    rdS |j         dk    rdS | j        r|j        r|j        d         j        rdS | j        dk    r|j         dk    s|j         dk    rdS |j        |j        z   | j        k    rdS | j        dk    r"|j        | j        k    r|j        | j        k    rdS dS )u-  Check if two adjacent chunks can be merged within budget.

        Spatial proximity (bbox overlap, page distance) is intentionally
        NOT checked here â€” budget merge is purely about filling token
        capacity with sequentially adjacent chunks.

        min_tokens is the floor this step works towards: a pair is merged
        only while at least one side is still below it, so two chunks that
        already stand on their own are left alone (merge_small_chunks
        semantics).  min_tokens=0 restores unconditional greedy packing.
        rj   Frk   r#   Úisolater
   T)rW   r   rV   rG   r   r%   r   r   )r   rK   rL   s      r   r…   z ChunkAssembler._can_budget_mergeO  sÝ   € ð Œ>˜_Ò,Ð,°´À/Ò0QÐ0QØ�5ØŒ>˜YÒ&Ð&Ø�5ð
 Ô'ð 	¨A¬Lð 	Ø”L ”OÔ3ð	à�5ð Œ?˜iÒ'Ð'ØŒ~ Ò(Ð(¨A¬N¸gÒ,EÐ,EØ�uØŒ=˜1œ=Ñ(¨4¬?Ò:Ð:Ø�5àŒO˜aÒÐØ”M T¤_Ò4Ð4Ø”M T¤_Ò4Ð4Ø�5Øˆtr   ç333333Ó?Úbbox_aÚbbox_bÚ	min_ratioc                 ó*   — t          | |¦  «        |k    S )z>Check if two single bboxes have sufficient horizontal overlap.)r   )rŒ   r�   rŽ   s      r   rI   z&ChunkAssembler._has_horizontal_overlapv  s   € õ (¨°Ñ7Ô7¸9ÒDÐDr   Úbboxes_aÚbboxes_bc                 óÆ   — | D ]]}t          |¦  «        dk    r
|dd…         n|}|D ]9}t          |¦  «        dk    r
|dd…         n|}t          ||¦  «        |k    r  dS Œ:Œ^dS )zžCheck if any bbox from list a overlaps horizontally with any from list b.

        Handles both 4-tuple (x0,y0,x1,y1) and 5-tuple (page,x0,y0,x1,y1).
        é   r   NTF)r,   r   )r�   r‘   rŽ   ÚbaÚba4ÚbbÚbb4s          r   rt   z ChunkAssembler._any_bbox_overlap{  s�   € ð ð 	 ð 	 ˆBÝ ™GœG qšL˜L�"�Q�R�R”&�&¨bˆCØð  ð  �Ý # B¡¤¨1¢ �b˜˜˜”f�f°"�Ý+¨C°Ñ5Ô5¸ÒBÐBØ˜4˜4˜4ð Cð ð ˆur   Úchunk_idc                 ó¤  — |                       |¦  «        \  }}t          |¦  «        }t          t                               d„ |D ¦   «         ¦  «        ¦  «        }t          |d„ |D ¦   «         t          d„ |D ¦   «         ¦  «        |d         j        |d         j        dz   f|d         j        |d         j        ||||t          |¦  «        ¬¦  «        S )zÌCreate a ProtoChunk from a contiguous run of SentenceUnits.

        Text is NOT materialized here (serialization does that once);
        token_count is the sum of precomputed unit counts (D12).
        c              3   ó2   K  — | ]}|j         |j        fV — Œd S r   )r)   r(   rQ   s     r   rT   z3ChunkAssembler._make_proto_chunk.<locals>.<genexpr>“  s<   è è € ð )
ð )
Ø)*ˆQŒY˜œÐ$ð)
ð )
ð )
ð )
ð )
ð )
r   c                 ó   — g | ]	}|j         ‘Œ
S r   )Úsent_idrQ   s     r   ú
<listcomp>z4ChunkAssembler._make_proto_chunk.<locals>.<listcomp>™  s   € Ð/Ð/Ð/ A�a”iÐ/Ð/Ð/r   c              3   ó$   K  — | ]}|j         V — Œd S r   rP   rQ   s     r   rT   z3ChunkAssembler._make_proto_chunk.<locals>.<genexpr>š  s$   è è € Ð9Ð9¨a˜AœMÐ9Ð9Ð9Ð9Ð9Ð9r   r#   r$   r   )r˜   Úsent_idsr%   Ú
unit_rangers   rr   Úbox_indicesre   rW   ÚtypesrV   )	Ú_infer_chunk_typesÚ_group_bboxes_by_pager	   ÚdictÚfromkeysr   rX   rœ   r)   )r   r˜   r   rW   Ú	all_typesre   r¡   s          r   r+   z ChunkAssembler._make_proto_chunk‰  sï   € ð #'×"9Ò"9¸%Ñ"@Ô"@Ñˆ�iå& uÑ-Ô-ˆå�4Ÿ=š=ð )
ð )
Ø.3ð)
ñ )
ô )
ñ 
ô 
ñ ô ˆõ ØØ/Ð/¨Ð/Ñ/Ô/ÝÐ9Ð9°5Ð9Ñ9Ô9Ñ9Ô9Ø˜aœÔ(¨%°¬)Ô*;¸aÑ*?Ð@Ø˜Q”xÔ'Ø˜2”YÔ&Ø#ØØ%ØÝ˜E‘{”{ð
ñ 
ô 
ð 	
r   c                 óœ  — t          ¦   «         }g }| D ]z}d}|j        rd}n>|j        rd}n4|j        rd}n*|j        rd}n |j        rd}n|j        rd}n|j        rd}nd	}||vr*|                     |¦  «         | 	                    |¦  «         Œ{d
}|D ]}||v r||fc S Œd|v rd|fS d|v rt          | ¦  «        dk    rd|fS d|v rd|fS d	|fS )zÌCollect all content types and determine the primary type.

        Returns (primary_type, all_types) where all_types preserves
        reading order and primary_type is the dominant element type.
        Nrj   r
   r   r	   rk   ÚcaptionÚfootnoteÚ	paragraph)r
   r   r	   r   )ÚsetrD   rE   rF   Úis_list_itemrG   rn   Úis_footnoteÚaddr*   r,   )r   Úseenr§   rS   ÚtÚ_ELEMENT_PRIORITYÚets          r   r£   z!ChunkAssembler._infer_chunk_types¥  sc  € õ ‰uŒuˆØˆ	Øð 	$ð 	$ˆAØˆAØÔ!ð  Ø#��ØÔ#ð  Ø��ØÔ$ð  Ø��Ø”ð 	 Ø��ØÔ"ð  Ø��Ø”ð  Ø��Ø”ð  Ø��à�Ø˜ˆ}ˆ}Ø—’˜‘”�Ø× Ò  Ñ#Ô#Ð#øð 8ÐØ#ð 	%ð 	%ˆBØ�TˆzˆzØ˜9�}Ð$Ð$Ð$ð à˜dÐ"Ð"Ø" IÐ-Ð-Ø˜ÐÐ¥ U¡¤¨q¢ Ø˜iÐ'Ð'Ø˜ÐÐØ˜yÐ(Ð(Ø˜IÐ%Ð%r   c                 ó>   — t          | ¦  «        D ]\  }}||_        Œ| S )z Renumber chunk IDs sequentially.)r&   r˜   )r-   r0   r<   s      r   r8   zChunkAssembler._renumberÒ  s-   € õ " &Ñ)Ô)ð 	ð 	‰HˆAˆuØˆEŒNˆNØˆr   N)r   r   r   r   TT)r‹   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚintÚfloatÚstrru   r   r	   r   r   r4   r?   r'   ÚstaticmethodrC   rB   r7   r9   rd   rx   r:   r…   ÚtuplerI   rt   r+   r£   r8   r   r   r   r   r      sÑ  € € € € € ðð ð ØØØ$Ø#'Ø'+ð=ð =àð=ð ð=ð ð	=ð
 ð=ð !ð=ð !%ð=ð =ð =ð =ð$*˜d <Ô0ð *¸$¸u¼+ð *È$ÈzÔJZð *ð *ð *ð *ð\&˜T *Ô-ð &°$°zÔ2Bð &ð &ð &ð &ð8¨ð À,ð ÐSWð ð ð ð ð$ ðQ |ð QÀð QÐQUð Qð Qð Qñ „\ðQð ðN Lð N°\ð NÀdð Nð Nð Nñ „\ðNðA *ð A°°jÔ1Að Að Að Að AðJ! d¨:Ô&6ð !¸4À
Ô;Kð !ð !ð !ð !ðF$ :ð $°*ð $Àð $ð $ð $ð $ðL ð,¨zð ,Èð ,ÐQUð ,ð ,ð ,ñ „\ð,ð D¨Ô$4ð ¸¸jÔ9Ið ð ð ð ð8# :ð #°*ð #Àð #ð #ð #ð #ðN ðEð E¨ð E°uð EÈð EÐY]ð Eð Eð Eñ „\ðEð ðð  Dð °Dð ÀUð ÐUYð ð ð ñ „\ðð
¨#ð 
°d¸<Ô6Hð 
ÈZð 
ð 
ð 
ð 
ð8 ð*& $ |Ô"4ð *&¸¸sÀDÈÄI¸~Ô9Nð *&ð *&ð *&ñ „\ð*&ðX ð˜$˜zÔ*ð ¨t°JÔ/?ð ð ð ñ „\ðð ð r   r   r!   c                 óf  — ddl m} g }g }| D ]f}|j        r|                     |¦  «         Œ|r$|                     t          |¦  «        ¦  «         g }|                     |j        |j        f¦  «         Œg|r"|                     t          |¦  «        ¦  «          |t          ¦  «        }|D ] \  }}||                              |¦  «         Œ!g }t          | 
                    ¦   «         ¦  «        D ]B}t          t          ||         ¦  «        ¦  «        }	|	D ]}|                     |g|¢R ¦  «         ŒŒC|S )aJ  Group sentence bboxes by page, then by edge-pair within each page.

    Consecutive list-items are pre-merged into a single union bbox before
    edge-pair grouping, since individual list-item x1 varies by text length
    while they share the same x0 (indentation level).

    Returns list of (page, x0, y0, x1, y1) 5-tuples.
    r#   ©Údefaultdict)ÚcollectionsrÀ   r­   r*   r6   Ú_flush_list_runr)   rJ   r	   ÚsortedÚkeysr   Úiter)
r   rÀ   Úmerged_entriesÚlist_runrS   Úpage_bboxesr)   rJ   rY   Úgroupeds
             r   r¤   r¤   Ú  sx  € ð (Ð'Ð'Ð'Ð'Ð'ð €NØ€HØð 7ð 7ˆØŒ>ð 	7Ø�OŠO˜AÑÔÐÐàð Ø×%Ò%¥o°hÑ&?Ô&?Ñ@Ô@Ð@Ø�Ø×!Ò! 1¤9¨a¬fÐ"5Ñ6Ô6Ð6Ð6Øð 9Ø×Ò�o¨hÑ7Ô7Ñ8Ô8Ð8ð �+�dÑ#Ô#€KØ'ð *ð *‰ˆ�Ø�GÔ×#Ò# DÑ)Ô)Ð)Ð)à€FÝ˜+×*Ò*Ñ,Ô,Ñ-Ô-ð ,ð ,ˆÝ�t K°Ô$8Ñ9Ô9Ñ:Ô:ˆØð 	,ð 	,ˆDØ�MŠM˜7Ð* TÐ*Ð*Ñ+Ô+Ð+Ð+ð	,à€Mr   c                 óà  — ddl m}  |t          ¦  «        }| D ]'}||j                                      |j        ¦  «         Œ(g }t          |                     ¦   «         ¦  «        D ]‰}||         }t          d„ |D ¦   «         ¦  «        }t          d„ |D ¦   «         ¦  «        }t          d„ |D ¦   «         ¦  «        }	t          d„ |D ¦   «         ¦  «        }
|                     ||||	|
ff¦  «         ŒŠ|S )z=Union consecutive list-item sentences into one bbox per page.r#   r¿   c              3   ó&   K  — | ]}|d          V — ŒdS )r#   Nr   ©rR   rL   s     r   rT   z"_flush_list_run.<locals>.<genexpr>	  ó&   è è € Ð&Ð&˜!��1”Ð&Ð&Ð&Ð&Ð&Ð&r   c              3   ó&   K  — | ]}|d          V — ŒdS )r   Nr   rÌ   s     r   rT   z"_flush_list_run.<locals>.<genexpr>
  rÍ   r   c              3   ó&   K  — | ]}|d          V — ŒdS )é   Nr   rÌ   s     r   rT   z"_flush_list_run.<locals>.<genexpr>  rÍ   r   c              3   ó&   K  — | ]}|d          V — ŒdS )é   Nr   rÌ   s     r   rT   z"_flush_list_run.<locals>.<genexpr>  rÍ   r   )
rÁ   rÀ   r	   r)   r*   rJ   rÃ   rÄ   ÚminÚmax)ÚitemsrÀ   Úby_pagerS   rY   r)   re   Úx0Úy0Úx1Úy1s              r   rÂ   rÂ      s  € à'Ð'Ð'Ð'Ð'Ð'Øˆk�$ÑÔ€GØð *ð *ˆØ�”	Ô×!Ò! !¤&Ñ)Ô)Ð)Ð)Ø€FÝ˜'Ÿ,š,™.œ.Ñ)Ô)ð 3ð 3ˆØ˜Ô!ˆÝÐ&Ð&˜vÐ&Ñ&Ô&Ñ&Ô&ˆÝÐ&Ð&˜vÐ&Ñ&Ô&Ñ&Ô&ˆÝÐ&Ð&˜vÐ&Ñ&Ô&Ñ&Ô&ˆÝÐ&Ð&˜vÐ&Ñ&Ô&Ñ&Ô&ˆØ�Š�w  R¨¨RÐ 0Ð1Ñ2Ô2Ð2Ð2Ø€Mr   rÈ   c                 óL  — ddl m}  |t          ¦  «        }| D ])}|\  }}}}}||                              ||||f¦  «         Œ*g }	t	          |                     ¦   «         ¦  «        D ]=}
t          t          ||
         ¦  «        ¦  «        }|	                     |
g|¢R ¦  «         Œ>|	S )z:Union all bboxes on each page into a single bbox per page.r#   r¿   )rÁ   rÀ   r	   r*   rÃ   rÄ   r   rÅ   )rÈ   rÀ   rÖ   ÚpbÚpager×   rØ   rÙ   rÚ   rY   r)   Úus               r   rf   rf     sÆ   € à'Ð'Ð'Ð'Ð'Ð'Øˆk�$ÑÔ€GØð /ð /ˆØ!Ñˆˆb�"�b˜"Ø�Œ×Ò˜b " b¨"Ð-Ñ.Ô.Ð.Ð.à€FÝ˜'Ÿ,š,™.œ.Ñ)Ô)ð %ð %ˆÝ•t˜G GÔ,Ñ-Ô-Ñ.Ô.ˆØ�Š�w�m �m�mÑ$Ô$Ð$Ð$Ø€Mr   c                 óV  — ddl m}  |t          ¦  «        }| D ])}|\  }}}}}||                              ||||f¦  «         Œ*g }	t	          |                     ¦   «         ¦  «        D ]B}
t          t          ||
         ¦  «        ¦  «        }|D ]}|	                     |
g|¢R ¦  «         ŒŒC|	S )z‡Re-group 5-tuple bboxes (page, x0, y0, x1, y1) by page.

    Preserves page info while merging compatible bboxes within each page.
    r#   r¿   )rÁ   rÀ   r	   r*   rÃ   rÄ   r   rÅ   )rÈ   rÀ   rÖ   rÜ   rÝ   r×   rØ   rÙ   rÚ   rY   r)   rÉ   rJ   s                r   r†   r†      sß   € ð
 (Ð'Ð'Ð'Ð'Ð'Øˆk�$ÑÔ€GØð /ð /ˆØ!Ñˆˆb�"�b˜"Ø�Œ×Ò˜b " b¨"Ð-Ñ.Ô.Ð.Ð.à€FÝ˜'Ÿ,š,™.œ.Ñ)Ô)ð ,ð ,ˆÝ�t G¨GÔ$4Ñ5Ô5Ñ6Ô6ˆØð 	,ð 	,ˆDØ�MŠM˜7Ð* TÐ*Ð*Ñ+Ô+Ð+Ð+ð	,à€Mr   N)r¸   Úmodelsr   r   r   r   r   r   Ú	frozensetrw   r   r	   r½   r¤   rÂ   rf   r†   r   r   r   ú<module>râ      s&  ððð ð zÐ yÐ yÐ yÐ yÐ yÐ yÐ yÐ yÐ yÐ yÐ yÐ yÐ yÐ yÐ yà�Ð6Ð6Ð6Ñ7Ô7€ðHð Hð Hð Hð Hñ Hô Hð HðV# D¨¤Kð #ð #ð #ð #ðL˜d 5œkð ð ð ð ð"  e¤ð °°e´ð ð ð ð ð d¨5¤kð °d¸5´kð ð ð ð ð ð r   