
    i                        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 d dlZd dl	m
Z
mZ d dlmZ d dlmZ d dlmZ d dlmZ d d	lmZ d d
lmZmZ d dlmZmZmZmZmZmZm Z m!Z!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,m-Z-m.Z. dZ/dZ0dZ1dZ2dZ3dZ4 ejj                  d      Z6dZ7de8e9e9f   fdZ:e G d d             Z;dpde9dz  de<de9dz  fdZ=de9de9fdZ>ddd d!d"ed#e<dz  d$e9dz  d%e?de;f
d&Z@dd'd"ed#e<dz  de.fd(ZAdd'd"ed#e<dz  de;fd)ZBdefd*ZCd+e9de9fd,ZDd-ej                  de9fd.ZFd-ej                  d/e9de9fd0ZGdddd1d"ed2e9d3e9d4e8d#e<dz  d5e9dz  d6e9dz  de*fd7ZHddddd8d"ed#e<d5e9d9e9d:e9d;e9dz  d<e9dz  d=e9dz  d>e8e9eIf   dz  de)dz  fd?ZJd"ed2e9d6e9dz  de?fd@ZKdeIde<dz  fdAZLd"ed#e<d5e9de<dz  fdBZMd"ed#e<d5e9dCe8deNe?e<dz  e<dz  f   f
dDZOdCe8de9dz  fdEZPd4e8de9dz  fdFZQd"ed5e9d#e<deRe8e9e9f      fdGZSdHdId"ed#e<dJe<deRe8e9eIf      fdKZTdLdId"ed#e<d5e9dJe<deRe)   f
dMZUdNeRe8e9e9f      de8e9eIf   fdOZVdPe9de9fdQZWdRe9de9dz  fdSZXdPe9de9dz  fdTZYdUe9dz  de9fdVZZdUe9dz  de9fdWZ[dXe9dCe9dYe;deNe9e8e8e9dz  f   fdZZ\dCe9dNeRe8e9e9f      d"ed#e<deNe9e9f   f
d[Z]dPe9d"ed#e<deNe9e9dz  f   fd\Z^d"ed#e<d]e9dUe9dz  dCe8dNeRe8e9e9f      ddfd^Z_dd'd"ed#e<dz  de,fd_Z`dd'd`e9dCe9d"ed#e<dz  de-f
daZadbe9dz  dce9dz  dde9dz  de9fdeZbdfecdge9dz  ddfdhZddCe8die8e9e9f   deNe9e9dz  f   fdjZedke8deNe9e9dz  f   fdlZfd4e8d"ede<fdmZgdfecde8fdnZhdqdd'd"edJe<d#e<dz  deRe*   fdoZiy)r    N)	dataclass)Any)HTTPExceptionstatus)select)Session)get_settings)VenueBookingSettings)Venue)is_greeting_only_messagemaybe_handle_booking_message)	#adopt_legacy_whatsapp_configurationbuild_whatsapp_assistant_promptget_booking_settings#get_effective_whatsapp_access_token&get_effective_whatsapp_phone_number_idget_saved_whatsapp_access_token"get_saved_whatsapp_phone_number_id'uses_legacy_whatsapp_fallback_for_venueuses_global_whatsapp_fallback)get_known_whatsapp_contact_nameremember_whatsapp_contact)!build_time_context_system_message)WhatsAppAssistantTurnWhatsAppEventLog) WhatsAppConfigValidationResponseWhatsAppSendTestResponseWhatsAppStatusResponsez/webhooks/whatsappinbound_messageoutbound_agentoutbound_errorassistant_errorwhatsapp-deterministicz<\|[^>]+?\|>Z   returnc                  l    t               } ddi}| j                  xs dj                         }|r||d<   |S )NContent-Typeapplication/json zX-Internal-API-Token)r	   llm_proxy_internal_tokenstrip)settingsheaderstokens      8PRENOTAZIONI_IA/backend/app/services/whatsapp_service.pybuild_internal_llm_headersr0   +   s@    ~H12G..4";;=E*/&'N    c                   B    e Zd ZU eed<   eed<   edz  ed<   edz  ed<   y)WhatsAppGraphConfigurationvenuer,   Naccess_tokenphone_number_id)__name__
__module____qualname__r   __annotations__r
   str r1   r/   r3   r3   4   s!    L""*4Zr1   r3   valuevisible_digitsc                     | sy t        |       |k  rdt        |       z  S dt        t        |       |z
  d      z   | | d   S )N*   )lenmax)r=   r>   s     r/   
mask_valuerD   <   sS    
5z^#SZCE
^3Q778?O9P8QRRr1   c                    | j                         }|st        t        j                  d      |j	                  d      }dj                  d |D              }t        |      dk  rt        t        j                  d      |rd| S |S )NzNumero di telefono non validostatus_codedetail+r)   c              3   B   K   | ]  }|j                         s|  y wN)isdigit).0	characters     r/   	<genexpr>z)normalize_phone_number.<locals>.<genexpr>J   s     O99;L;L;NYOs      )r+   r   r   HTTP_422_UNPROCESSABLE_ENTITY
startswithjoinrB   )r=   trimmedhas_plusdigitss       r/   normalize_phone_numberrW   D   sz    kkmG(L(LUtuu!!#&HWWOOOF
6{Q(L(LUtuu#Qvh<//r1   F)venue_idr6   strict_phone_number_matchdbrX   r6   rY   c           	         |r|j                         }|rt        t        t              j	                  t        t        j
                  t        j                  k(        j                  t        j                  |k(        j                  d      }| j                  |      j                         }|(|\  }}t        ||t        ||      t        ||            S t        | |      }	|	-|	d   |	d   }}t        ||t        ||      t        ||            S |rt!        d      t#        | |      \  }}
t        ||
t        |
|      t        |
|            S )N   )r4   r,   r5   r6   )expected_phone_number_idr   z3Nessun locale associato al phone_number_id ricevutorX   )r+   r   r
   r   rS   idrX   wherewhatsapp_phone_number_idlimitexecutefirstr3   r   r   r   
