o
    j-3                     @   s^  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	Z	d dl
Z
d dlmZmZmZmZ d dlmZ d dlmZmZ e
eZed	geegd
d Zed	geegdd ZdefddZdededdfddZdedB defddZ	d(dededededef
ddZ deded ed!edef
d"d#Z!ed	geegd$ed%efd&d'Z"dS ))    )api_viewpermission_classes)AllowAny)ResponsestatusN)AgentConfigAgentVoiceConfigAgentGuardrailAgentSystemTool)connections)_q_identensure_business_cluster_tablesGETc                 C   s    t tjjddd}td|iS )z+List available agent names (for discovery).nameT)flatagents)listr   objectsvalues_listr   )requestnames r   8/var/www/html/livekitdocker/backend/apps/agents/views.py
agent_list   s   r   c              	   C   s`  zt jddddj|d}W n t jy"   tdditjd Y S w t|dd	}i d
|j	d|j
d|jd|jd|jd|jd|jd|jd|jd|jd|jd|jd|jrct|jnd	d|r|rm|jnd	|rs|jnd	|ry|jnd	|r|jnd	|r|jnd	|r|jnd	dni ddd |jjddD ddd |jjddD }t|S )z0Worker fetches full config for an agent by name.voice_config
guardrailssystem_toolsknowledge_base)r   errorzAgent not foundr   Nidr   mcube_exenumber	mcube_gidstt_providertts_providerllm_provider	llm_modelsystem_promptdefault_languagefirst_message_inboundfirst_message_outboundknowledge_base_idvoice)voice_idtts_model_family
similarityspeed	stabilityoutput_formatc                 S      g | ]}|j qS r   )guardrail_key).0gr   r   r   
<listcomp>;       z agent_config.<locals>.<listcomp>T)enabledc                 S   r3   r   )tool_key)r5   tr   r   r   r7   <   r8   ) r   r   prefetch_relatedgetDoesNotExistr   r   HTTP_404_NOT_FOUNDgetattrpkr   r!   r"   r#   r$   r%   r&   r'   r(   r)   r*   r+   strr-   r.   r/   r0   r1   r2   r   filterr   )r   
agent_nameagentr,   datar   r   r   agent_config   sl   
	
rG   returnc                 C   s   | d u ri S t | tr| S t | ttfr| jddd} t | tr@|  r@zt| }t |tr2|W S i W S  t	y?   i  Y S w i S )Nutf-8replaceerrors)

isinstancedictbytes	bytearraydecoderB   stripjsonloads	Exception)valparsedr   r   r   
_json_dictA   s   

rX   platadvc           
      C   s  t | tr
t |tsdS | dp| dp| dp| d}t |trw|dp8|dp8|dp8|d	}|rNt|d	pBd
 sNt| |d	< |dpa|dpa|dpa|d}|rwt|dpkd
 swt| |d< | dp| dp| d}t |tr|dp|dp|d}|rt|dpd
 st| |d< |dp|d}|rt|dpd
 st| |d< t|dpd
 sdD ]}| |}	t |	tr|	 r|	 |d<  dS qdS dS )z
    Many tenants store STT/TTS under nested keys in `platform_settings` JSON
    (not copied by the flat scalar merge). Fill adv gaps used by MCube.
    Nsttasrspeech_to_textspeechmodel_idmodel	stt_modelstt_model_id languagelanguage_codelocalelangstt_language_codettstext_to_speechtextToSpeech	tts_modelr-   voiceIdtts_voice_idfirst_message)greetingopening_messageopening_line)rM   rN   r=   rB   rR   )
rY   rZ   r[   midrg   ri   tmtvkgvr   r   r   _apply_nested_platform_settingsQ   sZ   





rx   rowc                 C   s\   | si S t | d}i }|  D ]\}}|dkrq|||< q| D ]\}}|||< q#|S )u   
    Flatten `business_id_bots` row: scalar columns plus JSON `config`, with `config` winning on collision.
    Supports deployments that store MCube fields as real columns (prompt, llm_model, stt_model, …)
    and/or inside JSON `config`.
    config)rX   r=   items)ry   cfgoutrv   vr   r   r   _merge_business_id_bots_row   s   

r   rc   bidbot_pkbot_nameagent_idc           
   	   C   s  t |pd }t |pd }d| |gfg}|r#|d| ||gf |d| t ||gf |D ]L\}}z?td  /}||| | }|rddd |jD }	tt	t
|	|W  d   W   S W d   n1 snw   Y  W q1 ty}   Y q1w td	| ||| i S )
a8  
    Scalar columns + JSON `config` from livekitvoicebot_cluster.business_id_bots (per tenant/bot).

    Deployments vary: rows may be keyed by `bot_id` (selected cluster bot), `agent_id`
    (LiveKit id from `{bid}_bots`), or legacy `name`. Unknown columns are skipped without
    failing the whole lookup.
    rc   z
            SELECT * FROM business_id_bots
            WHERE business_id = %s AND bot_id = %s
            ORDER BY updated_at DESC
            LIMIT 1
            z
                SELECT * FROM business_id_bots
                WHERE business_id = %s AND (agent_id = %s OR CAST(agent_id AS CHAR) = %s)
                ORDER BY updated_at DESC
                LIMIT 1
                z
            SELECT * FROM business_id_bots
            WHERE business_id = %s AND (name = %s OR name = %s)
            ORDER BY updated_at DESC
            LIMIT 1
            clusterc                 S      g | ]}|d  qS r   r   r5   cr   r   r   r7          z2_fetch_business_id_bots_merged.<locals>.<listcomp>NzQbusiness_id_bots: no row matched business_id=%s bot_id=%s bot_name=%r agent_id=%r)rB   rR   appendr   cursorexecutefetchonedescriptionr   rN   ziprU   loginfo)
r   r   r   r   variantssqlparamscurrcolsr   r   r   _fetch_business_id_bots_merged   sP   
r   overriderF   keysc                 G   sX   | ||fD ]$}|D ]}||vs| |du rq	t| | }|r(|    S q	qdS )z\First non-empty among business_id_bots merge, advanced_settings JSON, then `{bid}_bots` row.Nrc   )r=   rB   rR   )r   rZ   rF   r   drv   sr   r   r   	_pick_str   s   r   business_idbot_idc              
   C   sd  z
t |}t |}W n ty   tdditjd Y S w t| | d}i }td  *}|dt	| d|g |
 }|rQdd	 |jD }	tt|	|}W d
   n1 s[w   Y  t|dpl|dpld }
t|dpwd }t|||
|}|s|ri }|s|stdditjdS t|d}t|r|dnd
}| D ]"\}}|dv rqt|ttfrqt||dpd rq|||< q|d}t|tr|dp|d}|r|dst| |d< t|| t|||ddd}t|dd }d}|r|dnd
}t|ttfr$|jddd}t|tr[| r[zt|}t|trMt|dpI|dpId }W n tyZ   d}Y nw t|||dd d!d"d#}ti d$|d%|d|d|d"|rt|d"pd ndd#|rt|d#pd ndd&t|||d&d'd(t|||d(d)d*t|||d*d+d,t|||d,d-d.d/t|||d/d0d1d2t|||d2d3d4t|||d4d5dt|||dd6p|d7t|||d7d8d9t|||d9d:d;t|||d;d<t|||d=d>t|||d?d@t|||dAdBt|||dC|r#|dnd
|r,|dDnd
dES )Fa>  
    Internal helper endpoint for MCube runtime.

    Reads `{business_id}_bots` on cluster DB plus `business_id_bots` (scalar columns + JSON `config`)
    (same database: livekitvoicebot_cluster). Returns fields the WS bridge / outbound worker
    need for prompts, providers, models, voice, MCube exenumber/gid.
    r   zInvalid business_id or bot_idr   _botsr   zSELECT * FROM z WHERE bot_id = %s LIMIT 1c                 S   r   r   r   r   r   r   r   r7      r   z,cluster_bot_mcube_config.<locals>.<listcomp>Nr   r   rc   r   zBot not foundadvanced_settingsplatform_settings)Nrc   r,   r-   rm   rn   r'   MCUBE_SYSTEM_PROMPTpromptz\n
rI   rJ   rK   ro   MCUBE_FIRST_MESSAGEmessage_onboardmessage_outboundmessage_inboundr   r   r&   MCUBE_LLM_MODELr%   MCUBE_LLM_PROVIDERr#   MCUBE_STT_PROVIDERrb   MCUBE_STT_MODEL_IDra   rh   MCUBE_STT_LANGUAGE_CODEr(   r$   MCUBE_TTS_PROVIDERrl   MCUBE_TTS_MODELMCUBE_TTS_VOICE_IDtts_encodingMCUBE_TTS_ENCODINGtts_chunk_msMCUBE_TTS_CHUNK_MStts_gainMCUBE_TTS_GAINplayback_pace_factorMCUBE_PLAYBACK_PACE_FACTORcheckpoint_everyMCUBE_CHECKPOINT_EVERYr!   mcube_exenumr"   conversation_behavior)r   r   r!   r"   r   r   )intrU   r   r   HTTP_400_BAD_REQUESTr   r   r   r   r   r   r   rN   r   rB   r=   rR   r   r?   rX   r{   rM   r   rx   r   rJ   rO   rP   rQ   rS   rT   )r   r   r   r   r   tablerF   r   ry   r   r   agent_id_for_bibbibrZ   rY   rA   pvvoice_nestedvidr'   r-   	voice_raw	voice_obj	first_msgr   r   r   cluster_bot_mcube_config   s   

 




$""	
r   )rc   )#rest_framework.decoratorsr   r   rest_framework.permissionsr   rest_framework.responser   rest_frameworkr   rS   loggingapps.agents.modelsr   r	   r
   r   	django.dbr   apps.cluster.dynamic_tablesr   r   	getLogger__name__r   r   rG   rN   rX   rx   r   r   rB   r   r   r   r   r   r   r   <module>   sF    
&0
G