Ë
    qýujl:  ã                   ó.  — d dl Z d dlZd dlZd dlm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mZ d d	lmZ d d
lmZmZmZmZmZ d dlmZmZmZ d dlm Z m!Z!m"Z" d dl#m$Z$  ejJ                  e&«      Z'dZ(de)fd„Z*dde+de+de+de+de+de+de+fd„Z,y)é    N)Údatetime)ÚListÚDict)ÚBadRequestError)Úsettings)Úclient)Úchat_system_prompt)ÚTOOL_SCHEMASÚdispatch_tool)Údisabled_tools_for)Úget_latest_summaryÚget_ticket_by_threadÚinsert_feedbackÚinsert_llm_usageÚinsert_summary)Úget_chat_historyÚsave_chat_messageÚget_takeover_status)Úcheck_quotaÚQuotaExceededErrorÚestimate_text_tokens)Úpublish_eventé   Úreturnc                 óÐ   — t        | dd«      xs i }t        |t        «      r*|j                  d«      xs |}|j                  d«      dk(  rydt	        | «      v xs dt	        | «      v S )z<True when a 400 came from Azure's content-management policy.ÚbodyNÚerrorÚcodeÚcontent_filterTzcontent management policy)ÚgetattrÚ
isinstanceÚdictÚgetÚstr)Úerrr   Úinners      ú0/var/www/html/strategist-ai/app/services/chat.pyÚ_is_content_filterr(      se   € ä�3˜ Ó%Ò+¨€DÜ�$œÔØ—‘˜Ó!Ò) TˆØ�9‰9�VÓÐ 0Ò0ØØœs 3›xÐ'ÒRÐ+FÌ#ÈcË(Ð+RÐRó    Ú	tenant_idÚ
user_queryÚ	thread_idÚ	user_nameÚroleÚuser_idÚlocationc              ƒ   ó  ‡/‡0K  — t         j                  d| › d|› d|› d|› �«       	 t        | d|¬«       t        | ||¬«      }t	        |«      dk(  }|rt        | d|¬«       |d	k(  r/t         j                  d
«       t        | ||||d|¬«       dg g dœdœS t        | ||¬«      }	|	r8|dk(  r3t         j                  d|› d�«       t        | ||||d|¬«       dg g dœdœS t        | ||||d|¬«       t        | «      }
t        |
«      }t        | |«      }|rd|d   › d�}||z  }|rd|› d�}||z  }|r(t         j                  d| › d|› �«       t        | d|«       t        | d«      }|rd|› d|› d�}||z  }t        | d «      }|rd!|› d"�}||z  }d#|d$œgŠ0|D ]'  }|d%   }|d	k(  rd&}|d'   }‰0j                  ||d$œ«       Œ) |}‰0j                  d|d$œ«       t        | d(|¬«       t        d)„ ‰0D «       «      d*z   }t        | d||¬+«       t        Š/|
rBt        D �cg c]  }|d,   d-   |
vr|‘Œ c}Š/t         j                  d.| › d/t        |
«      › �«       t         j                  d0«       | ||||d1œ}g }g }g }d2}d}d}t!        t"        «      D �]  } | dkD  r$t        d3„ ‰0D «       «      d*z   }!t        | d||!¬+«       t$        j&                  j)                  ˆ/ˆ0fd4„«      ƒ d2{  –—† }"|"j*                  }#|#�||#j,                  z  }||#j.                  z  }|"j0                  d   j2                  }|j4                  s|j6                  } �n�‰0j                  d&|j6                  xs d5|j4                  D �$cg c]=  }$|$j8                  d,|$j:                  j<                  |$j:                  j>                  d6œd7œ‘Œ? c}$d8œ«       |j4                  D �]×  }$	 tA        jB                  |$j:                  j>                  «      }%|$j:                  j<                  d:k(  r`|%jK                  d;g «      }&tM        |&tN        «      r|jQ                  |&«       n,t         jI                  d<tS        |&«      jT                  › d=�«       |j                  |$j:                  j<                  «       tW        |$j:                  j<                  |%|«      ƒ d2{  –—† }'‰0j                  d>|$j8                  tA        jX                  |'d?¬@«      dAœ«       |$j:                  j<                  dBk(  r?tM        |'tZ        «      r/|'jK                  dC«      dDk(  r|j                  |'dE   |'dF   d2dGœ«       |$j:                  j<                  dHk(  s�ŒœtM        |'tZ        «      s�Œ®|'jK                  dC«      dIk(  s�ŒÄ|jQ                  |'dJ   «       �ŒÚ �Œ t         jI                  dKt"        › dL| › dM|› dN�«       |sdO}t]        | dPt^        j`                  ||||z   dQ|i«       t        | d&|||d|¬«       	 tc        | ||||dR|dSœdTœ«       |ru	 |||xs dXd5d?ti        jj                  «       jm                  «       ti        jj                  «       jm                  «       |d2dY dZz   d[œ})d#d\d]|)d^œ}*to        d_| › d`�|*«      ƒ d2{  –—†  ||||dbœS c c}w 7 �Œ¹c c}$w # t@        jD                  tF        f$ r2 t         jI                  d9|$j:                  j<                  › �«       i }%Y �Œøw xY w7 �Œ:# td        $ r(}(t         jg                  dU| › d/|(› �dV¬W«       Y d2}(~(�Œd2}(~(ww xY w7 Œ�# td        $ r"}+t         jI                  da|+› �«       Y d2}+~+ŒÁd2}+~+ww xY w# tp        $ r},t         jI                  dc|,› �«       ‚ d2},~,wtr        $ rY}-tu        |-«      r$t         jI                  dd|› de�«       dfg g dgœcY d2}-~-S t         jg                  dh|-› �dV¬W«       dig g dgœcY d2}-~-S d2}-~-wtd        $ r*}.t         jg                  dj|.› �dV¬W«       dig g dgœcY d2}.~.S d2}.~.ww xY w­w)kzY
    Core RAG-based chat logic with AI ticketing and mandatory integrated analytics.
    z#Processing chat request for tenant z