ValueErrorr   )rZ   rX   r6   rY   normalized_phone_number_idstmtrowr,   r4   adopted_configurationbooking_settingss              r/   get_whatsapp_configurationrk   P   sZ    %4%:%:%<"%+U3eUXX)=)F)FFG+DDHbbcq	  **T"((*C"%%1%!DXu!U$J8UZ$[	  %H)C%! %0"7":<QRS<T%1%!DXu!U$J8UZ$[	  ) !VWW22IE%!89I5Q>?OQVW	 r1   r^   c           
      .   t               }t        | |      }t        |j                  xr |j                  xr |j
                        }|j                  j                  d       t         }t        |j                  |j                        }|r|sdn|rt        |j                        rdnd}t        di d|j                  j                  d|j                  j                  d|d	t!        |j                        d
|j                  xs dd|j                  j"                  xs dd|j                  j$                  xs dd|j                  j&                  xs d d|j                  j(                  xs d dt        |j                        dt        t+        |j                              dt        t-        |j                              d|dt        |j
                        dt        |j.                        d|j0                  dt        d|d|S )NrZ   rX   /z8Configurazione WhatsApp pronta per invio test e webhook.zLinea operativa, ma sta ancora usando un fallback legacy globale. Salva i dati direttamente nel locale per completare la migrazione.zPCompleta token, phone number id o verify token per attivare la linea del locale.rX   
