o
    iD                     @   sJ   d Z ddlZddlmZmZ ddlmZ ddlmZm	Z	 G dd dZ
dS )z\
Model Synchronization Service

Fetches available models from different AI providers' APIs.
    N)ListDict)Session)ModelProviderModelc                   @   sd  e Zd ZdZdefddZdedee fddZ	dedee
 fd	d
Zdedee
 fddZdedee
 fddZdedee
 fddZdedee
 fddZde
de
fddZdedefddZdedee
 fddZdedee
 fddZdedefddZdededee fd d!Zdedefd"d#Zdededee fd$d%Zdededee fd&d'Zd(S ))ModelSyncServicez3Service for synchronizing models from provider APIsdbc                 C   s   || _ d| _d S )Ng      >@)r   timeout)selfr    r   C/lsinfo/ai/hellotax_ai/base_platform/app/services/llm/model_sync.py__init__   s   
zModelSyncService.__init__providerreturnc           
         s  |j s|jstd fdd |I dH D }t }g }|D ]J}||d   jt	tj
|jktj|d k }|rV| D ]
\}}t||| qE|| q!td	d|ji|}	 j|	 ||	 q!|r jt	tj
|jktj|jdd  j  |S )
z
        Sync models for a specific provider

        Args:
            provider: The ModelProvider instance

        Returns:
            List of synced Model instances
        z1Provider must be configured before syncing modelsc                    s   g | ]}  |qS r   )_normalize_model_payload).0
model_datar
   r   r   
<listcomp>!   s    z9ModelSyncService.sync_provider_models.<locals>.<listcomp>Ncodeprovider_idfetch)synchronize_sessionr   )
configuredis_local
ValueError_discover_provider_modelssetaddr   queryr   filterr   idr   firstitemssetattrappendnotin_deletecommit)
r
   r   models_datasynced_codessynced_modelsr   existing_modelkeyvalue	new_modelr   r   r   sync_provider_models   s<   




z%ModelSyncService.sync_provider_modelsc                    s   |j dv r|jdkr| |I d H S |jdkr | |I d H S |jdks*|jdkr2| |I d H S |jdks<|jdkrD| |I d H S |jdv rQ| |I d H S |jdkr^| |I d H S |jdkrk| |I d H S t	d	|jpr|j )
N>   	local_mlxself_hostedopenai_compatible	anthropicgeminigoogle)qwenalibabadeepseekmistralz$Unsupported provider configuration: )
provider_kindprotocol_fetch_openai_compatible_modelsicon_fetch_anthropic_models_fetch_google_models_fetch_dashscope_models_fetch_deepseek_models_fetch_mistral_modelsr   r
   r   r   r   r   r   >   s    



z*ModelSyncService._discover_provider_modelsc                    sL  |j p|j}|stdi }| }|jdv r"|r"d| |d< n|jdkr.|r.||d< n|jdkr9|r9||d< tj| jd	4 I d
H #}|j|	d d|dI d
H }|
  | }W d
  I d
H  n1 I d
H smw   Y  g }|dg D ])}	|	dd}
| |
}|dkrqz||
|
|| |
|d|
|dk|dkdd	 qz|S )z(Fetch models from OpenAI-compatible APIszProvider base URL is required>   NbearerBearer Authorizationapi_keyzapi-key	x_api_keyz	x-api-keyr	   N//modelsheadersdatar!    unknownTchatd   )	r   nametypetagsenabledremote_model_idsupports_streamsupports_toolspriority)base_urldefault_base_urlr   get_api_key	auth_typehttpxAsyncClientr	   getrstripraise_for_statusjson_infer_openai_model_typer%   _get_openai_tags)r
   r   r\   rN   rH   clientresponserO   modelsmodelmodel_id
model_typer   r   r   r=   O   sF   
 
(


z0ModelSyncService._fetch_openai_compatible_modelsc              
      s^   dddg ddddddg dddddddd	gddd
d
ddgdddddddgddgS )zFetch models from Anthropic APIzclaude-3-5-sonnet-20241022rR   )rR   latestrecommendedTr   rT   rU   rV   rW   zclaude-3-5-haiku-20241022rR   fastcost-effectivezclaude-3-opus-20240229powerfulzclaude-3-sonnet-20240229zclaude-3-haiku-20240307rr   r   rD   r   r   r   r?   w   s@   z(ModelSyncService._fetch_anthropic_modelsc                    s  dddg ddddddddgdddddg d	ddd
d
dddgdddddg ddddddg ddddddg ddddddg ddddddg ddddddg ddddddg ddddddg ddddddg dddd d dg d!ddd"d"d#d#d$gddgS )%z=Fetch known models for DashScope-compatible Alibaba providerszqwen-maxrR   )rR   rn   rt   Trp   z	qwen-plusro   z
qwen-turborq   z	qwen-longlong-contextzqwen3-vl-embedding	embedding)rv   
multimodalvisionrn   rt   zqwen2.5-vl-embedding)rv   rw   rx   ztongyi-embedding-vision-plus)rv   rw   rx   ro   ztongyi-embedding-vision-flash)rv   rw   rx   rr   rs   zqwen3-vl-235b-a22b-instructrw   )rw   rx   rn   rt   zqwen3-vl-235b-a22b-thinking)rw   rx   rn   thinkingzqwen3-vl-plus)rw   rx   ro   zqwen3-vl-flash)rw   rx   rr   rs   zqwen-vl-max-latest)rw   rx   rt   zqwen-vl-plus-latest)rw   rx   rR   zqwen-audio-turboaudiotranscriptionr   rD   r   r   r   rA      s   				z(ModelSyncService._fetch_dashscope_modelsc           
   
         |j p|jpd}tj| jd4 I dH '}|j| ddd|  idI dH }|  | }W d  I dH  n1 I dH sAw   Y  g }|dg D ]}|d	d
}| 	|}	|
|||	| ||	dd qN|S )zFetch models from DeepSeek APIzhttps://api.deepseek.com/v1rJ   NrL   rG   rF   rM   rO   r!   rP   Trp   )r\   r]   r`   ra   r	   rb   r^   rd   re   _infer_deepseek_model_typer%   _get_deepseek_tags
r
   r   r\   rh   ri   rO   rj   rk   rl   rm   r   r   r   rB     ,   
