
    fi*                        d dl Z d dlZd dlmZ d dlZd dlmZ dZdee	e	f   fdZ
dej                  fdZde	de	fd	Zde	defd
Zdede	fdZdej$                  de	fdZdej(                  de	dee	e	f   de	fdZde	dz  de	dz  fdZdeee	e	f      defdZde	dedz  fdZde	de	fdZde	defdZde	deee	e	f      dedz  dedz  fdZde	deee	e	f      dedz  dedz  fdZdee	ef   de	fdZde	deee	e	f      d e dz  d!edz  dee	ef   f
d"Z!dddd#deee	e	f      d e dz  d!edz  de	dz  de"e	e	f   f
d$Z#y)%    N)HTTPException)get_settingsi   returnc                  `    t               } ddd}| j                  rd| j                   |d<   |S )Nzapplication/jsonzPowerUp/1.0)zContent-Typez
User-AgentzBearer Authorization)r   llm_api_key)settingsheaderss     +apps/backend-hub/app/services/llm_client.pybuild_llm_headersr      s9    ~H1OG%,X-A-A,B#C N    c                      t               } t        | j                  d      }t        |d      }t	        j
                  ||      S )Ng      @g      $@)connect)r   maxllm_request_timeout_secondsminhttpxTimeout)r	   timeout_secondsconnect_timeouts      r   build_llm_timeoutr      s8    ~H(>>DO/40O==/BBr   valuec                 d    dj                  | xs dj                               j                         S )N  )joinsplitstrip)r   s    r   _normalize_error_textr      s'    88U[b'')*0022r   c                     | j                         }d|v xs+ d|v xs% d|v xs t        t        j                  d|            S )Nz<!doctype htmlz<htmlz</html>z<[a-z][^>]*>)casefoldboolresearch)r   
normalizeds     r   _looks_like_html_errorr&   "   sO    !JJ& 	8j 	8
"	8 		/:67	r   status_codec                 4    | dk(  ry| dk(  ry| dk(  ry| dk\  ryy	)
Ni  zendpoint LLM non raggiungibilei  zautenticazione LLM non validai  zaccesso al servizio LLM negatoi  z,servizio LLM temporaneamente non disponibilezrisposta upstream non valida )r'   s    r   _fallback_http_detailr*   ,   s1    c/c.c/c=)r   excc                    t        | t        j                        rP| j                  }d}	 |j	                         }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      }t        |      d d }t        |      rt        |j                        }|rd|j                   d	| S d|j                   d	t        |j                         S t!        | d
d       }|t        |j"                        nd}t        |       j                         }| j$                  j&                  }|r|r
| d| d	| S |r| d	| S |r| d| S |S # t        $ r |j                  j                         }Y w xY w)Nr   errormessagedetailTensure_asciii  zHTTP z: requestz verso )
isinstancer   HTTPStatusErrorresponsejsondictgetstrr   dumps	Exceptiontextr   r&   r*   r'   getattrurl	__class____name__)	r+   r5   r/   payloaderror_payloadr2   request_urlr.   
error_names	            r   describe_llm_http_errorrE   8   s   #u,,-<<	+mmoG'4( 'G 4mT2 !2!29!=!bARARS[A\!b`bciikF X!6!V'++i:P!VTVW]]_F!ZZdCF 'v.t4!&)*8+?+?@F8//06(;;x++,B/DXEYEY/Z.[\\c9d+G&-&9#gkk"rK#hnnG''J;W[MG9==Ry))W[M22+  	+]]((*F	+s   CG# ##H
	H
