
    ȭi+                    .   U 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	Z	ddl
mZ ddlmZ  ej                  e      Z ej"                  dd	      Zd
ed<   dZd
ed<   dZded<   ddZ	 	 	 	 	 	 	 	 ddZddZddZddZddZ	 	 d	 	 	 	 	 	 	 	 	 ddZy)u  
Telnyx KB Sync — MODULE 10
===========================
Syncs platform KB chunks from Qdrant to a Telnyx AI Assistant's knowledge base.

Stories implemented:
  10.01 — Telnyx KB API Wrapper (upload, list, delete documents via REST)
  10.02 — sync_kb_to_assistant (pull chunks from Qdrant, push docs to Telnyx)

Usage:
    from core.kb.telnyx_sync import (
        telnyx_upload_document,
        telnyx_list_documents,
        telnyx_delete_document,
        sync_kb_to_assistant,
    )
    )annotationsN)defaultdict)Optional)
embed_text)search_platformTELNYX_API_KEY strzhttps://api.telnyx.com/v2TELNYX_API_BASEg      >@float_HTTP_TIMEOUTc                     dt          dddS )z0Return Authorization headers for the Telnyx API.zBearer zapplication/json)AuthorizationzContent-TypeAccept)r        ,/mnt/e/genesis-system/core/kb/telnyx_sync.py_auth_headersr   3   s     #>"23*$ r   c                  K   t          d|  d}||d}	 t        j                  t              4 d{   }|j	                  |t               |       d{   }ddd      d{    j                  dv r|j                         S t        j                  d|j                  | |       d	|j                   d
|j                  dd  |j                  dS 7 7 7 t# 1 d{  7  sw Y   xY w# t        j                  $ r(}t        j                  d|       d| ddcY d}~S d}~wt        $ r.}t        j                  d|       t        |      ddcY d}~S d}~ww xY ww)ah  
    Upload a document to a Telnyx AI Assistant's knowledge base.

    Sends a POST to /ai_assistants/{assistant_id}/knowledge_base_documents
    with the document title and content as plain text.

    Returns:
        API response dict on success (contains "data" with document_id, etc.).
        Error dict {"error": str, "status_code": int} on failure.
    /ai_assistants//knowledge_base_documents)titlecontenttimeoutN)headersjson)      z9telnyx_upload_document: HTTP %d for assistant=%s title=%rzHTTP : r   )errorstatus_codeu&   telnyx_upload_document: timeout — %sz	Timeout: r   u/   telnyx_upload_document: unexpected error — %s)r   httpxAsyncClientr   postr   r"   r   loggerwarningtextTimeoutExceptionr!   	Exceptionr
   )assistant_idr   r   urlpayloadclientresponseexcs           r   telnyx_upload_documentr1   <   sf     _\N:S
TCG
5$$]; 	U 	Uv#[[moG[TTH	U 	U :-==?" 	G  		
 X112"X]]4C5H4IJ#//
 	
	UT	U 	U 	U 	U$ !! >=sC$SE*1== 5FLS!445s   E&C3 CC3  CCCC3 'C(!C3 	E&
AC3 E&C3 CC3 C0$C'%C0,C3 3E#D)#E#$E&)E#5#EE#E&E##E&c                @  K   t          d|  d}	 t        j                  t              4 d{   }|j	                  |t                      d{   }ddd      d{    j                  dk(  r=|j                         }t        |t              r	d|v r|d   S t        |t              r|S g S t        j                  d|j                  |        g S 7 7 7 w# 1 d{  7  sw Y   xY w# t        $ r"}t        j                  d	|       g cY d}~S d}~ww xY ww)
z
    List all documents in a Telnyx AI Assistant's knowledge base.

    Returns:
        List of document dicts from the API response (may be empty on error).
    r   r   r   Nr   r   dataz/telnyx_list_documents: HTTP %d for assistant=%su#   telnyx_list_documents: error — %s)r   r#   r$   r   getr   r"   r   
isinstancedictlistr&   r'   r*   r!   )r+   r,   r.   r/   r4   r0   s         r   telnyx_list_documentsr9   l   s     _\N:S
TC$$]; 	F 	Fv#ZZ]_ZEEH	F 	F 3&==?D$%&D.F|#$%I=  	

 	#	FE	F 	F 	F 	F&  :C@	s   DC0 CC0 CCCC0 !C";C0 DC0 /D0C0 1D2"C0 DC0 CC0 C-!C$"C-)C0 0	D9DDDDDc                  K   t          d|  d| }	 t        j                  t              4 d{   }|j	                  |t                      d{   }ddd      d{    j                  dv ryt        j                  d|j                  | |       y	7 i7 H7 :# 1 d{  7  sw Y   JxY w# t        $ r }t        j                  d
|       Y d}~y	d}~ww xY ww)z
    Delete a document from a Telnyx AI Assistant's knowledge base.

    Returns:
        True if deletion succeeded (HTTP 200/204), False otherwise.
    r   z/knowledge_base_documents/r   Nr3   )r      Tz7telnyx_delete_document: HTTP %d for assistant=%s doc=%sFu$   telnyx_delete_document: error — %s)r   r#   r$   r   deleter   r"   r&   r'   r*   r!   )r+   document_idr,   r.   r/   r0   s         r   telnyx_delete_documentr>      s      _\N:TU`Ta
