ó
    ®”'j“¡  ã                  óJ  • S r SSKJr  SSKrSSKrSSKrSSKJr  SSKJ	r	  SSK
JrJrJrJrJrJr  SSKJr  SSKJrJrJrJrJrJrJrJr  SS	KJrJrJr  SS
K J!r!J"r"J#r#  SSK$J%r%  SSK&J'r'J(r(J)r)  SSK*J+r+J,r,J-r-J.r.J/r/J0r0J1r1  \S   r2Sr3Sr4S$S jr5        S%S jr6      S&S jr7 S'       S(S jjr8        S)S jr9S*S jr:S+S jr;S,S jr<        S-S jr=\\>\>\>\>\?4   r@ S.       S/S jjrAS0S jrBS1S jrCS2S jrD\" SS9 " S  S!5      5       rE " S" S#5      rFg)3u�  
CamelotCorrespondenceExtractor â€” the QUE-230 rebuild.

The rasterized page is the arbiter of what is a table and where. Per
page:

1. Extract + detect (concurrent): Camelot lattice and stream run on the
   CPU; the detector agent reads the page image and returns the real
   tables, top to bottom, each with a rough box and a description.
2. Correspondence: assign Camelot chunks to detected tables by 2D bbox
   overlap. Camelot's chunk boxes are precise PDF geometry; the detector's
   boxes are rough, so each detected table takes the chunk that covers it
   most (argmax), not every chunk that clips its band â€” that ignores the
   spill a rough boundary causes. Lattice is tried first (trusted source);
   stream is the fallback for tables no lattice chunk matched. One chunk
   that is the best match for two-or-more tables -> combined (kept whole,
   flagged, never split); because the overlap is 2D this covers both
   convergence axes (vertically stacked tables Camelot ran together, and
   side-by-side tables it fused column-wise). A table whose best chunk is
   truncated is completed from the leftover (orphan) chunks in step 3.
   Matching is deterministic â€” no LLM reads the cell values.
3. Assemble + completeness audit: join a table's matched chunks in order,
   then check the assembled data against the page's text layer (the same
   source Camelot reads) within the table's region. A value-like figure in
   the region's columns that is absent from the assembled data -> extend
   with the next leftover chunk and re-audit; if nothing supplies it,
   report the gap.

Report, don't drop (with guarded recovery): a detected table neither
flavor produced gets one targeted, region-constrained stream pass at the
detector's box. If that yields data it is emitted as extracted; otherwise
(Camelot error on an empty region, or an empty result) it is emitted with
status `detected_not_extracted` â€” reported explicitly, never silently
dropped. The recovery can only upgrade a miss or no-op â€” never worse than
reporting it.

