
    Gg                         S SK r S SKrS SKrS SKJrJrJr  S SKrS SKJ	r
  \
" 5         S SKJr  S SKJr  S SKJr  S SKJr  S SKJr  S S	KJr  S S
KJrJr  S SKJr   " S S5      rg)    N)ListUnionOptional)load_dotenv)OpenAIEmbeddings)WebBaseLoader)RecursiveCharacterTextSplitter)QdrantVectorStore)Document)QdrantClient)DistanceVectorParams)modelsc                       \ rS rSrSr\R                  " SS5      \R                  " SS5      SSS	4S
\S\S\S\S\	\   SS	4S jjr
SS jrS\\   S\4S jrS\\   S\4S jrS rSrg	)DocumentProcessor   u0   用于处理和向量化不同类型文档的类COLLECTION_NAMExiaolang_documentsEMBEDDING_MODELzPro/BAAI/bge-m3i   2   Ncollection_nameembedding_model
chunk_sizechunk_overlappersist_directoryreturnc                 v   [         R                  " [         R                  SS9  [         R                  " S5      U l        [        U[        R                  " S5      [        R                  " S5      S9U l        [        UU[        S9U l        USL U l        U=(       d    [        R                  " S	S
9U l        U R                  R!                  SU R                   35        Xl        [%        U R                  S9U l        U R)                  5         [+        U R&                  U R"                  U R                  S9U l        g)u  
初始化文档处理器

Args:
    collection_name: Qdrant集合名称
    embedding_model: OpenAI嵌入模型名称
    chunk_size: 文档分片大小
    chunk_overlap: 文档分片重叠大小
    persist_directory: 永久存储目录，None则使用临时目录
z4%(asctime)s - %(name)s - %(levelname)s - %(message)s)levelformatr   EMBEDDING_API_KEYEMBEDDING_API_BASE)modelapi_keybase_url)r   r   length_functionNqdrant_)prefixu   使用存储目录: )path)clientr   	embedding)loggingbasicConfigINFO	getLoggerloggerr   osgetenv
embeddingsr	   lensplitteris_temp_dirtempfilemkdtempstorage_dirinfor   r   r)   _ensure_collection_existsr
   vector_store)selfr   r   r   r   r   s         B   /Users/zhangyaohui/Desktop/AI课程/xiaolang/backend/src/AddDoc.py__init__DocumentProcessor.__init__   s   " 	',,"X	Z''(;< +!II12YY34 7!'
 -4,R0@0@	0R/0@0@/ABC  /"(8(89 	&&( .;; 00oo
    c           
      J  ^   T R                   R                  5       R                  n[        U 4S jU 5       5      (       d  T R                  R                  ST R                   35        T R                   R                  T R                  [        S[        R                  S9[        R                  " SS9[        R                  " SSS	9S
9  gT R                  R                  ST R                   35        g! [         a$  nT R                  R                  SU 35        e SnAff = f)u-   确保Qdrant集合存在，不存在则创建c              3   T   >#    U  H  oR                   TR                  :H  v   M     g 7f)N)namer   ).0
collectionr<   s     r=   	<genexpr>>DocumentProcessor._ensure_collection_exists.<locals>.<genexpr>Q   s      ]Q\:$*>*>>Q\s   %(u   创建新集合: i   )sizedistancei'  )indexing_threshold      )mef_construct)r   vectors_configoptimizers_confighnsw_configu   使用已有集合: u   创建集合时出错: N)r)   get_collectionscollectionsanyr/   r9   r   create_collectionr   r   COSINErestOptimizersConfigDiffHnswConfigDiff	Exceptionerror)r<   rS   es   `  r=   r:   +DocumentProcessor._ensure_collection_existsM   s    	++557CCK]Q\]]]  #4T5I5I4J!KL--$($8$8#/THOO#T&*&?&?+0' !% 3 3%(! . 
   #78L8L7M!NO 	KK 7s;<	s   CC4 (C4 4
D">DD"urlsc                   #     U R                   R                  SU 35        [        U5      nUR                  5       n[	        S5        [	        U5        U R                   R                  S[        U5       S35        U R                  U5      I Sh  vN $  N! [         a5  nU R                   R                  SU 35        S[        U5      0s SnA$ SnAff = f7f)u   
从URL加载文档并添加到向量存储

Args:
    urls: 要加载的URL列表
    
Returns:
    包含状态信息的字典
u   正在加载URLs: -----------docs------------u
   已加载 u
    个文档Nu   处理URL时出错: r[   )
r/   r9   r   loadprintr3   _process_documentsrZ   r[   str)r<   r^   loaderdocsr\   s        r=   add_urlsDocumentProcessor.add_urlsd   s     
	%KK1$89"4(F;;=D/0$KKKz#d)J?@006666 	%KK 4QC89SV$$	%sG   CBB BB CB 
C *C
CCCCrf   c                   #    U(       d  SSS.$  [        S5        [        U5        U R                  R                  U5      n[        S5        [        U5        U R                  R	                  S[        U5       S35        [        [        U5      5       Vs/ s H!  n[        [        R                  " 5       5      PM#     nnU R                  R                  X$S9  S	S
[        U5       S3[        U5      [        U5      S.$ s  snf ! [         a5  nU R                  R                  SU 35        S[        U5      0s SnA$ SnAff = f7f)ur   
处理文档并添加到向量存储

Args:
    docs: 文档列表
    
Returns:
    包含状态信息的字典
warningu   没有文档需要处理)statusmessager`   z-----------chunks------------u   文档已分割为 u    个块)	documentsidssuccessu   成功添加 u    个文档块)rk   rl   document_countchunk_countu   处理文档时出错: r[   N)rb   r4   split_documentsr/   r9   r3   rangerd   uuiduuid4r;   add_documentsrZ   r[   )r<   rf   chunks_rn   r\   s         r=   rc   $DocumentProcessor._process_documents{   s     '4NOO	%/0$K]]2248F12&MKK23v;-wGH /4CK.@A.@3tzz|$.@CA++f+F $*3v;-}E"%d)"6{	  B  	%KK 7s;<SV$$	%sH   EBD (C>=A D =E>D 
E*D=7E8E=EEc                 h   [        U S5      (       al  U R                  (       aZ  [        U S5      (       aH   SSKnUR                  U R                  SS9  U R
                  R                  SU R                   35        gggg! [         a(  nU R
                  R                  SU 35         SnAgSnAff = f)	u!   析构函数，清理临时资源r5   r8   r   NT)ignore_errorsu   已清理临时目录: u   清理临时目录时出错: )	hasattrr5   shutilrmtreer8   r/   r9   rZ   r[   )r<   r}   r\   s      r=   __del__DocumentProcessor.__del__   s    4''D,<,<}A]A]Gd..dC  #:4;K;K:L!MN	 B^,<'
  G!!$A!"EFFGs   AA? ?
B1	B,,B1)r)   r   r2   r5   r/   r4   r8   r;   )r   N)__name__
__module____qualname____firstlineno____doc__r0   r1   rd   intr   r>   r:   r   dictrg   r   rc   r   __static_attributes__ r@   r=   r   r      s    : )+		2CEY(Z(*		2CEV(W#&&(484
"%4
"%4
 !4
 !$	4

 %-SM4

 >B4
l.%49 % %."%T(^ "% "%HGr@   r   )r6   r0   r+   typingr   r   r   rt   dotenvr   _load_dotenvlangchain_openair   $langchain_community.document_loadersr   langchain.text_splitterr	   langchain_qdrantr
   langchain_core.documentsr   qdrant_clientr   qdrant_client.http.modelsr   r   qdrant_client.httpr   rW   r   r   r@   r=   <module>r      sG     	  ( (  .  . > B . - & < -SG SGr@   