
    Sh<=                        d dl mZ d dlmZ d dlZd dlZd dlZd dlZd dl	Z
d dlmZ d dlmZ  ej                  ej                   d        e         ed      Zd	Zd
 ZddefdZd ZddZd Zd Zd ZddZddZedk(  rw ej                  ej<                          ed        ed       	  e d      jC                         Z"e"jG                         dv r	 ed       ye"s5 ee"      Z$ ede$ d       Iy)     )QdrantClient)modelsN)load_dotenv)SentenceTransformerz)%(asctime)s - %(levelname)s - %(message)s)levelformatz%paraphrase-multilingual-mpnet-base-v2i   c                 $   d}d| dd}ddddd	| dgd
d}	 t        j                  |||      }|j                          |j                         d   d   d   d   S # t         j                  $ r}t        j                  d|         d}~ww xY w)uC   Gọi API OpenRouter để xử lý prompt với mô hình Llama-3.z-https://openrouter.ai/api/v1/chat/completionszBearer zapplication/json)AuthorizationzContent-Typezmeta-llama/llama-3-8b-instructsystemu   Bạn là trợ lý AI chuyên tư vấn về các thông tin của Trường Đại học Y Dược Cần Thơ, trả lời bằng tiếng Việt tối đa 40 từ.)rolecontentuser皙?)modelmessagestemperature)headersjsonchoicesr   messager   u    Lỗi khi gọi OpenRouter API: N)requestspostraise_for_statusr   RequestExceptionloggingerrorlenquestionsplitmincall_openrouter_llama3warningjoininfo	Exception)promptapi_keyurlr   dataresponsee
word_count	max_wordsrefinedrefined_word_counts              /RAG/ai_agent.pyr!   r!      s    
9C"7),*G
 2  +R  S/
 D==gDA!!#}}y)!,Y7	BB$$ 8<=s   AA B1B

Bcollection_namec                     t        |dd      5 }t        j                  |      }ddd       j                  dg       D ]*  }|j                  d      | k(  s|j                  dg       c S  g S # 1 sw Y   JxY w)uH   Tải danh sách keyword tương ứng với collection từ config.jsonrutf-8encodingNcollectionsr1   keywords)openr   loadget)r1   config_pathfconfig
collections        r0   load_keywords_from_configr@   A   sj    	k3	1Q1 
2jj3
>>+,?>>*b11 4 I 
2	1s   A..A7c                    t        j                  |       t        j                  |      }} t        t        j                  | |      t         j                  j                  |       t         j                  j                  |      z  z        S N)nparrayfloatdotlinalgnorm)vec1vec2s     r0   cosine_similarityrK   K   sU    $$$Dd#ryy~~d';biinnT>R'RSTT    c                    	 |D cg c]
  } ||       }}|D cg c]  }t        | |       c}	t        t        t        	            	fdd      d| }|D cg c]  }||   	|   f c}S c c}w c c}w c c}w )u4   Tìm từ khóa gần nhất với vector câu hỏic                     |    S rB    )isimilaritiess    r0   <lambda>z&find_closest_keyword.<locals>.<lambda>T   s	    arL   T)keyreverseN)rK   sortedranger   )