venue_name
configuredphone_number_id_maskedr6   r)   business_account_idbusiness_iddisplay_phone_numberverified_nameaccess_token_configuredphone_number_id_savedaccess_token_saveduses_global_fallbackverify_token_configuredapp_secret_configuredgraph_api_versionwebhook_pathwebhook_urlmessager<   )r	   rk   boolr5   r6   whatsapp_verify_tokenpublic_base_urlrstripWEBHOOK_PATHr   r,   r4   r   r   r_   namerD   whatsapp_business_account_idwhatsapp_business_idwhatsapp_display_phone_numberwhatsapp_verified_namer   r   whatsapp_app_secretwhatsapp_graph_api_version)rZ   rX   r,   graph_configurationrp   r~   using_global_fallbackr   s           r/   get_whatsapp_statusr      sJ   ~H4XN)66  B;N;^;^  Bck  dB  dB  CJ--44S9:<.IK9:M:V:VXkXqXqr 3 	C EFYF_F_` Sc  " $**--&,,11   **=*M*MN	
 ,;;Ar 088UU[Y[ (00EEK 199WW_[_ *22IIQT !%%8%E%E F ##EFYFbFb#cd   ?@S@\@\ ]^ 3 !%X%C%C D #8#?#?@  #==!" "#$  %& ' r1   c                     g }t        | |      }|j                  s|j                  d       |j                  s|j                  d       |r-t	        t
        j                  ddj                  |             |S )Nrm   whatsapp_access_tokenra   z2Configurazione WhatsApp incompleta per il locale: z, rF   )rk   r5   appendr6   r   r   HTTP_400_BAD_REQUESTrS   )rZ   rX   missingconfigurations       r/   require_graph_api_configurationr      su    G."xHM%%./((1233G		RYHZG[\
 	
 r1   c                  h    t               } | j                  st        t        j                  d      | S )Nz9Configurazione WhatsApp incompleta: WHATSAPP_VERIFY_TOKENrF   )r	   r   r   r   r   )r,   s    r/   require_webhook_configurationr      s2    ~H))33N
 	
 Or1   pathc                     t               }|j                  j                  d       d|j                   d| j	                  d       S )Nrn   )r	   whatsapp_api_base_urlr   r   lstrip)r   r,   s     r/   build_graph_urlr      sH    ~H,,33C898;^;^:__`aealalmpaq`rssr1   responsec                    	 | j                         }t	        |t
              r|j                  d      nd }t	        |t
              re|j                  d      xs d}|j                  d      }|j                  d      }dj                  d |||fD              }|xs d| j                   S | j                  xs d| j                   S # t        $ r  | j                  xs d| j                   cY S w xY w)	NzErrore Graph API errorr   zErrore Graph APIcodetypez - c              3   <   K   | ]  }|d vst        |        yw))Nr)   N)r;   )rM   parts     r/   rO   z&extract_graph_error.<locals>.<genexpr>   s     i4RV^hRhSYis   	)jsonre   textrG   
isinstancedictgetrS   )r   payloadr   r   r   
error_typedetailss          r/   extract_graph_errorr      s    K--/ %/w$=GKK 4E%))I&<*<yy YYv&
**iJg3NiiD-h.B.B-CDD==F/0D0D/EFF  K}}J"3H4H4H3I JJKs   C &C0/C0fallback_prefixc                    	 | j                         }d}t        |t              r|j                  d      }t        |t              r?t	        |j                  d      xs |j                  d      xs d      j                         }|s?t	        |j                  d      xs |j                  d      xs d      j                         }|st        j                  |d      }	 dj                  |j                               d d }|r| d	| S | d
| j                   dS # t        $ r | j                  j                         }Y bw xY w)Nr)   r   r   rH   T)ensure_ascii   : z ())r   r   r   r   r;   r+   dumpsre   r   rS   splitrG   )r   r   r   rH   error_payloads        r/   extract_http_errorr      s#   <--/ gt$#KK0M-.]..y9^]=N=Nx=X^\^_eegW[[2Rgkk)6LRPRSYY[ZZd;FXXflln%ds+F!""VH--b!5!5 6a88!  '$$&'s   D #EE)rX   contact_phonewa_message_id
event_typesummaryr   r   r   c                 j    t        ||||||      }| j                  |       | j                          |S )N)rX   r   r   r   r   r   )r   addflush)rZ   r   r   r   rX   r   r   	log_entrys           r/   create_log_entryr      s=     !##I FF9HHJr1   )assistant_routeassistant_modelsource_wa_message_idtracerolecontentr   r   r   r   c        	             |dk(  rt        |      ndj                  |j                               }	|	j                         }	|	sy t	        ||||	||||xs i       }
| j                  |
       | j                          |
S )N	assistantr   )rX   r   r   r   r   r   r   r   )!normalize_assistant_reply_contentrS   r   r+   r   r   r   )rZ   rX   r   r   r   r   r   r   r   normalized_contentturns              r/   create_assistant_turnr     s     HL{GZ:7C`c`h`hipivivix`y+113 #"''1kr	D FF4LHHJKr1   c                    |syt        t        j                        j                  t        j                  |k(  t        j
                  |k(        j                  d      }| j                  |      d uS )NFr\   )r   r   r_   r`   r   r   rb   scalar)rZ   r   r   rg   s       r/   has_event_logr   !  s_    ""#	**j8:J:X:X\i:i	j	q 	
 99T?$&&r1   c                     t        | t              r| S t        | t              r*| j                         r	 t        | j                               S y # t        $ r Y y w xY wrK   )r   intr;   r+   re   )r=   s    r/   parse_unix_timestampr   ,  sR    %%%++-	u{{}%%   		s   A 	AAc                 T   | j                  t        t              j                  t        j                  t
        k(  t        j                  |k(  t        j                  |k(        j                  t        j                  j                         t        j                  j                               j                  d            }d }|D ]c  }t        |j                  t              r|j                  ni }t!        t        |t              r|j#                  d      nd       }|Z|||kD  sb|}e |S )N
   	timestamp)scalarsr   r   r`   r   INBOUND_MESSAGE_EVENTrX   r   order_by
created_atdescr_   rb   r   r   r   r   r   )rZ   rX   r   recent_logslatest_timestampr   r   	candidates           r/   latest_inbound_timestampr   7  s    ** 	''+@@%%1**m;


 
"--2246F6I6I6N6N6P	Q	r	K $(  )	'1)2C2CT'J)##PR(ZPWY]E^[)Adhi	#y3C'C() r1   r   c                     t        |j                  d            }|yt        | ||      }|d|d fS ||t        z
  k  }|||fS )Nr   )FNN)rZ   rX   r   F)r   r   r   STALE_INBOUND_GRACE_SECONDS)rZ   rX   r   r   incoming_timestampr   is_stales          r/   is_stale_inbound_messager   M  sc    -gkk+.FG! /2Xef($..!%58S%STH')999r1   c                     | j                  d      dk7  ry | j                  di       j                  d      }t        |t              sy |j                         }|xs d S )Nr   r   body)r   r   r;   r+   )r   	text_bodycleaneds      r/   extract_message_textr   X  sT    {{6f$FB'++F3Ii%ooG?dr1   c                 \    | j                  d      }t        |t              sy t        |      S )Nassistant_reply)r   r   r;   r   )r   replys     r/   extract_logged_replyr   b  s)    KK)*EeS!,U33r1   c                @   t               }t        t              j                  t        j                  |k(  t        j
                  |k(        j                  t        j                  j                         t        j                  j                               j                  t        |j                  dz  d            }t        | j                  |            }|rYt        |      D cg c]5  }|j                   dv r%|j"                  r|j                   |j"                  d7 }}||j                   d  S t        t$              j                  t$        j                  |k(  t$        j
                  |k(  t$        j&                  j)                  t*        t,        g            j                  t$        j                  j                         t$        j                  j                               j                  t        |j                  dz  d            }t        | j                  |            }	g }t        |	      D ][  }
|
j&                  t*        k(  rt/        |
j0                        }d}nt3        |
j0                        }d}|sH|j5                  ||d       ] ||j                   d  S c c}w )N      >   userr   r   r   r   r   )r	   r   r   r`   rX   r   r   r   r   r_   rb   rC   assistant_history_limitlistr   reversedr   r   r   r   in_r   OUTBOUND_AGENT_EVENTr   r   r   r   )rZ   r   rX   r,   	turn_stmtturnsr   historyrg   logsr   r   r   s                r/   build_conversation_historyr   i  s2   ~H$%	!**h6!//=@

 
'22779;P;S;S;X;X;Z	[	s833a7;	<  I&'E !
yy11dll YY4<<8
 

 888:;; 	 	%%1**m;''++-BDX,YZ


 
"--2246F6I6I6N6N6P	Q	s833a7;	< 	 