Camelot stays the source of truth for cell values; nothing here rewrites
them. State is in-memory for the length of a run; there is no database.
é    )ÚannotationsN)Ú	dataclass)ÚPath)ÚDictÚListÚLiteralÚOptionalÚSetÚTuple)Úlogger)ÚCompletenessAuditorÚextracted_span_ptsÚget_completenessÚ
page_wordsÚ
repair_boxÚround_off_gridÚtabular_bandsÚvalue_tokens)ÚDetectedTableÚTableDetectorÚget_detector)ÚGridLocatorÚLocatedTableÚget_grid_locator)Ú	LLMClient)ÚCorrespondenceProvenanceÚExtractedTableÚ
FilledCell)ÚCAMELOT_FLAVOR_TIMEOUT_SÚCamelotCandidateÚdf_to_cellsÚgrid_to_markdownÚis_content_emptyÚrender_pagesÚrun_camelot_flavors_parallel)ÚlatticeÚstreamgš™™™™™É?g      <@c                óh   • SSK Jn  UR                  U 5      R                  u  p4US-  U-  US-  U-  4$ )z©Page width/height in PDF points, from the rendered image and its
DPI. Camelot bboxes are in points; this lets us normalize them into
the detector's 0..1 top-left frame.
r   ©ÚImageç      R@)ÚPILr*   ÚopenÚsize)Ú
page_imageÚdpir*   ÚwÚhs        ÚJ/home/mande/repo/quber/src/quber/core/extractors/camelot_correspondence.pyÚpage_size_ptsr4   \   s8   € õ
 à�:‰:�jÓ!×&Ñ&�D€AØˆt‰8�c‰>˜1˜t™8 c™>Ð)Ð)ó    c                ó’   • U u  p4pV[        X55      U-  n[        X55      U-  n[        XF5      [        XF5      p©SX¢-  -
  nSX’-  -
  nX{XŒ4$ )ztConvert a Camelot bbox (PDF points, bottom-left origin) to the
detector's frame (normalized 0..1, top-left origin).
ç      ð?©ÚminÚmax)ÚbboxÚ
page_w_ptsÚ
page_h_ptsÚx1Úy1Úx2Úy2Úx_leftÚx_rightÚy_bottom_ptsÚ	y_top_ptsÚtopÚbottoms                r3   Úcamelot_bbox_to_normrH   g   s]   € ð �N€BˆBÜ�‹[˜:Ñ%€FÜ�"‹k˜JÑ&€GÜ! "›k¬3¨r«;�)Ø
�	Ñ&Ñ
&€CØ�<Ñ,Ñ,€FØ˜Ð)Ð)r5   c                ó  • [        U S   US   5      [        U S   US   5      p2[        U S   US   5      [        U S   US   5      pT[        SXB-
  5      [        SXS-
  5      -  n[        SUS   US   -
  US   US   -
  -  5      nXg-  $ )ab  How much of the DETECTED box the chunk covers: intersection area as
a fraction of the detected box's area. Both rectangles are normalized
0..1 top-left.

We measure against the detected box (not the chunk) so the metric
answers "does this chunk fill this table" and is comparable across
chunks of different sizes when picking the best match for a table.
r   é   é   é   ç        g•Ö&è.>©r:   r9   )ÚchunkÚdetÚix1Úiy1Úix2Úiy2ÚinterÚdet_areas           r3   Úcoverage_fractionrW   v   sœ   € ô �5˜‘8˜S ™VÓ$¤c¨%°©(°C¸±FÓ&;ˆÜ�5˜‘8˜S ™VÓ$¤c¨%°©(°C¸±FÓ&;ˆÜ��S‘YÓ¤# c¨3©9Ó"5Ñ5€EÜ�4˜#˜a™& 3 q¡6™/¨c°!©f°s¸1±v©oÑ>Ó?€HØÑÐr5   c                ó   • X   nUR                   c  gUR                   u  pEpg[        XW5      n[        XW5      n	US:”  a  XS-
     R                   OSn
U
b$  [        U
S   U
S   5      n[        XˆU-   S-  5      nOX‚-
  nUS-   [        U 5      :  a  XS-      R                   OSnUb$  [        US   US   5      n[        X™U-   S-  5      n	OX’-   n	XHXi4$ )aŠ  The crop box for the table at index `di`, clamped vertically so it
does not bleed into the adjacent detected tables.

`detected` is in top-to-bottom order. The completeness audit checks
the table's top/bottom edges, so a crop that includes a neighbor's
rows makes it read the neighbor as a continuation. We split the gutter
to each neighbor's midpoint; only the outer edges keep the small pad.
Nr   rJ   rL   rK   )r;   r9   r:   Úlen)ÚdetectedÚdiÚpadÚdr>   r?   r@   rA   rF   rG   Ú	prev_bboxÚprev_bottomÚ	next_bboxÚnext_tops                 r3   Úneighbor_bounded_bboxrb   ˆ   sè   € ð 	‰€AØ‡v�v�~ØØ—V‘V�N€BˆBÜ
ˆb‹+€CÜ�‹[€FØ)+¨a«�˜a™Ñ ×%Ò%°T€IØÑÜ˜) A™,¨	°!©Ó5ˆÜ�#˜kÑ)¨QÑ.Ó/‰à‰iˆØ)+¨a©´#°h³-Ó)?�˜a™Ñ ×%Ò%ÀT€IØÑÜ�y ‘| Y¨q¡\Ó2ˆÜ�V xÑ/°1Ñ4Ó5‰à‘ˆØ�RÐ Ð r5   c                óú   • U u  p4pV[        S[        X55      5      U-  n[        S[        X55      5      U-  nS[        S[        XF5      5      -
  U-  n	S[        S[        XF5      5      -
  U-  n
US SU	S SUS SU
S 3$ )z³Inverse of camelot_bbox_to_norm: a normalized 0..1 top-left box ->
a Camelot `table_areas` string 'x1,y1,x2,y2' in PDF points (origin
bottom-left, so y1=top is the larger value).
rM   r7   z.1fÚ,rN   )r;   r<   r=   r>   rF   r@   rG   ÚleftÚrightÚtop_ptsÚ
bottom_ptss              r3   Únorm_bbox_to_table_areari   ¨   s”   € ð Ñ€BˆRÜˆs”C˜“KÓ  :Ñ-€DÜ�”S˜“[Ó! JÑ.€EØ”S˜œc #Ó.Ó/Ñ/°:Ñ=€GØœ˜C¤ SÓ!1Ó2Ñ2°jÑ@€JØ�3ˆZ�q˜ ˜ Q u¨S k°°:¸cÐ2BÐCÐCr5   c                ó„  • SSK nUR                  U [        U5      SU/S9nU(       d  gUS   n[        USS5      (       a  [	        UR
                  5      OSn[        US0 5      =(       d    0 n[        UR                  5      n	[        SU SU 3SUU[        UR                  S	S
5      =(       d    S
5      U	[        U	5      S9$ )us  Run a single region-constrained Camelot stream pass. Returns the
first table found in the region, or None if Camelot found none. Imports
camelot lazily (stream needs no OpenCV) and runs in-process; intended
to be called via asyncio.to_thread. Raises on Camelot-internal errors
(e.g. an empty region) â€” the caller guards and reports the table as
detected_not_extracted.
r   Nr'   )ÚpagesÚflavorÚtable_areasÚ_bboxÚparsing_reportz
recovery-pz-oÚaccuracyrM   )Úcandidate_idrl   Úpager;   rp   ÚcellsÚmarkdown)ÚcamelotÚread_pdfÚstrÚgetattrÚtuplern   r!   Údfr    ÚfloatÚgetr"   )
Ú
source_strrr   ÚareaÚordinalru   ÚtablesÚtr;   Úreportrs   s
             r3   Úcamelot_targetedrƒ   ·   s¿   € ó à×Ñ˜j´°D³	À(ÐY]ÐX^ÐÐ_€FÞØØˆq‰	€AÜ$ Q¨°×6Ñ6Œ5�—‘Œ>¸D€DÜ�QÐ(¨"Ó-×3°€FÜ˜Ÿ™Ó€EÜØ! $  r¨'¨Ð3ØØØÜ�v—z‘z *¨cÓ2×9°cÓ:ØÜ! %Ó(ñð r5   c                óR   • U R                   c  [        S5      $ U R                   S   * $ )zºSort key for top-to-bottom page order. Camelot bbox is in PDF
points with a bottom-left origin, so a larger top-y sits higher on
the page; we negate it. Chunks without a bbox sort last.
ÚinfrL   )r;   r{   )Úcands    r3   Ú	chunk_topr‡   Ó   s(   € ð
 ‡y�yÑÜ�U‹|ÐØ�I‰I�a‰Lˆ=Ðr5   c           	     ó�   • / nU  H8  nUR                  UR                   Vs/ s H  n[        U5      PM     sn5        M:     U$ s  snf )zÿConcatenate chunk cell grids in page order, values untouched. The
structured grid is the canonical intermediate: assembly, the
completeness audit and the fill all work on it, and markdown is
rendered once at the output. Camelot stays the source of truth.
)Úextendrs   Úlist)ÚchunksÚrowsÚcÚrs       r3   Úassemble_cellsr�   Ý   s@   € ð €DÛˆØ�‰ a§g¢gÓ.¢g ”T˜!–W¡gÑ.Ö/ñ à€Kùò /s   ¡A
c                óô   ^ ^• [        [        T 5      5       Vs/ s H  o3U;  d  M
  UPM     nnU(       d  gUc  US   $ [        US   US   5      [        US   US   5      -   S-  m[        UUU 4S jS9$ s  snf )an  Pick the unconsumed grid-located region best matching a detected table.

The detector's box drifts, but its vertical neighbourhood is roughly right
even when its extent is wrong, so we pair by nearest region center-y. When
the detector gave no box, fall back to reading order (first unconsumed).
Returns an index into `located`, or None if all regions are consumed.
Nr   rJ   rL   ç       @c                ól   >• [        TU    R                  S   TU    R                  S   -   S-  T-
  5      $ )NrJ   rL   r‘   )ÚabsÚregion)ÚiÚcenterÚlocateds    €€r3   Ú<lambda>Ú%nearest_grid_region.<locals>.<lambda>û   s:   ø€ ¬¨g°a©j×.?Ñ.?ÀÑ.BÀWÈQÁZ×EVÑEVÐWXÑEYÑ.YÐ]`Ñ-`ÐciÑ-iÔ)jr5   ©Úkey)ÚrangerY   r9   r:   )r—   ÚconsumedÚdetector_bboxr•   Ú
candidatesr–   s   `    @r3   Únearest_grid_regionr    é   s†   ù€ ô #¤3 w£<Ô0ÓFÒ0˜¸XÑ4E—!Ñ0€JÐFÞØØÑØ˜!‰}ÐÜ�- Ñ" M°!Ñ$4Ó5¼¸MÈ!Ñ<LÈmÐ\]ÑN^Ó8_Ñ_ÐcfÑf€FÜˆzÕjÑkÐkùò Gs
   ™	A5¦A5c                ó„   • U u  p4pV[        X55      U-
  U[        XF5      -
  U-
  [        X55      U-   U[        XF5      -
  U-   4$ )zªCamelot bbox (PDF points, bottom-left origin) -> a padded (left, top,
right, bottom) box in the top-left point frame used by PyMuPDF words and by
the rendered page image.r8   )r;   r=   r\   r>   r?   r@   rA   s          r3   Úbbox_to_top_leftr¢     sQ   € ð �N€BˆBäˆB‹�cÑØ”S˜“[Ñ  3Ñ&ÜˆB‹�cÑØ”S˜“[Ñ  3Ñ&ð	ð r5   c                óê  • Uu  p#pEU  Vs/ s H0  ofS   U:¼  d  M  US   U::  d  M  US   U:¼  d  M#  US   U::  d  M.  UPM2     nnUR                  S S9  / nSn	/ n
U HY  u  p¼pÞnU	b  [        XÉ-
  5      S:”  a-  U
(       a   UR                  S	R                  U
5      5        U/UpšMH  U
R                  U5        M[     U
(       a   UR                  S	R                  U
5      5        S
R                  U5      $ s  snf )z½Text-layer words inside the region (top-left point frame), grouped into
lines top-to-bottom, left-to-right. This is the value 'well' for the table,
scoped so no adjacent table can bleed in.r   rK   rJ   rL   c                ó.   • [        U S   S-  5      U S   4$ )NrJ   rL   r   )Úround)r1   s    r3   r˜   Ú%region_text_in_bbox.<locals>.<lambda>  s   € œE ! A¡$¨¡(›O¨Q¨q©TÑ2r5   rš   Né   Ú Ú
)Úsortr“   ÚappendÚjoin)Úwordsr”   re   rF   rf   rG   r1   ÚinsÚlinesÚcur_yÚcurÚ_x0Úy0Ú_x1Ú_y1Útxts                   r3   Úregion_text_in_bboxr·     sí   € ð  &Ñ€DˆuÙÓ
a’e� ™t t™|‹1°°!±¸±‹1À!ÀAÁ$È#Á+‹1ÐRSÐTUÑRVÐZ`ÑR`�1‘e€CÐ
aØ‡H�HÑ2€HÑ3Ø€EØ!€EØ€CÛ"%Ñˆ�˜3Ø‰=œC ¡
›O¨aÓ/ÞØ—‘˜SŸX™X c›]Ô+Ø˜ ’à�J‰J�sŽOñ #&ö Ø�‰�S—X‘X˜c“]Ô#Ø�9‰9�UÓÐùò bs   ŠC0šC0¥C0°C0»C0c           
     óX  • SSK Jn  US-  nUu  pVpxUR                  U 5      n	U	R                  [	        [        SXT-  5      5      [	        [        SXd-  5      5      [	        Xt-  5      [	        X„-  5      45      n
[        R                  " 5       nU
R                  USS9  UR                  5       $ )z–Crop the rendered page PNG to the table region (top-left points -> pixels
at `dpi`). This cropped image is the structural arbiter for the vetting LLM.r   r)   r+   rM   ÚPNG)Úformat)
r,   r*   r-   ÚcropÚintr:   ÚioÚBytesIOÚsaveÚgetvalue)r/   r”   r0   r*   Úsre   rF   rf   rG   Úimgr»   Úbufs               r3   Úcrop_region_pngrÄ   &  s’   € õ àˆd‰
€AØ%Ñ€DˆuØ
�*‰*�ZÓ
 €CØ�8‰8”Sœ˜S $¡(Ó+Ó,¬c´#°c¸3¹7Ó2CÓ.DÄcÈ%É)ÃnÔVYÐZ`ÑZdÓVeÐfÓg€DÜ
�*Š*‹,€CØ‡I�Iˆc˜%€IÑ Ø�<‰<‹>Ðr5   c                ób   • [        U 5       Vs1 s H  oR                  SS5      iM     sn$ s  snf )a  Normalized value tokens for grounding. `value_tokens` strips $ , ( ) but
NOT %, so we drop % too: an output '31.6%' must match a page-text '31.6'.
This is presence-grounding (is the figure in the source), not literal-drift
detection, so dropping % is correct.Ú%Ú )r   Úreplace)Útextr�   s     r3   Úgrounding_tokensrÊ   4  s,   € ô
 )5°TÔ(:Ó;Ò(: 1�I‰I�c˜2ÖÑ(:Ñ;Ð;ùÒ;s   Ž,T)Úfrozenc                  óL   • \ rS rSr% SrS\S'   S\S'   S\S'   S\S'   S	\S
'   Srg)ÚStructureCorrectioni<  aŽ  Output-stage structure-correction result threaded onto make_extracted.

`markdown` is the presentation render to emit -- the LLM's corrected
markdown when accepted, else the deterministic grid render -- and
`llm_corrected` records whether it differs from that grid render. The
structured grid cells remain the value source of record; only the
rendered presentation and the heading metadata change.
rw   ÚtitleÚsubtitleú	List[str]Ú	footnotesrt   ÚboolÚllm_corrected© N)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__Ú__annotations__Ú__static_attributes__rÔ   r5   r3   rÍ   rÍ   <  s$   ‡ ñð ƒJØƒMØÓØƒMØÖr5   rÍ   c                  óÚ  • \ rS rSr% S\S'   S\S'   S\S'   S\S	'   S\S
'   S\S'   S\S'   S\S'   S\S'   S\S'   S\S'   S\S'   S\S'   S\S'   SSSSSSSSSS\SS4                           S$S jjrS%S jr            S&S jr            S'S jr	                    S(S  jr
      S)                           S*S! jjrS%S" jrS#rg)+ÚCamelotCorrespondenceExtractoriN  r   Údetectorr   Úcompletenessr¼   r0   rÒ   Úrun_completenessÚrun_recoveryÚrun_fillÚrun_box_repairÚrun_grid_recoveryúOptional[GridLocator]Úgrid_locatorÚmax_concurrentr{   Úflavor_timeout_súOptional[LLMClient]ÚllmÚrun_llm_correctionzOptional[asyncio.Semaphore]Úcorrect_semNéÈ   Té   c                óö   • U=(       d
    [        5       U l        U=(       d
    [        5       U l        X0l        X@l        XPl        X`l        Xpl        X€l	        X�l
        X l        X°l        XÀl        XÐl        S U l        g ©N)r   rÞ   r   rß   r0   rà   rá   râ   rã   rä   ræ   rç   rè   rê   rë   rì   )ÚselfrÞ   rß   r0   rà   rá   râ   rã   rä   ræ   rç   rè   rê   rë   s                 r3   Ú__init__Ú'CamelotCorrespondenceExtractor.__init__^  sp   € ð  !×2¤L£NˆŒØ(×>Ô,<Ó,>ˆÔØŒØ 0ÔØ(ÔØ ŒØ,ÔØ!2Ôð )ÔØ,ÔØ 0Ôð ŒØ"4Ôð  ˆÕr5   c           
   ƒ  ó„  ^ ^^^^^^#   • [        T5      mTR                  5       (       d  [        T5      e[        R                  " SS9 n[        U5      n[        TT R                  US9m[        R                  " [        TT R                  5      I S h  v•N nU Vs/ s H!  n[        UR                  5      (       a  M  UPM#     nn[        R                  " S[        U5      [!        S U 5       5      [!        S U 5       5      [        U5      5        0 mU H.  nTR#                  UR$                  / 5      R'                  U5        M0     [        R(                  " T R*                  5      mSUU U4S jjm[        R,                  " U4S j[/        S	[        T5      S	-   5       5       6 I S h  v•N n[1        U5      m[        R,                  " UUUU U4S
 j[/        S	[        T5      S	-   5       5       6 I S h  v•N nU V	V
s/ s H  o™  H  oªPM     M     sn
n	sS S S 5        $  GNŠs  snf  N| N4s  sn
n	f ! , (       d  f       g = f7f)Nzquber-camelot-corr-)Úprefix)r0   Úout_dirzQcamelot: {} chunks ({} lattice, {} stream), {} populated after empty-shell filterc              3  óH   #   • U  H  oR                   S :X  d  M  Sv •  M     g7f)r&   rJ   N©rl   ©Ú.0r�   s     r3   Ú	<genexpr>Ú@CamelotCorrespondenceExtractor.extract_tables.<locals>.<genexpr>“  s   é € ÐCšz˜!¯X©X¸Ñ-B—A‘Ašzùó   ‚"™	"c              3  óH   #   • U  H  oR                   S :X  d  M  Sv •  M     g7f)r'   rJ   Nrø   rù   s     r3   rû   rü   ”  s   é € ÐBšz˜!¯X©X¸Ñ-A—A‘Ašzùrý   c              “  óð   >#   • T IS h  v•N   TR                   R                  TU S-
     5      I S h  v•N nS S S 5      IS h  v•N   U WR                  4$  NK N$ N! , IS h  v•N  (       d  f       N+= f7f)NrJ   )rÞ   Údetectr€   )rr   ÚresÚpage_imagesrñ   Úsems     €€€r3   Údetect_pageÚBCamelotCorrespondenceExtractor.extract_tables.<locals>.detect_pagež  sT   øé € ßš3Ø $§¡× 4Ñ 4°[ÀÈÁÑ5JÓ K×K�C÷ Ÿ3à˜SŸZ™ZÐ'Ð'ñ ÙK÷ Ÿ3Ÿ3˜3üsS   ƒA6ŠA‹A6Ž%A³A´A¸A6ÁAÁA6ÁAÁA6ÁA3Á"A%Á#A3Á/A6c              3  ó4   >#   • U  H  nT" U5      v •  M     g 7frð   rÔ   )rú   Úpr  s     €r3   rû   rü   £  s   øé € Ð/gÒHfÀ1±¸A·°ÒHfùs   ƒrJ   c              3  óº   >#   • U  HP  nTR                  UTUS -
     [        TR                  U/ 5      S S9TR                  U/ 5      [        T5      S9v •  MR     g7f)rJ   c                ó   • U R                   $ rð   )r   )r]   s    r3   r˜   ÚICamelotCorrespondenceExtractor.extract_tables.<locals>.<genexpr>.<lambda>«  s   € ÐST×S\ÒS\r5   rš   )rr   r/   rZ   r‹   ÚsourceN)Úprocess_pageÚsortedr|   rw   )rú   r  Úby_page_chunksÚby_page_detectedr  rñ   r  s     €€€€€r3   rû   rü   §  sk   øé € ð 	ò <˜ð ×%Ñ%ØØ#.¨q°1©uÑ#5Ü!'Ð(8×(<Ñ(<¸QÀÓ(CÑI\Ñ!]Ø-×1Ñ1°!°RÓ8Ü" 6›{ð &õ ò <ùs   ƒAA)rr   r¼   ÚreturnzTuple[int, List[DetectedTable]])r   ÚexistsÚFileNotFoundErrorÚtempfileÚTemporaryDirectoryr$   r0   ÚasyncioÚ	to_threadr%   rè   r#   rt   r   ÚinforY   ÚsumÚ
setdefaultrr   r«   Ú	Semaphorerç   Úgatherrœ   Údict)rñ   r  ÚtmpdirÚtmprŸ   r�   Ú	populatedÚ
detectionsÚpage_resultsrr   r�   r  r  r  r  r  s   ``         @@@@@r3   Úextract_tablesÚ-CamelotCorrespondenceExtractor.extract_tablesƒ  sØ  þé € Ü�f“ˆØ�}‰}�‰Ü# FÓ+Ð+ä×(Ò(Ð0EÒFÈ&Ü�v“,ˆCÜ& v°4·8±8ÀSÑIˆKô  '×0Ò0Ô1MÈvÐW[×WlÑWlÓm×mˆJÙ$.ÓS¢J˜qÔ6FÀqÇzÁz×6RŸ¡JˆIÐSÜ�KŠKØcÜ�J“ÜÑC™zÓCÓCÜÑB™zÓBÓBÜ�I“ôð ACˆNÛ�Ø×)Ñ)¨!¯&©&°"Ó5×<Ñ<¸QÖ?ñ ô ×#Ò# D×$7Ñ$7Ó8ˆC÷(ñ (ô
  'Ÿ~š~Ô/gÌÈaÔQTÐU`ÓQaÐdeÑQeÔHfÓ/gÐh×hˆJÜ?CÀJÓ?OÐä!(§¢÷	ð 	ô # 1¤c¨+Ó&6¸Ñ&:Ô;ó	ð"÷ ˆLñ #/Ô=¢,˜$»°1’A¹‘A¡,Ò=÷U GÑFò nùÚSñ( iñùó >÷U GÕFüs{   ‰A I Á	A
H/ÂHÂH/ÂH Â>H ÃC$H/Æ(H%Æ)A	H/Ç2H'Ç3	H/Ç<H)ÈH/È
I ÈH/È H/È'H/È)H/È/
H=È9I c              ƒ  óX  #   • U(       d*  U(       a!  [         R                  " SU[        U5      5        / $ [        U Vs/ s H  ofR                  S:X  d  M  UPM     sn[
        S9n[        U Vs/ s H  ofR                  S:X  d  M  UPM     sn[
        S9n[        X R                  5      u  pšU R                  (       a�  [        S U 5       5      (       av  [        R                  " [        [        U5      U5      I S h  v•N u  p¼n[        U5      nU H5  nUR                  c  M  [!        UR                  XëU5      nUc  M.  UUl        M7     U H4  nUR                  b  M  [         R"                  " SUUR$                  5        M6     ['        5       n/ nSU4SU4/nU GH  u  nn[)        [        U5      5       Vs/ s H  nUU;  d  M  UPM     nnU(       a  U(       d  MC  [+        U5       VVs0 s H,  u  nnUUR                  b  [-        UR                  Xš5      OS _M.     nnn0 nU Hi  nUU   R                  nUc  M  Su  nnUR/                  5        H#  u  nnUc  M  [1        UU5      nUU:”  d  M  UUnnM%     Uc  MX  U[2        :¼  d  Md  UUU'   Mk     [)        [        U5      5       Vs0 s H  nU/ _M     n n[        U5       H  nU UU      R5                  U5        M     U R/                  5        Hò  u  nn![        U!5      S:¼  d  M  UU   n"U! Vs/ s H  nUU   R$                  PM     n#nU"R6                   V$s/ s H  n$[9        U$5      PM     n%n$U R;                  U%UU"R                  XQ5      I S h  v•N n&UR5                  U R=                  U"U%UU!S	      UUU"R>                  /S
SU#U&S9
5        URA                  U!5        [         R                  " SUU"R>                  U#5        Mô     [)        [        U5      5       Vs/ s H  nU U   (       a  M  UU   PM     n'nU H�  nUU;   d  UU;  a  M  UU   n[        U U   5      S:w  a  M*  UU   /n(U RC                  UU   [E        UU5      U(S	   U(U'UUUUS9	I S h  v•N n)UR5                  U)5        URG                  U5        Mƒ     GM	     S n*['        5       n+[)        [        U5      5       GH©  nUU;   a  M  UU   n[E        UU5      n,S n-U RH                  (       a^  U,b[  [K        U,Xš5      n. [        R                  " [L        XQU.UR$                  5      I S h  v•N n"U"b  [Q        U"RR                  5      (       d  U"n-U-Gc  U RT                  (       Ga  U*cH  U RV                  =(       d
    [Y        5       n0U0U l+        U0R[                  U[        U5      U5      I S h  v•N n*[]        U*U+UR                  5      n1U1b£  U+RG                  U15        U*U1   R^                  n2[K        U2Xš5      n. [        R                  " [L        XQU.UR$                  5      I S h  v•N n"U"bD  [Q        U"RR                  5      (       d*  U"n-U2n,[         R                  " SUUR$                  U1S-   5        U-b‡  [         R                  " SUUR$                  [        U-RR                  Ra                  5       5      5        UR5                  U RC                  UU,U-U-// SUUUS9	I S h  v•N 5        URG                  U5        GM6  [         R"                  " SUUR$                  URb                  S S 5        UR5                  [e        URb                  SUU[g        SUR$                  URb                  S9S95        GM¬     U$ s  snf s  snf  GNƒs  snf s  snnf s  snf s  snf s  sn$f  GN+s  snf  GN/ GNx! [N         a/  n/S n"[         R"                  " SXR$                  U/5         S n/A/GNªS n/A/ff = f GN7 GNÄ! [N         a/  n/S n"[         R"                  " SXR$                  U/5         S n/A/GNöS n/A/ff = f GNJ7f)Nz>page {}: detector found 0 tables; dropping {} unmatched chunksr&   rš   r'   c              3  ó<   #   • U  H  oR                   S Lv •  M     g 7frð   )r;   )rú   r]   s     r3   rû   Ú>CamelotCorrespondenceExtractor.process_page.<locals>.<genexpr>Ó  s   é € Ð&LÂ8¸a§v¡v°TÕ'9Â8ùs   ‚zJpage {}: detected table {} has no bbox; geometric matching cannot place it)NrM   rK   r   Ú	extractedT)
r†   rs   rZ   rl   r  Ú
source_idsÚstatusÚcombinedÚcombined_ordinalsÚ
correctionz'page {}: chunk {} combined -> tables {}rJ   )	rZ   Úregion_bboxÚprimaryÚmatched_chunksÚorphan_queuerl   r  rr   r/   z2page {}: targeted recovery raised for table {}: {}z9page {}: grid-relocation recovery raised for table {}: {}z=page {}: table {} RELOCATED via grid locator (grid region {})z=page {}: table {} RECOVERED via targeted extraction ({} rows)zupage {}: table {} '{}' DETECTED-NOT-EXTRACTED (detector found it; lattice, stream, and recovery all produced nothing)é<   rÇ   Údetected_not_extracted)r)  Údetected_ordinalÚdetected_description)rÎ   rt   rr   r  Úcorrespondence)4r   r  rY   r  rl   r‡   r4   r0   rã   Úanyr  r  r   r   r   r;   r   Úwarningr   Úsetrœ   Ú	enumeraterH   ÚitemsrW   ÚMATCH_FRACTIONr«   rs   rŠ   Úapply_structure_correctionÚmake_extractedrq   ÚupdateÚfinalizerb   Úaddrá   ri   rƒ   Ú	Exceptionr#   rt   rä   ræ   r   Úlocater    r”   Ú
splitlinesÚdescriptionr   r   )3rñ   rr   r/   rZ   r‹   r  r�   r&   r'   r<   r=   Úpw_wordsÚph_wordsr­   Úbandsr]   ÚrepairedÚcoveredÚresultsÚsourcesrl   Úflavor_chunksr[   Ú	remainingÚciÚchunk_normsÚ
best_chunkÚdbbÚbest_ciÚbest_covÚcnormÚcovÚtables_for_chunkÚdisr†   ÚordinalsrŽ   Úcombined_cellsr,  r0  r/  ÚtableÚgrid_locatedÚconsumed_gridr”   Ú	recoveredr~   ÚexcÚlocatorÚgiÚgrid_regions3                                                      r3   r  Ú+CamelotCorrespondenceExtractor.process_page´  së  é € ö ö Ü—’ØTÐVZÔ\_Ð`fÓ\gôð ˆIä¡VÓE¢V ¯x©x¸9Ñ/DŸ!¡VÑEÌ9ÑUˆÜ¡FÓC¢F˜q¯h©h¸(Ñ.BŸ¡FÑCÌÑSˆä!.¨z¿8¹8Ó!DÑˆ
ð ××¤3Ñ&LÁ8Ó&L×#LÑ#LÜ.5×.?Ò.?Ä
ÌDÐQWËLÐZ^Ó._×(_Ñ%ˆH Ü! %Ó(ˆEÛ�Ø—6‘6‘>ÙÜ% a§f¡f¨e¸xÓH�ØÓ'Ø%�A–Fñ ó ˆAØ�v‰v‹~Ü—’Ø`ØØ—I‘Iöñ ô  ›EˆØ(*ˆð ˜Ð Ø�vÐð@
ˆô &-Ñ!ˆF�MÜ&+¬C°«MÔ&:ÓPÒ&: ¸bÈÑ>OŸÑ&:ˆIÐPÞ¦MÙô ' }Ô5ôSâ5‘E�B˜ð ÈQÏVÉVÑM_Ô)¨!¯&©&°*ÔIÐeiÒiÙ5ð ñ Sð *,ˆJÛ�Ø˜r‘l×'Ñ'�Ø‘;ÙØ$-Ñ!�˜Ø!,×!2Ñ!2Ö!4‘I�B˜Ø‘}Ù Ü+¨E°3Ó7�CØ˜X•~Ø,/° '˜¡'ñ "5ð Ó&¨8´~Õ+EØ%,�J˜r“Nñ  ô  HMÌSÐQ^ÓM_ÔG`Ó5aÒG`À°b¸"²fÑG`ÐÐ5aÜ˜ZÖ(�Ø  ¨B¡Ñ0×7Ñ7¸Ö;ñ )ð
 ,×1Ñ1Ö3‘��CÜ�s“8˜q•=Ø(¨Ñ,�DÙ?BÓCºs¸ ¨¡× 4Ô 4¹s�HÐCØ7;·z²zÓ%B²z°!¤d¨1¦g±z�NÐ%BØ'+×'FÑ'FØ&¨
°D·I±I¸vó(÷ "�Jð —N‘NØ×+Ñ+Ø!%Ø"0Ø%-¨c°!©fÑ%5Ø#)Ø#)Ø(,×(9Ñ(9Ð':Ø#.Ø%)Ø.6Ø'1ð ,ð ôð —N‘N 3Ô'Ü—K’KÐ IÈ4ÐQU×QbÑQbÐdlÖmñ/ 4ô: 9>¼cÀ-Ó>PÔ8QÓnÒ8Q°"ÐYiÐjlÕYmÓ-˜M¨"Ô-Ñ8QˆLÐnó  �Ø˜“= B¨jÓ$8ÙØ ‘^�ÜÐ'¨Ñ+Ó,°Ó1ÙØ"/°Ñ"3Ð!4�Ø"Ÿm™mØ% b™\Ü 5°hÀÓ CØ*¨1Ñ-Ø#1Ø!-Ø!Ø!ØØ)ð ,ð 
÷ 
�ð —‘˜uÔ%Ø—‘˜B–ô'  ñM &-ðF 6:ˆÜ"%£%ˆäœ˜H›×&ˆBØ�W‹}ÙØ˜‘ˆAÜ*¨8°RÓ8ˆFà48ˆIØ× ×  VÑ%7Ü.¨v°zÓN�ðoÜ!(×!2Ò!2Ô3CÀVÐSWÐYZ×YbÑYbÓ!c×c�Dð Ñ#Ô,<¸T¿]¹]×,KÑ,KØ $�Ið Ò  T×%;×%;Ð%;ØÑ'Ø"×/Ñ/×EÔ3CÓ3E�GØ(/�DÔ%Ø)0¯©¸
ÄDÈÃLÐRVÓ)W×#W�LÜ(¨°}ÀaÇfÁfÓM�Ø‘>Ø!×%Ñ% bÔ)Ø".¨rÑ"2×"9Ñ"9�KÜ2°;À
ÓW�DðÜ%,×%6Ò%6Ô7GÈÐW[Ð]^×]fÑ]fÓ%g×g˜ð Ñ'Ô0@ÀÇÁ×0OÑ0OØ$(˜	Ø!,˜ÜŸšØ[Ø ØŸI™IØ ™Fô	ð Ñ$Ü—’ØSØØ—I‘IÜ˜	×*Ñ*×5Ñ5Ó7Ó8ô	ð —‘ØŸ-™-Ø!"Ø$*Ø )Ø(1 {Ø%'Ø'Ø%Ø!Ø#-ð (ð 
÷ 
ôð —‘˜B”Úä�NŠNðFàØ—	‘	Ø—‘˜c˜rÐ"ôð �N‰NÜØŸ-™-ØØØ!Ü#;Ø7Ø)*¯©Ø-.¯]©]ñ$ñ
÷ñ_ 'ðz ˆùòU FùÚCò )`ùò4 QùóSùò* 6bùò  DùÚ%Bò"ùò0 oò
òF døÜ ó oØ�DÜ—N’NÐ#WÐY]×_hÑ_hÐjm×nÒnûðoúò $Xò  høÜ$ó Ø#˜ÜŸšØWÐY]×_hÑ_hÐjm÷ò ûðúò.
ùsk  ‚;`*½]4Á]4Á`*Á-]9Â]9Â
A1`*Ã;]>Ã<>`*Ä>`*ÅA`*Æ6
^Ç^Ç
 `*Ç*3^ÈA`*É/	`*É<`*Ê`*Ê'^Ê4A`*Ì	`*Ì^Ì(`*Ì8^Í#`*Í0^Í1B
`*Ï;^Ð	^ÐA`*Ñ4^#Ñ5B`*Ô*^)Ô.^&Ô/^)Ô3A;`*Ö._%Ö/A
`*×:*_+Ø$_(Ø%_+Ø)B4`*Û`'
ÛB!`*Þ`*Þ`*Þ&^)Þ)
_"Þ3$_ß`*ß_"ß"`*ß(_+ß+
`$ß5$`à`*à`$à$`*c              ƒ  ó˜  #   • U R                   b  U R                  (       a  Ub  Uc  g[        U5      n[        U5      (       a  g[        R
                  " [        [        U5      U5      I Sh  v•N u  pxn	[        X85      n
[        Xš5      nU
S   [        SU
S   [        -
  5      U
S   U
S   4n [        R
                  " [        X,U R                  5      I Sh  v•N nU R"                  c%  [        R$                  " U R&                  5      U l        U R"                   ISh  v•N    U R                   R)                  XÖU5      I Sh  v•N nSSS5      ISh  v•N   Wb0  UR*                  (       a  UR*                  R-                  5       (       d  gUR*                  n[/        U5      [/        S	R1                  S
 U	 5       5      5      -  n[/        U5      U-
  nU(       a"  [        R2                  " SU[5        U5      5        g[7        UR8                  UR:                  [=        UR>                  5      UUU:g  S9$  GNÇ GN_! [         a!  n[        R                   " SX^5         SnAgSnAff = f GNI GN'! [         a2  n[        R                   " SX^5         SnASSS5      ISh  v•N    gSnAff = f GNY! , ISh  v•N  (       d  f       GNo= f7f)a¨  Output-stage structure vetting (QUE-233). The cropped table image is
the arbiter of STRUCTURE (column/header layout); Camelot's cells and the
page text layer are the only sources of VALUES. The LLM fixes Camelot's
structural errors -- a spurious empty column from stream over-
segmentation, a header split across rows, a header misaligned from its
values -- and recovers any row Camelot truncated from the text layer.

Everything is scoped to this table's bbox (crop + region text) so an
adjacent table can never bleed in. A grounding guard then rejects the
correction if it introduced any value absent from both Camelot's grid
and the page text layer -- never emit an invented figure; fall back to
the deterministic grid markdown.

Skipped when correction is disabled, the page image or bbox is missing,
or the grid render is empty. Bounded by `correct_sem`; any failure or
rejection returns None so callers render the grid as before.
Nr   rM   rJ   rK   rL   z%page {}: table region crop failed: {}z)page {}: LLM structure vetting failed: {}r¨   c              3  ó*   #   • U  H	  oS    v •  M     g7f)r§   NrÔ   )rú   r1   s     r3   rû   ÚLCamelotCorrespondenceExtractor.apply_structure_correction.<locals>.<genexpr>î  s   é € ÐG\ÒV[ÐQRÈ!ÎÒV[ùs   ‚zTpage {}: structure correction REJECTED (ungrounded values {}); keeping grid markdown)rÎ   rÏ   rÑ   rt   rÓ   ) rê   rë   r"   r#   r  r  r   r   r¢   r·   r:   ÚCAPTION_PAD_PTSrÄ   r0   rA  r   Úerrorrì   r  rç   Úvet_structurert   ÚstriprÊ   r¬   r7  r  rÍ   rÎ   rÏ   rŠ   rÑ   )rñ   rs   r/   r;   r  rr   Úgrid_mdÚ_pwr=   r­   r”   Úregion_textÚcrop_boxÚcrop_pngr^  r,  Ú	correctedÚallowedÚ
ungroundeds                      r3   r<  Ú9CamelotCorrespondenceExtractor.apply_structure_correction²  sS  é € ð2 �8‰8Ñ 4×#:×#:¸jÑ>PÐTXÑT`ØÜ" 5Ó)ˆÜ˜G×$Ñ$Øä'.×'8Ò'8¼ÄTÈ&Ã\ÐSWÓ'X×!XÑˆ˜Ü! $Ó3ˆÜ)¨%Ó8ˆð
 ˜1‘Iœs 3¨¨q©	´OÑ(CÓDÀfÈQÁiÐQWÐXYÑQZÐ[ˆð	Ü$×.Ò.¬À
ÐVZ×V^ÑV^Ó_×_ˆHð
 ×ÑÑ#Ü&×0Ò0°×1DÑ1DÓEˆDÔØ×#×#Ó#ðØ#'§8¡8×#9Ñ#9¸(È[Ó#Y×Y�
÷ $×#ð Ñ j×&9×&9¸j×>QÑ>Q×>WÑ>W×>YÑ>YØð
 ×'Ñ'ˆ	Ü" 7Ó+Ô.>¸s¿x¹xÑG\ÑV[ÓG\Ó?\Ó.]Ñ]ˆÜ% iÓ0°7Ñ:ˆ
ÞÜ�NŠNØfØÜ�zÓ"ôð
 ä"Ø×"Ñ"Ø×(Ñ(Ü˜:×/Ñ/Ó0ØØ# wÑ.ñ
ð 	
òO "Yò `øÜó 	Ü�LŠLÐ@À$ÔLÜûð	úò $âYøÜó Ü—’ÐHÈ$ÔTÛ÷ $×#Ñ#ûðú÷ $×#×#Ò#üsÛ   ‚A*K
Á,H3Á-A K
Â.)H9 ÃH6ÃH9 ÃAK
ÄI'ÄK
Ä"J/Ä$I-ÅI*ÅI-ÅK
ÅJ,ÅC K
È6H9 È9
I$ÉIÉK
ÉI$É$K
É*I-É-
J)É7J$ÊJ/ÊK
ÊJ ÊK
Ê$J)Ê)J/Ê,K
Ê/KÊ5J8Ê6KËK
c
              ƒ  óÌ  #   • Sn
S nSn[        U5      n/ n[        U5      nU R                  (       Gaµ  S n U R                  R	                  [        U5      UUU Vs/ s H  nUR                  PM     sn[        U5      S9I S h  v•N nUR                  UR                  pËU(       d  U(       d  O\UR                  S5      nUR                  U5        [        U5      n[        R                  " SUUR                  UR                  5        MÔ  U(       Gd¡  U R                   (       Ga�  UGb‹  UR"                  (       Gay  [$        R&                  " [(        [        U5      U5      I S h  v•N u  nnn[+        U Vs/ s H  nUR                  PM     snU5      nUGb  [-        UUUUR"                  5      u  nnU(       aû  UnU Vs/ s HM  n[/        UR0                  UR2                  UR4                  UR6                  UR8                  UR:                  S9PMO     nnU R                  R	                  [        U5      UUU Vs/ s H  nUR                  PM     sn[        U5      S9I S h  v•N nUR                  UR                  pË[        R                  " SUUR                  [=        U5      U(       a  SOS	5        U(       d.  S
n
[        R>                  " SUUR                  U=(       d    S5        U RA                  XùUR                  Xx5      I S h  v•N nU RC                  UUUUUU Vs/ s H  nUR                  PM     snU
UUUUS9$ s  snf  GNÃ GNçs  snf s  snf s  snf  Nù NTs  snf 7f)Nr'  rÇ   )r  rr   r-  Úextracted_bboxesÚassembled_markdownr   z>page {}: table {} truncated; extending with {} and re-auditing)ÚvalueÚcolumnÚ	row_labelÚedgeÚxÚyzEpage {}: table {} ROUNDED OFF; filled {} text-layer figure(s); now {}Úcompletezstill incompleteÚ
incompletez/page {}: table {} INCOMPLETE; {} (gap reported)zedge truncated)r†   rs   rZ   rl   r  r(  r)  Úcompleteness_completeÚcompleteness_gapÚfilled_cellsr,  )"rŠ   r�   rà   rß   Úauditr   r;   r"   r|  ÚgapÚpopr«   r   r  r   rq   râ   Úmissing_figuresr  r  r   r   r   r   rv  rw  rx  ry  rz  r{  rY   r7  r<  r=  )rñ   rZ   r-  r.  r/  r0  rl   r  rr   r/   r)  r|  r‚  ÚusedÚfilledrs   Úverdictr�   ÚnxtÚ_r=   r­   ÚspanÚ	new_cellsÚplacedr  Ú	reverdictr,  s                               r3   r?  Ú'CamelotCorrespondenceExtractor.finalize   s/  é € ð 6AˆØ#'ˆØˆÜ�NÓ#ˆØ#%ˆô ˜tÓ$ˆà× × Ð ð ˆGØØ $× 1Ñ 1× 7Ñ 7Ü ›<ØØ +Ù6:Ó%;²d° a§f¤f±dÑ%;Ü'7¸Ó'>ð !8ð !÷ �ð !(× 0Ñ 0°'·+±+˜#Þ¦<Øð #×&Ñ& qÓ)�Ø—‘˜CÔ Ü& tÓ,�Ü—’ØTØØ×$Ñ$Ø×$Ñ$ô	ñ# ÷<  §§ °'Ò2EÈ'×Ja×JaÐJaÜ-4×->Ò->¼zÌ4ÐPVË<ÐY]Ó-^×'^Ñ$��:˜uÜ)¹4Ó*@º4°a¨1¯6¬6¹4Ñ*@À*ÓM�ØÒ#Ü(6°u¸eÀTÈ7×KbÑKbÓ(cÑ%�I˜vÞØ )˜ñ &,ó
"ò &, ô 'Ø&'§g¡gØ'(§x¡xØ*+¯+©+Ø%&§V¡VØ"#§#¡#Ø"#§#¡#ôñ &,ð ð 
"ð +/×*;Ñ*;×*AÑ*AÜ#'¨£<Ø!%Ø(3Ù>BÓ-Cºd¸¨a¯f¬f¹dÑ-CÜ/?ÀÓ/Fð +Bð +÷ %˜	ð )2×(:Ñ(:¸I¿M¹M #ÜŸšØcØ Ø$×,Ñ,Ü ›KÞ*2™JÐ8Jôö Ø%�Ü—’ØEØØ×$Ñ$Ø×+Ð+ô	ð  ×:Ñ:¸5ÈgÏlÉlÐ\bÓi×iˆ
Ø×"Ñ"ØØØØØÙ04Ó5²¨1˜Ÿœ±Ñ5ØØ"*Ø ØØ!ð #ð 
ð 	
ùòK &<ò	ò< (_ùÚ*@ùò

"ùò .Dñ	%ñ2 jùò 6ùs�   ‚AM$ÁMÁ1M$ÂMÂCM$Å"M	Å#M$Å4MÆ
4M$Æ>AMÈ'M$È9MÉM$É!MÉ"B&M$ÌMÌ	M$Ì!MÌ7M$Í	M$ÍM$ÍM$ÍM$c                óØ  • U=(       d    / nUR                   nSn/ n[        U5      nSnUbX  UR                  =(       d    UR                   nUR                  n[	        UR
                  5      nUR                  nUR                  n[        UUUUUR                  UR                  UUUR                  U[        UUR                  UR                   UUU
U=(       d    / UU	[        U5      US9S9$ )NrÇ   F)r)  r3  r4  Úmatched_flavorÚsource_candidate_idsr*  r+  r~  r  Úfilled_from_text_layerr€  )rÎ   rÏ   rt   rÑ   rr   r;   rl   r  Úcamelot_accuracyrÓ   r5  )rD  r"   rÎ   rÏ   rŠ   rÑ   rt   rÓ   r   rr   r;   rp   r   r   rÒ   )rñ   r†   rs   rZ   rl   r  r(  r)  r~  r  r*  r+  r€  r,  rÎ   rÏ   rÑ   rt   rÓ   s                      r3   r=  Ú-CamelotCorrespondenceExtractor.make_extractedv  s÷   € ð  $×) rˆð ×$Ñ$ˆØˆØ!ˆ	Ü# EÓ*ˆØˆØÑ!Ø×$Ñ$×<¨×(<Ñ(<ˆEØ!×*Ñ*ˆHÜ˜Z×1Ñ1Ó2ˆIØ!×*Ñ*ˆHØ&×4Ñ4ˆMÜØØØØØ—‘Ø—‘ØØØ!Ÿ]™]Ø'Ü3ØØ!)×!1Ñ!1Ø%-×%9Ñ%9Ø%Ø%/Ø!Ø"3×"9°rØ&;Ø!1Ü'+¨LÓ'9Ø)ññ
ð 	
r5   c                óL   • [         R                  " U R                  U5      5      $ )zlSync entry point for callers without an event loop (CLI,
scripts). Wraps the async path with `asyncio.run`.
)r  Úrunr"  )rñ   r  s     r3   Úextract_tables_syncÚ2CamelotCorrespondenceExtractor.extract_tables_sync±  s   € ô �{Š{˜4×.Ñ.¨vÓ6Ó7Ð7r5   )rß   rì   rÞ   r0   rè   ræ   rê   rç   rã   rà   râ   rä   rë   rá   )rÞ   zOptional[TableDetector]rß   zOptional[CompletenessAuditor]r0   r¼   rà   rÒ   rá   rÒ   râ   rÒ   rã   rÒ   rä   rÒ   ræ   rå   rç   r¼   rè   r{   rê   ré   rë   rÒ   r  ÚNone)r  r   r  úList[ExtractedTable])rr   r¼   r/   r   rZ   úList[DetectedTable]r‹   úList[CamelotCandidate]r  rw   r  rš  )rs   úList[List[str]]r/   úOptional[Path]r;   ú+Optional[Tuple[float, float, float, float]]r  rw   rr   r¼   r  úOptional[StructureCorrection])rZ   r   r-  rŸ  r.  r    r/  rœ  r0  rœ  rl   ÚFlavorr  rw   rr   r¼   r/   rž  r  r   )NrÇ   FNNN)r†   r    rs   r�  rZ   r   rl   r¡  r  rw   r(  rÐ   r)  z"Literal['extracted', 'incomplete']r~  zOptional[bool]r  rw   r*  rÒ   r+  zOptional[List[int]]r€  zOptional[List[FilledCell]]r,  r   r  r   )rÕ   rÖ   r×   rØ   rÚ   r   rò   r"  r  r<  r?  r=  r—  rÛ   rÔ   r5   r3   rÝ   rÝ   N  s¾  ‡ ØÓØ%Ó%Ø	ƒHØÓØÓØƒNØÓØÓØ'Ó'ØÓØÓØ	ÓØÓØ,Ó,ð -1Ø6:ØØ!%Ø!ØØ#Ø"&Ø.2ØØ":Ø#'Ø#'ð# à)ð# ð 4ð# ð ð	# ð
 ð# ð ð# ð ð# ð ð# ð  ð# ð ,ð# ð ð# ð  ð# ð !ð# ð !ð# ð 
õ# ôJ/>ðb|àð|ð ð|ð &ð	|ð
 'ð|ð ð|ð 
ô|ð|L
àðL
ð #ðL
ð :ð	L
ð
 ðL
ð ðL
ð 
'ôL
ð\t
àðt
ð Aðt
ð "ð	t
ð
 /ðt
ð -ðt
ð ðt
ð ðt
ð ðt
ð #ðt
ð 
ôt
ð~ 15Ø "ØØ15Ø37Ø48ð9
àð9
ð ð9
ð  ð	9
ð
 ð9
ð ð9
ð ð9
ð 3ð9
ð  .ð9
ð ð9
ð ð9
ð /ð9
ð 1ð9
ð 2ð9
ð 
õ9
÷v8r5   rÝ   )r/   r   r0   r¼   r  zTuple[float, float])r;   ú!Tuple[float, float, float, float]r<   r{   r=   r{   r  r¢  )rO   r¢  rP   r¢  r  r{   )g{®Gáz”?)rZ   r›  r[   r¼   r\   r{   r  rŸ  )r;   r¢  r<   r{   r=   r{   r  rw   )
r}   rw   rr   r¼   r~   rw   r   r¼   r  zOptional[CamelotCandidate])r†   r    r  r{   )r‹   rœ  r  r�  )r—   zList[LocatedTable]r�   zset[int]rž   rŸ  r  zOptional[int])g      @)r;   r¢  r=   r{   r\   r{   r  r¢  )r­   zList[WordBox]r”   r¢  r  rw   )r/   r   r”   r¢  r0   r¼   r  Úbytes)rÉ   rw   r  zSet[str])GrÙ   Ú
__future__r   r  r½   r  Údataclassesr   Úpathlibr   Útypingr   r   r   r	   r
   r   Úlogurur   Úquber.agents.completenessr   r   r   r   r   r   r   r   Úquber.agents.detectorr   r   r   Úquber.agents.grid_locatorr   r   r   Úquber.agents.llm_clientr   Úquber.core.extractors.baser   r   r   Ú!quber.core.extractors.camelot_llmr   r    r!   r"   r#   r$   r%   r¡  r;  rf  r4   rH   rW   rb   ri   rƒ   r‡   r�   r    r{   rw   ÚWordBoxr¢   r·   rÄ   rÊ   rÍ   rÝ   rÔ   r5   r3   Ú<module>r°     sÎ  ðñ&õP #ã Û 	Û Ý !Ý ß <× <å ÷	÷ 	ó 	÷ MÑ Lß QÑ QÝ -ß [Ñ [÷÷ ñ ð 
Ð$Ñ	%€ð €ð
 €ô*ð*Ø
+ð*Ø9>ð*ØLQð*à&ô*ðØ,ðØ3Tðà
ôð& :>ð!Ø!ð!Ø'*ð!Ø16ð!à0õ!ð@DØ
+ðDØ9>ðDØLQðDàôDôô8ô	ðlØðlàðlð ?ðlð ô	lð* ��u˜e U¨CÐ/Ñ
0€ð NQðØ
+ðØ9>ðØEJðà&õôô,ô<ñ �$Ñ÷ð ó ð÷"g	8ò g	8r5   