
    i                        d Z ddlmZ ddlZddlZddlmZmZ ddlm	Z	 ddl
Z
 G d de      Z G d d	e      Z G d
 de      ZddZddZy)u   
LLM Provider abstraction — provider-agnostic interface.

Primary: Google Gemini (free tier)
Fallback: Groq (free tier, Llama 3.1)
    )annotationsN)ABCabstractmethod)Anyc                  H    e Zd ZdZe	 	 d	 	 	 	 	 	 	 dd       Zedd       Zy)LLMProviderz&Abstract base class for LLM providers.Nc                   K   yw)z
        Send messages to LLM and get response.
        Returns: {"content": str, "tool_calls": [{"name": str, "arguments": dict}]}
        N )selfmessagestoolssystem_prompts       9/var/www/html/spbu.com/backend/app/assistant/providers.pychatzLLMProvider.chat   s      	s   c                     y )Nr
   r   s    r   namezLLMProvider.name"   s        NNr   zlist[dict[str, str]]r   zlist[dict[str, Any]] | Noner   z
str | Nonereturnzdict[str, Any]r   str)__name__
__module____qualname____doc__r   r   r   r
   r   r   r   r      sU    0 .2$(	
&
 +
 "	

 

 
  r   r   c                  :    e Zd ZdZd ZddZ	 	 d	 	 	 	 	 	 	 ddZy)	GeminiProviderz'Google Gemini API provider (free tier).c                ~    t        j                  dd      | _        t        j                  dd      | _        d| _        y )NGEMINI_API_KEY GEMINI_MODELzgemini-1.5-flashz0https://generativelanguage.googleapis.com/v1betaosgetenvapi_keymodelbase_urlr   s    r   __init__zGeminiProvider.__init__)   s/    yy!126YY~/AB
Jr   c                     y)Ngeminir
   r   s    r   r   zGeminiProvider.name.   s    r   Nc           
       K   | j                   st        d      | j                   d| j                   d| j                    }g }|D ](  }|d   dk(  rdnd}|j	                  |d|d   igd	       * d
|i}|r
dd|igi|d<   |r<g }	|D ]0  }
|	j	                  d|
d   |
d   |
j                  di       dgi       2 |	|d<   t        j                  d      4 d {   }|j                  ||       d {   }|j                          |j                         }d d d       d {    j                  dg       }|sdg dS |d   j                  di       j                  dg       }d}g }|D ]?  }d|v r||d   z  }d|v s|d   }|j	                  |d   |j                  di       d       A ||dS 7 7 7 # 1 d {  7  sw Y   xY ww)NzGEMINI_API_KEY not configuredz/models/z:generateContent?key=roleuserr(   textcontent)r.   partscontentsr2   systemInstructionfunctionDeclarationsr   description
parametersr   r6   r7   r      timeout)json
candidateszMaaf, tidak ada respons.r1   
tool_callsr   r"   functionCallargsr   	arguments)r'   
ValueErrorr)   r(   appendgethttpxAsyncClientpostraise_for_statusr<   )r   r   r   r   urlr3   msgr.   bodygemini_toolstoolclientrespdatar=   r2   r1   r?   partfcs                       r   r   zGeminiProvider.chat1   s     ||<==x

|3HW C [F26DOOTfc)n5M4NOP  !+H5)0FM3J2K(LD$% L##* $V'+M':&*hh|R&@. -%   )DM$$R00FSt44D!!#99;D 10 XXlB/
9LL1!!)R044WbA
D~4<'%.)!!vJ!#!3#   #*==1 14 1000sa   CGF4GF:4F65$F:G$F8%AG4G6F:8G:G GGGr   r   r   r   r   r   r   r*   r   r   r
   r   r   r   r   &   sC    1K
 .2$(	;>&;> +;> "	;>
 
;>r   r   c                  :    e Zd ZdZd ZddZ	 	 d	 	 	 	 	 	 	 ddZy)	GroqProviderz)Groq API provider (free tier, Llama 3.1).c                ~    t        j                  dd      | _        t        j                  dd      | _        d| _        y )NGROQ_API_KEYr"   
GROQ_MODELzllama-3.1-70b-versatilezhttps://api.groq.com/openai/v1r$   r   s    r   r*   zGroqProvider.__init__r   s.    yy4YY|-FG
8r   c                     y)Ngroqr
   r   s    r   r   zGroqProvider.namew   s    r   Nc           
     z  K   | j                   st        d      | j                   d}g }|r|j                  d|d       |D ]  }|j                  |d   |d   d        | j                  |ddd	}|r5|D cg c]!  }d
|d   |d   |j                  di       dd# c}|d<   d|d<   d| j                    dd}	t        j                  d      4 d {   }
|
j                  |||	       d {   }|j                          |j                         }d d d       d {    d   d   }|d   }|j                  dd      xs d}g }|j                  dg       D ]5  }|j                  |d
   d   t        j                  |d
   d         d       7 ||d S c c}w 7 7 7 # 1 d {  7  sw Y   xY ww)!NzGROQ_API_KEY not configuredz/chat/completionssystem)r.   r1   r.   r1   g333333?i   )r(   r   temperature
max_tokensfunctionr   r6   r7   r8   )typera   r   autotool_choicezBearer zapplication/json)AuthorizationzContent-Typer9   r:   )r<   headerschoicesr   messager"   r?   rC   rB   r>   )r'   rD   r)   rE   r(   rF   rG   rH   rI   rJ   r<   loads)r   r   r   r   rK   oai_messagesrL   rM   trf   rP   rQ   rR   choicerh   r1   r?   tcs                     r   r   zGroqProvider.chatz   s     ||:;;01 m LMCVY PQ  ZZ$	 
  
 A ' !&	'('7&'eeL"&=! 
DM #)D  't||n5.

 $$R00FStWEED!!#99;D 10
 i##++i,2
++lB/B:v.!ZZ:{(CD  0 #*==E
$ 1E 1000sg   A7F;9&F7F;F F;F&2F"3$F&F;"F$#A>F;"F&$F;&F8,F/-F84F;r   r   r   rU   r
   r   r   rW   rW   o   sB    39
 .2$(	<>&<> +<> "	<>
 
<>r   rW   c                     t        j                  d      r
t               S t        j                  d      r
t               S t	        d      )z9Get the configured primary provider, with fallback order.r!   rY   z?No LLM provider configured. Set GEMINI_API_KEY or GROQ_API_KEY.)r%   r&   r   rW   rD   r
   r   r   get_providerro      s<    	yy!"	yy ~
I r   c                    t        | t              rt        j                  d      r
t	               S t        | t              rt        j                  d      r
t               S y)z+Get the fallback provider if primary fails.rY   r!   N)
isinstancer   r%   r&   rW   )currents    r   get_fallback_providerrs      sA    '>*ryy/H~'<(RYY7G-Hr   )r   r   )rr   r   r   zLLMProvider | None)r   
__future__r   r<   r%   abcr   r   typingr   rG   r   r   rW   ro   rs   r
   r   r   <module>rw      sR    #  	 #  # (F>[ F>RG>; G>Tr   