o
    پi$#                     @   s~   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 d dl	m
Z
mZmZmZ d dlmZ eeZG dd deZdS )	    N)List)Tool)BaseFormatDetector)StreamingParseResultStructureInfoToolCallItem_GetInfoFunc)_is_complete_jsonc                       st   e Zd ZdZ fddZdedefddZdedee	 de
fd	d
Zdedee	 de
fddZdefddZ  ZS )DeepSeekV31Detectoru  
    Detector for DeepSeek V3 model function call format.

    The DeepSeek V3 format uses special Unicode tokens to delimit function calls
    with JSON code blocks for arguments.

    Format Structure:
    ```
    <｜tool▁calls▁begin｜><｜tool▁call▁begin｜>{function_name}<｜tool▁sep｜>{json_arguments}<｜tool▁calls▁end｜><｜end▁of▁sentence｜>
    ```
    Examples:
    ```
    <｜tool▁calls▁begin｜><｜tool▁call▁begin｜>get_current_weather<｜tool▁sep｜>{"location": "Tokyo"}<｜tool▁call▁end｜><｜tool▁call▁begin｜>get_current_weather<｜tool▁sep｜>{"location": "Paris"}<｜tool▁call▁end｜><｜tool▁calls▁end｜><｜end▁of▁sentence｜>
    ```

    Key Components:
    - Tool Calls Section: Wrapped between `<｜tool▁calls▁begin｜>` and `<｜tool▁calls▁end｜>`
    - Individual Tool Call: Wrapped between `<｜tool▁call▁begin｜>` and `<｜tool▁call▁end｜>`
    - Function Declaration: `<｜tool▁call▁begin｜>{function_name}<｜tool▁sep｜>`
    - Arguments: JSON code block between `<｜tool▁sep｜>` and `<｜tool▁call▁end｜>`
    - Supports multiple tool calls

    Reference: https://www.modelscope.cn/models/deepseek-ai/DeepSeek-V3.1
    c                    s2   t    d| _d| _d| _d| _d| _d| _d S )Nu   <｜tool▁calls▁begin｜>u   <｜tool▁calls▁end｜>u7   <｜tool▁call▁begin｜>.*?<｜tool▁call▁end｜>uN   <｜tool▁call▁begin｜>(.*)<｜tool▁sep｜>(.*)<｜tool▁call▁end｜> )super__init__	bot_token	eot_tokenfunc_call_regexfunc_detail_regex_last_argumentscurrent_tool_idself	__class__ a/home/ubuntu/.local/lib/python3.10/site-packages/sglang/srt/function_call/deepseekv31_detector.pyr   -   s   

zDeepSeekV31Detector.__init__textreturnc                 C   s
   | j |v S )z7Check if the text contains a deepseek format tool call.)r   )r   r   r   r   r   has_tool_call8   s   
z!DeepSeekV31Detector.has_tool_calltoolsc              
   C   s   | | j}|dkr|d|  n|}| j|vrt|g dS t| j|tj}g }z2|D ](}t| j	|tj}|
d}	|
d}
t|
}
|	|
d}|| || q-t||dW S  ty{ } ztd|  t|dW  Y d}~S d}~ww )	a$  
        One-time parsing: Detects and parses tool calls in the provided text.

        :param text: The complete text to parse.
        :param tools: List of available tools.
        :return: ParseResult indicating success or failure, consumed text, leftover text, and parsed calls.
        r   Nnormal_textcalls      )name
parameterszError in detect_and_parse: r    )findr   stripr   refindallr   DOTALLsearchr   groupjsonloadsextendparse_base_json	Exceptionloggererror)r   r   r   idxr    match_result_listr!   match_resultfunc_detail	func_name	func_argser   r   r   detect_and_parse<   s(   




z$DeepSeekV31Detector.detect_and_parsenew_textc              
   C   s  |  j |7  _ | j }| j|v pd|v }|s/d| _ | jdfD ]}||v r)||d}qt|dS t| ds:| || _g }ztj	d|tj
d}|r'|d }|d	 }	|d
}
| jdkrkd| _g | _dg| _t| j| jkr| ji  t| j| jksst| j| jkr| jd t| j| jks| js|t| j|dd d| _|i d| j| j< nu|	| jr|	t| jd n|	}|r|t| jd|d |  j|7  _| j| j  |7  < t|	r'zt|	}|| j| j d< W n
 tjy   Y nw |
r||d
d | _ nd| _ td|d}|  jd7  _d| _d| _|W S td|dW S  tyM } ztd|  t|dW  Y d}~S d}~ww )zQ
        Streaming incremental parsing tool calls for DeepSeekV3 format.
           <｜tool▁call▁begin｜>r      <｜tool▁call▁end｜>r&   _tool_indicesuS   <｜tool▁call▁begin｜>(.*)<｜tool▁sep｜>(.*?)(<｜tool▁call▁end｜>|$))patternstringflagsr"   r#      r   r   )
tool_indexr$   r%   T)r$   	argumentsNrF   r   Fz$Error in parse_streaming_increment: )_bufferr   r   replacer   hasattr_get_tool_indicesr@   r)   r,   r+   r-   r(   r   prev_tool_call_arrstreamed_args_for_toollenappendcurrent_tool_name_sentr   
startswithr   r	   r.   r/   JSONDecodeErrorendr2   r3   r4   )r   r=   r   current_textr   e_tokenr!   partial_matchr9   func_args_rawis_tool_endargument_diffparsed_argsresultr;   r   r   r   parse_streaming_incrementZ   s   







z-DeepSeekV31Detector.parse_streaming_incrementc                 C   s   dd S )Nc                 S   s   t d|  d dddS )Nr>   u   <｜tool▁sep｜>r?   )beginrR   trigger)r   )r$   r   r   r   <lambda>   s
    
z4DeepSeekV31Detector.structure_info.<locals>.<lambda>r   r   r   r   r   structure_info   s   z"DeepSeekV31Detector.structure_info)__name__
__module____qualname____doc__r   strboolr   r   r   r   r<   r[   r   r_   __classcell__r   r   r   r   r
      s    
or
   )r.   loggingr)   typingr   &sglang.srt.entrypoints.openai.protocolr   -sglang.srt.function_call.base_format_detectorr   #sglang.srt.function_call.core_typesr   r   r   r   sglang.srt.function_call.utilsr	   	getLoggerr`   r3   r
   r   r   r   r   <module>   s    
