
    9zhVG                     ^   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        d}t        d|      5  t)        || |	      }d d d        j+                  dd|d        t-               }t        d!|      5  |j.                  j0                  j3                  d"d#|d$d%d&d'd(d)d*d+id,id(gd-d.d/gd01      }d d d        j4                  d   }t7        |d2d       }t7        |d3d       }|d4k(  rs|rqt7        |d4d       rd|j8                  d   }t;        j<                  t7        |j>                  d5d6      xs d6      }|j                  d(g       xs g }|j@                  xs d7}ng }|r|j@                  ndxs d8}tC        |d9      }tE        jF                  d:|      }tI        |      dkD  rtK        jL                  |d      }|jO                  t               jQ                  tR        t         jT                  tR        jV                  k(        jY                  tR        jV                  | k(  tR        j                  t        j                  k(        j[                  t         j\                        j_                         }ta        d; |D              }|dk(  }| xr tI        |      dk(  }|r	 t        d<|      5  |jc                         |j%                          d d d        |g g d=|d>}t        |      }t        t               |z
  dz        }d?jQ                  |jg                         D  cg c]  \  }} | d@|   c} }      }!|!r|! d| ndA| |j                  d<   |dfS |rt        dB|      5  |D "cg c]  }"|"jh                  dk(  s|" }#}"|#r|#d   j@                  n|}$|#D "cg c]  }"|"jj                  s|"jj                   }%}"g }&|#dd  D ]{  }"|"j@                  s|"j@                  j                         s+|"j@                  j                         |"jj                  k7  sS|&jm                  |"j@                  j                                } 	 dCjQ                  |$g|%z         d dD }'t        |'|	d      }
|
j                  d      xs dj                         }|jO                  tn              jq                  |	dEF      js                         }(|jO                  tn              jq                  |	dGF      j_                         })|(r|(j@                  nd}*|)rtK        jt                  |)      j@                  nd}|*xs djw                  tI        |%      dkD  r|%d   ndtI        |%      dkD  r|%d   ndtI        |%      dHkD  r|%dH   ndI      }+d d d        dJ},dK$ dLdMjQ                  %D -cg c]  }-|-s|-	 c}-      z   dNz   &rdOdMjQ                  |&d dP       z   dNz   ndz   rdQ|z   dNz   ndz   dRz   }.t        dS|      5  t-               j.                  j0                  j3                  d"dTd|,d d|.d gU      }/d d d        /j4                  d   jx                  j@                  j                         xs dV}+ dN| }g }t        dW|      5  t!        | dX|Y      }0|j#                  |0       |j%                          |j'                  |0       d d d        |||rg n|||r|nd|dZ}t        |      }t        t               |z
  dz        }d?jQ                  |jg                         D  cg c]  \  }} | d@|   c} }      }!|!r|! d| ndA| |j                  d<   |S # t        $ r d}d|d<   Y w xY w# 1 sw Y   xY w# 1 sw Y   KxY w# 1 sw Y   4xY w# 1 sw Y   xY w# 1 sw Y   xY w# t        $ r |je                          Y w xY wc c} }w c c}"w c c}"w # t        $ r d}d|d<   Y Uw xY w# 1 sw Y   oxY wc c}-w # 1 sw Y   xY w# 1 sw Y   QxY wc c} }w # t        $ rB}1tz        j|                  j                  d[       t        d\t        |1      d
      d]fcY d }1~1S d }1~1ww xY w)^N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   u   Format all mathematical expressions as LaTeX. Use $$...$$ for display equations and \(...\) for inline. Use \times (not ×), \cdot, \frac{a}{b}, exponents as ^{…}, subscripts as _{…}. Do not output plain-text formulas like 'Pn=Pn-1×(1+r)-M'.build_payloadsystem)r   ra   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>c  s     @qvv/?1@s   db_delete_offtopic_userF)r   	followupschoices
is_summaryr   z, z;dur=z
total;dur=summary_prepr%   i  summary_intro_1r   quote   )
iteration1
iteration2
iteration3u   You are writing a concise, session-level executive summary. Touch each of the selected topics in order, connect them logically, and end with 3–5 actionable next steps. Use clear markdown with bullets.zORIGINAL QUESTION:
z

SELECTED TOPICS (path):
- z
- rR   zUSER FREE-TEXT NOTES:
-    zRAG ADDENDUM (optional):
zIPlease produce a single executive summary that references the above path.openai_summarygffffff?)r   r   r   z(leere Zusammenfassung)db_store_ai	assistant)r4   r   ra   )r   r   r   r   footer_quoter   zError in /messagesserver_errori  )Ar   argsr   r   r'   r;   r   r   rB   r&   r   rL   r   r~   r   headersr   rn   ro   rp   r   insertrF   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   r   rX   r   r8   r9   choiceformatr   r(   r)   r   r   )2r4   r   r'   r   t_all
quote_textr   	user_textr   r&   rag_resr   resptotaluser_msg
MATH_RULESmessages_payloadopenai_clientr   msg_objfinish	tool_callr   r   ai_textr   past_messagesturnr   	off_topicpayloadkvserver_timingrZ   
user_turnsoriginal_questionbutton_choices
free_textsrag_seed	intro_docquotes
intro_textintro_filledsummary_systemcsummary_usersummary_respai_msges2                                                     r"   post_messager     s	   <<FI.D	
BGNEJS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+?	@
I 	 ?G, 	N5b'9M	N 	H#LM *+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/ &)6KA!&&F:JaK
K=GJqM$9$9Y!;E!Ya!//!Y!Y  
#AB =AyyQYY__%6199??;LPQP_P_;_"))!))//*;<=
-"xx):(;n(LMetTH3H	YZ[G$+KK
$;$Ar#H#H#JL HHX&Y:KYLUW  HHX&Y'YBSU 
 3<Y..
>DV]]62::"
 * 0b88585H15Lq 1RT585H15Lq 1RT585H15Lq 1RT  9  E&T]  ''8&9 :. /17=]A[\a=]1^_agh[e/&++j!n2MMPVVkmo NZ0<?&H_ac ^	^  '1 0277CCJJ' #!)nE!'LA  K   #**1-55==CCEbIbG &d7)4GG ='* 	<W;PFFF6NBIIKF);	<
 "(g$+5Z2
 w\^e+t34		gmmo"NdaaSaS>"NOQ^=/eW(Mfpqvpwdx_%A ! -#%L+,GK(-	- -	@ 	@	N 	N	 	l      'S L!Y ! -#%L+,GK(-#& &d >^  	< 	< #O  I

123q6BCSHHIs  Bf- f- c3 1cAf- )f- 5Ad 7f- d3f- ?dG%f- 3d4 ?"d'!d4 )A
f- 3e
&f- +f- :e;?eee;1eee;*e;'e;-+e;A	e$"C,e;f- ,f
4f
8Af- ?9f8Af- 
AfAf- &f'
7$f- c0,c3/c00c33c=8f-  d
f- df- d$f- 'd1,d4 4ef- e	f- 
e;$e84e;7e88e;;f f- ff- f$f- -	g867g3-g83g8__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=\I >\IB zGG
    r!   