clientbase_urlr
   c                 z  K   t               }|j                  r|j                  S | j                  | d|       d {   }|j                          |j	                         }|j                  dg       D ]4  }t        |t              s|j                  d      s&t        |d         c S  t        dd      7 zw)Nz/models)r
   dataid  z8Nessun modello disponibile sull'endpoint LLM configurator'   r/   )	r   assistant_modelr8   raise_for_statusr6   r3   r7   r9   r   )rF   rG   r
   r	   r5   rA   items          r   resolve_llm_modelrP   _   s     ~H'''ZZ8*G 4gZFFHmmoGFB' #dD!dhhtntDz?"# C0j
kk Gs   <B;B9A	B;	B;B;c                 6    | xs dj                         }|xs d S )Nr   )r   )r   cleaneds     r   _clean_model_namerS   n   s    {!!#G?dr   messagesc                 ~    t        j                  | d      }t        dt        |      dz  t        |       dz  z         S )NFr0            )r6   r:   r   len)rT   
serializeds     r   _estimate_prompt_tokensr[   s   s6    H59Jq3z?a'CMB,>?@@r   modelc                 T    | j                         j                         }d|v ryd|v ryy )Nzqwen/qwen3-32bip  gpt-ossi@  )lowerr   r\   r%   s     r   _model_request_token_limitra   y   s/    $$&J:%Jr   replyc                     t        j                  dd| t         j                  t         j                  z        j	                         }|xs | j	                         S )Nz<think>.*?</think>r   )flags)r#   sub
IGNORECASEDOTALLr   )rb   rR   s     r   _strip_reasoning_blocksrh      s>    ff*BR]]RYY=VW]]_G#ekkm#r   c                 6    | j                         }d|v xs d|v S )Nr^   z
qwen/qwen3)r_   r`   s     r   "_model_needs_reasoning_token_floorrj      s"    J
"@lj&@@r   requested_max_tokensc                 2   t               }|j                  dkD  r|j                  nd }||}n+|}t        |       rt        |t              }|t        ||      }|y t        |       }||S t        |      }||z
  dz
  }|dk  ryt        dt        ||            S )Nr      rV   )r   assistant_max_tokensrj   r   &_REASONING_MODEL_MIN_COMPLETION_TOKENSr   ra   r[   )	r\   rT   rk   r	   configured_max_tokenstarget_max_tokensrequest_token_limitprompt_tokenssafe_completion_tokenss	            r   _effective_max_tokensru      s     ~H=E=Z=Z]^=^H99dh#10-e4 #$57] ^ , #$57L M 4U;"  +H5M0=@3F"q#')?@AAr   c                 p    t        | ||      }|	|t        k  ry t        t        t        d|dz              S )Nr\   rT   rk   i      )ru   ro   r   r   )r\   rT   rk   current_max_tokenss       r   _rate_limit_retry_max_tokensrz      sH     /1
 !%7;a%a5s4ASWXAX7YZZr   rA   c                 n   | j                  di g      d   j                  di       j                  d      }|s%| j                  di g      d   j                  d      }|sD| j                  di g      d   j                  d      }|dk(  rt        dd	
      t        dd
      t        t        |            S )Nchoicesr   r.   contentr<   finish_reasonlengthrK   z9Risposta LLM vuota: limite output consumato dal reasoningrL   z,Risposta LLM priva di contenuto utilizzabile)r8   r   rh   r9   )rA   rb   r~   s      r   extract_llm_replyr      s    KK	B4(+//	2>BB9MEIt,Q/33F;It4Q7;;OLH$C8stt4bcc"3u:..r   temperature
max_tokensc                 D   t               }| ||j                  n||d}t        | ||      }|d| j                         v r||d<   n||d<   d| j                         v rB|j                  xs dj                         }|r||d<   t        |j                        |d<   d	|d
<   |S )N)r\   r   rT   rw   r^   max_completion_tokensr   r   reasoning_effortinclude_reasoningTdisable_tool_validation)r   assistant_temperatureru   r_   assistant_reasoning_effortr   r"   assistant_include_reasoning)r\   rT   r   r   r	   rA   effective_max_tokensr   s           r   _build_chat_payloadr      s     ~H9D9Lx55R]"G
 1'
 '%/CG+,$8GL!EKKM!$??E2LLN*:G&''+H,P,P'Q#$-1)*Nr   )r   r   r\   c                   K   t               }|j                  j                  d      t               	 t	        j
                  t                     4 d {   |xs t               d {   }dt        dt        d z  dt        j                  f fd}	  |||       d {   }|j                          d d d       d {    j!                         }
t#        |
      fS 7 7 ~7 E# t        j                  $ r}|j                  j                  dk(  rt        | |      }	|	y	  |||	       d {  7  }|j                          |j!                         }
t#        |
      |fcY d }~cd d d       d {  7   S # t        j                  $ r}|}Y d }~nd }~ww xY wt%        |j&                        }|j                  j                  dk7  s|r||k(  r |}t        | |      xs |} |||       d {  7  }|j                          Y d }~[d }~ww xY w7 X# 1 d {  7  sw Y   ixY w# t        j(                  $ r}t+        d	d
t-        |             |d }~ww xY ww)N/)timeoutactive_modelrk   r   c           
      h   K   j                   dt        | |             d {   S 7 w)Nz/chat/completions)r\   rT   r   r   )r
   r6   )postr   )r   rk   rG   rF   r
   rT   r   s     r   _post_chat_completionz:request_llm_chat_completion.<locals>._post_chat_completion   sI     #[[j 12#,*!)$/#7	 ) 	 	 	 	s   (202i  rw   rK   zErrore comunicazione LLM: rL   )r   llm_base_urlrstripr   r   AsyncClientr   rP   r9   intResponserN   r4   r5   r'   rz   r6   r   rS   assistant_fallback_model	HTTPErrorr   rE   )rT   r   r   r\   r	   resolved_modelr   r5   r+   reduced_max_tokensrI   	retry_excfallback_modelfallback_max_tokensrG   rF   r
   s   ``            @@@r   request_llm_chat_completionr      sj     ~H$$++C0H!G2z$$->-@A /	, /	,V"X,=fhPW,X&XN
# 
UX[_U_ 
didrdr 
 
 ,!6~z!RR))+#/	, /	,f ==?DT"N22i/	,&X S(( ,<<++s2)E,!)-7*&
 *5K-B>Se-f'f'fH$557 $,==?D#4T#:N#JJC/	, /	, /	,:  %44 ,"+C,
 "383T3T!U<<++s2.N^lLl!/0,!)-7 "
 " $ "7~GZ![[[))++;,%/	, /	, /	, /	,` ?? z6PQhilQmPn4opvyyzs  0I4"H? C0H? H)3C24-H)"C6.C4/C6H? H&H? I40H? 2H)4C66H#
)H4F
 EF
H2H#3H)7H? FH? 	I4
F)F$H$F))AHHHH)H##H)&H? )H</H20H<7H? ?I1I,,I11I4)$r6   r#   fastapir   r   app.core.configr   ro   r7   r9   r   r   r   r   r"   r&   r   r*   r   rE   r   rP   rS   listr[   ra   rh   rj   ru   rz   objectr   floatr   tupler   r)   r   r   <module>r      s    	 !  ( *. &4S> C5== C3 3 3# $ 	*s 	*s 	*$ $S $NlE$5$5 l ltTWY\T\~ lbe lS4Z C$J 
Ad4S>&: As Ac cDj $3 $3 $
Ac Ad A
BB 4S>"B *	B
 	4ZB>[[ 4S>"[ *	[
 	4Z[ 	/tCK0 	/S 	/ 4S>" 	
 d
 
#v+F !%!@34S>"@3 @3 d
	@3
 :@3 38_@3r   