, user_id z	, thread z, user Ú	ai_tokens)r/   r   Úai_conversationsÚadminzIAdmin response detected. Logging to Firestore and skipping AI processing.zAdmin InteractionzMessage saved successfully.)ÚurlsÚimages)ÚtextÚ	resourcesÚuserzThread z: is under human takeover. Logging message and skipping AI.z User Interaction (Human Handled)z:Human takeover active. A real person will respond shortly.zChat Interactionz*

[SESSION CONTEXT: A support ticket (ID: Ú	ticket_idzÄ) is already active for this session. Do NOT ask for the user's name, email, or phone number again as we already have them. Only focus on the new issue details if the user reports something else.]z>

[USER INFO: The person you are talking to identification is z. Do NOT ask for their name.]z(Updating location preference for tenant z to: r0   z'

[LANGUAGE: Use professional business z^ English. Adapt your vocabulary, tone, and spelling to align with local business standards in z=. Prefer English unless context strongly suggests otherwise.]Úbrand_personazU

[BRAND PERSONA: You must strictly follow these personality traits while answering: ú]Úsystem)r.   Úcontentr.   Ú	assistantr>   Úai_responsesc              3   óR   K  — | ]  }t        |j                  d d«      «      –— Œ! y­w©r>   Ú N©r   r#   ©Ú.0Úmsgs     r'   ú	<genexpr>z$get_chat_response.<locals>.<genexpr>t   s"   è ø€ Ò#eÐUXÔ$8¸¿¹ÀÈBÓ9O×$PÑ#eùs   ‚%'éè  )r/   Úrequested_amountÚfunctionÚnamezTools disabled for z: zCalling LLM with tool loop...)r*   r,   r-   r/   ÚhistoryNc              3   óX   K  — | ]"  }t        |j                  d «      xs d«      –— Œ$ y­wrB   rD   rE   s     r'   rH   z$get_chat_response.<locals>.<genexpr>�   s)   è ø€ ò /ØGJÔ(¨¯©°Ó);Ò)A¸r×Bñ/ùs   ‚(*c                  ó|   •— t         j                  j                  j                  t        j
                  ‰‰ dd¬«      S )NrI   g      N@)ÚmodelÚmessagesÚtoolsÚmax_completion_tokensÚtimeout)Úopenai_clientÚchatÚcompletionsÚcreater   Ú	LLM_MODEL)Úactive_toolsrQ   s   €€r'   ú<lambda>z#get_chat_response.<locals>.<lambda>˜   s8   ø€ œ×*Ñ*×6Ñ6×=Ñ=Ü"×,Ñ,Ø%Ø&Ø*.Ø ð >ó € r)   rC   )rL   Ú	arguments)ÚidÚtyperK   )r.   r>   Ú