query_vectorr8   embedding_functop_kkwkeyword_vectorsvectop_indicesrP   rQ   s
            @r0   find_closest_keywordr^   P   s    4<=Hb~b)HO=DSTOS%lC8OTLs<017PZ^_`fafgK4?@KqXa[,q/*K@@ >T@s   A/A4A9c                    	 | j                         }||j                  D cg c]  }|j                   c}vre| j                  |t	        j
                  t        t        j                  j                               t        j                  d| dt         d       y| j                  |      }|j                  j                  j                  j                  t        k7  r=t!        d|j                  j                  j                  j                   dt               t        j                  d| d	       yc c}w # t"        $ r}t        j$                  d
|         d}~ww xY w)u=   Khởi tạo collection trong Qdrant nếu chưa tồn tại.)sizedistance)r1   vectors_configu   [RAG] Đã tạo collection 'u   ' với vector size .u.   Collection tồn tại nhưng có vector size u    khác với yêu cầu z[RAG] Collection 'u0   ' đã tồn tại với vector size phù hợp.u#   Lỗi khi khởi tạo collection: N)get_collectionsr7   namecreate_collectionqdrant_modelsVectorParamsVECTOR_SIZEDistanceCOSINEr   r$   get_collectionr>   paramsvectorsr`   
ValueErrorr%   r   )clientr1   r7   ccollection_infor+   s         r0   initialize_qdrant_collectionrs   X   sS   ,,.;3J3J"K3Ja1663J"KK$$ /,99$*33::  %  LL88II]^i]jjklm$33ODO%%,,4499[H #QRaRhRhRoRoRwRwR|R|Q}  ~V  Wb  Vc  "d  e  eLL-o->>nop #L  ;A3?@s/   D; D6A(D; BD; 6D; ;	E"EE"c                     | sy| j                  d      }t        t        j                  |            }dj	                  |      j                         }g d}|D ]  }|j                  |d      } |r|S | S )uA   Làm sạch văn bản: loại bỏ lặp lại và chuẩn hóa. . )u   Web - Thẻ Span: u   Web - Đoạn văn: u   Web - Danh sách: u   Web - Tiêu đề: )r   listdictfromkeysr#   stripreplace)text	sentencesunique_sentencescleaned_textcleaning_patternspatterns         r0   
clean_textr   o   sy     

4 IDMM)4599-.446L %#++GR8 % (<1T1rL   c                     	 t         j                  |       j                         }t        j                  dt        |              |S # t        $ r}t        j                  d|         d}~ww xY w)uC   Tạo embedding cho văn bản sử dụng model đã khởi tạo.z[RAG] Embedding dimension: u   Lỗi khi tạo embedding: N)_embedding_modelencodetolistr   r$   r   r%   r   )r|   embr+   s      r0   get_embeddingr      sd    %%d+22423s8*=>
 3A378s   AA 	A/A**A/c                 ^   | sddiS t         j                  j                  dd      }t         j                  j                  d      }t         j                  j                  d      }|t        d      	 t	        d	d
d      5 }t        j                  |      }ddd       	 j                  dg       }|rt        |t              st        d      |d   }|d   }|d   }	t        j                  d|        	 |rt!        ||      }nt!        |      }t#        ||       ddlm} 	 |j)                  |d|j*                         t        j                  d       |j1                  |      }t        j                  d| d|j0                          	 | j3                         }|j5                         d!v ry"t        j                  d#|        t7        |      }t9        |      }dd$lm}m}m} d%}d}|rtA        ||t6        d&'      }|d   \  }}t        j                  d(| d)|d*d+       |d,k\  r4d-} | |d ||.      /      g0      }t        j                  d1|        n0d-} | |d ||.      /      g0      }t        j                  d2       	 |jC                  |||r|ndd3d-d%4      }|s-|r+t        j.                  d5       |jC                  ||d6d-d%7      }|D ]  }tE        d9|jF                   d:|jH                  d*       tE        d;|jJ                  j                  d<i       j                  d=d>             tE        d?|jJ                  j                  d<i       j                  d@d>             tE        dA|jJ                  j                  dd>              |s@t        j.                  dB| dC       	 tM        ||      }t        j                  dD       dE|dFS |r|}n|D cg c]  }|jH                  d,k\  s| }}|s<t        j.                  dI       	 tM        ||      }t        j                  dJ       dE|dFS g }d>}dK}|D ]k  }tQ        |jJ                  j                  dd>            } tS        |      tS        |       z   |k  r	|dL| z   z  }K|jU                  |j3                                | }m |r|jU                  |j3                                tW        |      D !"cg c]  \  }!}"|!d&z    dM|"  }#}!}"dNjY                  |#      }$|	 dO|  dP|$ dQ}%	 tM        |%|      }|S # 1 sw Y   xY w# t        $ r t        j                  d        t
        j                  $ r t        j                  d        w xY w# t        t        f$ r}
