
    hT                        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 d dlm Z m!Z"m#Z#m$Z$m%Z%m&Z&m'Z'  ee(      Z) e        de*de+fdZ,de-de*de+fdZ.de-de*fdZ/de*de-fdZ0de-fdZ1e)jd                  d        Z3e)jh                  d        Z5de-de$fdZ6defdZ7e	d        Z8d:de*de-de*fdZ9de:de-de*fd Z;e)jy                  d!      d"        Z=e)j}                  d#      d$        Z?e)jy                  d%d&g'      d(        Z@e)jy                  d)d*g'      d+        ZAe)jy                  d,d&g'      d-        ZBe)jy                  d.d&g'      d/        ZCe)jy                  d0d*g'      d1        ZDe)jy                  d2d&g'      d3        ZEe(d4k(  re)j                  d5d6d7d89       yy);    N)perf_counter)contextmanager)Flaskgrequestjsonifyrender_templateabort)functext)OpenAI)SessionLocalinit_dbgenerate_rag_addendum)build_messages_payload)ThreadPoolExecutor)TenantSessionUserCaseMessageDocumentTopic	user_textreturnc                 t    | xs dj                         j                         }|j                  d      xs d|v S )N z!jetzt fassen wir die konversationzusammenfassung)striplower
startswith)r   ts     /var/www/html/dynbot5004/app.py_is_summary_promptr%   (   s9    	b!'')A<<;<V@QUV@VV    case_idc                    t        |      ry	 | j                  t              j                  t        t        j
                  t        j                  k(        j                  t        j                  |k(  t        j                  t        j                  k(  t        j                  dk(        j                         }|dk\  S # t        $ r Y yw xY w)z
    Keep your UI-driven summary detection, plus an optional turn-based heuristic.
    Prefer prompt heuristic to avoid DB count fragility.
    Tuser   F)r%   queryr   joinr   r'   idfilter	tenant_idr   rolecount	Exception)dbr'   r   turnss       r$   _is_summary_turnr5   ,   s    
 )$	HHWtD'//TWW45vdgg($..AKK*GY_I_`uw	 	 z s   B,B; ;	CCc                      y )N )r3   r'   s     r$   _build_full_cycle_summaryr8   ?   s    r&   rag_seedr/   c                     t        | |d      S )z
    Return the SAME shape you currently return from /mode=rag so the frontend can
    drop it straight into renderRagInnerHTML(...).
    Example keys: { reply, referenzstory_html, referenzstory_sections, ... }
    r*   r/   top_kr   )r9   r/   s     r$   _build_rag_payloadr=   C   s     !YaHHr&   c                  @    t        t        j                  dd            S )zASingle source of truth: bind from systemd Environment=TENANT_ID=4	TENANT_ID4)intosgetenvr7   r&   r$   current_tenant_idrD   N   s    ryyc*++r&   c                      t               t        _        t               t        _        t
        j                  j                  dt        j                   dt        j                   dt        j                          y )Nz	[TENANT]  )rD   r   r/   r   r3   apploggerinfor   methodpathr7   r&   r$   bind_tenant_and_sessionrL   R   sE    #%AK>ADJJOOi}Agnn-=Qw||nMNr&   c                     t        t        dd       }|$	 | r|j                          |j                          y y # |j                          w xY w)Nr3   )getattrr   rollbackclose)excr3   s     r$   teardown_sessionrR   X   sA    	D$	B	~	HHJ 
 HHJs	   9 Ac                     t         j                  j                  t              j	                  | t         j
                        j                         }|st        d       |S )z=Ensure the case belongs to the current tenant, otherwise 404.)r-   r/   i  )r   r3   r+   r   	filter_byr/   firstr
   )r'   cases     r$   ensure_caserW   b   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_KEYr   zOPENAI_API_KEY not setu#   🔑 OPENAI_API_KEY ends with …%sNapi_key)rB   rC   r    RuntimeErrorlogging	getLoggerrI   r   r[   s    r$   get_openai_clientr`   i   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   rA   )labelbagt0s      r$   timedrf   q   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searchrk   rstripfindall	enumerateappendr    r,   )
r   rg   mheadbodyblocksoutidx_numcontents
             r$   truncate_numbered_blocksr{   y   s    
		%t,A
""4(D	
DZZCTJF
C )&)*<A F 0_dG