tool_callsz(Malformed tool arguments from model for Úattach_resourcesr8   z0attach_resources returned non-list 'resources' (z); ignoring.ÚtoolF)Úensure_ascii)r.   Útool_call_idr>   Úsend_documentÚstatusÚsentÚ	file_nameÚurl)Úlabelrh   ÚimageÚrecommend_productsÚfoundÚproductszTool loop hit the z3-round bound without a final text response (tenant=z	, thread=z). Returning fallback text.zaI've noted your request and taken the appropriate action. Is there anything else I can help with?ÚChatr,   rV   )Úinteraction_typer/   )r,   r-   ÚquestionÚanswerÚmetadataz1Failed to log interaction to Postgres for tenant T)Úexc_infoÚ	Anonymouséd   z...)r,   r/   r-   ÚsummaryÚtakeover_activeÚ
created_atÚ
updated_atÚlast_message_previewÚnew_thread_createdzA new conversation has started)r^   ÚeventÚmessageÚdataÚtenant_z:conversation_listz'Failed to publish new thread to redis: )r7   r8   rR   rm   zQuota exceeded during chat: z4Azure content filter blocked the request for thread ú.zoI can't help with that request. Please rephrase it, or ask me something about our products, pricing or support.)r7   r8   rR   zBad request to the LLM: z)I encountered an error. Please try again.zError in chat generation: );ÚloggerÚinfor   r   Úlenr   r   r   r	   r   r   r   ÚappendÚsumr
   ÚsortedÚrangeÚMAX_TOOL_ROUNDSÚanyioÚ	to_threadÚrun_syncÚusageÚprompt_tokensÚcompletion_tokensÚchoicesr}   r_   r>   r]   rK   rL   r\   ÚjsonÚloadsÚJSONDecodeErrorÚ	TypeErrorÚwarningr#   r!   ÚlistÚextendr^   Ú__name__r   Údumpsr"   r   r   rY   r   Ú	Exceptionr   r   ÚutcnowÚ	isoformatr   r   r   r(   )1r*   r+   r,   r-   r.   r/   r0   rM   Úis_new_threadÚis_takeover_activeÚdisabled_toolsÚsystem_promptÚexisting_ticket_initialÚsession_contextÚuser_contextÚcurrent_locationÚlanguage_contextr;   Úpersona_contextrG   Úrole_valÚcontent_valÚdisplay_queryÚprojected_chat_tokensÚtÚtool_ctxr8   rm   Ú