4 !D$&Gd^ ;	#88*9+<+<=GD*9+<+<=GD9:; H444677C
s   #:J   )rb   rb   c                 @   t        | j                  t        t              j	                  t        j
                  |k(        j                  t        j                  j                         t        j                  j                               j                  t        |dz  d                        }g }i }|D ]  }|j                  |j                        }|at        |      |k\  r/|j                  d|j                  |j                  |j                   d d d}|||j                  <   |j#                  |       t%        |d         dz   |d<   |j                  dk(  r|d   s|j                   |d<   |j                  d	k(  s|d
   r|j                   |d
<    |r|S t        | j                  t        t&              j	                  t&        j
                  |k(  t&        j                  j)                  d       t&        j*                  j-                  t.        t0        g            j                  t&        j                  j                         t&        j                  j                               j                  t        |dz  d                        }g }	t3               }
|D ]  }t5        |j                  xs d      j7                         }|r||
v r2t9        |j:                  t<              r|j:                  ni }|j*                  t.        k(  rt?        |      n
tA        |      }|	j#                  |d|j                  |j*                  t.        k(  rdnd	||j*                  t.        k(  r|nd |j*                  t0        k(  r|nd d       |
jC                  |       t        |	      |k\  s |	S  |	S )N   x   r   )r   
turn_countlast_turn_at	last_rolelast_messagelast_user_messagelast_assistant_messager   r\   r   r  r   r  r   P   r)   )"r   r   r   r   r`   rX   r   r   r   r_   rb   rC   r   r   rB   r   r   r   r   r   is_notr   r   r   r   setr;   r+   r   r   r   r   r   r   )rZ   rX   rb   r   grouped
by_contactr   entryr   fallback_groupedfallback_seenr   r   r   r  s                  r/   list_whatsapp_conversationsr    s9   


()U(11X=>X+66;;=?T?W?W?\?\?^_U3urz3'(		
E (*G/1J ;t112=7|u$!%!3!3 $!YY $%)*.E .3Jt))*NN5!!%"56:l99u-@'A)-E%&99#E2J,K.2llE*++;. 


#$U ))X5 ..55d; ++//1FH\0]^
 X&11668:J:M:M:R:R:TUU3urz2&'		
K 13!eM  	I339r:@@B >'1)2C2CT'J)##PR8A8L8LPe8e+G4k  AH  lI!. ) 4 4'0';';?T'TVZe ,5>5I5IMb5b\hl:C:N:NRf:f,lp
	
 	-( E))( r1   <   c           	      x   t        |      }t        | j                  t        t              j                  t        j                  |k(  t        j                  |k(        j                  t        j                  j                         t        j                  j                               j                  |                  S rK   )rW   r   r   r   r   r`   rX   r   r   r   r   r_   rb   )rZ   rX   r   rb   normalized_phones        r/   list_whatsapp_assistant_turnsr    s     .m<


()U%..(:%337GG X+66;;=?T?W?W?\?\?^_U5\	

 
r1   conversationc                    g }| dd  D ]  }t        |t              st        |j                  d      xs d      j	                         }dj                  t        |j                  d      xs d      j                               }|r|s|j                  |t        |      dk  r|n|d d  dd	        t        |       |d
S )Nir   r)   r   r         z...r   )countrecent)	r   r   r;   r   r+   rS   r   r   rB   )r  recent_messagesr  r   r   s        r/   summarize_conversation_historyr    s    Obc" 
%&599V$*+113((3uyy39r:@@BC7&)'lc&97'$3-PS?T	

 \"! r1   r   c                 &   t               }| j                  dd      j                         }t        |j                  d      }t        |      |k  r|S |d |dz
   j                         }d|v r#|j                  dd      d   j                         }| dS )N

   r\   r   r   u   …)r	   replacer+   rC   assistant_reply_max_charsrB   r   rsplit)r   r,   r   	max_chars	truncateds        r/   trim_reply_for_whatsappr$    s    ~HmmFD)//1GH66<I
7|y )a-(//1I
i$$S!,Q/668	[r1   raw_textc                    | j                         }|sy |j                  d      r.t        j                  dd|      }t        j                  dd|      }g }|j                  d      r"|j	                  d      r|j                  |       |j                  d      }|j                  d      }|dk7  r'|dk7  r"||kD  r|||dz    }||vr|j                  |       |D ]m  }	 t        j                  |      }t        |t              s*|j                  d	      }t        |t              sL|j                         s]|j                         c S  y # t        j                  $ r Y w xY w)
Nz```z^```(?:json)?\s*r)   z\s*```${}r\   r   )r+   rR   resubendswithr   findrfindr   loadsJSONDecodeErrorr   r   r   r;   )	r%  r   json_candidatesstartendembeddedjson_candidateparsedr   s	            r/   !extract_content_from_json_payloadr7    sC    IE"FF.I>	FF:r95	!#OC Y%7%7%<y)NN3E
//#
C{sbyS5[US1W-?*""8,) '	ZZ/F fd#jj+G'3'GMMO}}&'  ## 		s   E		EEc                    | j                  dd      j                         }|sy t        |      }|r|}d|v r2|j                  dd      d   j                         }t        |      }|r|}t        j                  d|      j                         }|sy t        |      }|r|}t        j                  d|      j                         }|r|j                  d      ry |S )Nr  r  z<|message|>r\   r)   z{"role")r  r+   r7  r   CONTROL_TOKEN_PATTERNr+  rR   )r   r   json_contentnested_json_contents       r/   r   r   <  s    mmFD)//1G4W=L--q1!4::<?H)G#''G4::<G;GD%#''G4::<Gg((3Nr1   sender_namec                 d    | xs dj                         }|r|j                         d   }d| dS 	 y)Nr)   r   zCiao zt! Ti aiuto volentieri con le prenotazioni. Se vuoi riservare un tavolo, scrivimi giorno, orario e numero di persone.zxCiao! Ti aiuto volentieri con le prenotazioni. Se vuoi riservare un tavolo, scrivimi giorno, orario e numero di persone.r+   r   r<  display_name
first_names      r/   build_whatsapp_greeting_replyrB  Z  sN    %2,,.L!'')!,
J<  X X	

	Tr1   c                 d    | xs dj                         }|r|j                         d   }d| dS 	 y)Nr)   r   zScusami zc, non ho capito bene la richiesta. Puoi riscrivermela indicando giorno, orario e numero di persone?zjScusami, non ho capito bene la richiesta. Puoi riscrivermela indicando giorno, orario e numero di persone?r>  r?  s      r/   build_whatsapp_unclear_replyrD  h  sN    %2,,.L!'')!,