t        j                  d|
         d}
~
ww xY w# t,        $ r#}
t        j.                  d|
        Y d}
~
~d}
~
ww xY w# t,        $ r}
t        j                  d |
         d}
~
ww xY w# t,        $ r%}
t        j                  d8|
        g }Y d}
~
Td}
~
ww xY w# t,        $ r2}
t        j                  dG|
        ddHtO        |
       icY d}
~
S d}
~
ww xY wc c}w # t,        $ r2}
t        j                  dG|
        ddHtO        |
       icY d}
~
S d}
~
ww xY wc c}"}!w # t,        $ r"}
t        j                  dR|
        Y d}
~
ySd}
~
ww xY w# t,        $ r4}
t        j                  dT|
 d-U       ddVtO        |
       icY d}
~
S d}
~
ww xY w)Wu9   Xử lý câu hỏi sử dụng RAG với Qdrant và LLM.r   zInput text is required.
QDRANT_URLzhttp://localhost:6333OPENROUTER_API_KEYQDRANT_API_KEYNu:   OPENROUTER_API_KEY không được cấu hình trong .env!config.jsonr3   r4   r5   u$   Không tìm thấy file config.json!u6   File config.json có định dạng không hợp lệ!r7   u;   Cấu trúc collections trong config.json không hợp lệr   r1   r&   u*   Cấu hình collection không hợp lệ: u   [RAG] Sử dụng collection: )r(   r'   )r(   )PayloadSchemaTyper   )r1   
field_namefield_schemau)   [RAG] Đã bật text index cho 'content'uB   [RAG] Không thể tạo text index (có thể đã tồn tại): )r1   u.   [RAG] Số lượng điểm trong collection 'z': u   Lỗi khi kết nối Qdrant: )hellohiu	   xin chàou   chàou   chào bạnu   Xin chào! Tôi là trợ lý AI của Trường Đại học Y Dược Cần Thơ. Tôi có thể giúp bạn tìm kiếm thông tin về trường đại học này.u)   [RAG] Câu hỏi dùng để truy vấn: )FilterFieldCondition	MatchTextF   )rY   u   [RAG] Từ khóa gần nhất: z (score=z.3f)r   T)r|   )rS   match)mustu0   [RAG] Sử dụng filter MatchText cho keyword: uZ   [RAG] Không tìm thấy keyword phù hợp, dùng MatchText trực tiếp từ câu hỏi   )r1   rW   query_filterlimitwith_payloadwith_vectorsuP   [RAG] Không có kết quả với filter, fallback sang truy vấn vector gốc   )r1   rW   r   r   r   u#   [RAG] Lỗi khi truy vấn Qdrant: zID: z	, Score: zTitle:metadatatitleru   zSection:sectionzContent:u;   [RAG] Qdrant trả về kết quả rỗng cho collection ''uH   [RAG] Đã gọi LLM trực tiếp do không có kết quả từ Qdrantu*   Không tìm thấy tài liệu liên quan.)r"   answeru#   Lỗi khi gọi LLM trực tiếp: zLLM error: u?   [RAG] Không có tài liệu nào đạt ngưỡng score >= 0.2uS   [RAG] Đã gọi LLM trực tiếp do không có tài liệu đạt ngưỡng scorei   rv   
u    

Câu hỏi của quý khách: u!   


        Thông tin có sẵn:
u   


        Trả lời:u'   Lỗi khi gọi LLM để trả lời: u@   Xin lỗi, tôi gặp lỗi khi xử lý câu hỏi của bạn.u   Lỗi trong quá trình RAG: )exc_infozRAG error: )-osenvironr;   ro   r9   r   r:   FileNotFoundErrorr   r   JSONDecodeError