tools_usedÚai_responseÚtotal_prompt_tokensÚtotal_completion_tokensÚround_indexÚcurrent_projected_tokensÚresponserŒ   ÚtcÚ	tool_argsÚcandidate_resourcesÚtool_resultÚpg_errÚthread_payloadÚpayloadÚws_errÚqeÚbreÚerZ   rQ   s1                                                  @@r'   Úget_chat_responser¾   %   s+	  ùè ø€ ô ‡K�KÐ5°i°[À
È7È)ÐS\Ð]fÐ\gÐgnÐoxÐnyÐzÔ{ðucä�I˜{°GÕ<ä" 9¨iÀÔIˆÜ˜G›¨Ñ)ˆñ Ü˜	Ð#5¸wÕGð �7Š?Ü�K‰KÐcÔdÜ˜i¨¨z¸9ÀiÐQdÐnuÕvØ9ÐQSÐ_aÑHbÑcÐcô 1°¸IÈwÔWÐÙ $¨&¢.Ü�K‰K˜' ) Ð,fÐgÔhÜ˜i¨¨z¸9ÀiÐQsð  ~Eõ  FØXÐprð  Añ  hBñ  Cð  Cô 	˜) T¨:°yÀ)ÐM_ÐipÕqô ,¨IÓ6ˆÜ*¨>Ó:ˆô #7°yÀ)Ó"LÐÙ"Ø LÐMdÐepÑMqÐLrð  swð  xˆOØ˜_Ñ,ˆMáØ]Ð^gÐ]hð  iFð  GˆLØ˜\Ñ)ˆMñ Ü�K‰KÐBÀ9À+ÈUÐS[ÐR\Ð]Ô^Ü˜9 j°(Ô;ä-¨i¸ÓDÐÙØ!JÐK[ÐJ\ð  ]{ð  |Lð  {Mð  MJð   KÐØÐ-Ñ-ˆMä*¨9°oÓFˆÙØ wð  yFð  xGð  GHð  IˆOØ˜_Ñ,ˆMà%°-Ñ@ÐAˆØò 	HˆCØ˜6‘{ˆHØ˜7Ò"Ø&�Ø˜i™.ˆKØ�O‰O X¸+ÑFÕGð	Hð #ˆà�‰ °MÑBÔCô 	�I˜~°wÕ?Ü #Ñ#eÐ\dÔ#eÓ eÐhlÑ lÐÜ�I˜{°GÐNcÕdô
 $ˆÙÜ'3ö L !Ø  ™}¨VÑ4¸NÑJò ò LˆLä�K‰KÐ-¨i¨[¸¼6À.Ó;QÐ:RÐSÔTô 	�‰Ð3Ô4Ø!*¸Ø!*°wÈ7ñTˆàˆ	ØˆØˆ
ØˆØÐØ"#Ðä ¤Ó1ó O	ˆKð ˜QŠÜ+.ñ /ØNVô/ó ,àñ,Ð(ô ˜I {¸GØ-EõGô #Ÿ_™_×5Ñ5ôó÷ ˆHð —N‘NˆEØÐ Ø# u×':Ñ':Ñ:Ð#Ø'¨5×+BÑ+BÑBÐ'à×"Ñ" 1Ñ%×-Ñ-ˆCØ—>’>Ø!Ÿk™k�Úà�O‰OØ#ØŸ;™;Ò,¨"ð "Ÿn™nöð ð Ÿ5™5¨*Ø*,¯+©+×*:Ñ*:ÈÏÉ×I^ÑI^Ñ!_óaòñô ð —n‘nó "=�ð#Ü $§
¡
¨2¯;©;×+@Ñ+@Ó A�Ið —;‘;×#Ñ#Ð'9Ò9Ø*3¯-©-¸ÀRÓ*HÐ'Ü!Ð"5´tÔ<Ø!×(Ñ(Ð)<Õ=äŸ™ð Ü $Ð%8Ó 9× BÑ BÐCÀ<ðQôð ×!Ñ! "§+¡+×"2Ñ"2Ô3Ü$1°"·+±+×2BÑ2BÀIÈxÓ$X×X�ð —‘¨ÀÇÁÜ,0¯J©J°{ÐQVÔ,Wñ!Yô Zð
 —K‘K×$Ñ$¨Ò7Ü& {´DÔ9Ø'ŸO™O¨HÓ5¸Ò?Ø×$Ñ$¨{¸;Ñ/GØ-8¸Ñ-?Ø/3ñ&5ô 6ð —K‘K×$Ñ$Ð(<Ô<Ü& {´DÖ9Ø'ŸO™O¨HÓ5¸Ô@Ø—O‘O K°
Ñ$;Ö<òE"=ðQO	ôX �N‰NØ$¤_Ð$5ð 6Ø$˜+ Y¨y¨kÐ9TðVôñ
 ðEˆKô 	˜ F¬H×,>Ñ,>Ð@SØ0Ð2EÐH_Ñ2_Ø% yÐ1ô	3ô
 	˜) [°+¸yÈ)ÐUgÐqxÕyð		sÜ˜IØ&Ø&Ø&Ø%Ø17ÀGÑLñ(ô ñ ðSà!*Ø&Ø!*Ò!9¨kØ!Ø',Ü"*§/¡/Ó"3×"=Ñ"=Ó"?Ü"*§/¡/Ó"3×"=Ñ"=Ó"?Ø,6°t¸Ð,<¸uÑ,Dñ	"�ð %Ø1Ø?Ø*ñ	�ô $ g¨i¨[Ð8JÐ$KÈWÓU×UÐUð $°)ÀjØ$ñ&ð 	&ùò_Lð6ûò,øô ×,Ñ,¬iÐ8ò #Ü—N‘NÐ%MÈbÏkÉk×N^ÑN^ÐM_Ð#`ÔaØ "“Ið#úð YúôZ ò 	sÜ�L‰LÐLÈYÈKÐWYÐZ`ÐYaÐbÐmqˆL×rÒrûð	súð* VùÜò SÜ—‘Ð!HÈÈÐQ×RÑRûðSûô ò Ü�‰Ð5°b°TÐ:Ô;ØûÜò cô ˜cÔ"Ü�N‰NÐQÐR[ÐQ\Ð\]Ð^Ô_ðLàØñ	õ ô 	�‰Ð/°¨uÐ5ÀˆÔEØCÐRTÐ_aÑbÕbûÜò cÜ�‰Ð1°!°Ð5ÀˆÔEØCÐRTÐ_aÑbÕbûðcüse  „"`§A-] Â`ÂA] Ã`ÃD:] ÈZÈ*B2] ËZËB] Í*AZÎ,] Ï)ZÏ/C] Ò1[+Ò2B)] Õ] Õ/] ÖA7] ×=[. Ø] ØA/\$ Ú\"Ú\$ Ú	] Ú`Ú] Ú] ÚA[(Û$] Û'[(Û(] Û.	\Û7\Ü] Ü\Ü] Ü"\$ Ü$	]Ü-]
Ý] Ý
]Ý] Ý	`
Ý]4Ý4`
Þ )_Þ)`
Þ*`Þ/_ß`
ß`ß`
ß `ß?`
à `à`
à
`)ÚdefaultNr9   NN)-r‰   r�   Úloggingr   Útypingr   r   Úopenair   Úapp.core.configr   Úapp.core.llm_clientr   rU   Úapp.core.promptsr	   Úapp.services.chat_toolsr
   r   Úapp.services.tools_settingsr   Úapp.services.databaser   r   r   r   r   Úapp.services.firestore_servicer   r   r   Úapp.services.quotasr   r   r   Úapp.services.redis_servicer   Ú	getLoggerr—   r�   rˆ   Úboolr(   r$   r¾   © r)   r'   ú<module>rÏ      s»   ðÛ Û Û Ý ß å "å $Ý 7Ý /ß ?Ý :÷õ ÷ dÑ cß UÑ UÝ 4à	ˆ×	Ñ	˜8Ó	$€ð €ðS˜tó Sñ{c sð {c¸ð {cÈð {cÐdgð {cÐvyð {cð  NQð {cð  dgô {cr)   