zl #O O	

	Kr1   	recipientr   c                   t               }t        |       }t        |      }|j                  r|j                  st        t        j                  d      t        |j                   d      }dd|dd|dd	}t        j                  |j                  
      5 }|j                  |d|j                   dd|      }	d d d        	j                  dk\  r)t        |	      }
t        t        j                  d|
       |	j!                         }d }t#        |t$              r|j'                  d      nd }t#        |t(              r(|r&|d   }t#        |t$              r|j'                  d      }||||fS # 1 sw Y   xY w)Nz0Configurazione WhatsApp incompleta per il localerF   z	/messageswhatsapp
individualr   F)preview_urlr   )messaging_productrecipient_typetor   r   timeoutBearer r(   )Authorizationr'   r-   r   r   zInvio WhatsApp fallito: messagesr   r_   )r	   rW   r$  r6   r5   r   r   r   r   httpxClientwhatsapp_timeout_secondspostrG   r   HTTP_502_BAD_GATEWAYr   r   r   r   r   )rE  r   r   r,   normalized_recipientclean_messageendpointrequest_bodyclientr   error_detailr   
message_idrR  first_messages                  r/   deliver_whatsapp_text_messager`  v  sx    ~H1)<+G4M((0J0J(C(CL~-"?"?!@	JKH'&" !
	L 
h??	@ 
F;;#*=+E+E*F!G 2   

 s"*84(C(CNfgsftLuvvmmoGJ*4Wd*Cw{{:&H(D!h mT*&**40Jw
BB-
 
s   %E//E8c                   t               }	 t        ||      \  }}|j                  j                  d       d}t        |j                  |j                  xs d      }	t               }
dd|	dd|
dg|d	| di}t        j                  |j                  
      5 }|j!                  |t#               |      }d d d        j$                  dk\  r't'        |d      }t        t        j
                  |      |j)                         }d }t+        |t,              r|j/                  d      nd }t+        |t,              r}|j/                  d      }t+        |t0              r\|rZ|d   }t+        |t,              rE|j/                  d      }t+        |t,              r|j/                  d      }|s|j/                  d      }t+        |t              r|j3                         st        t        j
                  d      t5        |      }|st        t        j
                  d      t7        |      t        |xs d      fS # t        $ r*}t        t        j
                  t        |            |d }~ww xY w# 1 sw Y   xY w)Nr^   rF   rn   /llm/openai/chat/completionsr)   rR  systemr   r   rM  rQ  r   zAssistente non disponibilemodelchoicesr   r   r   r   z)Assistente privo di risposta utilizzabilez0Assistente privo di risposta pulita utilizzabile)r	   r   re   r   r   rW  r;   assistant_api_base_urlr   r   r   whatsapp_assistant_promptr   rS  rT  assistant_timeout_secondsrV  r0   rG   r   r   r   r   r   r   r+   r   r$  )r   r  rZ   rX   r,   r4   rj   excrZ  system_prompttime_context_promptr[  r\  r   rH   r   r   rd  re  first_choicemessage_payloadnormalized_replys                         r/   request_assistant_replyro    sL    ~H_"6rH"M 1188=>>Z[H3EJJ@P@j@j@pnpqM;=-8*=>
 
 0	
L 
h@@	A 
V;;.0  

 s"#H.JK(C(CFSSmmoGE$.w$=GKK 4E'4 ++i(gt$"1:L,-"."2"29"=ot4+//	:E(,,V4EeS!(C(CLwxx8?(C(CL~"#34c%+26FFF[  _(C(CCPSHU[^^_
 
s#   H5 I+5	I(>%I##I(+I5c                   t        |       }	 t        ||      \  }}|j                  xs dj	                         }|s|d fS t               }|j                  j                  d       d}t        |j                  |      }	t               }
d}dd|	dd|
dd|dd	d
| dgd}	 t        j                  |j                        5 }|j                  |t               |      }d d d        j"                  dk\  r|d fS |j%                         }d }t'        |t(              r|j+                  d      nd }t'        |t(              r}|j+                  d      }t'        |t,              r\|rZ|d   }t'        |t(              rE|j+                  d      }t'        |t(              r|j+                  d      }|s|j+                  d      }t'        |t.              r|j	                         s|d fS t1        |      }|s|d fS t        |      t/        |xs d      fS # t        $ r |d fcY S w xY w# 1 sw Y   AxY w# t        j                   $ r |d fcY S w xY w)Nr^   r)   rn   rb  a  Riceverai un messaggio prenotazioni gia verificato dal sistema. Riscrivilo applicando le istruzioni del locale, ma senza alterare alcun fatto operativo. Mantieni invariati disponibilita, stato della prenotazione, data, ora, durata, numero di persone, area, nome cliente, alternative proposte e call to action. Puoi pero riformulare la durata con un'unita di misura equivalente, per esempio da 120 minuti a 2 ore, se le istruzioni del locale lo richiedono. Se un'istruzione locale puo essere applicata solo cambiando la formulazione, fallo. Se richiederebbe di inventare o cambiare i fatti, ignorala. Restituisci solo il testo finale del messaggio da inviare al cliente.r   rc  r   r   z3Riscrivi questo messaggio senza cambiare i fatti:

)temperaturerR  rM  rQ  r   rd  re  r   r   r   )r$  r   re   rg  r+   r	   rf  r   r   r   r   rS  rT  rh  rV  r0   	HTTPErrorrG   r   r   r   r   r   r;   r   )r   rZ   rX   
base_replyr4   rj   custom_promptr,   rZ  rj  rk  rewrite_guardrailsr[  r\  r   r   rewritten_replyrd  re  rl  rm  rn  s                         r/   maybe_personalize_booking_replyrw    sj    )/J "6rH"M &??E2LLNM4~H1188=>>Z[H3EJJNM;=	P  -8*=>*<=*_`j_k(lm	
L \\("D"DE 	{{24! # H	 s"4mmoGO$.w$=GKK 4E'4 ++i(gt$"1:L,-"."2"29"=ot4&5&9&9)&DO&&2&6&6v&>Oos+?3H3H3J48I4"#34c%+26FFFE   4 B	 	 ??  4 s;   H $ H- H !H- HH H*%H- -IIsenderc                 4   t        |      }|sy d }t        }d}	d|t        |      |j                  d      d}
	 t	        |      }t        | |      }	 t        | |||||j                  j                        }||j                  }t        |j                  | |      \  }}|j                  }|j                  }	|