(


z'ModelSyncService._fetch_deepseek_modelsr   c                 C   sV   t |}|d|d |d|ddk |d|ddk |dd |S )	NrX   r   rY   rU   rR   rZ   r[   rS   )dict
setdefaultrb   )r
   r   payloadr   r   r   r   1  s   z)ModelSyncService._normalize_model_payloadrl   c                 C   s0   |  }d|v r
dS d|v rdS d|v rdS dS )z'Infer model type from DeepSeek model IDrR   coderr   rv   lowerr
   rl   model_id_lowerr   r   r   r}   9  s   z+ModelSyncService._infer_deepseek_model_typec              	      sN   dddg ddddddg ddddddg d	ddd
d
dg dddgS )z#Fetch models from Google Gemini APIzgemini-2.0-flash-exprR   )rR   rn   experimentalTrp   zgemini-1.5-pro)rR   rt   ru   zgemini-1.5-flash)rR   rr   ro   ztext-embedding-004rv   )rv   textrn   r   rD   r   r   r   r@   F  s4   	z%ModelSyncService._fetch_google_modelsc           
   
      r|   )zFetch models from Mistral APIzhttps://api.mistral.ai/v1rJ   NrL   rG   rF   rM   rO   r!   rP   Trp   )r\   r]   r`   ra   r	   rb   r^   rd   re   _infer_mistral_model_typer%   _get_mistral_tagsr   r   r   r   rC   j  r   z&ModelSyncService._fetch_mistral_modelsc                 C   s   |  }d|v r
dS dS )z&Infer model type from Mistral model IDembedrv   rR   r   r   r   r   r   r     s   z*ModelSyncService._infer_mistral_model_typerm   c                 C   s   |g}d|v r| ddg d|v r|d d|v r$d|vr$|d d|v s,d	|v r1|d d
|v r<| ddg d|v rE|d d|v rN|d d|v rW|d d|v r`|d d|v ri|d d|v rr|d |S )zGet tags for OpenAI modelsgpt-4orn   rw   turborr   gpt-4rt   01251106zdall-e-3zhigh-qualityzdall-e-2rs   whisperr{   ttsztext-to-speechztext-embedding-3largezhigh-dimensionsmall)extendr%   r
   rl   rm   rV   r   r   r   rg     s0   








z!ModelSyncService._get_openai_tagsc                    sr   |   t fdddD rdS d v sd v rdS d v s#d v r%d	S d
 v r+dS d v r1dS d v r7dS dS )z%Infer model type from OpenAI model IDc                 3   s    | ]}| v V  qd S )Nr   )r   xr   r   r   	<genexpr>  s    z<ModelSyncService._infer_openai_model_type.<locals>.<genexpr>)r   zgpt-3.5r   chatgptrR   rv   adazdall-edalleimager   zaudio-transcriptionr   zaudio-generation
moderationrQ   )r   any)r
   rl   r   r   r   rf     s   z)ModelSyncService._infer_openai_model_typec                 C   sH   |g}d|v r| d d|v r| d d|v sd|v r"| d |S )zGet tags for DeepSeek modelsrR   r   r   v2v3rn   )r%   r   r   r   r   r~     s   


z#ModelSyncService._get_deepseek_tagsc                 C   s^   |g}d|v r| d d|v sd|v r|ddg d|v r$| d d|v r-| d	 |S )
zGet tags for Mistral modelsr   rt   r   tinyrr   rs   rn   r   rv   )r%   r   r   r   r   r   r     s   


z"ModelSyncService._get_mistral_tagsN)__name__
__module____qualname____doc__r   r   r   r   r   r0   r   r   r=   r?   rA   rB   r   strr}   r@   rC   r   rg   rf   r~   r   r   r   r   r   r      s$    *(*u$	r   )r   r`   typingr   r   sqlalchemy.ormr   
app.modelsr   r   r   r   r   r   r   <module>   s    