| 
					
				 | 
			
			
				@@ -1,18 +1,24 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from collections.abc import Generator 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from typing import Optional, Union 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+from urllib.parse import urlparse 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import tiktoken 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from core.model_runtime.entities.llm_entities import LLMResult 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-from core.model_runtime.entities.message_entities import PromptMessage, PromptMessageTool 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-from core.model_runtime.model_providers.openai_api_compatible.llm.llm import OAIAPICompatLargeLanguageModel 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+from core.model_runtime.entities.message_entities import ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    PromptMessage, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    PromptMessageTool, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+from core.model_runtime.model_providers.openai.llm.llm import OpenAILargeLanguageModel 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+class DeepSeekLargeLanguageModel(OpenAILargeLanguageModel): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-class DeepseekLargeLanguageModel(OAIAPICompatLargeLanguageModel): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def _invoke(self, model: str, credentials: dict, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 prompt_messages: list[PromptMessage], model_parameters: dict, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 tools: Optional[list[PromptMessageTool]] = None, stop: Optional[list[str]] = None, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 stream: bool = True, user: Optional[str] = None) \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             -> Union[LLMResult, Generator]: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-         
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         self._add_custom_parameters(credentials) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return super()._invoke(model, credentials, prompt_messages, model_parameters, tools, stop, stream, user) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -21,7 +27,87 @@ class DeepseekLargeLanguageModel(OAIAPICompatLargeLanguageModel): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         self._add_custom_parameters(credentials) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         super().validate_credentials(model, credentials) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # refactored from openai model runtime, use cl100k_base for calculate token number 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def _num_tokens_from_string(self, model: str, text: str, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                tools: Optional[list[PromptMessageTool]] = None) -> int: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Calculate num tokens for text completion model with tiktoken package. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        :param model: model name 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        :param text: prompt text 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        :param tools: tools for tool calling 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        :return: number of tokens 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        encoding = tiktoken.get_encoding("cl100k_base") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        num_tokens = len(encoding.encode(text)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if tools: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            num_tokens += self._num_tokens_for_tools(encoding, tools) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return num_tokens 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # refactored from openai model runtime, use cl100k_base for calculate token number 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def _num_tokens_from_messages(self, model: str, messages: list[PromptMessage], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                  tools: Optional[list[PromptMessageTool]] = None) -> int: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        """Calculate num tokens for gpt-3.5-turbo and gpt-4 with tiktoken package. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Official documentation: https://github.com/openai/openai-cookbook/blob/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        main/examples/How_to_format_inputs_to_ChatGPT_models.ipynb""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        encoding = tiktoken.get_encoding("cl100k_base") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        tokens_per_message = 3 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        tokens_per_name = 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        num_tokens = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        messages_dict = [self._convert_prompt_message_to_dict(m) for m in messages] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for message in messages_dict: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            num_tokens += tokens_per_message 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for key, value in message.items(): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                # Cast str(value) in case the message value is not a string 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                # This occurs with function messages 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                # TODO: The current token calculation method for the image type is not implemented, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                #  which need to download the image and then get the resolution for calculation, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                #  and will increase the request delay 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if isinstance(value, list): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    text = '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    for item in value: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if isinstance(item, dict) and item['type'] == 'text': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            text += item['text'] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    value = text 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if key == "tool_calls": 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    for tool_call in value: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        for t_key, t_value in tool_call.items(): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            num_tokens += len(encoding.encode(t_key)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            if t_key == "function": 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                for f_key, f_value in t_value.items(): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                    num_tokens += len(encoding.encode(f_key)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                    num_tokens += len(encoding.encode(f_value)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                num_tokens += len(encoding.encode(t_key)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                num_tokens += len(encoding.encode(t_value)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    num_tokens += len(encoding.encode(str(value))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if key == "name": 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    num_tokens += tokens_per_name 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # every reply is primed with <im_start>assistant 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        num_tokens += 3 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if tools: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            num_tokens += self._num_tokens_for_tools(encoding, tools) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return num_tokens 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     @staticmethod 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def _add_custom_parameters(credentials: dict) -> None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         credentials['mode'] = 'chat' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        credentials['endpoint_url'] = 'https://api.deepseek.com/' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        credentials['openai_api_key']=credentials['api_key'] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if 'endpoint_url' not in credentials or credentials['endpoint_url'] == "": 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            credentials['openai_api_base']='https://api.deepseek.com' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            parsed_url = urlparse(credentials['endpoint_url']) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            credentials['openai_api_base']=f"{parsed_url.scheme}://{parsed_url.netloc}" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 |