
    Mi7@                         S r SSKrSSKrSSKJrJrJrJr  SSKJ	r	  SSK
Jr  SSKJrJr  SSKJrJr  SS	KJr   " S
 S5      rg)z
Link Extractor for Crawl4AI

Extracts head content from links discovered during crawling using URLSeeder's
efficient parallel processing and caching infrastructure.
    N)DictListOptionalAny   )AsyncLogger)AsyncUrlSeeder)SeedingConfigCrawlerRunConfig)LinksLink)calculate_total_scorec                   8   \ rS rSrSrSS\\   4S jjrS rS r	S r
S	 rSS
\S\S\4S jjrS\S\S\4S jrS\S\\\4   S\\   4S jrS\\   S\\\4   S\\\\4      4S jrS\\   S\S\\\4   S\\\\4      4S jrS\S\\\\4      S\S\4S jrSrg)LinkPreview   al  
Extracts head content from links using URLSeeder's parallel processing infrastructure.

This class provides intelligent link filtering and head content extraction with:
- Pattern-based inclusion/exclusion filtering
- Parallel processing with configurable concurrency
- Caching for performance
- BM25 relevance scoring
- Memory-safe processing for large link sets
Nloggerc                 ,    Xl         SU l        SU l        g)z^
Initialize the LinkPreview.

Args:
    logger: Optional logger instance for recording events
NF)r   seeder_owns_seeder)selfr   s     o/var/www/eduai.edurigo.com/storigo/production/storigo_env/lib/python3.13/site-packages/crawl4ai/link_preview.py__init__LinkPreview.__init__   s     04!    c                 B   #    U R                  5       I Sh  vN   U $  N7f)zAsync context manager entry.N)startr   s    r   
__aenter__LinkPreview.__aenter__)   s     jjl 	s   c                 @   #    U R                  5       I Sh  vN   g N7f)zAsync context manager exit.N)close)r   exc_typeexc_valexc_tbs       r   	__aexit__LinkPreview.__aexit__.   s     jjls   c                    #    U R                   (       dB  [        U R                  S9U l         U R                   R                  5       I Sh  vN   SU l        gg N7f)z"Initialize the URLSeeder instance.)r   NT)r   r	   r   r   r   r   s    r   r   LinkPreview.start2   sB     {{(<DK++((*** $D *s   AA	A
Ac                    #    U R                   (       aF  U R                  (       a4  U R                   R                  SSS5      I Sh  vN   SU l         SU l        ggg N7f)zClean up resources.NF)r   r   r%   r   s    r   r!   LinkPreview.close9   sI     ;;4,,++''dD999DK %D -;9s   AAAAlevelmessagetagc                     U R                   (       a7  [        U R                   US5      nU(       a  U" X#UR                  S0 5      S9  ggg)z%Helper method to safely log messages.Nparams)r,   r-   r/   )r   getattrget)r   r+   r,   r-   kwargs
log_methods         r   _logLinkPreview._log@   s>    ;; eT:J7FJJxQS<TU  r   linksconfigreturnc                   #    UR                   nU R                  5       I Sh  vN   U R                  X5      nU(       d  U R                  SS5        U$ U R                  SSS[	        U5      0S9  U R                  XC5      I Sh  vN nU R                  XU5      nU R                  SSS[	        U Vs/ s H  owR                  S	5      S
:X  d  M  UPM     sn5      0S9  U$  N N]s  snf 7f)a  
Extract head content for filtered links and attach to Link objects.

Args:
    links: Links object containing internal and external links
    config: CrawlerRunConfig with link_preview_config settings
    
Returns:
    Links object with head_data attached to filtered Link objects
Ninfoz#No links matched filtering criteriaz2Extracting head content for {count} filtered linkscountr/   z9Completed head extraction for links, {success} successfulsuccessstatusvalid)link_preview_configr   _filter_linksr4   len_extract_heads_parallel_merge_head_datar1   )r   r6   r7   link_configfiltered_urlshead_resultsupdated_linksrs           r   extract_link_headsLinkPreview.extract_link_headsG   s      00 jjl **5>IIfCDL		&N!3}#56 	 	8 "99-UU --e6J		&U#S\)`\UU8_X_E_!\)`%ab 	 	d + 	 V *as:    C(CA C(C!-C(1C#C#C(!C(#C(rE   c                   ^ / nUR                   (       an  UR                  UR                   Vs/ s H!  oDR                  (       d  M  UR                  PM#     sn5        U R	                  SSS[        UR                  5      0S9  UR                  (       an  UR                  UR                   Vs/ s H!  oDR                  (       d  M  UR                  PM#     sn5        U R	                  SSS[        UR                  5      0S9  UR                  nU(       aK  U V^s/ s H!  m[        U4S jU 5       5      (       d  M  TPM#     nnU R	                  SSS[        U5      0S9  UR                  nU(       aK  U V^s/ s H!  m[        U4S jU 5       5      (       a  M  TPM#     nnU R	                  SS	S[        U5      0S9  UR                  nUS
:  a'  [        U5      U:  a  USU nU R	                  SSSU0S9  [        5       n	/ n
U H-  mTU	;  d  M  U	R                  T5        U
R                  T5        M/     U R	                  SSS[        U
5      0S9  U
$ s  snf s  snf s  snf s  snf )z
Filter links based on configuration parameters.

