|
@@ -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}"
|
|
|
+
|