Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions apps/locales/en_US/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -6715,3 +6715,6 @@ msgstr ""
#: .\apps\xpack\views\system_api_key_views.py:58
msgid "Add personal system API_KEY"
msgstr ""

msgid "Tencent Cloud"
msgstr ""
3 changes: 3 additions & 0 deletions apps/locales/zh_CN/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -6853,3 +6853,6 @@ msgstr "删除个人系统 API_KEY"
#: .\apps\xpack\views\system_api_key_views.py:58
msgid "Add personal system API_KEY"
msgstr "添加个人系统 API_KEY"

msgid "Tencent Cloud"
msgstr "腾讯云"
3 changes: 3 additions & 0 deletions apps/locales/zh_Hant/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -6867,3 +6867,6 @@ msgstr "刪除個人系統 API_KEY"
#: .\apps\xpack\views\system_api_key_views.py:58
msgid "Add personal system API_KEY"
msgstr "添加個人系統 API_KEY"

msgid "Tencent Cloud"
msgstr "腾訊云"
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
from setting.models_provider.impl.qwen_model_provider.qwen_model_provider import QwenModelProvider
from setting.models_provider.impl.siliconCloud_model_provider.siliconCloud_model_provider import \
SiliconCloudModelProvider
from setting.models_provider.impl.tencent_cloud_model_provider.tencent_cloud_model_provider import \
TencentCloudModelProvider
from setting.models_provider.impl.tencent_model_provider.tencent_model_provider import TencentModelProvider
from setting.models_provider.impl.vllm_model_provider.vllm_model_provider import VllmModelProvider
from setting.models_provider.impl.volcanic_engine_model_provider.volcanic_engine_model_provider import \
Expand All @@ -45,6 +47,7 @@ class ModelProvideConstants(Enum):
model_gemini_provider = GeminiModelProvider()
model_volcanic_engine_provider = VolcanicEngineModelProvider()
model_tencent_provider = TencentModelProvider()
model_tencent_cloud_provider = TencentCloudModelProvider()
model_aws_bedrock_provider = BedrockModelProvider()
model_local_provider = LocalModelProvider()
model_xinference_provider = XinferenceModelProvider()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# coding=utf-8
"""
@project: maxkb
@Author:虎
@file: __init__.py.py
@date:2024/3/28 16:25
@desc:
"""
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# coding=utf-8
"""
@project: MaxKB
@Author:虎
@file: llm.py
@date:2024/7/11 18:32
@desc:
"""
from typing import Dict

from django.utils.translation import gettext_lazy as _, gettext
from langchain_core.messages import HumanMessage

from common import forms
from common.exception.app_exception import AppApiException
from common.forms import BaseForm, TooltipLabel
from setting.models_provider.base_model_provider import BaseModelCredential, ValidCode


class TencentCloudLLMModelParams(BaseForm):
temperature = forms.SliderField(TooltipLabel(_('Temperature'),
_('Higher values make the output more random, while lower values make it more focused and deterministic')),
required=True, default_value=0.7,
_min=0.1,
_max=1.0,
_step=0.01,
precision=2)

max_tokens = forms.SliderField(
TooltipLabel(_('Output the maximum Tokens'),
_('Specify the maximum number of tokens that the model can generate')),
required=True, default_value=800,
_min=1,
_max=100000,
_step=1,
precision=0)


class TencentCloudLLMModelCredential(BaseForm, BaseModelCredential):

def is_valid(self, model_type: str, model_name, model_credential: Dict[str, object], model_params, provider,
raise_exception=False):
model_type_list = provider.get_model_type_list()
if not any(list(filter(lambda mt: mt.get('value') == model_type, model_type_list))):
raise AppApiException(ValidCode.valid_error.value,
gettext('{model_type} Model type is not supported').format(model_type=model_type))

for key in ['api_base', 'api_key']:
if key not in model_credential:
if raise_exception:
raise AppApiException(ValidCode.valid_error.value, gettext('{key} is required').format(key=key))
else:
return False
try:

model = provider.get_model(model_type, model_name, model_credential, **model_params)
model.invoke([HumanMessage(content=gettext('Hello'))])
except Exception as e:
if isinstance(e, AppApiException):
raise e
if raise_exception:
raise AppApiException(ValidCode.valid_error.value,
gettext(
'Verification failed, please check whether the parameters are correct: {error}').format(
error=str(e)))
else:
return False
return True

def encryption_dict(self, model: Dict[str, object]):
return {**model, 'api_key': super().encryption(model.get('api_key', ''))}

api_base = forms.TextInputField('API URL', required=True)
api_key = forms.PasswordInputField('API Key', required=True)

def get_model_params_setting_form(self, model_name):
return TencentCloudLLMModelParams()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code appears to be properly structured, including importing necessary modules and defining classes with specific functionalities. However, here are a few improvements and points to consider:

Improvements:

  1. Whitespace Consistency: The code uses inconsistent indentation levels (4 spaces vs. tabs). It's recommended to stick with one style consistently.

  2. Comments and Formatting: Ensure comments explain complex logic or decisions clearly. Also, format functions and variables using PEP8 conventions for better readability.

  3. Docstring Style: Use Google-style docstrings instead of Django-style doc strings for consistency.

  4. Error Handling: Consider adding more detailed logging around exceptions to help with debugging.

  5. Security Practices: Always ensure sensitive information like API keys is handled securely, especially when they're being used to interact with external services.

  6. Type Hints: Although Python 3 supports type hints well, it might be helpful to include them in all class methods where applicable.

  7. Testing: Add unit tests to cover different scenarios, such as valid and invalid credentials, model invocation failures, etc.

Here are some example adjustments:

# Importing necessary modules
from typing import Dict

from django.utils.translation import gettext_lazy as _, gettext
from langchain_core.messages import HumanMessage

from common import forms
from common.exception.app_exception import AppApiException
from common.forms import BaseForm, TooltipLabel
from setting.models_provider.base_model_provider import BaseModelCredential, ValidCode


class TencentCloudLLMModelParams(BaseForm):
    """
     Parameters for the Tencent Cloud LLM model.
    """

    temperature = forms.SliderField(
       TooltipLabel(_('Temperature'), _('Higher values make the output more random, while lower values make it more focused and deterministic')),
        required=True,
        default_value=0.7,
        _min=0.1,
        _max=1.0,
        _step=0.01,
        precision=2
    )

    max_tokens = forms.SliderField(
        TooltipLabel(_('Output the maximum Tokens'),
                     _('Specify the maximum number of tokens that the model can generate')),
        required=True,
        default_value=800,
        _min=1,
        _max=100000,
        _step=1,
        precision=0
    )


class TencentCloudLLMModelCredential(BaseForm, BaseModelCredential):

    def __init__(self, *args, provider=None, **kwargs):
        self.provider = provider
        super().__init__(*args, **kwargs)

    def is_valid(self, model_type: str, model_name, model_credential: Dict[str, object], model_params, provider,
                 raise_exception=False) -> bool:
        """
        Validates the Tencent Cloud LLM model credential.

        :param model_type: Type of the model
        :param model_name: Name of the model
        :param model_credential: Dictionary containing model credentials
        :param model_params: Parameter settings for the model
        :param provider: Model provider instance
        :param raise_exception: Flag indicating whether to raise an exception in case of validation failure
        :return: Boolean indicating whether the credentials are valid
        """
        if not any(list(filter(lambda mt: mt.get('value') == model_type, provider.get_model_type_list()))):
            raise AppApiException(ValidCode.valid_error.value,
                                  gettext('{model_type} Model type is not supported').format(model_type=model_type))

        required_keys = ['api_base', 'api_key']
        missing_keys = [key for key in required_keys if key not in model_credential]
        if missing_keys:
            msg = "Required fields '{}' are missing.".format(", ".join(missing_keys))
            if raise_exception:
                raise AppApiException(ValidCode.valid_error.value, msg)
            else:
                return False

        try:
            model = provider.get_model(model_type, model_name, model_credential, **model_params)
            model.invoke([HumanMessage(content=gettext('Hello'))])
        except AppApiException as e:
            if isinstance(e, AppApiException):
                raise e
            elif raise_exception:
                raise AppApiException(ValidCode.valid_error.value,
                                      gettext(
                                          'Verification failed, please check whether the parameters are correct: {error}').format(
                                          error=str(e)))
            else:
                return False

        return True

    def encryption_dict(self, model: Dict[str, object]) -> Dict[str, object]:
        """
       Encrypts sensitive information from the model dictionary.

       :param model: Original model dictionary
       :return: Encrypted model dictionary
       """
        return {**model, 'api_key': super(TencentCloudLLMModelCredential, self).encryption(model.get('api_key', ''))}

    @property
    def api_base(self) -> str:
        """API base URL."""
        return self.cleaned_data['api_base']

    @property
    def api_key(self) -> str:
        """API key."""
        return self.cleaned_data['api_key']

    def get_model_params_setting_form(self, model_name) -> TencentCloudLLMModelParams:
        """
        Returns the form for configuring model parameters.

        :param model_name: Name of the model
        :return: Form for configuring model parameters
        """
        return TencentCloudLLMModelParams()

