Ë
    uPêjê2  ã                  óÞ   — d Z ddlmZ ddlZddlmZmZ ddlmZm	Z	m
Z
mZ ddlZddlmZ ddlmZ ddlmZmZ dd	lmZ dd
lmZmZ ddlmZ ddlmZ ddlmZmZ erddlm Z   G d„ de«      Z!y)z©
Base RAG Ingestion class.

Provides abstract methods for:
- OCR
- Chunking
- Embedding
- Vector Store operations

Providers can inherit and override methods as needed.
é    )ÚannotationsN)ÚABCÚabstractmethod)ÚTYPE_CHECKINGÚAnyÚFinalÚcast)Úverbose_logger)Úuuid4)ÚDEFAULT_CHUNK_OVERLAPÚDEFAULT_CHUNK_SIZE)Úasync_safe_get)Úget_async_httpx_clientÚhttpxSpecialProvider)Úextract_text_from_pdf)ÚRecursiveCharacterTextSplitter)ÚRAGIngestOptionsÚRAGIngestResponse)ÚRouterc                  óô   — e Zd ZU dZdZded<   	 d	 	 	 dd„Zdd„Zedd„«       Z		 	 	 d	 	 	 	 	 	 	 dd	„Z
	 	 	 	 	 	 dd
„Z	 	 	 	 	 	 	 	 dd„Z	 	 	 	 dd„Ze	 d	 	 	 	 	 	 	 	 	 	 	 	 	 dd„«       Z	 	 	 d	 	 	 	 	 	 	 dd„Zy)ÚBaseRAGIngestiona  
    Base class for RAG ingestion.

    Providers should inherit from this class and override methods as needed.
    For example, OpenAI handles embedding internally when attaching files to
    vector stores, so it overrides the embedding step to be a no-op.
    FÚboolÚsupports_existing_file_idNc                óÀ  — || _         || _        dt        «       › �| _        |j	                  d«      | _        t        t        t        t        f   |j	                  d«      xs ddi«      | _
        |j	                  d«      | _        t        t        t        t        f   |j	                  d«      xs i «      | _        |j	                  d«      | _        | j                  «        y )	NÚingest_ÚocrÚchunking_strategyÚtypeÚautoÚ	embeddingÚvector_storeÚname)Úingest_optionsÚrouterr   Ú	ingest_idÚgetÚ
ocr_configr	   ÚdictÚstrr   r   Úembedding_configÚvector_store_configÚingest_nameÚ_load_credentials_from_config)Úselfr#   r$   s      úi/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/rag/ingestion/base_ingestion.pyÚ__init__zBaseRAGIngestion.__init__/   sÇ   € ð
 -ˆÔØˆŒØ"¤5£7 )Ð,ˆŒð )×,Ñ,¨UÓ3ˆŒÜ15Ü””c�‰NØ×ÑÐ2Ó3ÒG¸ÀÐ7Gó2
ˆÔð !/× 2Ñ 2°;Ó ?ˆÔÜ37¼¼SÄ#¸X¹È×HZÑHZÐ[iÓHjÒHpÐnpÓ3qˆÔ Ø)×-Ñ-¨fÓ5ˆÔð 	×*Ñ*Õ,ó    c                ó4  — ddl m} | j                  j                  d«      }|rut        j
                  rd|j                  |«      }|sy|j                  «       D ]  \  }}|| j                  |<   Œ dD ]#  }|| j                  v sŒ||vsŒ| j                  |= Œ% yyy)a¹  
        Load credentials from litellm_credential_name if provided in vector_store config.

        This allows users to specify a credential name in the vector_store config
        which will be resolved from litellm.credential_list. When a stored
        credential is used, its values take precedence over caller-supplied
        equivalents so endpoint and identity fields stay consistent with the
        credential definition.
        r   )ÚCredentialAccessorÚlitellm_credential_nameN)Úapi_baseÚaws_sts_endpointÚaws_web_identity_token)Ú.litellm.litellm_core_utils.credential_accessorr3   r+   r&   ÚlitellmÚcredential_listÚget_credential_valuesÚitems)r.   r3   Úcredential_nameÚcredential_valuesÚkeyÚvalues         r/   r-   z.BaseRAGIngestion._load_credentials_from_configE   s¬   € õ 	Và!%×!9Ñ!9×!=Ñ!=Ð>WÓ!XˆÙœw×6Ò6Ø'9×'OÑ'OÐP_Ó'`ÐÙ$ØØ/×5Ñ5Ó7ò 6‘
��UØ05�×(Ñ(¨Ò-ð6ðò 6�ð
 ˜$×2Ñ2Ò2°sÐBSÒ7SØ×0Ñ0°Ñ5ñ6ð  7ˆ?r1   c                ó:   — | j                   j                  dd«      S )zGet the vector store provider.Úcustom_llm_providerÚopenai)r+   r&   )r.   s    r/   rB   z$BaseRAGIngestion.custom_llm_provider`   s   € ð ×'Ñ'×+Ñ+Ð,AÀ8ÓLÐLr1   c              ƒ  ó\  K  — |r|\  }}}|||dfS |r„t        t        j                  ¬«      }t        ||«      ƒ d{  –—† }|j	                  «        |j
                  }|j                  d«      d   xs d}|j                  j                  dd«      }|||dfS |rddd|fS t        d«      ‚7 Œm­w)	aG  
        Upload / prepare file for ingestion.

        Args:
            file_data: Tuple of (filename, content_bytes, content_type)
            file_url: URL to fetch file from
            file_id: Existing file ID to use

        Returns:
            Tuple of (filename, file_content, content_type, existing_file_id)
        N)Úllm_providerú/éÿÿÿÿÚdocumentzcontent-typezapplication/octet-streamz,Must provide file_data, file_url, or file_id)