cU"W]]_-./0!D6MrV[[-===r&   timingstotal_msc                     | j                         D cg c]  \  }}| d|  }}}|j                  d|        dj                  |      S c c}}w )Nz;dur=z
total;dur=, )itemsrr   r,   )r|   r}   kvpartss        r$   _server_timing_headerr      sP    (/81s%s^8E8	LL:hZ()99U 9s   A/c                      t        d      S )Nz
index.html)r	   r7   r&   r$   indexr      s    <((r&   z	/__whoamic                  &    dt         j                  iS )Nr/   )r   r/   r7   r&   r$   whoamir      s    %%r&   z/tenantsPOST)methodsc                      t         j                  } t        t        j                  d         }| j                  |       | j                          | j                  |       t        d|j                  i      dfS )Nname)r   r/      )
r   r3   r   r   jsonaddcommitrefreshr   r-   )r3   r#   s     r$   create_tenantr      sT    	
BGLL()AFF1Iryy{BJJqMK&',,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)
Nr*   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   rj   r   z{topic})topicquestion)r   r3   r/   r+   r   r.   order_byr   randomlimitallr2   rG   rH   	exceptionexecuter   fetchallreplacer   rr   r   r   )r3   r/   
raw_topicsrowsrresultsr#   s          r$   get_random_topicsr      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   r'   )r   r3   r   get_jsonr/   getstruuiduuid4r    r+   r   rT   rU   r   r   r   ChatSessionr-   r   r   ascr   )	r3   datar/   r   r   r   r)   	chat_sessrV   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   r'   r   )r   r3   r/   r   r   r   r   r   r   r   r   r-   )r3   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)r0   rz   	timestamp)r   r3   rW   r+   r   r,   r   r'   r-   r.   r/   r   r   r   r   r0   rz   	isoformat)r'   r3   msgsrs   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                   012345 t         j                  j                  dd      }t        j                  }t        |        i 5t               }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	i      d
fS |dk(  rt        || |      rHt        t               |z
  dz        }	t        dd|	id      }
t        d|	i|	      |
j                  d<   |
dfS t        d5      5  	 t!        ||d      }|j                  d      xs |j                  d      xs dj                         }d d d        t        5d      }
t        t               |z
  dz        }	t        5|	      |
j                  d<   |
dfS t        d5      5  t%        | d||      }|j'                  |       |j)                          |j+                  |       d d d        t        d5      5  t        || |      }|j-                  t$              j/                  t0        t$        j2                  t0        j4                  k(        j7                  t0        j4                  | k(  t0        j                  |k(        j9                  t$        j:                        j=                         }d d d        rt        d5      5  D cg c]  }|j>                  dk(  s| }}|r|d   j@                  n|}|D cg c]  }|jB                  s|jB                   }}g }|dd  D ]D  }|j@                  xs dj                         }|s$||jB                  k7  s4|jE                  |       F 	 t        d5      5  |j-                  tF              j7                  tF        j                  |k(  tF        jH                  dk(        j9                  tK        jL                               jO                  d       j=                         }|j-                  tF              j7                  tF        j                  |k(  tF        jH                  d!k(        j9                  tK        jL                               jO                  d      jQ                         }|r|j@                  nd}|rtM        jR                  |      j@                  nd}|xs djU                  tW        |      dkD  r|d   ndtW        |      dkD  r|d   ndtW        |      d"kD  r|d"   nd#      }d d d        d$2d%| d&d'j/                  |      xs d( g}|r#|jE                  d)d*j/                  |      z          d+j/                  |      3d,j/                  |g|z   |z         1tY        jZ                  d-d.      0|4d d d        0235fd/}145fd0}t]        d"1      5 }|j_                  |      }|j_                  |      }|ja                         } |ja                         }!d d d         d+  } t        d25      5  t%        | d3| 4      }"|j'                  |"       |j)                          |j+                  |"       d d d        | g g d|xs dd!5d5}#t        |#      }
t        t               |z
  dz        }	t        5|	      |
