Ë
    §‘ˆj„  ã                   óÈ   — d Z ddlZddlmZ ddlmZ ddlmZ ddlm	Z	m
Z
  ej                  e«      Zdeded	efd
„Zded	efd„Zded	efd„Zdededed	dfd„Zdeded	efd„Zy)zÞEmbeds products once and caches the vectors on content_hash.

Phase 1 proved this mechanism: its second run over 218 products made zero model
calls. Re-pairing after a small catalog change must re-embed only what changed.
é    N)Úsql)Úget_db_connection)ÚNO_CONTENT_HASH)Ú_cosineÚ_embed_batchÚaÚbÚreturnc                 ó   — t        | |«      S ©N)r   )r   r	   s     ú>/var/www/html/strategist-ai/app/services/pairing/embeddings.pyÚcosiner      s   € Ü�1�a‹=Ðó    Úproductc                 ó  — t        d„ | j                  d«      xs g D «       «      }| j                  d«      xs d| j                  d«      xs d| j                  d«      xs ddj                  |«      g}dj                  d	„ |D «       «      S )
zzSorted, so attribute order -- which is not stable across runs -- cannot
    change the text and force a needless re-embed.c              3   óª   K  — | ]K  }|j                  d «      r8|j                  d«      �'|j                  d «      › d|j                  d«      › �–— ŒM y­w)ÚkeyÚvalueNÚ )Úget)Ú.0r   s     r   ú	<genexpr>z!embedding_text.<locals>.<genexpr>   sL   è ø€ ò 8àØ�5‰5�Œ<˜AŸE™E '›NÐ6ð �5‰5�‹<ˆ.˜˜!Ÿ%™% ›.Ð)Ô*ñ8ùs   ‚AAÚ
attributesÚnameÚ ÚdescriptionÚcategoryr   z. c              3   ód   K  — | ](  }|sŒ|j                  «       sŒ|j                  «       –— Œ* y ­wr   )Ústrip)r   Úps     r   r   z!embedding_text.<locals>.<genexpr>   s    è ø€ ÒA 1²°q·w±wµy�Q—W‘W—YÑAùs   ‚0Š0›0)Úsortedr   Újoin)r   r   Úpartss      r   Úembedding_textr$      s…   € ô ñ 8à—+‘+˜lÓ+Ò1¨rô8ó 8€Jð �[‰[˜Ó Ò& B¨¯©°MÓ(BÒ(HÀbØ�[‰[˜Ó$Ò*¨¨C¯H©H°ZÓ,@ðB€Eà�9‰9ÑA¨ÔAÓAÐAr   Ú	tenant_idc                 óÐ  — t        «       }	 |j                  «       5 }|j                  t        j                  d«      j                  t        j                  | «      «      «       |j                  «       D ���ci c]  \  }}}||t        |«      f“Œ c}}}cd d d «       |j                  «        S c c}}}w # 1 sw Y   nxY w	 |j                  «        y # |j                  «        w xY w)NzNSELECT product_key, content_hash, vector FROM {}.strategist_product_embeddings)
r   ÚcursorÚexecuter   ÚSQLÚformatÚ
IdentifierÚfetchallÚlistÚclose)r%   ÚconnÚcurr   Úhash_Úvectors         r   Úload_cachedr3   !   sÆ   € ÜÓ€Dð	Ø�[‰[‹]ð 	>˜cØ�K‰KœŸ™ð8ó÷ ‰f”S—^‘^ IÓ.Ó/ô1ð
 /2¯l©l«n÷>ð >Ù*˜˜U Fð ˜%¤ f£Ð.Ñ.ô >÷	>ð 	>ð 	�
‰
�ùô>÷	>ð 	>úð 	>ð 	�
‰
�øˆ�
‰
�ús5   ŒC œAB5Á7B.
ÂB5Â	C Â.B5Â5B>Â:C ÃC%Úproduct_keyr2   c                 óà  — t        «       }	 |j                  «       5 }|j                  t        j                  d«      j                  t        j                  | «      «      ||xs t        |f«       d d d «       |j                  «        |j                  «        y # 1 sw Y   Œ*xY w# t        $ r+ |j                  «        t        j                  d|d¬«       Y ŒPw xY w# |j                  «        w xY w)NzìINSERT INTO {}.strategist_product_embeddings (product_key, content_hash, vector) VALUES (%s, %s, %s) ON CONFLICT (product_key) DO UPDATE SET content_hash = EXCLUDED.content_hash, vector = EXCLUDED.vector, computed_at = CURRENT_TIMESTAMPz#Could not cache an embedding for %sT)Úexc_info)r   r'   r(   r   r)   r*   r+   r   ÚcommitÚ	ExceptionÚrollbackÚloggerÚerrorr.   )r%   r4   Úcontent_hashr2   r/   r0   s         r   Ústorer=   /   sÉ   € ÜÓ€DðØ�[‰[‹]ð 	H˜cØ�K‰KœŸ™ðLó÷ ‰f”S—^‘^ IÓ.Ó/Ø˜lÒ=¬o¸vÐFôH÷	Hð 	�‰Œð 	�
‰
�÷	Hð 	Hûô ò $Ø�‰ŒÜ�‰Ð:¸KØ"ð 	ö 	$ð$ûð
 	�
‰
�ús;   ŒB$ œABÁ/B$ ÂB!ÂB$ Â$1CÃC ÃCÃC ÃC-Úproductsc                 óŽ  — t        | «      }i g }}|D ]Z  }|d   }|j                  d«      xs t        }|j                  |«      }|r|d   |k(  r|d   r	|d   ||<   ŒJ|j                  |«       Œ\ |r™t	        |D �	cg c]  }	t        |	«      ‘Œ c}	| ¬«      }
t        |
«      t        |«      k7  r"t        j                  d| t        |«      «       |S t        ||
«      D ]-  \  }}|||d   <   t        | |d   |j                  d«      |«       Œ/ t        j                  d| t        |«      t        |«      z
  t        |«      «       |S c c}	w )Nr4   r<   r   é   )r%   zGEmbedding failed for %s; %d products will be scored on attributes alonez%%s: %d embeddings reused, %d computed)r3   r   r   Úappendr   r$   Úlenr:   r;   Úzipr=   Úinfo)r%   r>   ÚcachedÚvectorsÚstaler   r   ÚcurrentÚentryr    Úcomputedr2   s               r   Úvectors_forrK   D   sN  € Ü˜Ó#€FØ˜ˆU€Gàò 	"ˆØ�mÑ$ˆØ—+‘+˜nÓ-Ò@´ˆØ—
‘
˜3“ˆñ �U˜1‘X Ò(¨U°1ªXØ  ™8ˆG�CŠLà�L‰L˜Õ!ð	"ñ Ü¸EÖ B°q¤°Õ!2Ò BØ*3ô5ˆäˆx‹=œC ›JÒ&Ü�L‰Lð /Ø09¼3¸u»:ôGàˆNÜ" 5¨(Ó3ò 	7‰OˆG�VØ.4ˆG�G˜MÑ*Ñ+Ü�)˜W ]Ñ3Ø—+‘+˜nÓ-¨võ7ð	7ô
 ‡K�KÐ7Øœ3˜x›=¬3¨u«:Ñ5´s¸5³zôCà€Nùò !Cs   Á:E)Ú__doc__ÚloggingÚpsycopg2r   Úapp.services.infra.databaser   Úapp.services.enrichment.jobr   Úapp.services.catalog.productsr   r   Ú	getLoggerÚ__name__r:   r-   Úfloatr   ÚdictÚstrr$   r3   r=   rK   © r   r   ú<module>rX      s«   ðñó
 å å 9Ý 7ß ?à	ˆ×	Ñ	˜8Ó	$€ðˆdð �tð  ó ð	B˜Dð 	B Só 	Bð˜3ð  4ó ð�Sð  sð À$ð È4ó ð*˜3ð ¨$ð °4ô r   