
    5jGB                    ~   S r SSKJr  SSKJrJr  SSKJr  SSKJ	r	  SSK
Jr  SSKJrJrJr  SSKJrJrJrJrJr  SS	KJrJr  SS
KJr  SSKJrJr  SSKJrJ r J!r!J"r"            SS jr#SS.         SS jjr$                  SS jr%SSS jjr& S         SS jjr' S         SS jjr(g)z@Chat del agente con GPT 5.5, archivos OpenAI y code interpreter.    )annotations)AnyIterator)Session)settings)
AgentModel)can_use_familia_hybridcreate_familia_base_for_gpt try_deterministic_familia_report)attach_file_to_containerchat_with_openai_responsesis_container_expired!stream_chat_with_openai_responsesupload_local_file_to_openai)search_agent_knowledge
strip_html)select_agent_file_rows)	agent_dirensure_responses_dir)check_familia_rut_requirementextract_rut_from_messageis_familia_report_request!resolve_student_context_for_agentc                   SSK Jn  SSKJn  [	        UR
                  5        U R                  U5      R                  UR                  UR
                  :H  5      R                  5       n[        XR
                  X#5      n/ nU(       a-  [        U5      U:  a  SUl        SUl        U R                  5         / n	U H  n
[        UR
                  5      U
R
                  -  nUR!                  5       (       d  M<  U" XX5      nU(       d  MN  U	R#                  U5        U
R$                  (       d  Mr  UR#                  U
R$                  5        M     XXg4$ )z[Devuelve (openai_file_ids, nombres usados, total archivos del agente, filas seleccionadas).r   )AgentFileModel)ensure_openai_file_for_rowN)app.backend.db.modelsr   )app.backend.services.openai_agent_servicer   r   idqueryfilteragent_idcountr   lenopenai_container_idopenai_container_updated_atflushr   is_fileappenddisplay_name)dbagentmessagehitsr   r   totalselected_rowsselected_namesopenai_file_idsrow	disk_path	openai_ids                YC:\Users\jesus\Desktop\proyecto_pie360\backend\app\backend\services\agent_chat_service.py_prepare_openai_filesr7   !   s    5T" 	 	''5883	4	 

 +2xxGM "N]#e+$(!,0)