j                  |j                  xs i        |	|
d<   t        |      |
d	<   |rN| d
| }||
d<   nAt!        |      rt#        |      }t        }d}	d }|	|
d<   nt%        ||| |      \  }}d}	d }|	|
d<   t1        |||      \  }}}}t-        | t2        d| |j                  d      ||r||k7  r|nd ||	|
||d|||       t5        | ||d||	|||
	       y # t&        $ r}t)        |      }t        }d}	|}|	|
d<   |j*                  |
d<   t-        | t.        d| d|j*                   |j                  d      |||j*                  ||
d|||j                  d             Y d }~d }~ww xY w# t&        $ r^}t-        | t.        d| d|j*                   |j                  d      |||j*                  |
d|||j                  d             Y d }~y d }~ww xY w)Nr#   rG  r_   )surfaceincoming_textr  source_message_idrm   )rZ   sender_phoner<  r{  rX   turn_duration_minutesr^   routepersonalizedz+prompt:personalization_modelzgreeting-onlyzllm-freeformzfallback-unclearr]  zAssistente in fallback verso r   )r|  incoming_messager  rH   fallback_replyassistant_tracerZ   r   r   r   rX   r   r   r   zRisposta agente non inviata a )r|  r  r  rH   r  zRisposta agente inviata a )r|  r   assistant_base_replyr   r   r  requestr   r   )	rZ   rX   r   r   r   r   r   r   r   )r   DETERMINISTIC_WHATSAPP_MODELr  r   rW   r   r   r,   r~  r   rw  r   r  updater   r   r   rB  ro  r   rD  rH   r   ASSISTANT_ERROR_EVENTr`  r   r   )rZ   rX   rx  r<  r   r  r{  r  r   r   r  normalized_senderr   booking_resultr   r  ri  rE  r[  response_payloadreply_message_ids                        r/   reply_to_inbound_text_messager  .  s?    )1M'+2O.O&6|D$[[.	*OR26:=hW9	9.'+!&9&B&B&X&XN )'5';';$9X"((%:6!6
 #1"@"@"0"6"6&&~';';'ArB+:(267L2M/()8(9BWAX&YO?TO$;<)-8"?"L">"1'+$+:(3J=Zfhju}3~0"0'+$+:(0 Gd-G
C	<!13C. ',YK8!(T!2.<PUim|U|$8  CG...#(	
 &!$ ''-