r   r   ÚRAGr   Úraise_for_statusÚcontentÚsplitÚheadersr&   Ú
ValueError)	r.   Ú	file_dataÚfile_urlÚfile_idÚfilenameÚfile_contentÚcontent_typeÚhttp_clientÚresponses	            r/   ÚuploadzBaseRAGIngestion.uploade   sÄ   è ø€ ñ" Ø3<Ñ0ˆH�l LØ˜\¨<¸Ð=Ð=áÜ!7ÔEY×E]ÑE]Ô!^ˆKÜ$2°;ÀÓ$I×IˆHØ×%Ñ%Ô'Ø#×+Ñ+ˆLØ—~‘~ cÓ*¨2Ñ.Ò<°*ˆHØ#×+Ñ+×/Ñ/°Ð@ZÓ[ˆLØ˜\¨<¸Ð=Ð=áØ˜˜t WÐ,Ð,äÐGÓHÐHð Jús   ‚:B,¼B*½A.B,c              ƒ  ó
  K  — | j                   r|sy| j                   j                  dd«      }|r
d|v rd\  }}nd\  }}t        j                  |«      j	                  d«      }d|› d	|› �}| j
                  �*| j
                  j                  |d
|||i¬«      ƒ d{  –—† }n#t        j                  |d
|||i¬«      ƒ d{  –—† }t        |d«      r.|j                  r"dj                  d„ |j                  D «       «      S y7 Œc7 ŒA­w)zø
        Perform OCR on file content to extract text.

        Args:
            file_content: Raw file bytes
            content_type: MIME type of the file

        Returns:
            Extracted text or None if OCR not configured/needed
        NÚmodelzmistral/mistral-ocr-latestÚimage)Ú	image_urlr[   )Údocument_urlr\   úutf-8zdata:z;base64,r   )rY   rH   Úpagesz

