
    +Ϳh;                     ^   d dl 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	 d dl
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 d d	lmZ d d
lmZmZ m!Z!m"Z"m#Z#m$Z$m%Z%  ee&      Z' e        de(fdZ)e'jT                  d        Z+e'jX                  d        Z-de(de"fdZ.defdZ/e	d        Z0d0de1de(de1fdZ2e'jg                  d      d        Z4e'jk                  d      d        Z6e'jg                  ddg      d        Z7d dl8mZ e'jg                  dd g      d!        Z9e'jg                  d"dg      d#        Z:e'jg                  d$dg      d%        Z;e'jg                  d&d g      d'        Z<e'jg                  d(dg      d)        Z=e&d*k(  re'j}                  d+d,d-d./       yy)1    N)perf_counter)contextmanager)Flaskgrequestjsonifyrender_templateabort)functext)OpenAI)SessionLocalinit_db)generate_rag_addendum)build_messages_payload)TenantSessionUserCaseMessageDocumentTopicreturnc                  @    t        t        j                  dd            S )zASingle source of truth: bind from systemd Environment=TENANT_ID=4	TENANT_ID4)intosgetenv     /var/www/html/dynbot5004/app.pycurrent_tenant_idr#   '   s    ryyc*++r!   c                      t               t        _        t               t        _        t
        j                  j                  dt        j                   dt        j                   dt        j                          y )Nz	[TENANT]  )r#   r   	tenant_idr   dbapploggerinfor   methodpathr    r!   r"   bind_tenant_and_sessionr-   +   sE    #%AK>ADJJOOi}Agnn-=Qw||nMNr!   c                     t        t        dd       }|$	 | r|j                          |j                          y y # |j                          w xY w)Nr'   )getattrr   rollbackclose)excr'   s     r"   teardown_sessionr3   1   sA    	D$	B	~	HHJ 
 HHJs	   9 Acase_idc                     t         j                  j                  t              j	                  | t         j
                        j                         }|st        d       |S )z=Ensure the case belongs to the current tenant, otherwise 404.)idr&   i  )r   r'   queryr   	filter_byr&   firstr
   )r4   cases     r"   ensure_caser;   ;   s@    44::d%%AKK%HNNPDc
Kr!   c                      t        j                  d      xs dj                         } | st        d      t	        j
                         j                  d| dd        t        |       S )z1Use env OPENAI_API_KEY only. Never hardcode keys.OPENAI_API_KEY zOPENAI_API_KEY not setu#   🔑 OPENAI_API_KEY ends with …%sNapi_key)r   r   stripRuntimeErrorlogging	getLoggerr*   r   r@   s    r"   get_openai_clientrF   B   sY    yy)*0b779G344BGBCLQ'""r!   c              #      K   t               }	 d  t        t               |z
  dz        || <   y # t        t               |z
  dz        || <   w xY ww)N  )r   r   )labelbagt0s      r"   timedrL   J   sI     	B7,.2-56E
S,.2-56E
s   A/ AAAr   	max_itemsc                    t        j                  d|       }|s| S | d|j                          j                  d      }| |j                         d }t        j                  d|      }|s| S g }t        |d| d      D ],  \  }\  }}	|j                  | d|	j                                 . |r|dz   nd	dj                  |      z   S )
uR   Keep only the first N numbered list items (1., 2., …) to avoid overlong replies.z(?m)^\s*\d+\.\s+N
z((?ms)^\s*(\d+)\.\s+(.*?)(?=^\s*\d+\.|\Z)   )startz. 

r>   )	researchrQ   rstripfindall	enumerateappendrB   join)
r   rM   mheadbodyblocksoutidx_numcontents
             r"   truncate_numbered_blocksrb   R   s    
		%t,A
""4(D	
DZZCTJF
C )&)*<A F 0_dG