A  	:;GO:O0O#2 '6OG$.1jjON+07xr#**N)0T):(/$0!jj&5'6 "$%kk$/ 	8  ,4VHBszzlK%,[[%6$+ ,**#2  !++d+	
 	!sD   H0 C(F :H0 	H-%A>H(#H0 (H--H0 0	J9AJJc          
         t        | |      }t        |j                   d      }t        j                  t               j                        5 }|j                  |dd|j                   i      }d d d        j                  dk\  r)t        |      }t        t        j                  d| 	      |j                         }d
}t        |j                  d      xs d      j!                         |j"                  _        t        |j                  d      xs d      j!                         |j"                  _        t)        | d|||j*                  j,                  |j                  d             | j/                          t1        d|j                  xs d|j                  d      |j                  d      |      S # 1 sw Y   JxY w)Nrm   z*?fields=display_phone_number,verified_namerM  rP  rO  )r-   r   z!Verifica token WhatsApp fallita: rF   zConnessione a Meta riuscita.rt   r)   ru   config_validationrZ   r   r   r   rX   r   T)successr6   rt   ru   rH   )r   r   r6   rS  rT  r	   rU  r   r5   rG   r   r   r   rW  r   r;   r+   r,   r   r   r   r4   r_   commitr   )rZ   rX   r   rZ  r\  r   rH   r   s           r/   validate_whatsapp_configr    s   3rHMM-"?"?!@@jklH	lnEE	F 
&::$0J0J/K&LM  

 s"$X.(C(CNopvowLxyymmoG+F;>w{{Ka?b?hfh;i;o;o;qM847O8T8ZXZ4[4a4a4cM1&$$''kk"89 IIK+%55;$[[)?@kk/2 /
 
s   #F99GrL  c                   |j                         }t        ||      }	 t        | ||      \  }}}}	t	        |dd| ||d	|j                  j                  ||	
       |j                          t        d||	d      S # t        $ rg}
t	        |t
        d|  d|
j                   | ||
j                  d|j                  j                  t        |              |j                          |
d }
~
ww xY w)Nrm   r  zInvio test fallito verso r   )rL  r   rH   r  outbound_testzMessaggio test inviato a )r  r   r  Tz%Messaggio test inviato correttamente.)r  rE  r^  rH   )r+   r   r`  r   r   OUTBOUND_ERROR_EVENTrH   r4   r_   rW   r  r   )rL  r   rZ   rX   rY  r   rE  r[  r   r^  ri  s              r/   send_test_whatsapp_messager    s    MMOM3rHMM7T'8
4	<*" "+I;7(g>$$''  IIK#6	 -  
+/t2cjj\B-3::N"((++04	
 				
s   A= =	C-A"C((C-modeverify_token	challengec                 |    t               }| dk7  s||j                  k7  s|t        t        j                  d      |S )N	subscribez!Verifica webhook WhatsApp fallitarF   )r   r   r   r   HTTP_403_FORBIDDEN)r  r  r  r,   s       r/   verify_webhook_handshaker    s?    ,.H{lh.L.LLPYPa(A(AJmnnr1   r   	signaturec                    t               }|j                  s(|j                  rt        t        j
                  d      y |st        t        j                  d      dt        j                  |j                  j                  d      | t        j                        j                         z   }t        j                  ||      st        t        j                  d      y )Nz#WHATSAPP_APP_SECRET non configuratorF   zFirma webhook WhatsApp mancantezsha256=utf-8z!Firma webhook WhatsApp non valida)r	   r   is_productionr   r   HTTP_503_SERVICE_UNAVAILABLEHTTP_401_UNAUTHORIZEDhmacnewencodehashlibsha256	hexdigestcompare_digest)r   r  r,   expecteds       r/   validate_webhook_signaturer  	  s    ~H''!!"??<  	444
 	

 488H$@$@$G$G$PRVX_XfXfgqqssHx3446
 	
 4r1   contacts_by_wa_idc                 (   | j                  d      }|j                  |xs d|xs d      }| j                  d      xs d}|dk(  rB| j                  di       j                  d      xs d}d| d	|d d
  j                         }||fS d| d| }||fS )Nfromr)   sconosciutor   unknownr   r   zMessaggio in arrivo da r      z
Messaggio z in arrivo da )r   r+   )r   r  rx  r<  message_typer   r   s          r/   summarize_incoming_messager     s    [[ F#''"f6MNK;;v&3)LvKK+//7=2	+K=9Tc?:KLRRT F? |nN;-HF?r1   status_itemc                 n    | j                  d      }| j                  d      xs d}d|xs d d| }||fS )Nrecipient_idr   r  zAggiornamento messaggio verso r  r   )r   )r  rE  delivery_statusr   s       r/   summarize_status_updater  -  sG    /I!ooh/<9O.y/IM.J"_L]^GIr1   c                 	   d}| j                  d      }t        |t              s t        |dd|        |j	                          y|D ]  }t        |t
              s|j                  dg       D ]  }t        |t
              s|j                  di       }t        |t
              s8|j                  d	i       }t        |t
              r|j                  d
      nd }d }	t        |t              r|j                         r	 t        ||d      }	|j                  dg       }
|
D ci c]d  }t        |t
              rR|j                  d      rA|j                  d      |j                  di       j                  d|j                  d            f }}|j                  dg       }|D ]$  }t        |t
              st        |t        |j                  d            r7t        |      }t        ||      \  }}|j                  |xs d|xs d      }|rt        ||      nd }|r&t        ||r||k7  r|n||      }||j                   }n|r|}|rp|rn|	lt#        ||	j$                  j&                  ||      \  }}}|rCt        |dd| |||d|	j$                  j&                  ||j                  d             |dz  }t        |t        |||	|	j$                  j&                  nd ||j                  d             |r<|r:|	8t)        ||	j$                  j&                  |d||j                  d      ddd        |dz  }|rR|rP|	Nt+        |||	j$                  j&                  !      }t-        ||	j$                  j&                  ||||"       |dz  }|s|s|	t        |t.        d#||d$||j                  d      %       |dz  }' |j                  d&g       }|D ]_  }t        |t
              st1        |      \  }}t        |d'|||	|	j$                  j&                  nd ||j                  d             |dz  }a   |dk(  rt        |dd(|        d}|j	                          |S # t        $ r d }	Y ow xY wc c}w ))Nr   r  webhook_unknownzWebhook WhatsApp senza entry)rZ   r   r   r   r\   changesr=   metadatar6   T)rZ   r6   rY   contactswa_idprofiler   rR  r_   )r   r   r)   r  )phoner@  rZ   )rZ   rX   r   r   inbound_ignoredzHMessaggio WhatsApp ignorato perche piu vecchio del contesto attuale per )r   r   latest_processed_timestampr  r   rG  zinbound-webhook)rz  source)rZ   rX   r   r   r   r   r   )r   rX   )rZ   rX   rx  r<  r   r  zFMessaggio WhatsApp ricevuto su una linea non associata a nessun locale)r   r6   )rZ   r   r   r   r   r   statusesr  z0Webhook WhatsApp ricevuto senza messaggi o stati)r   r   r   r   r  r   r;   r+   rk   re   r   r   r   r  r   r   r@  r   r4   r_   r   r   r  r  r  )r   rZ   processed_eventsentriesr  changer=   r  r6   venue_configurationr  contactr  rR  r   message_textr   rx  r<  stored_contact_nameremembered_contactstale_messager   r   r  r  r  rE  s                               r/   process_webhook_payloadr  4  s   kk'"Ggt$B+<Fdnuv
		 H&%&ii	2. E	&Ffd+JJw+EeT*yyR0HAKHVZA[hll+<=aeO"&/3/O4I4I4K/*D(726+' yyR0H  (!gt,W1E G$gkk)R&@&D&DVW[[Y`Ma&bb! ! yyR0H# Z*!'40 0EU\U`U`aeUfg3G<"<WFW"X/33FLb&BYMZU[&Efb&Qae#)B$4?KSYDY[_r*&
 *5&8&E&E("5Kl/B/NJb!4!:!:!=!=&, '	KGM#57G %(!'8&nounv$w+26H>N%
 &9%>%>%A%A*0*1++d*; )A-(  4##=P=\06699bf"(")++d"3 l/B/N)!4!:!:!=!=&,# ,-4[[->*4@QR !A% l/B/N#=&,!4!:!:!=!=$L
 2!4!:!:!=!=%$/ '%1 %)$1D1L$#8 h,3 X&,&-kk$&7 %)$uZ*x yyR0H' &!+t4%<[%I" 0#'=P=\06699bf"+"-//$"7 !A% &qE	&H&T 1(F		
 IIKC " /*.'/!s   =Q,!A)Q>,Q;:Q;c                 (   | si S 	 t        j                  | j                  d            }t        |t              st        t        j                  d      |S # t        t         j                  f$ r!}t        t        j                  d      |d }~ww xY w)Nr  z#Payload webhook WhatsApp non validorF   )
r   r/  decodeUnicodeDecodeErrorr0  r   r   r   r   r   )r   r   ri  s      r/   parse_webhook_bodyr    s    	|**T[[12 gt$(C(CLqrrN	  4 45 |(C(CLqrx{{|s   $A B0BBc                N   t        t              j                  t        j                  j	                         t        j
                  j	                               }|"|j                  t        j                  |k(        }|j                  |      }t        | j                  |            S rK   )r   r   r   r   r   r_   r`   rX   rb   r   r   )rZ   rb   rX   rg   s       r/   list_whatsapp_logsr    s|    "#,,-=-H-H-M-M-OQaQdQdQiQiQklDzz*33x?@::eD

4 !!r1   )rA   )2   )jr  r  r   r*  dataclassesr   typingr   rS  fastapir   r   
sqlalchemyr   sqlalchemy.ormr   app.core.configr	   app.models.bookingr
   app.models.venuer   &app.services.booking_assistant_servicer   r   %app.services.booking_settings_servicer   r   r   r   r   r   r   r   r   %app.services.whatsapp_contact_servicer   r   !app.services.time_context_servicer   app.models.whatsappr   r   app.schemas.whatsappr   r   r   r   r   r   r  r  r  compiler9  r   r   r;   r0   r3   r   rD   rW   r   rk   r   r   r   r   Responser   r   r   objectr   r   r   r   tupler   r   r   r   r   r  r  r  r$  r7  r   rB  rD  r`  ro  rw  r  r  r  r  bytesr  r  r  r  r  r  r<   r1   r/   <module>r     s      	 !   )  " ( 3 " i
 
 
 m O G s s#) ' ' ) 7 "

?3   DcN       ScDj S# ScDj S	0# 	0# 	0  "&&+.. Dj. 4Z	.
  $.  .b @D #w ##* #H^ #L LP 7 cDj Tn s t# t# t
G%.. GS G9 9# 9# 98   $ $  	
  Dj : : < #'"&'+&*  	
   4Z 4Z * Vt# T!@'g 'c '#* 'QU ' 3: G s 3 SVY]S] ,:G :s :3 :Y] :bghlnqtxnxz}  AE  {E  iE  cF :$ 3: 4$ 43: 4.87 .8c .8S .8UYZ^_bdg_gZhUi .8b MO Gw G# Gc GSWX\]`bh]hXiSj G^   	
  

 *d38n1E $sTZ{J[ *
3 
3 
 d
 BS S4Z <sTz c cDj S -C-C-C .	-C
 3dC$J&'-C`7G7GtCH~&7G 	7G
 7G 38_7GtKGKGKG 	KG
 3d
?KG\FF F 	F
 tF F tCH~&F 
FR EI ! !sTz !Mm !H ^b $3 $ $' $PSVZPZ $f~ $N3: S4Z TWZ^T^ cf 
U 
sTz 
d 
.
 
c3h 
TYZ]_bei_iZiTj 
 %S4Z2H \T \w \3 \~	U 	t 	"t "7 "3 "#* "X\]mXn "r1   