
    i                         d Z ddlZddlZddlZddlZ ej
                  e      ZdZdZ	dZ
dZdZdefd	Zd
ej                  dee   deee      fdZdedee   fdZdee   deee      fdZy)u   
embedding_service.py

OpenAI Embedding API를 사용하는 임베딩 서비스.
- 단일 텍스트 임베딩: get_embedding()
- 배치 임베딩: get_embeddings_batch()
    Nztext-embedding-3-smalli   d         returnc                  ^    t         j                  j                  d      } | st        d      | S )u   
    환경변수에서 OpenAI API 키를 읽어 반환한다.

    Raises:
        ValueError: OPENAI_API_KEY 환경변수가 설정되지 않은 경우.
    OPENAI_API_KEYu   OPENAI_API_KEY 환경변수가 설정되지 않았습니다. 올바른 API 키를 OPENAI_API_KEY 환경변수에 설정하세요.)osenvironget
ValueErrorapi_keys    G/home/jay/workspace/.worktrees/task-2116-dev1/libs/embedding_service.py_get_api_keyr      s4     jjnn-.G S
 	
 N    clienttextsc                 P   d}t        t              D ]O  }	 | j                  j                  |t        t
              }|j                  D cg c]  }|j                   }}|c S  t        j!                  dt               |J |c c}w # t        j                  $ rL}|}t        d|z  z  }t        j                  d|dz   t        |       t        j                  |       Y d}~d}~wt        j                  $ r,}|}t        j                  d|dz   t        |       Y d}~d}~ww xY w)u  
    OpenAI embeddings.create를 호출하며 에러 시 재시도한다.

    재시도 정책:
    - openai.RateLimitError (HTTP 429): 지수 백오프(1, 2, 4초) 후 재시도
    - openai.APIError: 최대 3회(초기 시도 포함) 재시도
    - 3회 모두 실패 시 원래 예외를 raise

    Args:
        client: OpenAI 클라이언트 인스턴스.
        texts: 임베딩할 텍스트 목록.

    Returns:
        임베딩 벡터 목록. 각 벡터는 1536차원 float 리스트.

    Raises:
        openai.APIError: 최대 재시도 횟수 초과 시.
        openai.RateLimitError: 최대 재시도 횟수 초과 시.
    N)inputmodel
dimensions   uF   Rate limit 에러 발생 (시도 %d/%d). %d초 후 재시도합니다.r   u$   API 에러 발생 (시도 %d/%d): %su@   최대 재시도 횟수(%d회) 초과. 에러를 raise합니다.)range_MAX_RETRIES
embeddingscreate_EMBEDDING_MODEL_EMBEDDING_DIMENSIONSdata	embeddingopenaiRateLimitError_BACKOFF_BASEloggerwarningtimesleepAPIErrorerror)	r   r   last_exceptionattemptresponseitemvectorsexcbackoffs	            r   _call_embeddings_with_retryr1   '   s   . (,N& 	((//&0 0 H
 FN]])ST$..)SG)SN> LLSUab%%%
5 *T $$ 		  N#q'z2GNNX!	 JJw 	 NNN6!	 	s6   4B	
BB	B		D%AC##D%9!D  D%textc                     t               }t        j                  |      }t        j	                  d| dd        t        || g      }|d   S )uM  
    단일 텍스트의 임베딩 벡터를 반환한다.

    Args:
        text: 임베딩할 텍스트 문자열.

    Returns:
        1536차원 float 리스트.

    Raises:
        ValueError: OPENAI_API_KEY 환경변수가 설정되지 않은 경우.
        openai.APIError: API 호출이 3회 모두 실패한 경우.
    r   u%   단일 텍스트 임베딩 요청: %rN2   r   )r   r!   OpenAIr$   debugr1   )r2   r   r   r.   s       r   get_embeddingr7   d   sF     nG]]7+F
LL8$s)D)&4&9G1:r   c           	      4   | sg S t               }t        j                  |      }g }t        |       }t	        d|t
              D ]R  }| ||t
        z    }t        j                  d|dz   |t        |      z   |       t        ||      }|j                  |       T |S )u  
    여러 텍스트의 임베딩 벡터를 배치로 반환한다.

    100개를 초과하는 경우 100개씩 분할하여 여러 번 API를 호출한다.

    Args:
        texts: 임베딩할 텍스트 문자열 목록.

    Returns:
        각 텍스트에 대응하는 1536차원 벡터 목록.
        입력이 빈 리스트인 경우 빈 리스트를 반환한다.

    Raises:
        ValueError: OPENAI_API_KEY 환경변수가 설정되지 않은 경우.
        openai.APIError: API 호출이 3회 모두 실패한 경우.
    r   r   u*   배치 임베딩 요청: %d~%d / 총 %d개r   )
r   r!   r5   lenr   _BATCH_SIZEr$   r6   r1   extend)r   r   r   all_vectorstotalbatch_startbatchbatch_vectorss           r   get_embeddings_batchrA   z   s    " 	nG]]7+F%'KJEQ{3 	*kK+$=>8!O#e*$		
 4FEB=)	* r   )__doc__loggingr	   r&   r!   	getLogger__name__r$   r   r   r:   r   r#   strr   r5   listfloatr1   r7   rA    r   r   <module>rJ      s     	  			8	$+  c :MM:9: 
$u+:z U ,%S	 %d4;.? %r   