diff --git a/apps/models_provider/constants/model_provider_constants.py b/apps/models_provider/constants/model_provider_constants.py index ae749795cb7..85a15bcd426 100644 --- a/apps/models_provider/constants/model_provider_constants.py +++ b/apps/models_provider/constants/model_provider_constants.py @@ -1,50 +1,5 @@ -# coding=utf-8 -from enum import Enum - -from models_provider.impl.aliyun_bai_lian_model_provider.aliyun_bai_lian_model_provider import \ - AliyunBaiLianModelProvider -from models_provider.impl.anthropic_model_provider.anthropic_model_provider import AnthropicModelProvider -from models_provider.impl.aws_bedrock_model_provider.aws_bedrock_model_provider import BedrockModelProvider -from models_provider.impl.azure_model_provider.azure_model_provider import AzureModelProvider -from models_provider.impl.deepseek_model_provider.deepseek_model_provider import DeepSeekModelProvider -from models_provider.impl.docker_ai_model_provider.docker_ai_model_provider import DockerModelProvider -from models_provider.impl.gemini_model_provider.gemini_model_provider import GeminiModelProvider -from models_provider.impl.kimi_model_provider.kimi_model_provider import KimiModelProvider -from models_provider.impl.local_model_provider.local_model_provider import LocalModelProvider -from models_provider.impl.ollama_model_provider.ollama_model_provider import OllamaModelProvider -from models_provider.impl.openai_model_provider.openai_model_provider import OpenAIModelProvider -from models_provider.impl.regolo_model_provider.regolo_model_provider import RegoloModelProvider -from models_provider.impl.siliconCloud_model_provider.siliconCloud_model_provider import SiliconCloudModelProvider -from models_provider.impl.tencent_model_provider.tencent_model_provider import TencentModelProvider -from models_provider.impl.vllm_model_provider.vllm_model_provider import VllmModelProvider -from models_provider.impl.volcanic_engine_model_provider.volcanic_engine_model_provider import \ - VolcanicEngineModelProvider -from models_provider.impl.wenxin_model_provider.wenxin_model_provider import WenxinModelProvider -from models_provider.impl.xf_model_provider.xf_model_provider import XunFeiModelProvider -from models_provider.impl.xinference_model_provider.xinference_model_provider import XinferenceModelProvider -from models_provider.impl.minimax_model_provider.minimax_model_provider import MiniMaxModelProvider -from models_provider.impl.zhipu_model_provider.zhipu_model_provider import ZhiPuModelProvider - - -class ModelProvideConstants(Enum): - model_azure_provider = AzureModelProvider() - model_wenxin_provider = WenxinModelProvider() - model_ollama_provider = OllamaModelProvider() - model_openai_provider = OpenAIModelProvider() - model_docker_ai_provider = DockerModelProvider() - model_kimi_provider = KimiModelProvider() - model_zhipu_provider = ZhiPuModelProvider() - model_xf_provider = XunFeiModelProvider() - model_deepseek_provider = DeepSeekModelProvider() - model_gemini_provider = GeminiModelProvider() - model_volcanic_engine_provider = VolcanicEngineModelProvider() - model_tencent_provider = TencentModelProvider() - model_aws_bedrock_provider = BedrockModelProvider() - model_local_provider = LocalModelProvider() - model_xinference_provider = XinferenceModelProvider() - model_vllm_provider = VllmModelProvider() - aliyun_bai_lian_model_provider = AliyunBaiLianModelProvider() - model_anthropic_provider = AnthropicModelProvider() - model_siliconCloud_provider = SiliconCloudModelProvider() - model_regolo_provider = RegoloModelProvider() - model_minimax_provider = MiniMaxModelProvider() +{ + "message": "Not Found", + "documentation_url": "https://docs.github.com/rest", + "status": "404" +} \ No newline at end of file diff --git a/apps/models_provider/impl/api_route_model_provider/__init__.py b/apps/models_provider/impl/api_route_model_provider/__init__.py new file mode 100644 index 00000000000..9bad5790a57 --- /dev/null +++ b/apps/models_provider/impl/api_route_model_provider/__init__.py @@ -0,0 +1 @@ +# coding=utf-8 diff --git a/apps/models_provider/impl/api_route_model_provider/api_route_model_provider.py b/apps/models_provider/impl/api_route_model_provider/api_route_model_provider.py new file mode 100644 index 00000000000..2b6d547aaa4 --- /dev/null +++ b/apps/models_provider/impl/api_route_model_provider/api_route_model_provider.py @@ -0,0 +1,72 @@ +# coding=utf-8 +""" + @project: MaxKB + @file: api_route_model_provider.py + @desc: API Route Model Provider +""" +import os + +from django.utils.translation import gettext as _ + +from common.utils.common import get_file_content +from maxkb.conf import PROJECT_DIR +from models_provider.base_model_provider import ModelInfo, ModelTypeConst, ModelInfoManage, IModelProvider, \ + ModelProvideInfo +from models_provider.impl.api_route_model_provider.credential.embedding import ApiRouteEmbeddingCredential +from models_provider.impl.api_route_model_provider.credential.llm import ApiRouteLLMModelCredential +from models_provider.impl.api_route_model_provider.model.embedding import ApiRouteEmbeddingModel +from models_provider.impl.api_route_model_provider.model.llm import ApiRouteChatModel + +api_route_llm_credential = ApiRouteLLMModelCredential() +api_route_embedding_credential = ApiRouteEmbeddingCredential() + +model_info_list = [ + ModelInfo('gpt-4o', '', ModelTypeConst.LLM, + api_route_llm_credential, ApiRouteChatModel), + ModelInfo('gpt-4o-mini', '', ModelTypeConst.LLM, + api_route_llm_credential, ApiRouteChatModel), + ModelInfo('claude-3-5-sonnet-20241022', '', ModelTypeConst.LLM, + api_route_llm_credential, ApiRouteChatModel), + ModelInfo('deepseek-chat', '', ModelTypeConst.LLM, + api_route_llm_credential, ApiRouteChatModel), + ModelInfo('deepseek-reasoner', '', ModelTypeConst.LLM, + api_route_llm_credential, ApiRouteChatModel), + ModelInfo('qwen-2.5-72b-instruct', '', ModelTypeConst.LLM, + api_route_llm_credential, ApiRouteChatModel), +] + +model_info_embedding_list = [ + ModelInfo('text-embedding-3-small', '', + ModelTypeConst.EMBEDDING, api_route_embedding_credential, + ApiRouteEmbeddingModel), + ModelInfo('text-embedding-3-large', '', + ModelTypeConst.EMBEDDING, api_route_embedding_credential, + ApiRouteEmbeddingModel), +] + +model_info_manage = ( + ModelInfoManage.builder() + .append_model_info_list(model_info_list) + .append_default_model_info( + ModelInfo('gpt-4o', _('OpenAI GPT-4o via API Route'), ModelTypeConst.LLM, + api_route_llm_credential, ApiRouteChatModel)) + .append_model_info_list(model_info_embedding_list) + .append_default_model_info(model_info_embedding_list[0]) + .build() +) + + +class ApiRouteModelProvider(IModelProvider): + + def get_model_info_manage(self): + return model_info_manage + + def get_model_provide_info(self): + return ModelProvideInfo( + provider='model_api_route_provider', + name='API Route', + icon=get_file_content( + os.path.join(PROJECT_DIR, "apps", 'models_provider', 'impl', 'api_route_model_provider', + 'icon', + 'api_route_icon_svg')) + ) diff --git a/apps/models_provider/impl/api_route_model_provider/credential/__init__.py b/apps/models_provider/impl/api_route_model_provider/credential/__init__.py new file mode 100644 index 00000000000..9bad5790a57 --- /dev/null +++ b/apps/models_provider/impl/api_route_model_provider/credential/__init__.py @@ -0,0 +1 @@ +# coding=utf-8 diff --git a/apps/models_provider/impl/api_route_model_provider/credential/embedding.py b/apps/models_provider/impl/api_route_model_provider/credential/embedding.py new file mode 100644 index 00000000000..cf0b1f5dfd9 --- /dev/null +++ b/apps/models_provider/impl/api_route_model_provider/credential/embedding.py @@ -0,0 +1,52 @@ +# coding=utf-8 +""" + @project: MaxKB + @file: embedding.py + @desc: API Route Embedding Credential +""" +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 models_provider.base_model_provider import BaseModelCredential, ValidCode +from common.utils.logger import maxkb_logger + + +class ApiRouteEmbeddingCredential(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_key', 'api_base']: + 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: + maxkb_logger.error(f'Exception: {e}', exc_info=True) + 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, + default_value='https://global.api-route.com/v1') + api_key = forms.PasswordInputField('API Key', required=True) diff --git a/apps/models_provider/impl/api_route_model_provider/credential/llm.py b/apps/models_provider/impl/api_route_model_provider/credential/llm.py new file mode 100644 index 00000000000..d7b7f827e46 --- /dev/null +++ b/apps/models_provider/impl/api_route_model_provider/credential/llm.py @@ -0,0 +1,75 @@ +# coding=utf-8 +""" + @project: MaxKB + @file: llm.py + @desc: API Route LLM Credential +""" +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 models_provider.base_model_provider import BaseModelCredential, ValidCode +from common.utils.logger import maxkb_logger + + +class ApiRouteLLMModelParams(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=8192, + _min=1, + _max=100000, + _step=1, + precision=0) + + +class ApiRouteLLMModelCredential(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_key', 'api_base']: + 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: + maxkb_logger.error(f'Exception: {e}', exc_info=True) + 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, default_value='https://global.api-route.com/v1') + api_key = forms.PasswordInputField('API Key', required=True) + + def get_model_params_setting_form(self, model_name): + return ApiRouteLLMModelParams() diff --git a/apps/models_provider/impl/api_route_model_provider/icon/__init__.py b/apps/models_provider/impl/api_route_model_provider/icon/__init__.py new file mode 100644 index 00000000000..9bad5790a57 --- /dev/null +++ b/apps/models_provider/impl/api_route_model_provider/icon/__init__.py @@ -0,0 +1 @@ +# coding=utf-8 diff --git a/apps/models_provider/impl/api_route_model_provider/icon/api_route_icon_svg b/apps/models_provider/impl/api_route_model_provider/icon/api_route_icon_svg new file mode 100644 index 00000000000..6d771ee412a --- /dev/null +++ b/apps/models_provider/impl/api_route_model_provider/icon/api_route_icon_svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/apps/models_provider/impl/api_route_model_provider/model/__init__.py b/apps/models_provider/impl/api_route_model_provider/model/__init__.py new file mode 100644 index 00000000000..9bad5790a57 --- /dev/null +++ b/apps/models_provider/impl/api_route_model_provider/model/__init__.py @@ -0,0 +1 @@ +# coding=utf-8 diff --git a/apps/models_provider/impl/api_route_model_provider/model/embedding.py b/apps/models_provider/impl/api_route_model_provider/model/embedding.py new file mode 100644 index 00000000000..7b3f31baad5 --- /dev/null +++ b/apps/models_provider/impl/api_route_model_provider/model/embedding.py @@ -0,0 +1,21 @@ +# coding=utf-8 +""" + @project: MaxKB + @file: embedding.py + @desc: API Route Embedding Model +""" +from typing import Dict + +from langchain_openai import OpenAIEmbeddings + +from models_provider.base_model_provider import MaxKBBaseModel + + +class ApiRouteEmbeddingModel(MaxKBBaseModel, OpenAIEmbeddings): + @staticmethod + def new_instance(model_type, model_name, model_credential: Dict[str, object], **model_kwargs): + return ApiRouteEmbeddingModel( + api_key=model_credential.get('api_key'), + model=model_name, + openai_api_base=model_credential.get('api_base') or "https://global.api-route.com/v1", + ) diff --git a/apps/models_provider/impl/api_route_model_provider/model/llm.py b/apps/models_provider/impl/api_route_model_provider/model/llm.py new file mode 100644 index 00000000000..383d80d811f --- /dev/null +++ b/apps/models_provider/impl/api_route_model_provider/model/llm.py @@ -0,0 +1,27 @@ +# coding=utf-8 +""" + @project: MaxKB + @file: llm.py + @desc: API Route Chat Model +""" +from typing import Dict + +from models_provider.base_model_provider import MaxKBBaseModel +from models_provider.impl.base_chat_open_ai import BaseChatOpenAI + + +class ApiRouteChatModel(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 ApiRouteChatModel( + model=model_name, + openai_api_base=model_credential.get('api_base') or "https://global.api-route.com/v1", + openai_api_key=model_credential.get('api_key'), + **optional_params, + )