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 )DeepSeekV3Detectoru  
    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<｜tool▁sep｜>{function_name}
```json
{json_arguments}
```<｜tool▁calls▁end｜><｜end▁of▁sentence｜>
    ```
    Examples:
    ```
    <｜tool▁calls▁begin｜><｜tool▁call▁begin｜>function<｜tool▁sep｜>get_current_weather
```json
{"location": "Tokyo"}
```<｜tool▁call▁end｜>
<｜tool▁call▁begin｜>function<｜tool▁sep｜>get_current_weather
```json
{"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: `function<｜tool▁sep｜>{function_name}`
    - Arguments: JSON code block between ````json` and ````
    - Supports multiple tool calls

    Reference: https://huggingface.co/deepseek-ai/DeepSeek-V3-0324?chat_template=default
    c                    s2   t    d| _d| _d| _d| _d| _d| _d S )Nu   <｜tool▁calls▁begin｜>u   <｜tool▁calls▁end｜>7   <｜tool▁call▁begin｜>.*?<｜tool▁call▁end｜>ub   <｜tool▁call▁begin｜>(.*)<｜tool▁sep｜>(.*)\n```json\n(.*)\n```<｜tool▁call▁end｜> )super__init__	bot_token	eot_tokenfunc_call_regexfunc_detail_regex_last_argumentscurrent_tool_idself	__class__ `/home/ubuntu/.local/lib/python3.10/site-packages/sglang/srt/function_call/deepseekv3_detector.pyr   -   s   

zDeepSeekV3Detector.__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_call6   s   
z DeepSeekV3Detector.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#DeepSeekV3Detector.detect_and_parsenew_textc              
   C   s  |  j |7  _ | j }| j|v pd|v }|s0d| _ | jddfD ]}||v r*||d}qt|dS t| ds;| || _g }ztj	d|tj
d}|r,|d	 }|d
 }	| jdkrgd| _g | _dg| _t| j| jkr}| ji  t| j| jksot| j| jkr| jd t| j| jks| js|t| j|dd d| _|i d| j| j< n~|	| 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 d}t	||tj
}|r|| d | _ nd| _ td|d}|  jd7  _d| _d| _|W S td|dW S  tyR } ztd|  t|dW  Y d}~S d}~ww )zQ
        Streaming incremental parsing tool calls for DeepSeekV3 format.
        u   <｜tool▁call▁begin｜>r   z```u   <｜tool▁call▁end｜>r'   _tool_indicesuK   <｜tool▁call▁begin｜>(.*)<｜tool▁sep｜>(.*)\n```json\n(.*)\n```.*)patternstringflagsr#   r$   r   r   )
tool_indexr%   r&   T)r%   	argumentsNrD   r   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/   r0   JSONDecodeErrorendr3   r4   r5   )r   r>   r   current_textr   e_tokenr"   partial_matchr:   func_args_rawargument_diffparsed_argstool_call_end_patternmatchresultr<   r   r   r   parse_streaming_incrementX   s   






z,DeepSeekV3Detector.parse_streaming_incrementc                 C   s   dd S )Nc                 S   s   t d|  d dd|  d dS )N>z	
```json
z
```<)beginrQ   trigger)r   )r%   r   r   r   <lambda>   s
    

z3DeepSeekV3Detector.structure_info.<locals>.<lambda>r   r   r   r   r   structure_info   s   z!DeepSeekV3Detector.structure_info)__name__
__module____qualname____doc__r   strboolr   r   r   r   r=   r[   r   r`   __classcell__r   r   r   r   r
      s    	
tr
   )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	   	getLoggerra   r4   r
   r   r   r   r   <module>   s    
