From 153b61bd790e65f0b0fe6594987029d8c8cb16e6 Mon Sep 17 00:00:00 2001 From: wxg0103 <727495428@qq.com> Date: Wed, 5 Feb 2025 15:26:05 +0800 Subject: [PATCH] feat: support siliconCloud MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --story=1017720 --user=王孝刚 【模型管理】-支持SiliconCloud供应商的大语言模型、向量模型 https://www.tapd.cn/57709429/s/1650888 --- .../models_provider/base_model_provider.py | 9 +- .../constants/model_provider_constants.py | 3 + .../aliyun_bai_lian_model_provider.py | 4 +- .../siliconCloud_model_provider/__init__.py | 8 + .../credential/embedding.py | 51 +++++++ .../credential/image.py | 72 +++++++++ .../credential/llm.py | 77 ++++++++++ .../credential/reranker.py | 52 +++++++ .../credential/stt.py | 47 ++++++ .../credential/tti.py | 88 +++++++++++ .../credential/tts.py | 66 +++++++++ .../model/embedding.py | 23 +++ .../model/image.py | 20 +++ .../siliconCloud_model_provider/model/llm.py | 38 +++++ .../model/reranker.py | 20 +++ .../siliconCloud_model_provider/model/stt.py | 59 ++++++++ .../siliconCloud_model_provider/model/tti.py | 58 ++++++++ .../siliconCloud_model_provider/model/tts.py | 64 ++++++++ .../siliconCloud_model_provider.py | 137 ++++++++++++++++++ 19 files changed, 891 insertions(+), 5 deletions(-) create mode 100644 apps/setting/models_provider/impl/siliconCloud_model_provider/__init__.py create mode 100644 apps/setting/models_provider/impl/siliconCloud_model_provider/credential/embedding.py create mode 100644 apps/setting/models_provider/impl/siliconCloud_model_provider/credential/image.py create mode 100644 apps/setting/models_provider/impl/siliconCloud_model_provider/credential/llm.py create mode 100644 apps/setting/models_provider/impl/siliconCloud_model_provider/credential/reranker.py create mode 100644 apps/setting/models_provider/impl/siliconCloud_model_provider/credential/stt.py create mode 100644 apps/setting/models_provider/impl/siliconCloud_model_provider/credential/tti.py create mode 100644 apps/setting/models_provider/impl/siliconCloud_model_provider/credential/tts.py create mode 100644 apps/setting/models_provider/impl/siliconCloud_model_provider/model/embedding.py create mode 100644 apps/setting/models_provider/impl/siliconCloud_model_provider/model/image.py create mode 100644 apps/setting/models_provider/impl/siliconCloud_model_provider/model/llm.py create mode 100644 apps/setting/models_provider/impl/siliconCloud_model_provider/model/reranker.py create mode 100644 apps/setting/models_provider/impl/siliconCloud_model_provider/model/stt.py create mode 100644 apps/setting/models_provider/impl/siliconCloud_model_provider/model/tti.py create mode 100644 apps/setting/models_provider/impl/siliconCloud_model_provider/model/tts.py create mode 100644 apps/setting/models_provider/impl/siliconCloud_model_provider/siliconCloud_model_provider.py diff --git a/apps/setting/models_provider/base_model_provider.py b/apps/setting/models_provider/base_model_provider.py index 455bdcf99c7..556ecee20ff 100644 --- a/apps/setting/models_provider/base_model_provider.py +++ b/apps/setting/models_provider/base_model_provider.py @@ -16,6 +16,7 @@ from common.exception.app_exception import AppApiException from django.utils.translation import gettext_lazy as _ + class DownModelChunkStatus(Enum): success = "success" error = "error" @@ -71,7 +72,8 @@ def get_model_params(self, model_type, model_name): model_info = self.get_model_info_manage().get_model_info(model_type, model_name) return model_info.model_credential - def is_valid_credential(self, model_type, model_name, model_credential: Dict[str, object], model_params: Dict[str, object], raise_exception=False): + def is_valid_credential(self, model_type, model_name, model_credential: Dict[str, object], + model_params: Dict[str, object], raise_exception=False): model_info = self.get_model_info_manage().get_model_info(model_type, model_name) return model_info.model_credential.is_valid(model_type, model_name, model_credential, model_params, self, raise_exception=raise_exception) @@ -101,7 +103,7 @@ def is_cache_model(): def filter_optional_params(model_kwargs): optional_params = {} for key, value in model_kwargs.items(): - if key not in ['model_id', 'use_local', 'streaming']: + if key not in ['model_id', 'use_local', 'streaming', 'show_ref_label']: optional_params[key] = value return optional_params @@ -109,7 +111,8 @@ def filter_optional_params(model_kwargs): class BaseModelCredential(ABC): @abstractmethod - def is_valid(self, model_type: str, model_name, model: Dict[str, object], model_params, provider, raise_exception=True): + def is_valid(self, model_type: str, model_name, model: Dict[str, object], model_params, provider, + raise_exception=True): pass @abstractmethod diff --git a/apps/setting/models_provider/constants/model_provider_constants.py b/apps/setting/models_provider/constants/model_provider_constants.py index 94f4ef3b4eb..b0b0d0d45e6 100644 --- a/apps/setting/models_provider/constants/model_provider_constants.py +++ b/apps/setting/models_provider/constants/model_provider_constants.py @@ -19,6 +19,8 @@ from setting.models_provider.impl.ollama_model_provider.ollama_model_provider import OllamaModelProvider from setting.models_provider.impl.openai_model_provider.openai_model_provider import OpenAIModelProvider 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_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 \ @@ -49,3 +51,4 @@ class ModelProvideConstants(Enum): model_vllm_provider = VllmModelProvider() aliyun_bai_lian_model_provider = AliyunBaiLianModelProvider() model_anthropic_provider = AnthropicModelProvider() + model_siliconCloud_provider = SiliconCloudModelProvider() diff --git a/apps/setting/models_provider/impl/aliyun_bai_lian_model_provider/aliyun_bai_lian_model_provider.py b/apps/setting/models_provider/impl/aliyun_bai_lian_model_provider/aliyun_bai_lian_model_provider.py index 846c8154778..aa62bdf7fe5 100644 --- a/apps/setting/models_provider/impl/aliyun_bai_lian_model_provider/aliyun_bai_lian_model_provider.py +++ b/apps/setting/models_provider/impl/aliyun_bai_lian_model_provider/aliyun_bai_lian_model_provider.py @@ -28,7 +28,7 @@ from setting.models_provider.impl.aliyun_bai_lian_model_provider.model.tti import QwenTextToImageModel from setting.models_provider.impl.aliyun_bai_lian_model_provider.model.tts import AliyunBaiLianTextToSpeech from smartdoc.conf import PROJECT_DIR -from django.utils.translation import gettext_lazy as _ +from django.utils.translation import gettext_lazy as _, gettext aliyun_bai_lian_model_credential = AliyunBaiLianRerankerCredential() aliyun_bai_lian_tts_model_credential = AliyunBaiLianTTSModelCredential() @@ -92,7 +92,7 @@ def get_model_info_manage(self): return model_info_manage def get_model_provide_info(self): - return ModelProvideInfo(provider='aliyun_bai_lian_model_provider', name=_('Alibaba Cloud Bailian'), + return ModelProvideInfo(provider='aliyun_bai_lian_model_provider', name=gettext('Alibaba Cloud Bailian'), icon=get_file_content( os.path.join(PROJECT_DIR, "apps", "setting", 'models_provider', 'impl', 'aliyun_bai_lian_model_provider', diff --git a/apps/setting/models_provider/impl/siliconCloud_model_provider/__init__.py b/apps/setting/models_provider/impl/siliconCloud_model_provider/__init__.py new file mode 100644 index 00000000000..2dc4ab10db4 --- /dev/null +++ b/apps/setting/models_provider/impl/siliconCloud_model_provider/__init__.py @@ -0,0 +1,8 @@ +# coding=utf-8 +""" + @project: maxkb + @Author:虎 + @file: __init__.py.py + @date:2024/3/28 16:25 + @desc: +""" diff --git a/apps/setting/models_provider/impl/siliconCloud_model_provider/credential/embedding.py b/apps/setting/models_provider/impl/siliconCloud_model_provider/credential/embedding.py new file mode 100644 index 00000000000..51e5c3621ad --- /dev/null +++ b/apps/setting/models_provider/impl/siliconCloud_model_provider/credential/embedding.py @@ -0,0 +1,51 @@ +# coding=utf-8 +""" + @project: MaxKB + @Author:虎 + @file: embedding.py + @date:2024/7/12 16:45 + @desc: +""" +from typing import Dict + +from django.utils.translation import gettext as _ + +from common import forms +from common.exception.app_exception import AppApiException +from common.forms import BaseForm +from setting.models_provider.base_model_provider import BaseModelCredential, ValidCode + + +class SiliconCloudEmbeddingCredential(BaseForm, BaseModelCredential): + def is_valid(self, model_type: str, model_name, model_credential: Dict[str, object], model_params, provider, + raise_exception=True): + 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, + _('{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, _('{key} is required').format(key=key)) + else: + return False + try: + model = provider.get_model(model_type, model_name, model_credential) + model.embed_query(_('Hello')) + except Exception as e: + if isinstance(e, AppApiException): + raise e + if raise_exception: + raise AppApiException(ValidCode.valid_error.value, + _('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) diff --git a/apps/setting/models_provider/impl/siliconCloud_model_provider/credential/image.py b/apps/setting/models_provider/impl/siliconCloud_model_provider/credential/image.py new file mode 100644 index 00000000000..a3ae4025241 --- /dev/null +++ b/apps/setting/models_provider/impl/siliconCloud_model_provider/credential/image.py @@ -0,0 +1,72 @@ +# coding=utf-8 +import base64 +import os +from typing import Dict + +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 +from django.utils.translation import gettext_lazy as _, gettext + + +class SiliconCloudImageModelParams(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 SiliconCloudImageModelCredential(BaseForm, BaseModelCredential): + api_base = forms.TextInputField('API URL', required=True) + api_key = forms.PasswordInputField('API Key', required=True) + + 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) + res = model.stream([HumanMessage(content=[{"type": "text", "text": gettext('Hello')}])]) + for chunk in res: + print(chunk) + 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', ''))} + + def get_model_params_setting_form(self, model_name): + return SiliconCloudImageModelParams() diff --git a/apps/setting/models_provider/impl/siliconCloud_model_provider/credential/llm.py b/apps/setting/models_provider/impl/siliconCloud_model_provider/credential/llm.py new file mode 100644 index 00000000000..5c5888570b7 --- /dev/null +++ b/apps/setting/models_provider/impl/siliconCloud_model_provider/credential/llm.py @@ -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 SiliconCloudLLMModelParams(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 SiliconCloudLLMModelCredential(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 SiliconCloudLLMModelParams() diff --git a/apps/setting/models_provider/impl/siliconCloud_model_provider/credential/reranker.py b/apps/setting/models_provider/impl/siliconCloud_model_provider/credential/reranker.py new file mode 100644 index 00000000000..616124e9256 --- /dev/null +++ b/apps/setting/models_provider/impl/siliconCloud_model_provider/credential/reranker.py @@ -0,0 +1,52 @@ +# coding=utf-8 +""" + @project: MaxKB + @Author:虎 + @file: reranker.py + @date:2024/9/9 17:51 + @desc: +""" +from typing import Dict + +from django.utils.translation import gettext as _ +from langchain_core.documents import Document + +from common import forms +from common.exception.app_exception import AppApiException +from common.forms import BaseForm +from setting.models_provider.base_model_provider import BaseModelCredential, ValidCode +from setting.models_provider.impl.aliyun_bai_lian_model_provider.model.reranker import AliyunBaiLianReranker +from setting.models_provider.impl.siliconCloud_model_provider.model.reranker import SiliconCloudReranker + + +class SiliconCloudRerankerCredential(BaseForm, BaseModelCredential): + + def is_valid(self, model_type: str, model_name, model_credential: Dict[str, object], model_params, provider, + raise_exception=False): + if not model_type == 'RERANKER': + raise AppApiException(ValidCode.valid_error.value, + _('{model_type} Model type is not supported').format(model_type=model_type)) + for key in ['dashscope_api_key']: + if key not in model_credential: + if raise_exception: + raise AppApiException(ValidCode.valid_error.value, _('{key} is required').format(key=key)) + else: + return False + try: + model: SiliconCloudReranker = provider.get_model(model_type, model_name, model_credential) + model.compress_documents([Document(page_content=_('Hello'))], _('Hello')) + except Exception as e: + if isinstance(e, AppApiException): + raise e + if raise_exception: + raise AppApiException(ValidCode.valid_error.value, + _('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, 'dashscope_api_key': super().encryption(model.get('dashscope_api_key', ''))} + + dashscope_api_key = forms.PasswordInputField('API Key', required=True) diff --git a/apps/setting/models_provider/impl/siliconCloud_model_provider/credential/stt.py b/apps/setting/models_provider/impl/siliconCloud_model_provider/credential/stt.py new file mode 100644 index 00000000000..db25ec6d1d5 --- /dev/null +++ b/apps/setting/models_provider/impl/siliconCloud_model_provider/credential/stt.py @@ -0,0 +1,47 @@ +# coding=utf-8 +from typing import Dict + +from django.utils.translation import gettext as _ + +from common import forms +from common.exception.app_exception import AppApiException +from common.forms import BaseForm +from setting.models_provider.base_model_provider import BaseModelCredential, ValidCode + + +class SiliconCloudSTTModelCredential(BaseForm, BaseModelCredential): + api_base = forms.TextInputField('API URL', required=True) + api_key = forms.PasswordInputField('API Key', required=True) + + 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, + _('{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, _('{key} is required').format(key=key)) + else: + return False + try: + model = provider.get_model(model_type, model_name, model_credential) + model.check_auth() + except Exception as e: + if isinstance(e, AppApiException): + raise e + if raise_exception: + raise AppApiException(ValidCode.valid_error.value, + _('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', ''))} + + def get_model_params_setting_form(self, model_name): + pass diff --git a/apps/setting/models_provider/impl/siliconCloud_model_provider/credential/tti.py b/apps/setting/models_provider/impl/siliconCloud_model_provider/credential/tti.py new file mode 100644 index 00000000000..fbea6989017 --- /dev/null +++ b/apps/setting/models_provider/impl/siliconCloud_model_provider/credential/tti.py @@ -0,0 +1,88 @@ +# coding=utf-8 +from typing import Dict + +from django.utils.translation import gettext_lazy as _, gettext + +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 SiliconCloudTTIModelParams(BaseForm): + size = forms.SingleSelect( + TooltipLabel(_('Image size'), + _('The image generation endpoint allows you to create raw images based on text prompts. When using the DALL·E 3, the image size can be 1024x1024, 1024x1792 or 1792x1024 pixels.')), + required=True, + default_value='1024x1024', + option_list=[ + {'value': '1024x1024', 'label': '1024x1024'}, + {'value': '1024x1792', 'label': '1024x1792'}, + {'value': '1792x1024', 'label': '1792x1024'}, + ], + text_field='label', + value_field='value' + ) + + quality = forms.SingleSelect( + TooltipLabel(_('Picture quality'), _(''' +By default, images are produced in standard quality, but with DALL·E 3 you can set quality: "hd" to enhance detail. Square, standard quality images are generated fastest. + ''')), + required=True, + default_value='standard', + option_list=[ + {'value': 'standard', 'label': 'standard'}, + {'value': 'hd', 'label': 'hd'}, + ], + text_field='label', + value_field='value' + ) + + n = forms.SliderField( + TooltipLabel(_('Number of pictures'), + _('You can use DALL·E 3 to request 1 image at a time (requesting more images by issuing parallel requests), or use DALL·E 2 with the n parameter to request up to 10 images at a time.')), + required=True, default_value=1, + _min=1, + _max=10, + _step=1, + precision=0) + + +class SiliconCloudTextToImageModelCredential(BaseForm, BaseModelCredential): + api_base = forms.TextInputField('API URL', required=True) + api_key = forms.PasswordInputField('API Key', required=True) + + 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) + res = model.check_auth() + print(res) + 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', ''))} + + def get_model_params_setting_form(self, model_name): + return SiliconCloudTTIModelParams() diff --git a/apps/setting/models_provider/impl/siliconCloud_model_provider/credential/tts.py b/apps/setting/models_provider/impl/siliconCloud_model_provider/credential/tts.py new file mode 100644 index 00000000000..b80bdc78861 --- /dev/null +++ b/apps/setting/models_provider/impl/siliconCloud_model_provider/credential/tts.py @@ -0,0 +1,66 @@ +# coding=utf-8 +from typing import Dict + +from django.utils.translation import gettext_lazy as _, gettext + +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 SiliconCloudTTSModelGeneralParams(BaseForm): + # alloy, echo, fable, onyx, nova, shimmer + voice = forms.SingleSelect( + TooltipLabel('Voice', + _('Try out the different sounds (Alloy, Echo, Fable, Onyx, Nova, and Sparkle) to find one that suits your desired tone and audience. The current voiceover is optimized for English.')), + required=True, default_value='alloy', + text_field='value', + value_field='value', + option_list=[ + {'text': 'alloy', 'value': 'alloy'}, + {'text': 'echo', 'value': 'echo'}, + {'text': 'fable', 'value': 'fable'}, + {'text': 'onyx', 'value': 'onyx'}, + {'text': 'nova', 'value': 'nova'}, + {'text': 'shimmer', 'value': 'shimmer'}, + ]) + + +class SiliconCloudTTSModelCredential(BaseForm, BaseModelCredential): + api_base = forms.TextInputField('API URL', required=True) + api_key = forms.PasswordInputField('API Key', required=True) + + 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.check_auth() + 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', ''))} + + def get_model_params_setting_form(self, model_name): + return SiliconCloudTTSModelGeneralParams() diff --git a/apps/setting/models_provider/impl/siliconCloud_model_provider/model/embedding.py b/apps/setting/models_provider/impl/siliconCloud_model_provider/model/embedding.py new file mode 100644 index 00000000000..e8b6c0f5cf1 --- /dev/null +++ b/apps/setting/models_provider/impl/siliconCloud_model_provider/model/embedding.py @@ -0,0 +1,23 @@ +# coding=utf-8 +""" + @project: MaxKB + @Author:虎 + @file: embedding.py + @date:2024/7/12 17:44 + @desc: +""" +from typing import Dict + +from langchain_community.embeddings import OpenAIEmbeddings + +from setting.models_provider.base_model_provider import MaxKBBaseModel + + +class SiliconCloudEmbeddingModel(MaxKBBaseModel, OpenAIEmbeddings): + @staticmethod + def new_instance(model_type, model_name, model_credential: Dict[str, object], **model_kwargs): + return SiliconCloudEmbeddingModel( + api_key=model_credential.get('api_key'), + model=model_name, + openai_api_base=model_credential.get('api_base'), + ) diff --git a/apps/setting/models_provider/impl/siliconCloud_model_provider/model/image.py b/apps/setting/models_provider/impl/siliconCloud_model_provider/model/image.py new file mode 100644 index 00000000000..bb840f8c6dc --- /dev/null +++ b/apps/setting/models_provider/impl/siliconCloud_model_provider/model/image.py @@ -0,0 +1,20 @@ +from typing import Dict + +from setting.models_provider.base_model_provider import MaxKBBaseModel +from setting.models_provider.impl.base_chat_open_ai import BaseChatOpenAI + + +class SiliconCloudImage(MaxKBBaseModel, BaseChatOpenAI): + + @staticmethod + def new_instance(model_type, model_name, model_credential: Dict[str, object], **model_kwargs): + optional_params = MaxKBBaseModel.filter_optional_params(model_kwargs) + return SiliconCloudImage( + model_name=model_name, + openai_api_base=model_credential.get('api_base'), + openai_api_key=model_credential.get('api_key'), + # stream_options={"include_usage": True}, + streaming=True, + stream_usage=True, + **optional_params, + ) diff --git a/apps/setting/models_provider/impl/siliconCloud_model_provider/model/llm.py b/apps/setting/models_provider/impl/siliconCloud_model_provider/model/llm.py new file mode 100644 index 00000000000..9d79c6e0761 --- /dev/null +++ b/apps/setting/models_provider/impl/siliconCloud_model_provider/model/llm.py @@ -0,0 +1,38 @@ +# 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 langchain_openai.chat_models import ChatOpenAI + +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 SiliconCloudChatModel(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) + return SiliconCloudChatModel( + model=model_name, + openai_api_base=model_credential.get('api_base'), + openai_api_key=model_credential.get('api_key'), + **optional_params + ) diff --git a/apps/setting/models_provider/impl/siliconCloud_model_provider/model/reranker.py b/apps/setting/models_provider/impl/siliconCloud_model_provider/model/reranker.py new file mode 100644 index 00000000000..089048ad165 --- /dev/null +++ b/apps/setting/models_provider/impl/siliconCloud_model_provider/model/reranker.py @@ -0,0 +1,20 @@ +# coding=utf-8 +""" + @project: MaxKB + @Author:虎 + @file: reranker.py.py + @date:2024/9/2 16:42 + @desc: +""" +from typing import Dict + +from langchain_community.document_compressors import DashScopeRerank + +from setting.models_provider.base_model_provider import MaxKBBaseModel + + +class SiliconCloudReranker(MaxKBBaseModel, DashScopeRerank): + @staticmethod + def new_instance(model_type, model_name, model_credential: Dict[str, object], **model_kwargs): + return SiliconCloudReranker(model=model_name, dashscope_api_key=model_credential.get('dashscope_api_key'), + top_n=model_kwargs.get('top_n', 3)) diff --git a/apps/setting/models_provider/impl/siliconCloud_model_provider/model/stt.py b/apps/setting/models_provider/impl/siliconCloud_model_provider/model/stt.py new file mode 100644 index 00000000000..4bb07da2135 --- /dev/null +++ b/apps/setting/models_provider/impl/siliconCloud_model_provider/model/stt.py @@ -0,0 +1,59 @@ +import asyncio +import io +from typing import Dict + +from openai import OpenAI + +from common.config.tokenizer_manage_config import TokenizerManage +from setting.models_provider.base_model_provider import MaxKBBaseModel +from setting.models_provider.impl.base_stt import BaseSpeechToText + + +def custom_get_token_ids(text: str): + tokenizer = TokenizerManage.get_tokenizer() + return tokenizer.encode(text) + + +class SiliconCloudSpeechToText(MaxKBBaseModel, BaseSpeechToText): + api_base: str + api_key: str + model: str + + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.api_key = kwargs.get('api_key') + self.api_base = kwargs.get('api_base') + + @staticmethod + def new_instance(model_type, model_name, model_credential: Dict[str, object], **model_kwargs): + optional_params = {} + if 'max_tokens' in model_kwargs and model_kwargs['max_tokens'] is not None: + optional_params['max_tokens'] = model_kwargs['max_tokens'] + if 'temperature' in model_kwargs and model_kwargs['temperature'] is not None: + optional_params['temperature'] = model_kwargs['temperature'] + return SiliconCloudSpeechToText( + model=model_name, + api_base=model_credential.get('api_base'), + api_key=model_credential.get('api_key'), + **optional_params, + ) + + def check_auth(self): + client = OpenAI( + base_url=self.api_base, + api_key=self.api_key + ) + response_list = client.models.with_raw_response.list() + # print(response_list) + + def speech_to_text(self, audio_file): + client = OpenAI( + base_url=self.api_base, + api_key=self.api_key + ) + audio_data = audio_file.read() + buffer = io.BytesIO(audio_data) + buffer.name = "file.mp3" # this is the important line + res = client.audio.transcriptions.create(model=self.model, language="zh", file=buffer) + return res.text + diff --git a/apps/setting/models_provider/impl/siliconCloud_model_provider/model/tti.py b/apps/setting/models_provider/impl/siliconCloud_model_provider/model/tti.py new file mode 100644 index 00000000000..6849753c19d --- /dev/null +++ b/apps/setting/models_provider/impl/siliconCloud_model_provider/model/tti.py @@ -0,0 +1,58 @@ +from typing import Dict + +from openai import OpenAI + +from common.config.tokenizer_manage_config import TokenizerManage +from setting.models_provider.base_model_provider import MaxKBBaseModel +from setting.models_provider.impl.base_tti import BaseTextToImage + + +def custom_get_token_ids(text: str): + tokenizer = TokenizerManage.get_tokenizer() + return tokenizer.encode(text) + + +class SiliconCloudTextToImage(MaxKBBaseModel, BaseTextToImage): + api_base: str + api_key: str + model: str + params: dict + + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.api_key = kwargs.get('api_key') + self.api_base = kwargs.get('api_base') + self.model = kwargs.get('model') + self.params = kwargs.get('params') + + @staticmethod + def new_instance(model_type, model_name, model_credential: Dict[str, object], **model_kwargs): + optional_params = {'params': {'size': '1024x1024', 'quality': 'standard', 'n': 1}} + for key, value in model_kwargs.items(): + if key not in ['model_id', 'use_local', 'streaming']: + optional_params['params'][key] = value + return SiliconCloudTextToImage( + model=model_name, + api_base=model_credential.get('api_base'), + api_key=model_credential.get('api_key'), + **optional_params, + ) + + def is_cache_model(self): + return False + + def check_auth(self): + chat = OpenAI(api_key=self.api_key, base_url=self.api_base) + response_list = chat.models.with_raw_response.list() + + # self.generate_image('生成一个小猫图片') + + def generate_image(self, prompt: str, negative_prompt: str = None): + chat = OpenAI(api_key=self.api_key, base_url=self.api_base) + res = chat.images.generate(model=self.model, prompt=prompt, **self.params) + file_urls = [] + for content in res.data: + url = content.url + file_urls.append(url) + + return file_urls diff --git a/apps/setting/models_provider/impl/siliconCloud_model_provider/model/tts.py b/apps/setting/models_provider/impl/siliconCloud_model_provider/model/tts.py new file mode 100644 index 00000000000..1b17cbb825a --- /dev/null +++ b/apps/setting/models_provider/impl/siliconCloud_model_provider/model/tts.py @@ -0,0 +1,64 @@ +from typing import Dict + +from openai import OpenAI + +from common.config.tokenizer_manage_config import TokenizerManage +from common.util.common import _remove_empty_lines +from setting.models_provider.base_model_provider import MaxKBBaseModel +from setting.models_provider.impl.base_tts import BaseTextToSpeech + + +def custom_get_token_ids(text: str): + tokenizer = TokenizerManage.get_tokenizer() + return tokenizer.encode(text) + + +class SiliconCloudTextToSpeech(MaxKBBaseModel, BaseTextToSpeech): + api_base: str + api_key: str + model: str + params: dict + + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.api_key = kwargs.get('api_key') + self.api_base = kwargs.get('api_base') + self.model = kwargs.get('model') + self.params = kwargs.get('params') + + @staticmethod + def new_instance(model_type, model_name, model_credential: Dict[str, object], **model_kwargs): + optional_params = {'params': {'voice': 'alloy'}} + for key, value in model_kwargs.items(): + if key not in ['model_id', 'use_local', 'streaming']: + optional_params['params'][key] = value + return SiliconCloudTextToSpeech( + model=model_name, + api_base=model_credential.get('api_base'), + api_key=model_credential.get('api_key'), + **optional_params, + ) + + def check_auth(self): + client = OpenAI( + base_url=self.api_base, + api_key=self.api_key + ) + response_list = client.models.with_raw_response.list() + # print(response_list) + + def text_to_speech(self, text): + client = OpenAI( + base_url=self.api_base, + api_key=self.api_key + ) + text = _remove_empty_lines(text) + with client.audio.speech.with_streaming_response.create( + model=self.model, + input=text, + **self.params + ) as response: + return response.read() + + def is_cache_model(self): + return False diff --git a/apps/setting/models_provider/impl/siliconCloud_model_provider/siliconCloud_model_provider.py b/apps/setting/models_provider/impl/siliconCloud_model_provider/siliconCloud_model_provider.py new file mode 100644 index 00000000000..fa493e96359 --- /dev/null +++ b/apps/setting/models_provider/impl/siliconCloud_model_provider/siliconCloud_model_provider.py @@ -0,0 +1,137 @@ +# 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.siliconCloud_model_provider.credential.embedding import \ + SiliconCloudEmbeddingCredential +from setting.models_provider.impl.siliconCloud_model_provider.credential.llm import SiliconCloudLLMModelCredential +from setting.models_provider.impl.siliconCloud_model_provider.credential.reranker import SiliconCloudRerankerCredential +from setting.models_provider.impl.siliconCloud_model_provider.credential.stt import SiliconCloudSTTModelCredential +from setting.models_provider.impl.siliconCloud_model_provider.credential.tti import \ + SiliconCloudTextToImageModelCredential +from setting.models_provider.impl.siliconCloud_model_provider.model.embedding import SiliconCloudEmbeddingModel +from setting.models_provider.impl.siliconCloud_model_provider.model.llm import SiliconCloudChatModel +from setting.models_provider.impl.siliconCloud_model_provider.model.reranker import SiliconCloudReranker +from setting.models_provider.impl.siliconCloud_model_provider.model.stt import SiliconCloudSpeechToText +from setting.models_provider.impl.siliconCloud_model_provider.model.tti import SiliconCloudTextToImage +from smartdoc.conf import PROJECT_DIR +from django.utils.translation import gettext_lazy as _ + +openai_llm_model_credential = SiliconCloudLLMModelCredential() +openai_stt_model_credential = SiliconCloudSTTModelCredential() +openai_reranker_model_credential = SiliconCloudRerankerCredential() +openai_tti_model_credential = SiliconCloudTextToImageModelCredential() +model_info_list = [ + ModelInfo('deepseek-ai/DeepSeek-R1-Distill-Llama-8B', '', ModelTypeConst.LLM, + openai_llm_model_credential, SiliconCloudChatModel + ), + ModelInfo('deepseek-ai/DeepSeek-R1-Distill-Qwen-7B', '', ModelTypeConst.LLM, + openai_llm_model_credential, + SiliconCloudChatModel), + ModelInfo('deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B', '', + ModelTypeConst.LLM, openai_llm_model_credential, + SiliconCloudChatModel), + ModelInfo('Qwen/Qwen2.5-7B-Instruct', + '', + ModelTypeConst.LLM, openai_llm_model_credential, + SiliconCloudChatModel), + ModelInfo('Qwen/Qwen2.5-Coder-7B-Instruct', '', + ModelTypeConst.LLM, openai_llm_model_credential, + SiliconCloudChatModel), + ModelInfo('internlm/internlm2_5-7b-chat', '', + ModelTypeConst.LLM, openai_llm_model_credential, + SiliconCloudChatModel), + ModelInfo('Qwen/Qwen2-1.5B-Instruct', '', + ModelTypeConst.LLM, openai_llm_model_credential, + SiliconCloudChatModel), + ModelInfo('THUDM/glm-4-9b-chat', '', + ModelTypeConst.LLM, openai_llm_model_credential, + SiliconCloudChatModel), + ModelInfo('FunAudioLLM/SenseVoiceSmall', '', + ModelTypeConst.STT, openai_stt_model_credential, + SiliconCloudSpeechToText), +] +open_ai_embedding_credential = SiliconCloudEmbeddingCredential() +model_info_embedding_list = [ + ModelInfo('netease-youdao/bce-embedding-base_v1', '', + ModelTypeConst.EMBEDDING, open_ai_embedding_credential, + SiliconCloudEmbeddingModel), + ModelInfo('BAAI/bge-m3', '', + ModelTypeConst.EMBEDDING, open_ai_embedding_credential, + SiliconCloudEmbeddingModel), + ModelInfo('BAAI/bge-large-en-v1.5', '', + ModelTypeConst.EMBEDDING, open_ai_embedding_credential, + SiliconCloudEmbeddingModel), + ModelInfo('BAAI/bge-large-zh-v1.5', '', + ModelTypeConst.EMBEDDING, open_ai_embedding_credential, + SiliconCloudEmbeddingModel), +] + +model_info_tti_list = [ + ModelInfo('deepseek-ai/Janus-Pro-7B', '', + ModelTypeConst.TTI, openai_tti_model_credential, + SiliconCloudTextToImage), + ModelInfo('stabilityai/stable-diffusion-3-5-large', '', + ModelTypeConst.TTI, openai_tti_model_credential, + SiliconCloudTextToImage), + ModelInfo('black-forest-labs/FLUX.1-schnell', '', + ModelTypeConst.TTI, openai_tti_model_credential, + SiliconCloudTextToImage), + ModelInfo('stabilityai/stable-diffusion-3-medium', '', + ModelTypeConst.TTI, openai_tti_model_credential, + SiliconCloudTextToImage), + ModelInfo('stabilityai/stable-diffusion-xl-base-1.0', '', + ModelTypeConst.TTI, openai_tti_model_credential, + SiliconCloudTextToImage), + ModelInfo('stabilityai/stable-diffusion-2-1', '', + ModelTypeConst.TTI, openai_tti_model_credential, + SiliconCloudTextToImage), +] +model_rerank_list = [ + ModelInfo('netease-youdao/bce-reranker-base_v1', '', ModelTypeConst.RERANKER, + openai_reranker_model_credential, SiliconCloudReranker + ), + ModelInfo('BAAI/bge-reranker-v2-m3', '', ModelTypeConst.RERANKER, + openai_reranker_model_credential, SiliconCloudReranker + ), +] +model_info_manage = ( + ModelInfoManage.builder() + .append_model_info_list(model_info_list) + .append_default_model_info( + ModelInfo('gpt-3.5-turbo', _('The latest gpt-3.5-turbo, updated with OpenAI adjustments'), ModelTypeConst.LLM, + openai_llm_model_credential, SiliconCloudChatModel + )) + .append_model_info_list(model_info_embedding_list) + .append_default_model_info(model_info_embedding_list[0]) + .append_model_info_list(model_info_tti_list) + .append_default_model_info(model_info_tti_list[0]) + .append_default_model_info(ModelInfo('whisper-1', '', + ModelTypeConst.STT, openai_stt_model_credential, + SiliconCloudSpeechToText)) + .append_model_info_list(model_rerank_list) + .append_default_model_info(model_rerank_list[0]) + + .build() +) + + +class SiliconCloudModelProvider(IModelProvider): + + def get_model_info_manage(self): + return model_info_manage + + def get_model_provide_info(self): + return ModelProvideInfo(provider='model_siliconCloud_provider', name='SiliconCloud', icon=get_file_content( + os.path.join(PROJECT_DIR, "apps", "setting", 'models_provider', 'impl', 'siliconCloud_model_provider', + 'icon', + 'siliconCloud_icon_svg')))