These changes improve code maintainability, readability, and security practices while adhering to best coding standards.

Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# coding=utf-8
"""
@project: maxkb
@Author:虎
@file: llm.py
@date:2024/4/18 15:28
@desc:
"""
from typing import List, Dict

from langchain_core.messages import BaseMessage, get_buffer_string

from common.config.tokenizer_manage_config import TokenizerManage
from setting.models_provider.base_model_provider import MaxKBBaseModel
from setting.models_provider.impl.base_chat_open_ai import BaseChatOpenAI


def custom_get_token_ids(text: str):
tokenizer = TokenizerManage.get_tokenizer()
return tokenizer.encode(text)


class TencentCloudChatModel(MaxKBBaseModel, BaseChatOpenAI):

@staticmethod
def is_cache_model():
return False

@staticmethod
def new_instance(model_type, model_name, model_credential: Dict[str, object], **model_kwargs):
optional_params = MaxKBBaseModel.filter_optional_params(model_kwargs)
azure_chat_open_ai = TencentCloudChatModel(
model=model_name,
openai_api_base=model_credential.get('api_base'),
openai_api_key=model_credential.get('api_key'),
**optional_params,
custom_get_token_ids=custom_get_token_ids
)
return azure_chat_open_ai

def get_num_tokens_from_messages(self, messages: List[BaseMessage]) -> int:
try:
return super().get_num_tokens_from_messages(messages)
except Exception as e:
tokenizer = TokenizerManage.get_tokenizer()
return sum([len(tokenizer.encode(get_buffer_string([m]))) for m in messages])

def get_num_tokens(self, text: str) -> int:
try:
return super().get_num_tokens(text)
except Exception as e:
tokenizer = TokenizerManage.get_tokenizer()
return len(tokenizer.encode(text))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are the potential improvements and corrections to your Python code:

  1. The @staticmethod decorator should be used before new_instance, not inside it.

  2. The constructor parameters should match those expected by base classes, but there is no clear implementation for them yet, assuming they're not necessary or will be added later.

  3. It seems like get_num_tokens_from_messages() calls a private method _tokenize_chat_message() that does not exist in this class. This might need further investigation if needed.

  4. Instead of using raw strings for docstrings (e.g., """..."""), use triple quotes without whitespace at ends ('''...''') which is more pythonic.

  5. The function names could be more descriptive.

  6. Consider adding error handling when encoding messages with the tokenizer. For example:

messages = [BaseMessage(content="Hello")]  # Example message instance

try:
    num_tokens = maxkb.model.TencentCloudChatModel.get_num_tokens_from_messages(messages)
    print(f"Number of tokens: {num_tokens}")
except ValueError as ve:
    print("Tokenization error:", ve)
  1. Ensure that the imported modules (langchain_core etc.) have valid imports for the versions installed in your environment.

  2. Add type hints where possible, especially on functions and variables where their types are crucial.

Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# coding=utf-8
"""
@project: maxkb
@Author:虎
@file: openai_model_provider.py
@date:2024/3/28 16:26
@desc:
"""
import os