cU"W]]_-./0!D6MrV[[-===r!   /c                      t        d      S )Nz
index.html)r	   r    r!   r"   indexre   d   s    <((r!   z	/__whoamic                  &    dt         j                  iS )Nr&   )r   r&   r    r!   r"   whoamirg   h   s    %%r!   z/tenantsPOST)methodsc                      t         j                  } t        t        j                  d         }| j                  |       | j                          | j                  |       t        d|j                  i      dfS )Nname)rk   r&      )
r   r'   r   r   jsonaddcommitrefreshr   r6   )r'   ts     r"   create_tenantrr   l   sT    	
BGLL()AFF1Iryy{BJJqMK&',,r!   )r   z/topics/randomGETc            
          t         j                  } t         j                  }	 | j                  t              j                  t        j                  |k(        j                  t        j                               j                  d      j                         }g }|D ]L  }|j)                  |j*                  |j,                  xs dj%                  d|j*                  xs d      d	       N t'        |      S # t        $ r t        j                  j                  d       | j                  t!        d      d|i      j#                         }|D cg c](  }|d   |d   xs dj%                  d|d   xs d      d	* nc c}w }}t'        |      cY S w xY w)
N   z9[topics/random] ORM query failed; falling back to raw SQLz
                SELECT topic, question
                FROM topics
                WHERE tenant_id = :tid
                ORDER BY RANDOM()
                LIMIT 3
            tidr   rP   r>   z{topic})topicquestion)r   r'   r&   r7   r   filterorder_byr   randomlimitall	Exceptionr(   r)   	exceptionexecuter   fetchallreplacer   rX   rw   rx   )r'   r&   
raw_topicsrowsrresultsrq   s          r"   get_random_topicsr   u   s_   	
BI  HHUOveoo23x&uQxsu 	8 G WW)r229aggmL
 	
 77   