c              3  óN   K  — | ]  }t        |d «      sŒ|j                  –— Œ y­w)ÚmarkdownN)Úhasattrr`   )Ú.0Úpages     r/   ú	<genexpr>z'BaseRAGIngestion.ocr.<locals>.<genexpr>´   s   è ø€ Òi°ÌwÐW[Ð]gÕOh˜tŸ}�}Ñiùs   ‚%”%)r'   r&   Úbase64Ú	b64encodeÚdecoder$   Úaocrr9   ra   r^   Újoin)	r.   rS   rT   Ú	ocr_modelÚdoc_typeÚurl_keyÚb64_contentÚdata_urlÚocr_responses	            r/   r   zBaseRAGIngestion.ocrˆ   s  è ø€ ð �Š¡lØàŸ?™?×.Ñ.¨wÐ8TÓUˆ	ñ ˜G |Ñ3Ø 8ÑˆH‘gà >ÑˆH�gô $×-Ñ-¨lÓ;×BÑBÀ7ÓKˆØ! , ¨x¸°}ÐEˆð �;‰;Ð"Ø!%§¡×!1Ñ!1ØØ  (¨G°XÐ>ð "2ó "÷ ‰Lô
 ")§¡ØØ  (¨G°XÐ>ô"÷ ˆLô �< Ô)¨l×.@Ò.@Ø—;‘;Ñi¸×9KÑ9KÔiÓiÐiàðøð
ús%   ‚BDÂC?Â#DÂ?DÃ A DÄDc                ó  — d}|r|}n|r|s	 |j                  d«      }|sg S | j                  xs i }|j                  dt        «      }|j                  dt        «      }|j                  d	d«      }||d
œ}	|r||	d	<   t        di |	¤Ž}
|
j                  |«      S # t        $ rh |j                  d«      r;t        j                  d«       t        |«      }|s2t        j                  d«       g cY S t        j                  d«       g cY S Y Œêw xY w)a  
        Split text into chunks using RecursiveCharacterTextSplitter.

        Args:
            text: Text from OCR (if used)
            file_content: Raw file content bytes
            ocr_was_used: Whether OCR was performed

        Returns:
            List of text chunks
        Nr]   s   %PDFz(PDF detected, attempting text extractionzkPDF text extraction failed. Install 'pypdf' or 'PyPDF2' for PDF support, or enable OCR with a vision model.z,Binary file detected, skipping text chunkingÚ
chunk_sizeÚchunk_overlapÚ
separators)rq   rr   © )rg   ÚUnicodeDecodeErrorÚ
startswithr
   Údebugr   r   r&   r   r   r   Ú
split_text)r.   ÚtextrS   Úocr_was_usedÚtext_to_chunkÚsplitter_argsrq   rr   rs   Úsplitter_kwargsÚtext_splitters              r/   ÚchunkzBaseRAGIngestion.chunk¸   s+  € ð$ %)ˆÙØ ‰MÙ¡,ðØ ,× 3Ñ 3°GÓ <�ñ  ØˆIð  $×5Ñ5Ò;¸ˆØ)×-Ñ-¨lÔ<NÓOˆ
Ø,×0Ñ0°ÔBWÓXˆØ)×-Ñ-¨l¸DÓAˆ
ð %Ø*ñ2
ˆñ Ø,6ˆO˜LÑ)ä=ÑPÀÑPˆØ×'Ñ'¨Ó6Ð6øôC &ò à×*Ñ*¨7Ô3Ü"×(Ñ(Ð)SÔTÜ$9¸,Ó$G�MÙ(Ü&×,Ñ,ðAôð  "š	ä"×(Ñ(Ð)WÔXØ’Iñ )ðús   �B ÂAD	Ã-D	ÄD	c              ƒ  óN  K  — | j                   r|sy| j                   j                  dd«      }| j                  �&| j                  j                  ||¬«      ƒ d{  –—† }nt	        j                  ||¬«      ƒ d{  –—† }|j
                  D �cg c]  }|d   ‘Œ	 c}S 7 ŒA7 Œ#c c}w ­w)z¦
        Generate embeddings for text chunks.

        Args:
            chunks: List of text chunks

        Returns:
            List of embeddings or None
        NrY   ztext-embedding-3-small)rY   Úinputr    )r*   r&   r$   Ú
aembeddingr9   Údata)r.   ÚchunksÚembedding_modelrV   Úitems        r/   ÚembedzBaseRAGIngestion.embedô   s’   è ø€ ð ×$Ò$©FØà!%×!6Ñ!6×!:Ñ!:¸7ÐD\Ó!]ˆà�;‰;Ð"Ø!Ÿ[™[×3Ñ3¸/ÐQWÐ3ÓX×X‰Hä$×/Ñ/°oÈVÔT×TˆHà.6¯m©mÖ< d��[Ó!Ò<Ð<ð	 YøàTúâ<ùs6   ‚AB%ÁBÁB%Á:BÁ;B%ÂB ÂB%ÂB%Â B%c              ƒ  ó   K  — y­w)a  
        Store content in vector store.

        This method must be implemented by provider-specific subclasses.

        Args:
            file_content: Raw file bytes
            filename: Name of the file
            content_type: MIME type
            chunks: Text chunks (if chunking was done locally)
            embeddings: Embeddings (if embedding was done locally)
            existing_file_id: Provider file ID supplied by the caller, if any

        Returns:
            Tuple of (vector_store_id, file_id)
        Nrt   )r.   rS   rR   rT   r„   Ú
embeddingsÚexisting_file_ids          r/   ÚstorezBaseRAGIngestion.store  s   è ø� ùs   ‚c           
   ƒ  óŒ  K  — | j                  |||¬«      ƒ d{  –—† \  }}}}	 |r.| j                  s"t        | j                  j                  › d�«      ‚| j                  ||¬«      ƒ d{  –—† }| j                  ||| j                  du¬«      }	| j                  |	¬«      ƒ d{  –—† }
| j                  ||||	|
|¬«      ƒ d{  –—† \  }}t        | j                  d|xs d	|xs |¬
«      S 7 ŒÒ7 Œƒ7 ŒK7 Œ.# t        $ rC}t        j                  d|«       t        | j                  dd	dt        |«      ¬«      cY d}~S d}~ww xY w­w)as  
        Execute the full ingestion pipeline.

        Args:
            file_data: Tuple of (filename, content_bytes, content_type)
            file_url: URL to fetch file from
            file_id: Existing file ID to use

        Returns:
            RAGIngestResponse with status and IDs

        Raises:
            ValueError: If no input source is provided
        )rO   rP   rQ   Nz^ does not support ingesting an existing file_id. Upload file data or provide file_url instead.)rS   rT   )ry   rS   rz   )r„   )rS   rR   rT   r„   r‰   rŠ   Ú	completedÚ )ÚidÚstatusÚvector_store_idrQ   zRAG Pipeline failed: %sÚfailed)r�   r�   r‘   rQ   Úerror)rW   r   rN   Ú	__class__Ú__name__r   r   r'   r‡   r‹   r   r%   Ú	Exceptionr
   Ú	exceptionr)   )r.   rO   rP   rQ   rR   rS   rT   rŠ   Úextracted_textr„   r‰   r‘   Úresult_file_idÚes                 r/   ÚingestzBaseRAGIngestion.ingest(  s‰  è ø€ ð* HLÇ{Á{ØØØð HSó H
÷ B
Ñ>ˆ�, Ð.>ð0	Ù¨×(FÒ(FÜ Ø—~‘~×.Ñ.Ð/ð 0Dð Dóð ð +/¯(©(Ø)Ø)ð +3ó +÷ %ˆNð !ŸJ™JØ#Ø)Ø!Ÿ_™_°DÐ8ð 'ó ˆFð '+§j¡j¸ jÓ&?× ?ˆJð 59·J±JØ)Ø!Ø)ØØ%Ø!1ð 5?ó 5÷ /Ñ+ˆO˜^ô %Ø—>‘>Ø"Ø /Ò 5°2Ø&Ò:Ð*:ô	ð ðOB
øð%øð !@øð/ùô  ò 	Ü×$Ñ$Ð%>ÀÔBÜ$Ø—>‘>ØØ "ØÜ˜!“fôõ ûð	üsu   ‚EšC-›	E¥AC5 Á+C/Á,9C5 Â%C1Â&C5 ÃC3Ã'C5 Ã,EÃ/C5 Ã1C5 Ã3C5 Ã5	EÃ>8D<Ä6EÄ7EÄ<EÅE)N)r#   r   r$   zRouter | None)ÚreturnÚNone)rœ   r)   )NNN)rO   útuple[str, bytes, str] | NonerP   ú
str | NonerQ   rŸ   rœ   z7tuple[str | None, bytes | None, str | None, str | None])rS   úbytes | NonerT   rŸ   rœ   rŸ   )ry   rŸ   rS   r    rz   r   rœ   ú	list[str])r„   r¡   rœ   úlist[list[float]] | None)rS   r    rR   rŸ   rT   rŸ   r„   r¡   r‰   r¢   rŠ   rŸ   rœ   ztuple[str | None, str | None])rO   rž   rP   rŸ   rQ   rŸ   rœ   r   )r•   Ú
__module__Ú__qualname__Ú__doc__r   Ú__annotations__r0   r-   ÚpropertyrB   rW   r   r   r‡   r   r‹   r›   rt   r1   r/   r   r   $   s…  … ñð ',Ð˜tÓ+ð
 !%ð-à(ð-ð ó-ó,6ð6 òMó ðMð 48Ø#Ø"ð	!Ià0ð!Ið ð!Ið ð	!Ið
 
Aó!IðF.à"ð.ð !ð.ð 
ó	.ð`:7àð:7ð #ð:7ð ð	:7ð
 
ó:7ðx=àð=ð 
"ó=ð2 ð (,ðà"ðð ðð !ð	ð
 ðð -ðð %ðð 
'òó ðð8 48Ø#Ø"ð	Kà0ðKð ðKð ð	Kð
 
ôKr1   r   )"r¥   Ú
__future__r   re   Úabcr   r   Útypingr   r   r   r	   r9   Úlitellm._loggingr
   Úlitellm._uuidr   Úlitellm.constantsr   r   Ú$litellm.litellm_core_utils.url_utilsr   Ú&litellm.llms.custom_httpx.http_handlerr   r   Ú"litellm.rag.ingestion.file_parsersr   Úlitellm.rag.text_splittersr   Úlitellm.types.ragr   r   r   r   rt   r1   r/   ú<module>r³      sO   ðñ
õ #ã ß #ß 2Ó 2ã Ý +Ý ß GÝ ?÷õ EÝ Eß AáÝôO�sõ Or1   