from common.util.file_util import get_file_content
from setting.models_provider.base_model_provider import IModelProvider, ModelProvideInfo, ModelInfo, \
ModelTypeConst, ModelInfoManage
from setting.models_provider.impl.openai_model_provider.credential.embedding import OpenAIEmbeddingCredential
from setting.models_provider.impl.openai_model_provider.credential.image import OpenAIImageModelCredential
from setting.models_provider.impl.openai_model_provider.credential.llm import OpenAILLMModelCredential
from setting.models_provider.impl.openai_model_provider.credential.stt import OpenAISTTModelCredential
from setting.models_provider.impl.openai_model_provider.credential.tti import OpenAITextToImageModelCredential
from setting.models_provider.impl.openai_model_provider.credential.tts import OpenAITTSModelCredential
from setting.models_provider.impl.openai_model_provider.model.embedding import OpenAIEmbeddingModel
from setting.models_provider.impl.openai_model_provider.model.image import OpenAIImage
from setting.models_provider.impl.openai_model_provider.model.llm import OpenAIChatModel
from setting.models_provider.impl.openai_model_provider.model.stt import OpenAISpeechToText
from setting.models_provider.impl.openai_model_provider.model.tti import OpenAITextToImage
from setting.models_provider.impl.openai_model_provider.model.tts import OpenAITextToSpeech
from setting.models_provider.impl.tencent_cloud_model_provider.credential.llm import TencentCloudLLMModelCredential
from setting.models_provider.impl.tencent_cloud_model_provider.model.llm import TencentCloudChatModel
from smartdoc.conf import PROJECT_DIR
from django.utils.translation import gettext_lazy as _

openai_llm_model_credential = TencentCloudLLMModelCredential()
model_info_list = [
ModelInfo('deepseek-v3', '', ModelTypeConst.LLM,
openai_llm_model_credential, TencentCloudChatModel
),
ModelInfo('deepseek-r1', '', ModelTypeConst.IMAGE,
openai_llm_model_credential, TencentCloudChatModel
),
]

model_info_manage = (
ModelInfoManage.builder()
.append_model_info_list(model_info_list)
.append_default_model_info(
ModelInfo('deepseek-v3', _('The latest gpt-3.5-turbo, updated with OpenAI adjustments'), ModelTypeConst.LLM,
openai_llm_model_credential, TencentCloudChatModel
))
.build()
)


class TencentCloudModelProvider(IModelProvider):

def get_model_info_manage(self):
return model_info_manage

def get_model_provide_info(self):
return ModelProvideInfo(provider='model_tencent_cloud_provider', name=_('Tencent Cloud'), icon=get_file_content(
os.path.join(PROJECT_DIR, "apps", "setting", 'models_provider', 'impl', 'tencent_cloud_model_provider',
'icon',
'tencent_cloud_icon_svg')))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is one potential issue: The model_info_list variable is not being assigned to anything, which might cause an error in downstream operations if used. You can fix this by assigning it directly within the ModelInfoManage.builder() call:

model_info_manage = (
    ModelInfoManage.builder()
    .append_model_info_list([
        ModelInfo('deepseek-v3', '', ModelTypeConst.LLM,
              openai_llm_model_credential, TencentCloudChatModel
              ),
        ModelInfo('deepseek-r1', '', ModelTypeConst.IMAGE,
              openai_llm_model_credential, TencentCloudChatModel
              )
    ])
    .append_default_model_info(
       ModelInfo('deepseek-v3', _('The latest gpt-3.5-turbo, updated with OpenAI adjustments'), ModelTypeConst.LLM,
                   openai_llm_model_credential, TencentCloudChatModel)
    )
    .build()
)

Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@
from common.util.file_util import get_file_content
from setting.models_provider.base_model_provider import IModelProvider, ModelProvideInfo, ModelInfo, ModelTypeConst, \
ModelInfoManage
from setting.models_provider.impl.openai_model_provider.credential.embedding import OpenAIEmbeddingCredential
from setting.models_provider.impl.openai_model_provider.credential.llm import OpenAILLMModelCredential
from setting.models_provider.impl.openai_model_provider.model.embedding import OpenAIEmbeddingModel
from setting.models_provider.impl.volcanic_engine_model_provider.credential.embedding import VolcanicEmbeddingCredential
from setting.models_provider.impl.volcanic_engine_model_provider.credential.image import \
VolcanicEngineImageModelCredential
Expand Down