Args:
    links: Links object containing internal and external links
    link_config: Configuration dictionary for link extraction
    
Returns:
    List of filtered URL strings
debugzAdded {count} internal linksr;   r<   zAdded {count} external linksc              3   R   >#    U  H  n[         R                   " TU5      v   M     g 7fNfnmatch.0patternurls     r   	<genexpr>,LinkPreview._filter_links.<locals>.<genexpr>   s!     UDTwsG44DT   $'z,After include patterns: {count} links remainc              3   R   >#    U  H  n[         R                   " TU5      v   M     g 7frO   rP   rR   s     r   rV   rW      s!     YHXW7??388HXrX   z,After exclude patterns: {count} links remainr   NzLimited to {max_links} links	max_linksz)Final filtered URLs: {count} unique links)include_internalextendinternalhrefr4   rB   include_externalexternalinclude_patternsanyexclude_patternsrZ   setaddappend)r   r6   rE   rF   linkra   rU   rc   rZ   seenunique_urlss         `    r   rA   LinkPreview._filter_linksp   sR     ''  !T)))$))!TUIIg=%s5>>':;  = ''  !T)))$))!TUIIg=%s5>>':;  = '77,,UDTUU }   IIgM%s='9:  < '77,,YHXYY }   IIgM%s='9:  <  ))	q=S/);)*95MIIg=)95  7 u C$""3' !
 			'F!3{#34 	 	6 a "U "Us/   II-III<I8I#I#urlsc           
        #    UR                   nUR                  nU(       a  U R                  SS[        U5      US.S9  [	        SU[        USS5      UR                  UR                  UR                  (       a  SOSUS	9nU(       a  U R                  XU5      I Sh  vN nU$ U R                  R                  UUUUR                  S
9I Sh  vN nU$  N6 N7f)a  
Extract head content for URLs using URLSeeder's parallel processing.

Args:
    urls: List of URLs to process
    link_config: Configuration dictionary for link extraction
    
Returns:
    List of dictionaries with url, status, head_data, and optional relevance_score
r:   zNStarting batch processing: {total} links with {concurrency} concurrent workers)totalconcurrencyr<   Thits_per_secNbm25)extract_headrn   ro   queryscore_thresholdscoring_methodverboserk   r7   rn   timeout)ru   rn   r4   rB   r
   r0   rr   rs   _extract_with_progressr   extract_head_for_urlsrw   )r   rk   rE   ru   rn   seeding_configresultss          r   rC   #LinkPreview._extract_heads_parallel   s      %%!--IIfn'*4yM  O '# ndC##'77%0%6%66D
  77kZZG  !KK==%'#++	 >  G  [s$   BCC/CCCCrz   c           	      t  #    [        U5      nUR                  n[        SUS-  5      nSnSnSn	U R                  SS5        U R                  R                  UUUUR                  S9I Sh  vN n
U
 H)  nUS-  nUR                  S5      S	:X  a  US-  nM$  U	S-  n	M+     U R                  SS
UUUU	S.S9  U
$  NK7f)z-Extract head content with progress reporting.r   
   r   r:   zProcessing links in batches...rv   Nr>   r?   zcBatch processing completed: {completed}/{total} processed, {successful} successful, {failed} failed)	completedrm   