j                  d<   |
dfS d6}$t        d75      5  tc        || |      }%d d d        %je                  dd8|$d9       tg               }&t        d:5      5  |&jh                  jj                  jm                  tY        jZ                  d;d.      d<|%d=d>d?d@dAdBdCdDidEidAgdFdGdHgdIJ      }
d d d        
jn                  d   }'tq        |'dKd       }(tq        |'dLd       })|)dMk(  r|(rtq        |(dMd       r|(jr                  d   }*|*jt                  jv                  d>k(  rb	 ty        jz                  |*jt                  j|                  xs dN      }+|+j                  dAg       d dO },|(j@                  xs dj                         } n7g },|(j@                  xs dj                         } ng },|(r|(j@                  ndxs dP} t        | dQ      } t        j                  dR|       }-tW        |-      dkD  rtM        j                  |-d      }-tW        |-      dk(  }.|.r	 t        dS5      5  |j                         |j)                          d d d        | g g dT5dU}#t        |#      }
t        t               |z
  dz        }	t        5|	      |
j                  d<   |
dfS t        d25      5  t%        | d3| 4      }"|j'                  |"       |j)                          |j+                  |"       d d d        | |,|-dT5dU}#t        |#      }
t        t               |z
  dz        }	t        5|	      |
j                  d<   |
dfS # t"        $ r d}d5d<   Y w xY w# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   QxY wc c}w c c}w # 1 sw Y   xY w# t"        $ r d}d}Y !w xY w# 1 sw Y   xY w# 1 sw Y   IxY w# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w# t"        $ r dAg i}+Y w xY w# 1 sw Y   xY w# t"        $ r |j                          Y w xY w# 1 sw Y   >xY w# t"        $ rB}/t        j                  j                  dV       t        dWt        |/      dX      dYfcY d }/~/S d }/~/ww xY w)ZNmodeprimaryr   Tr   rz   button_choiceerroremptyi  ragrb   rag_skip)replyr|   zServer-Timing   rag_addendumr*   r;   addendumr   rj   	rag_errordb_store_userr)   )r'   r0   rz   r   history_fetchsummary_prepr   tenant_introquote   summary_intro   )
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 crisp recommendations.zOriginale Frage: zAuswahl/Themenpfad: r   z(keine)u)   Zusätzliche Hinweise/Präzisierungen:
- z
- rl   rF   OPENAI_MODEL_SUMMARYzgpt-4o-minic                  :   t               } t               }|j                  j                  j	                  dddddg      }|j
                  d   j                  j                  xs dj                         }t        t               | z
  dz        d	<   |xs d
S )Ng      ?systemr0   rz   r)   )modeltemperaturer   r   r   rb   openai_summaryz(leere Zusammenfassung))
r   r`   chatcompletionscreatechoicesmessagerz   r    rA   )re   clientresptxtmodel_for_summarysummary_systemsummary_userr|   s       r$   _run_summaryz"post_message.<locals>._run_summary  s    !^*,{{..55+ #!)nE!'lC 6  ||A..66<"CCE,/"1D0L,M()777r&   c                      t               } 	 t        d      }t        t               | z
  dz        d<   |S # t        $ r ddd}Y .w xY w)Nr*   r;   r   
rag_failed)r   r   rb   r   )r   r   r2   rA   )re   resr9   tenant_for_ragr|   s     r$   _run_ragzpost_message.<locals>._run_rag  s[    !^?/NZ[\C +.|~/Bd.J*K'
 ! ?$&>C?s   9 A
	A
)max_workersdb_store_ai	assistant)r'   r0   rz   )r   	followupsr   
is_summaryfooter_quoterag_includedr   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_payloadr   r   openaiOPENAI_MODEL_PRIMARYg333333?functionextract_followupsuA   Suggest 6–8 follow-up questions based on the assistant's reply.object	questionsarraytypestring)r  r   )r  
propertiesrequired)r   description
parameters)r  r   auto)r   r   r   toolstool_choicer   finish_reason
tool_callsz{}   z(no text reply provided))rg   z\*\*(.*?)\*\*db_delete_offtopic_userF)r   r   r   r   r|   zError in /messagesserver_error)r   detaili  )Ir   argsr   r   r3   rW   r   r   r    r/   r   r5   rA   r   headersrf   r   r2   r   r   r   r   r+   r,   r   r'   r-   r.   r   r   r   r0   rz   r   rr   r   kindr   r   r   rU   choiceformatlenrB   rC   r   submitresultr   insertr`   r   r   r   r   rN   r  r   r   r   loads	argumentsr{   rm   rp   sampledeleterO   rG   rH   r   r   )6r'   r   r3   t_all
quote_textr   r   r   r/   totalr   rag_resr   user_msgr   past_messagesrs   
user_turnsoriginal_questionbutton_choices
free_textsr   quotes	intro_doc
intro_textintro_filledr   r   r   exfut_summaryfut_ragai_textrag_payloadai_msgpayload
MATH_RULESmessages_payloadopenai_clientr  msg_objfinishtool	tool_argsr   r   	off_topicer   r9   r   r   r   r|   s6                                                   @@@@@@r$   post_messager=  )  s
   <<FI.D	