bC$$]; 	I 	Iv#]]3]HHH	I 	I :-E  		
 	IH	I 	I 	I 	I  ;SAs   C!B5 BB5 B BB B5 #B$B5 6C!7"B5 C!B5 B B5  B2&B)'B2.B5 5	C>CC!CC!c                    t        t              }| D ](  }|j                  dd      }||   j                  |       * |D ]  }||   j	                  d         t        |      S )z
    Group chunk dicts by source_url.

    Within each group, chunks are sorted by chunk_index (ascending) so that
    document content is assembled in the correct reading order.
    
source_urlr	   c                &    | j                  dd      S )Nchunk_indexr   r5   )cs    r   <lambda>z&_group_chunks_by_url.<locals>.<lambda>   s    quu]A'> r   )key)r   r8   r5   appendsortr7   )chunksgroupschunkr,   s       r   _group_chunks_by_urlrL      st     %0$5F "iib)s5!"
  @s>?@ <r   c                t    |r|d   j                  dd      nd}|s| }dj                  d |D              }||fS )z
    Build a (title, content) tuple from an ordered list of chunk dicts.

    - Title  = first chunk's ``title`` field (falls back to the URL).
    - Content = chunk texts joined by double newline.
    r   r   r	   z

c              3  f   K   | ])  }|j                  d d      s|j                  d d       + yw)r(   r	   NrC   ).0rD   s     r   	<genexpr>z"_build_document.<locals>.<genexpr>   s)     YquuVUWGX!%%+Ys   11)r5   join)r,   ordered_chunksr   r   s       r   _build_documentrS      sF     3AN1!!'2.bEkkY^YYG'>r   c                  K   | |dddg d}	 t        |       }	 t        || ||d
      }t        |      |d<   |st        j                  d|        |S t        |      }	|	j                         D ]  \  }
}t        |
|      \  }}|j                         st        j                  d|
       <t        |||       d	{   }d|v rE|dxx   dz  cc<   |d   j	                  d|
d|d           t        j                  d|
|d          |dxx   dz  cc<   t        j                  d|
|        |S # t        $ rK}d| d| }t        j                  d|       |dxx   dz  cc<   |d   j	                  |       |cY d	}~S d	}~ww xY w# t        $ rK}d| d| }t        j                  d|       |dxx   dz  cc<   |d   j	                  |       |cY d	}~S d	}~ww xY w7 $w)u~  
    Sync platform KB chunks from Qdrant to a Telnyx AI Assistant's knowledge base.

    Steps:
    1. Embed the platform name as a broad query vector to retrieve all chunks.
    2. Search Qdrant for up to max_chunks chunks for this platform.
    3. Group chunks by source_url — one Telnyx document per unique URL.
    4. Upload each document to the Telnyx assistant.
    5. Return sync statistics.

    Returns:
        {
            "platform": str,
            "assistant_id": str,
            "documents_synced": int,
            "chunks_total": int,
            "errors": int,
            "error_details": list[str],
        }
    r   )platformr+   documents_syncedchunks_totalerrorserror_detailszembed_text failed for platform=r    zsync_kb_to_assistant: %srX      rY   Ng        )query_vectorrU   customer_idtop_kscore_thresholdz$search_platform failed for platform=rW   uH   sync_kb_to_assistant: 0 chunks found for platform=%r — nothing to syncu;   sync_kb_to_assistant: empty content for url=%r — skipping)r+   r   r   r!   zUpload failed for url=u4   sync_kb_to_assistant: upload error for url=%r — %srV   z=sync_kb_to_assistant: uploaded document for url=%r (title=%r))r   r*   r&   r!   rG   r   leninforL   itemsrS   stripdebugr1   r'   )rU   r+   r\   
max_chunksstatsr[   r0   msgrI   groupedr,   rR   r   r   results                  r   sync_kb_to_assistantri      s'    6 $E!(+ %#
  KE.V	
  #6*G  '}} ^(n=w}}LLVX[\-%
 
 f(Oq O/"))(r&/1BC NNFw $%*%LLO3> LG  /|2cUC/5h1o%%c*   4XL3%H/5h1o%%c*6
sl   
G D/ F BG 9G:A5G /	F8A E>8F9G >FG 	GA GGG GG )returnzdict[str, str])r+   r
   r   r
   r   r
   rj   r7   )r+   r
   rj   
list[dict])r+   r
   r=   r
   rj   bool)rI   rk   rj   zdict[str, list[dict]])r,   r
   rR   rk   rj   ztuple[str, str])Ni  )
rU   r
   r+   r
   r\   zOptional[str]rd   intrj   r7   )__doc__
__future__r   loggingoscollectionsr   typingr   r#   core.kb.embedderr   core.kb.qdrant_storer   	getLogger__name__r&   getenvr   __annotations__r   r   r   r1   r9   r>   rL   rS   ri   r   r   r   <module>rz      s   $ #  	 #   ( 0			8	$  bii 0"5 52 2 u -5-5-5 -5 
	-5`DD&$ "&	iii i 	i
 
ir   