isinstancerw   KeyError
IndexErrorr$   r   rs   qdrant_client.http.modelsr   create_payload_indexTEXTr%   r"   countrz   lowerr   r@   r   r   r   r^   searchprintidscorepayloadr!   strr   r   append	enumerater#   )&
input_text
qdrant_urlr'   qdrant_api_keyr=   r>   r7   collection_configr1   prompt_templater+   rp   r   points_countrefined_inputrW   r8   r   r   r   
use_filterr   closest_keywordsbest_keyword
best_scoresearch_resultpointr   filtered_points	documentstemp_doc
max_lengthr   rP   doccontext_linescontextr&   s&                                         r0   	RAG_agentr      s2   233.EFJjjnn12GZZ^^$45NUVV-w71YYq\F 8
jj3*[$"?Z[['N+,=>+H5
 LL1/1BCD!j.IF!j1F$V_=?	f'' /$.33 ( 
 LLDE ||O|DEoEVVYZfZlZlYmno
C1"((* $XX }@PQ$]3,_=OO
3L(Mabc'7':$L*LL:<.Q[\_P``abcS !
%& )"+">  OP\~^_!
%& )"+"?  y{	"MM /)-7\T!" * M !Z rs &$3!-!%!& !. ! #ED
)EKK+<=>(EMM--j"=AA'2NO*emm//
B?CCIrRS*emm//	2>?	 # OOYZiYjjklm9/wGgh#O[abb
 +O2?V-5;;RUCUu-OVOO]^9/wGrs#O[abb 	
$E !2!29b!ABG8}s7|+j8C'M)  !12" % X^^-. +4I*>
*>3qse2cUO*> 	 
 ))M*%&&H U  'y )	V+FG<FMY 87 <= NO j! B1#FG,  	fOO`ab`cdee	f
  6qc:;F  	MM?sCDM	   9 CA3GH;s1vh!7889 W  9 CA3GH;s1vh!7889&
  	VMMCA3GHU	V  15aS9DI;s1vh/001ss  3T5 T(T5  >V  7.W &3V0 7W "[/ 4C[/ A
X	 C[/ 9%X: 	[/ (Y8=Y8[/ %Y= B%[/ &Z;:[/ [ (T2-T5 5AU= V-V((V-0	W9WW WW 	X(XX		X7X2,[/ 2X77[/ :	Y5'Y0*Y5+[/ 0Y55[/ =	Z8'Z3-Z8.[/ 3Z88	[/ 	[,
['"[/ '[,,[/ /	\,8)\'!\,'\,c                     	 t        |       }|S # t        $ r+}t        j                  dt	        |              Y d}~yd}~ww xY w)u   
    Xử lý văn bản đầu vào bằng AI Agent với Qdrant.
    Args:
        input_text (str): Văn bản đầu vào cần xử lý
    Returns:
        Kết quả xử lý từ AI Agent hoặc thông báo lỗi
    u+   Lỗi trong quá trình xử lý AI Agent: N)r   r%   r   r   r   )r   r*   r+   s      r0   process_with_ai_agentr   S  sA    Z( CCF8LMs    	A!>A__main__)r   z=== AI Agent Qdrant CLI ===u,   Nhập câu hỏi (gõ 'exit' để thoát):u   Bạn: )exitquitqu   Kết thúc.zAI: r   )r   )r   rB   )%qdrant_clientr   qdrant_client.httpr   rg   r   r   r   r   numpyrC   dotenvr   sentence_transformersr   basicConfigINFOr   ri   r!   r   r@   rK   r^   rs   r   r   r   r   __name__DEBUGr   inputrz   
user_inputr   resultrO   rL   r0   <module>r      s   & 6  	     5   ',,/Z [  ''NO *Xs U
A.20@1D zGgmm,	
'(	
89
9%++-
!66.!&z2VHB  	 rL   