BGNEJFIt,2XXi(.B557	/28b??AKK	GW-.33 5=GY7\^e3t;<U8KLM0EzSXFY[`0a_-Sy ~w/ --3IZ[\G$+KK
$;$Yw{{7?S$YWY#`#`#bL- \gFGD%/478E,A'5,QDLL)9
 ?G, 	@wV'0OHFF8biik2::h+?	@ ?G, 	)"gyAJ !4goo896$''W,dnn	.IJ8G--.35 	 ~w/ 8+)6KA!&&F:JaK
K=GJqM$9$9Y!;E!Ya!//!Y!Y
#AB /A99?113Csaoo5"))#./$~w7 HHX.%vh&8&8I&Ex}}X_G_`'x6$uQx"su  HHX.%vh&8&8I&Ex}}XgGgh'x6$uQx$uw " ;DY%6%6
FLV]]6%:%B%BRT
(2(8b'@'@=@=PST=Tq(9Z\=@=PST=Tq(9Z\=@=PST=Tq(9Z\ (A (#8@  ((9':;*499^+D+Q	*RS LL!MPVP[P[\fPg!gh%{{5188%6$7.$H:$UV$&II.Dm$T!!*q8+t8 $2 /b ii5))H-%,,.%nn.	/ &d7)4G}g. @ {GTv		RZZ-?@
 !"!+!1r $""
G 7#D%/478E,A'5,QDLL)9I 	 ?G, 	N5b'9M	NH#LM)+8W% 	 %%1188ii 6F)& 3'j$,+6TZ\dSe8f*g)4'!  #! 9 D	( a&)T2$7\!g''<QU2V%%a(D}}!!%882 $

4==+B+B+Jd KI &MM+r:2A>	"??0b779	"??0b779I*1wrX>XG +7a@**-w7w<!mmGQ/G \Q&	4g> 5IIh'5
 !#"G 7#D%/478E,A'5,QDLL)9 ='* 	<W;PFFF6NBIIKF);	<
 "
 w\^e+t34(=gu(M_%SyY ! -#%L+,GK(-	- - 	@ 	@	 	" L!Y , ! $#%L!#J$I8+ 8+d/ /@ @6	N 	N
	 	: ! 2!,b 1I2*5 5 	< 	<   I

123q6BCSHHIs  B k5 Ak5 ,k5 8h:Ag=>Ak5 
k5 Ah!k5 ,B3h.k5 6i&;h;h;i&-i ?i ,i&:i&
i&i*Fi9iBi&#k5 )Ai3,k5 Aj Ak5  k5 .j<3k5 /AjA-k5 0-j' Ck5  k ,"j;k Ak5 k5 +Ak(,Ak5 =hhhhhk5 !h+&k5 .h83k5 ;
i&i	
ii#i&"i##i&&i0+k5 3i=8k5  j
k5 jk5 j$k5 'j84k5 7j88k5 ;k k k%!k5 $k%%k5 (k2-k5 5	m >7l;5m ;m __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)r*   )GrB   rm   r   r^   r   r   timer   
contextlibr   flaskr   r   r   r   r	   r
   sqlalchemy.sqlr   r   r   r   r3   r   r   rag_servicer   utils.prompt_managerr   concurrent.futuresr   modelsr   r   r   r   r   r   r   r   __name__rG   r   boolr%   rA   r5   r8   r=   rD   before_requestrL   teardown_requestrR   rW   r`   rf   r{   dictr   router   r   r   r   r   r   r   r   r=  runr7   r&   r$   <module>rR     s   
 	      % D D %  $ - 7 1   Ho 	
W# W$ W# # $ &3 3 I I I,3 , O O
    #6 # 7 7>3 >3 >s >4 3 3  3) ) & & :x(- )- eW-' .'T ?VH-> .>B 8fX&2 '2 )E7; <& *VH=OI >OIj zGG
    r&   