
    i                        d Z ddlmZ ddl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 ddlmZmZ  ee          ZdZd	Zd
Z G d d          ZdS )u  
向量化服务 —— 批量生成文本嵌入向量，支持并发控制、自动重试和速率限制。
Batch embedding service with retry logic and rate limiting.

搜索查询的向量化结果会缓存到 Redis（TTL 1 小时），避免重复调用外部 API。
    )annotationsN)Any)EmbeddingClient)
get_logger)get_cached_embeddingset_cached_embedding      g       @c                  @    e Zd ZdZdeeeddddZddZddZ	ddZ
dS )EmbeddingServiceu  向量化服务，将文本列表分批发送到 Embedding API 生成向量，支持并发控制和失败重试。

    Generate embeddings in batches with error handling and retry logic.
    单条查询（embed_single）支持 Redis 缓存，避免重复调用外部 API。
    N   )redis
batch_sizemax_retriesretry_delaymax_concurrencyclientr   r   aioredis.Redis | Noner   intr   r   floatr   c               ~    || _         || _        || _        || _        || _        t          j        |          | _        d S )N)_client_redis_batch_size_max_retries_retry_delayasyncio	Semaphore
_semaphore)selfr   r   r   r   r   r   s          ,D:\work\zm-rag\backend\app\core\embedding.py__init__zEmbeddingService.__init__%   s@     %''!+O<<    texts	list[str]returnlist[list[float]]c                F   K   sg S  fdt          dt                     j                  D             }t                              dt                    t          |           j                    fdt          |          D             }t          j        |ddi d{V }g }t          |          D ]o\  }}t          |t                    r@t          
                    d	|t          |          
           t          d| d|           ||                    |           pt          |          t                    k    r/t          dt                     dt          |                     t                              dt          |                     |S )u  批量生成嵌入向量：按 batch_size 分批、控制并发数、失败自动重试。

        Generate embeddings for a list of chunk texts.

        Splits into batches, processes with controlled concurrency,
        and retries on failure.

        Args:
            texts: List of text strings to embed.

        Returns:
            List of embedding vectors (same order as input).

        Raises:
            RuntimeError: If any batch fails after all retries.
        c                4    g | ]}||j         z            S  )r   ).0ir    r$   s     r!   
<listcomp>z1EmbeddingService.embed_chunks.<locals>.<listcomp>M   s;     
 
 
 !a$***+
 
 
r#   r   embedding_start)total_textsbatchesr   c                B    g | ]\  }}                     ||          S r*   )_process_batch)r+   	batch_idxbatchr    s      r!   r-   z1EmbeddingService.embed_chunks.<locals>.<listcomp>Z   s=     
 
 
 	5 y11
 
 
r#   return_exceptionsTNbatch_embedding_failed)r4   errorBatch z embedding failed: z#Embedding count mismatch: expected z, got embedding_complete)total_vectors)rangelenr   loggerinfo	enumerater   gather
isinstanceBaseExceptionr7   strRuntimeErrorextend)r    r$   r0   tasksbatch_resultsall_vectorsidxresults   ``      r!   embed_chunkszEmbeddingService.embed_chunks6   s     &  	I
 
 
 
 
1c%jj$*:;;
 
 

 	E

LL'	 	 	
 	
 	

 
 
 
$-g$6$6
 
 
 &neLtLLLLLLLL *,$]33 
	' 
	'KC&-00 ,f++    
 #=S==V==  v&&&&{s5zz))*c%jj * *;''* *  
 	(K8H8HIIIr#   r3   c                  K   | j         4 d{V  d}t          d| j        dz             D ]}	 | j                            |           d{V }t
                              d|t          |          |           |c cddd          d{V  S # t          $ r}|}t
          	                    d||t          |                     || j        k     rE| j        d|dz
  z  z  }t          j        d|d	z            }t          j        ||z              d{V  Y d}~d}~ww xY wt!          d
| d| j         d|           # 1 d{V swxY w Y   dS )z(Process a single batch with retry logic.N   batch_embedded)r4   r$   attemptbatch_embed_retry)r4   rO   r7      r   g?r8   z failed after z
 retries: )r   r;   r   r   embed_textsr=   debugr<   	ExceptionwarningrC   r   randomuniformr   sleeprD   )	r    r$   r3   
last_errorrO   vectorsebackoffjitters	            r!   r2   zEmbeddingService._process_batchz   sS      ? 	 	 	 	 	 	 	 	+/J D$5$9:: > >>$(L$<$<U$C$CCCCCCCGLL('!%jj '	 !    #NN	 	 	 	 	 	 	 	 	 	 	 	 	 	 ! > > >!"JNN+' '!!ff	 #    !222 #'"3qWq[7I"J!'7S=!A!A%mGf,<=========>      $2C         7	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	s<   E AB:E 
D A=DE D   E  
E
E
textrC   list[float]c                $  K   | j         Ct          | j         |           d{V }|&t                              d|dd                    |S | j                            |           d{V }| j         t          | j         ||           d{V  |S )u   Embed a single text (convenience for query embedding).

        优先从 Redis 缓存读取（TTL 1 小时），缓存未命中时调用 API 并写入缓存。
        Checks Redis cache first (1h TTL); on miss, calls API and stores result.
        Nembedding_cache_hit(   )r^   )r   r   r=   rS   r   embed_queryr   )r    r^   cachedvectors       r!   embed_singlezEmbeddingService.embed_single   s       ;"/TBBBBBBBBF!2crcCCC |//55555555 ;"&t{D&AAAAAAAAAr#   )r   r   r   r   r   r   r   r   r   r   r   r   )r$   r%   r&   r'   )r$   r%   r3   r   r&   r'   )r^   rC   r&   r_   )__name__
__module____qualname____doc__DEFAULT_BATCH_SIZEMAX_RETRIESRETRY_DELAYr"   rK   r2   rf   r*   r#   r!   r   r      s          (,,&( = = = = = ="B B B BH" " " "H     r#   r   )rj   
__future__r   r   rV   typingr   redis.asyncioaioredis#app.infrastructure.embedding_clientr   app.utils.loggerr   app.utils.query_cacher   r   rg   r=   rk   rl   rm   r   r*   r#   r!   <module>ru      s     # " " " " "                     ? ? ? ? ? ? ' ' ' ' ' ' L L L L L L L L	H		
  T T T T T T T T T Tr#   