successfulfailedr<   )rB   rn   maxr4   r   ry   rw   r1   )r   rk   rz   rE   
total_urlsrn   
batch_sizer   r   r   r{   results               r   rx   "LinkPreview._extract_with_progress   s      Y
!--J",-
 	
 			&:; 99!#''	 : 
 
 FNIzz(#w.a
!  			&#,)$. &	 	 	 1
s   A(B8*B6+AB8original_linksrG   c                    0 nU H  nUR                  S5      nUR                  S0 5      UR                  SS5      UR                  S5      UR                  S5      S.nU(       a  XtU'   UR                  S5      nU(       d  M~  X:w  d  M  XtU'   M     / n	UR                   GHn  n
U
R                  U;   Ga  XJR                     nUR                  S5      n[        U
R                  U
R                  U
R
                  U
R                  US   US   UR                  S5      [        U
S	S
5      US9	nUb(  UR                  =(       d    0 Ul        XR                  S'   [        UR                  UR                  [        USS5      [        UR                  R                  5      S9Ul        U	R!                  U5        GM  [        [        U
S	S
5      S
[        USS5      [        UR                  R                  5      S9U
l        U	R!                  U
5        GMq     / nUR"                   GHn  n
U
R                  U;   Ga  XJR                     nUR                  S5      n[        U
R                  U
R                  U
R
                  U
R                  US   US   UR                  S5      [        U
S	S
5      US9	nUb(  UR                  =(       d    0 Ul        XR                  S'   [        UR                  UR                  [        USS5      [        UR                  R                  5      S9Ul        UR!                  U5        GM  [        [        U
S	S
5      S
[        USS5      [        UR                  R                  5      S9U
l        UR!                  U
5        GMq     [%        S X-    5       5      (       a#  S nU	R'                  USS9  UR'                  USS9  [)        U	US9$ )z
Merge head extraction results back into Link objects.

Args:
    original_links: Original Links object
    head_results: Results from head extraction
    
Returns:
    Links object with head_data attached to matching links
rU   	head_datar>   unknownerrorrelevance_score)r   r>   r   r   original_urlintrinsic_scoreN)	r^   texttitlebase_domainr   head_extraction_statushead_extraction_errorr   contextual_scorescore_linksF)r   r   score_links_enabledquery_providedc              3      #    U  H:  n[        US 5      =(       a"    UR                  =(       a    SUR                  ;   v   M<     g7f)r   r   Nhasattrr   )rS   rg   s     r   rV   /LinkPreview._merge_head_data.<locals>.<genexpr>  s=      @>4 t[)ddnndARVZVdVdAdd>s   AAc                     [        U S5      (       a0  U R                  (       a  SU R                  ;   a  U R                  S   $ g)Nr   r   g        r   )rg   s    r   get_relevance_score9LinkPreview._merge_head_data.<locals>.get_relevance_score  s7    4--$..EVZ^ZhZhEh>>*;<<r   T)keyreverse)r]   r`   )r1   r]   r^   r   r   r   r   r0   r   r   r   r   boolr@   rr   total_scorerf   r`   rb   sortr   )r   r   rG   r7   url_to_head_datar   rU   	head_infor   updated_internalrg   r   updated_linkupdated_externalr   s                  r   rD   LinkPreview._merge_head_data  s   " "F**U#C#ZZR8 **Xy9G,#)::.?#@	I (1%!::n5L| 31:. # "++Dyy,,,YY7	#,==1B#C #** $ 0 0'4+4X+>*3--*@$+D2CT$J%5
  $/-9-C-C-IrL*@P**+<= ,A$0$@$@%1%B%B(/u(M#'(B(B(H(H#I	,( !''5 $9$+D2CT$J%)(/u(M#'(B(B(H(H#I	$  !''-Q ,V "++Dyy,,,YY7	#,==1B#C #** $ 0 0'4+4X+>*3--*@$+D2CT$J%5
  $/-9-C-C-IrL*@P**+<= ,A$0$@$@%1%B%B(/u(M#'(B(B(H(H#I	,( !''5 $9$+D2CT$J%)(/u(M#'(B(B(H(H#I	$  !''-Q ,V  @+>@ @ @
 !!&94!H!!&94!H%%
 	
r   )r   r   r   rO   )LINK_EXTRACT)__name__
__module____qualname____firstlineno____doc__r   r   r   r   r%   r   r!   strr4   r   r   rJ   r   r   r   rA   rC   r
   rx   rD   __static_attributes__ r   r   r   r      sP   		"x4 	"
%&V# V V# V'' !' 
	'R?5 ?tCH~ ?$s) ?B-3i- #s(^- 
d38n		-^23i2 &2 #s(^	2
 
d38n	2hG
G
 4S>*G
 !	G

 
G
r   r   )r   asynciorQ   typingr   r   r   r   async_loggerr   async_url_seederr	   async_configsr
   r   modelsr   r   utilsr   r   r   r   r   <module>r      s3      , , % , :  (I
 I
r   