XY zz   I	
 (* 	 fjj`aQqT!
/C/CIqQRtzWY/Z[jjjw% s   A3C3 3AF
-E87FFz/init-sessionc                  V   t         j                  } t        j                  d      xs i }t         j                  }|j                  d      xs t        t        j                               j                         }|j                  d      xs dj                         }|j                  d      xs dj                         }| j                  t              j                  ||      j                         }|s@t        |||	      }| j                  |       | j                          | j!                  |       | j                  t"              j                  ||
      j                         }|sJt#        ||j$                  |      }| j                  |       | j                          | j!                  |       | j                  t&              j                  ||j$                        j)                  t&        j$                  j+                               j                         }|sht'        ||j$                  |j$                  |j                  d      xs d       }| j                  |       | j                          | j!                  |       t-        |j$                  ||j$                  d      S )NTsilentsession_tokenusernamezDefault Useremailzdefault@example.com)r&   r   )r&   r   r   )r&   r   )r&   user_idr   )r&   
session_id
case_title)r&   r   r   title)r   r   r4   )r   r'   r   get_jsonr&   getstruuiduuid4rB   r7   r   r8   r9   rn   ro   rp   ChatSessionr6   r   rz   ascr   )	r'   datar&   r   r   r   user	chat_sessr:   s	            r"   init_sessionr      s   	
B4(.BDI XXo.C#djjl2CJJLM $6==?HXXg7"7>>@E 	9y89<57 	
 i(%H
t
		


4 	9y9F57 
 GG'
	
 	y
		


9 	9yY\\9B8DGGKKM"57	 	 GG ||88L)1T	
 	t
		


4ll&77  r!   z/casesc                  :   t         j                  } t         j                  }t        |t        j
                  j                  d      xs dd d       }| j                  |       | j                          | j                  |       t        d|j                  i      dfS )Nr   r>      r&   r   r4   rl   )r   r'   r&   r   r   rm   r   rn   ro   rp   r   r6   )r'   r&   new_cases      r"   create_caser      su    	
BIi0@0@0I0ORQURU/VWHFF8biik2::h#7Ix{{+,c11r!   z/cases/<int:case_id>/historyc           
      >   t         j                  }t        |        |j                  t              j                  t        t        j                  t        j                  k(        j                  t        j                  | k(  t        j                  t         j                  k(        j                  t        j                        j                         }t        d|D cg c]4  }|j                  |j                   |j                  j#                         d6 c}i      S c c}w )Nmessages)rolera   	timestamp)r   r'   r;   r7   r   rY   r   r4   r6   ry   r&   rz   r   r}   r   r   ra   	isoformat)r4   r'   msgsrZ   s       r"   get_historyr      s    	
B 	4goo016$''W$dnn&CD8G%%&35 	 
 VV		@U@U@WX
  
s   9D
z/cases/<int:case_id>/messagesc                    t         j                  j                  dd      }t        j                  }t        |        i }t               }d}	 t        j                  d      xs i }|j                  d      xs dj                         }|j                  d      xs dj                         }t        j                  }	|st        dd	d
      dfS |dk(  rt        d|      5  	 t        ||	d      }
|
j                  d      xs dj                         }d d d        t        |d      }t        t               |z
  dz        }d|j                  dd       d| |j                  d<   |dfS t        d|      5  t!        | d||      }|j#                  |       |j%                          |j'                  |       d d d        t        d|      5  t)        || |	      }d d d        t+               }t        d|      5  |j,                  j.                  j1                  dd d!d"d#d$d%d&d'd(id)id%gd*d+d,gd-.      }d d d        j2                  d   }t5        |d/d       }t5        |d0d       }|d1k(  rs|rqt5        |d1d       rd|j6                  d   }t9        j:                  t5        |j<                  d2d3      xs d3      }|j                  d%g       xs g }|j>                  xs d4}ng }|r|j>                  ndxs d5}tA        |d6      }tC        jD                  d7|      }tG        |      dkD  rtI        jJ                  |d      }|jM                  t               jO                  tP        t         jR                  tP        jT                  k(        jW                  tP        jT                  | k(  tP        j                  t        j                  k(        jY                  t         jZ                        j]                         }t_        d8 |D              }|dk(  }| xr tG        |      dk(  }|r	 t        d9|      5  |ja                         |j%                          d d d        |g g d:|d;}t        |      }t        t               |z
  dz        }d<jO                  |je                         D cg c]  \  }}| d=|  c}}      } | r|  d| nd>| |j                  d<   |dfS |r4t        d?|      5  |jM                  tf              ji                  |	d@A      jk                         }!|jM                  tf              ji                  |	dBA      j]                         }"|!r|!j>                  nd}#|"rtI        jl                  |"      j>                  nd}|D $cg c]  }$|$jn                  dk(  s|$jp                    }%}$|#xs djs                  tG        |%      dkD  r|%d   ndtG        |%      dkD  r|%d   ndtG        |%      dCkD  r|%dC   ndD      }&|& dE| }d d d        g }n$tG        |      dkD  rtI        jJ                  |d      }t        dF|      5  t!        | dG|H      }'|j#                  |'       |j%                          |j'                  |'       d d d        |||rg n|||r|nd|dI}t        |      }t        t               |z
  dz        }d<jO                  |je                         D cg c]  \  }}| d=|  c}}      } | r|  d| nd>| |j                  d<   |S # t        $ r d}d|d<   Y w xY w# 1 sw Y   xY w# 1 sw Y   |xY w# 1 sw Y   gxY w# 1 sw Y   xY w# 1 sw Y   xY w# t        $ r |jc                          Y /w xY wc c}}w c c}$w # 1 sw Y   xY w# 1 sw Y   #xY wc c}}w # t        $ rB}(tt        jv                  jy                  dJ       t        dKt{        |(      d
      dLfcY d }(~(S d }(~(ww xY w)MNmodeprimaryr>   Tr   ra   button_choicebad_requestzMissing 'content')errordetaili  ragrag_addendumru   )r&   top_kaddendumrP   	rag_error)replytimingsrH   zrag_addendum;dur=r   z, total;dur=zServer-Timing   db_store_userr   )r4   r   ra   r   build_payloadopenaizgpt-4o-minig333333?functionextract_followupsuA   Suggest 6–8 follow-up questions based on the assistant's reply.object	questionsarraytypestring)r   items)r   
propertiesrequired)rk   description
parameters)r   r   auto)modeltemperaturer   toolstool_choicemessagefinish_reason
tool_calls	argumentsz{}u\   Vielen Dank für Ihre Auswahl. Hier sind mögliche nächste Schritte oder Zusammenfassungen.z(no text reply provided))rM   z\*\*(.*?)\*\*c              3   @   K   | ]  }|j                   d k(  sd  yw)r   rP   N)r   ).0rZ   s     r"   	<genexpr>zpost_message.<locals>.<genexpr>Y  s     @qvv/?1@s   db_delete_offtopic_userF)r   	followupschoices
is_summaryr   z, z;dur=z
total;dur=summary_prepsummary_intro_1r   quote   )
iteration1
iteration2
iteration3rR   db_store_ai	assistant)r4   r   ra   )r   r   r   r   footer_quoter   zError in /messagesserver_errori  )>r   argsr   r   r'   r;   r   r   rB   r&   r   rL   r   r~   r   headersr   rn   ro   rp   r   rF   chatcompletionscreater   r/   r   rm   loadsr   ra   rb   rS   rV   lenr{   sampler7   rY   r   r4   r6   ry   rz   r   r}   sumdeleter0   r   r   r8   r9   choicer   r   formatr(   r)   r   r   ))r4   r   r'   r   t_all
quote_textr   	user_textr   r&   rag_resr   resptotaluser_msgmessages_payloadopenai_clientr   msg_objfinish	tool_callr   r   ai_textr   past_messagesturnr   	off_topicpayloadkvserver_timing	intro_docquotes
intro_textrZ   button_choicesintro_filledai_msges)                                            r"   post_messager	     s   <<FI.D	
BGNEJ[It,2XXi(.B557	/28b??AKK	]>QRSUXXX 5=~w/ --3IZ[\G$+KK
$;$Ar#H#H#JL- \gFGD%/478E.?N[\@]?^^jkpjq,rDLL)9 ?G, 	@wVY^klHFF8biik2::h+?	@
 ?G, 	N5b'9M	N *+8W% 	 %%1188#)& 3'j$,+6TZ\dSe8f*g)4'!  #! 9 D	( a&)T2$7\!g''<QU2V**1-I::gi&8&8+tLTPTUDb17RIoo  H  *HGI*1wrX>XG +7a@**-w7w<!mmGQ/G HHWtD'//TWW45vdgg($..AKK*GHx))*su 	 @m@@ai
 $^<#g,!*;	4g>  IIh'IIK  !#"G 7#D%/478E II'--/&R$!Q!E!~&RSMUb}o\%,Qjtuzt{h|DLL)9 ~w/ 9HHX& y9<MyNuw  HHX& y9GyDsu 
 3<Y..
>DV]]62::"
;H!]aAFFV\L\!//!]!] * 0b88585H15Lq 1RT585H15Lq 1RT585H15Lq 1RT  9  
 *N$wi8'9( G7|a --3 ='* 	<W;PFFF6NBIIKF);	<
 "(g$+5Z2
 w\^e+t34		gmmo"NdaaSaS>"NOQ^=/eW(Mfpqvpwdx_%Q ! -#%L+,GK(-	- -	@ 	@
	N 	N
	 	l      'S& "^9 94	< 	< #O  I

123q6BCSHHIsS  B^0 ^0 \$ 1\A^0 )^0 5A\17^0 \>^0 7?]6G%^0 ]% ("]
]% A
^0 ^
-&^0 ^0 #B ^^^&A^ ;^0 ;A^<A^0 ^*
($^0 \!\$ \!!\$$\.)^0 1\;6^0 >]^0 ]^0 ]"]% %^>^0 ^	^0 ^^^0 ^'"^0 0	_;97_60_;6_;__main__z0.0.0.0i  )z//var/www/html/decompression/certs/fullchain.pemz-/var/www/html/decompression/certs/privkey.pemT)hostportssl_contextdebug)ru   )?r   rS   r   rD   rm   r{   timer   
contextlibr   flaskr   r   r   r   r	   r
   sqlalchemy.sqlr   r   r   r   r'   r   r   rag_servicer   utils.prompt_managerr   modelsr   r   r   r   r   r   r   r   __name__r(   r   r#   before_requestr-   teardown_requestr3   r;   rF   rL   r   rb   routere   r   rg   rr   
sqlalchemyr   r   r   r   r	  runr    r!   r"   <module>r     s*   
 	      % D D %  $ - 7   Ho 	
,3 , O O
    #6 # 7 7>3 >3 >s >$ 3) ) & & :x(- )- eW-' .'T ?VH-> .>B 8fX&2 '2 )E7; <$ *VH=dI >dIR zGG
    r!   