!#Oehh'#&&0	  "".r#I	9""9-%%c&6&67  E@@    Nbase_doc_namec                  [        U5      n[        U 5      n[        U5      U:w  a  USU nU Vs/ s H  ofU:w  d  M
  UPM     nn[        U=(       a    X4;   5      n[        U5      n	U(       a  U	(       a  SU SU	 SU S3n
OU(       a  XR:  a
  SU SU S3n
OSU S3n
U
/nUSS	  H2  nX:X  a  UR                  S
U 35        M  UR                  SU 35        M4     U$ s  snf )zNMensajes claros: conteo alineado con los archivos realmente enviados a OpenAI.Nz	Enviando z' archivo(s) al modelo (1 base PIE360 + z del caso). El agente tiene z archivo(s) en total.z de z! archivo(s) del agente al modelo.z) archivo(s) al modelo para esta consulta.   zBase PIE360: zArchivo del caso: )listr$   boolr)   )r2   r1   total_in_agentr:   namesnnm
case_nameshas_base
case_countsummarystepsnames                r6   _file_preparation_step_messagesrI   G   s     EOA
5zQbq	$<um(;"uJ<M<m&<=HZJJs   *| ,-..CE 	
 
A.s$~..OP 	 aS IJIEbq	 LL=/0LL-dV45	 
 L/ =s
   	CCc                   [        X4XQR                  U S9nU(       a  U(       a  [        R                  (       d  XgSS4$ [	        X$U5      n	[        U	S   U	S   5      n
UR                  (       a1  [        UR                  5      (       d   [        UR                  U
5        U
/UQU	S   /UQU	S   U	S   4$ ! [         a     N!f = f)u   
Si aplica informe familia híbrido, sube base con identificación PIE360 para que GPT redacte.
Devuelve (file_ids, names, base_doc_name, template_name).
)r+   Nr4   r*   template_name)r	   r   r   openai_api_keyr
   r   r%   r   r&   r   	Exception)r+   r,   r"   r-   student_contextr0   r2   r1   template_pathbasefile_ids              r6   _attach_familia_hybrid_baserR   n   s     +7]T\T\acdMx7N7Nd::&x-PD)${*;T.=QRG  )=e>_>_)`)`	$U%>%>H 
#?#	n	//^_	   		s   B3 3
C ?C c                    U(       a1  SnSR                  S U 5       5      nSU=(       d    S S3nU U U 3$ SU(       a  SU S	3-   $ S
-   $ )Nu<   Según los documentos indexados localmente de este agente:

z

---

c           	   3  V   #    U  H  nS US    SUS   S-    SUS   SS  3v   M!     g7f)	z**fileNamez** (fragmento 
chunkIndex   z)
contentNi   ).0hits     r6   	<genexpr>"_fallback_reply.<locals>.<genexpr>   sH      "
 Z!L0AA0E/Fc#i.Y]Z]J^I_`s   ')z

_(zRespuesta sin OpenAIz)._u   No encontré información relevante en los documentos de este agente. Sube archivos en la configuración del agente o reformula la pregunta.z () )join)r-   r.   reasonintrobodysuffixs         r6   _fallback_replyre      s}    P!! "
"
 
 &:$:;3?vh''	Q#Rxq>	- *,	-r8   c                N   U R                  [        5      R                  [        R                  U:H  5      R	                  5       nU(       d  SSS.$ U=(       d    SR                  5       nU(       d  SSS.$ [        XXSS9nU Vs/ s H  nUS   US   US	   US
   S.PM     nn[        X5      n	U	(       a  U	U[        U5      S.$ [        R                  (       d   [        XXV5      u      p[        X5      n[        XR                  X[U5      nU(       a<  U R                  5         US   U[        U5      SUR                  S5      =(       d    / S.$  [%        XVS5      U[        U5      S.$  ['        UR(                  5      (       a  S Ul        S Ul        U R-                  5         [        XXV5      u  pnn[        X5      n[/        U UUR                  UUUUU5      u  pnnU R                  5         U R1                  U5        [3        U UUUUUUUS9nU R                  5         US   U[        U5      UR                  SS5      UR                  S5      UR                  S5      UR                  S5      =(       d    / UR                  S5      S.$ s  snf ! [          a    U R#                  5          GN\f = f! [          ak  nU R#                  5         [5        UR6                  =(       d    S5      S S n[%        XVSU 35      U[        U5      [9        U5      U=(       d    S S.s S nA$ S nAff = f)NerrorAgente no encontrado)statusr-   r_      El mensaje está vacíotop_kfileIdrU   rV   scorerm   rU   rV   rn   reply	citations
usedChunksrq   r   responseFilesrq   rr   rs   openaiFilesUsedrt   Configure OPENAI_API_KEY)rN   r0   instruction_file_namesfamilia_base_doc_namerv   containerIdmodelresponseFilesWarningrq   rr   rs   rv   rz   r{   rt   r|   x   No se pudo usar OpenAI: )rq   rr   rs   warningrolePreview)r    r   r!   r   firststripr   r   r$   r   rL   r7   r   r   commitgetrM   rollbackre   r   r&   r%   r'   rR   refreshr   r   role_instructionsstr)r+   r"   r-   rl   r,   trimmedr.   r[   rr   
rut_prompt_r0   rN   deterministicr2   r1   total_filesr:   _tplresultexcrole_previews                         r6   chat_with_agentr      s1    HHZ ''
(ABHHJE!.DEE}"##%G!.GHH!"ED  C (mJl+\		
    /r;J"d)
 	
 ""	%:2g%T"Aq!?LO<HHgoM 		*73!*"%d)'(%2%6%6%G%M2   %W4NO"d)
 	
8
 A ABB(,E%04E-HHJF[wG
Cm <BH?ZHH	@
< 			


5++'#1"/	
 			 G_"d)%zz*;Q?!::m4ZZ(#ZZ8>B$*JJ/E$F	
 		
_D  	KKM	n  	

!%"9"9"?R@#F$W6Nse4TU"d)3x'/4
 	
	
s9   J	A4J )DJ/ J,+J,/
L$9A LL$L$c              #  	  #    U R                  [        5      R                  [        R                  U:H  5      R	                  5       nU(       d  SSS.v   g U=(       d    SR                  5       nU(       d  SSS.v   g SSS.v   [        XXSS9nU Vs/ s H  nUS	   US
   US   US   S.PM     nnU(       a  SS[        U5       S3S.v   [        X5      n	U	(       a  SU	U[        U5      S.S.v   g [        R                  (       d   [        XXV5      u      p[        X5      n[        XR                  X[U5      nU(       aB  U R                  5         SUS   U[        U5      SUR                  S5      =(       d    / S.S.v   g  S[%        XVS5      U[        U5      S.S.v   g  [)        UR*                  5      (       a  S Ul        S Ul        U R/                  5         SSS.v   [        XXV5      u  nnnnSSKJn  U" UR                  U5      u  nnUS:X  a  U(       a  SSU S3S.v   [        X5      nU(       aQ  UR                  S5      =(       d    SnUR                  S 5      =(       d    SnU(       a  S!U S"3OSnSS#U U S3S.v   O5[5        U5      (       a%  [7        U5      nU(       d  SS$S.v   OSS%U S&3S.v   [9        U UUR                  UUUUU5      u  nnnnU(       a  U(       a  SS'U S(3S.v   U R                  5         U R;                  U5        U(       a"  U(       a  [=        UUUUS)9 H
  nSUS.v   M     OU(       d  SS*S.v   [?        U UUUUUUUS+9 H  nU(       d  M  UR                  S,5      S:X  a  US-   nU R                  5         SUS   U[        U5      UR                  S.S5      UR                  S/5      UR                  S05      UR                  S5      =(       d    / UR                  S15      S2.S.v   M  Uv   M     g s  snf ! [          aK  nU R#                  5         S[%        XV['        U5      5      U[        U5      ['        U5      S.S.v    S nAg S nAff = f! [          aE  nU R#                  5         S[%        XVS3U 35      U[        U5      ['        U5      S.S.v    S nAg S nAff = f7f)4Nrg   rh   )typer-   r_   rj   stepu3   Buscando fragmentos relevantes en tus documentos…rk   rm   rU   rV   rn   ro   zSe encontraron z5 fragmento(s) relacionados en los archivos indexados.donerp   )r   datarq   r   rt   ru   )rq   rr   rs   r   rw   u4   Preparando archivos relevantes para esta consulta…)"resolve_familia_template_from_rowsformz Plantilla formulario detectada: .student_full_namezel estudiantestudent_identification_numberz (RUT r^   z!Estudiante encontrado en PIE360: zTInforme familia: incluye el RUT del estudiante en el mensaje (ej. RUT 23.442.145-K).u0   No se encontró estudiante en PIE360 con el RUT z#. Verifica el RUT en la plataforma.u*   Identificación cargada desde PIE360 en «uW   ». GPT redactará el contenido según el rol usando la cartilla y archivos del caso…r9   uA   No hay archivos adjuntos; responderé solo con el rol del agente.)rx   rN   r0   ry   r   r   rv   rz   r{   r|   r}   r   ) r    r   r!   r   r   r   r   r$   r   r   rL   r7   r   r   r   r   rM   r   re   r   r   r&   r%   r'   (app.backend.utils.agent_familia_templater   r   r   rR   r   rI   r   )r+   r"   r-   rl   r,   r   r.   r[   rr   r   r   r0   rN   r   r   r2   r1   r   r   base_tpltpl_kindstudent_namestudent_rutrut_partrutr:   template_usedstep_msgeventpayloads                                 r6   iter_chat_with_agent_eventsr     sC     HHZ ''
(ABHHJE+ABB}"##%G+DEE&[
\\!"ED  C (mJl+\		
    (T3hi
 	

 /r;J#&!$i
 	
 	""	%:2g%T"Aq!?LO<HHgoM 		"!.w!7%.&)$i+,)6):):?)K)Qr	 	  4 (8RS&!$i
 	
 	x
 A ABB(,E%04E-HHJ*`aaF[wG
Cm 	`?-X(v(=hZqI 
 <BH*../BCVL)--.MNTRTK2=}A.2H>|nXJVWX  'w//*73C"2  #J3% P< <  IdHH	I
E ]@ Pj k  			


5~;+	  &(;; !!.qrr6#1+'"/	
E yy F*-		"!(!1%.&)$i+2;;7H!+L'.{{='A!(W!5)0_)E)K07<R0S	  ;	
k^  	KKM,WCHE!*"%d)"3x	  	H  


(:RSVRW8XY&!$is8	
 	


sj   BSP/AS	A:P !S%I/Q2 S
Q/$AQ*%S*Q//S2
S<;R<7S<SS)
r+   r   r,   r   r-   r   r.   list[dict[str, Any]]returnz&tuple[list[str], list[str], int, list])
r2   	list[str]r1   r   r?   intr:   
str | Noner   r   )r+   r   r,   r   r"   r   r-   r   rN   zdict[str, Any] | Noner0   r=   r2   r   r1   r   r   z3tuple[list[str], list[str], str | None, str | None])N)r-   r   r.   r   ra   r   r   r   )   )
r+   r   r"   r   r-   r   rl   r   r   zdict[str, Any] | dict[str, str])
r+   r   r"   r   r-   r   rl   r   r   zIterator[dict[str, Any]]))__doc__
__future__r   typingr   r   sqlalchemy.ormr   app.backend.core.configr   r   r   3app.backend.services.agent_familia_generate_servicer	   r
   r   r   r   r   r   r   r   &app.backend.utils.agent_document_indexr   r   &app.backend.utils.agent_file_selectionr   app.backend.utils.agent_filesr   r   &app.backend.utils.agent_student_lookupr   r   r   r   r7   rI   rR   re   r   r   rY   r8   r6   <module>r      s   F "   " , , 
  V I I #A#A#A #A 	#A
 ,#AV !%$$$ $
 $ $N  	
 +    9B* 	q
q
q
 q
 	q

 %q
p 	O
O
O
 O
 	O

 O
r8   