Skip to content
Closed
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
2 changes: 2 additions & 0 deletions apps/models_provider/constants/model_provider_constants.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# coding=utf-8
from enum import Enum

from models_provider.impl.atlas_cloud_model_provider.atlas_cloud_model_provider import AtlasCloudModelProvider
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
Expand Down Expand Up @@ -28,6 +29,7 @@


class ModelProvideConstants(Enum):
model_atlas_cloud_provider = AtlasCloudModelProvider()
model_azure_provider = AzureModelProvider()
model_wenxin_provider = WenxinModelProvider()
model_ollama_provider = OllamaModelProvider()
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from models_provider.base_model_provider import (
IModelProvider,
ModelInfo,
ModelInfoManage,
ModelProvideInfo,
ModelTypeConst,
)
from models_provider.impl.atlas_cloud_model_provider.credential.llm import AtlasCloudLLMModelCredential
from models_provider.impl.atlas_cloud_model_provider.model.llm import AtlasCloudChatModel


atlas_cloud_llm_model_credential = AtlasCloudLLMModelCredential()
atlas_cloud_llm_list = [
ModelInfo("google/gemini-2.5-flash", "", ModelTypeConst.LLM, atlas_cloud_llm_model_credential, AtlasCloudChatModel),
ModelInfo("google/gemini-2.5-pro", "", ModelTypeConst.LLM, atlas_cloud_llm_model_credential, AtlasCloudChatModel),
ModelInfo(
"anthropic/claude-sonnet-4.6", "", ModelTypeConst.LLM, atlas_cloud_llm_model_credential, AtlasCloudChatModel
),
ModelInfo("openai/gpt-4o", "", ModelTypeConst.LLM, atlas_cloud_llm_model_credential, AtlasCloudChatModel),
ModelInfo(
"deepseek-ai/deepseek-v3.2", "", ModelTypeConst.LLM, atlas_cloud_llm_model_credential, AtlasCloudChatModel
),
ModelInfo("moonshotai/kimi-k2.5", "", ModelTypeConst.LLM, atlas_cloud_llm_model_credential, AtlasCloudChatModel),
ModelInfo("zai-org/glm-5", "", ModelTypeConst.LLM, atlas_cloud_llm_model_credential, AtlasCloudChatModel),
ModelInfo("openai/gpt-5.4", "", ModelTypeConst.LLM, atlas_cloud_llm_model_credential, AtlasCloudChatModel),
ModelInfo("qwen/qwen3.7-max", "", ModelTypeConst.LLM, atlas_cloud_llm_model_credential, AtlasCloudChatModel),
]

model_info_manage = (
ModelInfoManage.builder()
.append_model_info_list(atlas_cloud_llm_list)
.append_default_model_info(atlas_cloud_llm_list[0])
.build()
)


class AtlasCloudModelProvider(IModelProvider):
def get_model_info_manage(self):
return model_info_manage

def get_model_provide_info(self):
return ModelProvideInfo(provider="model_atlas_cloud_provider", name="Atlas Cloud", icon="")
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ATLAS_CLOUD_API_BASE = "https://api.atlascloud.ai/v1"
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
from typing import Dict

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

from common import forms
from common.exception.app_exception import AppApiException
from common.forms import BaseForm, TooltipLabel
from common.utils.logger import maxkb_logger
from models_provider.base_model_provider import BaseModelCredential, ValidCode
from models_provider.impl.atlas_cloud_model_provider.constants import ATLAS_CLOUD_API_BASE


class AtlasCloudLLMModelParams(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 AtlasCloudLLMModelCredential(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(item.get("value") == model_type for item in 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),
)
return False

try:
model = provider.get_model(model_type, model_name, model_credential, **model_params)
model.invoke([HumanMessage(content=gettext("Hello"))])
except Exception as exc:
maxkb_logger.error("Exception: %s", exc, exc_info=True)
if isinstance(exc, AppApiException):
raise exc
if raise_exception:
raise AppApiException(
ValidCode.valid_error.value,
gettext("Verification failed, please check whether the parameters are correct: {error}").format(
error=str(exc)
),
)
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=ATLAS_CLOUD_API_BASE)
api_key = forms.PasswordInputField("API Key", required=True)

def get_model_params_setting_form(self, model_name):
return AtlasCloudLLMModelParams()
Empty file.
21 changes: 21 additions & 0 deletions apps/models_provider/impl/atlas_cloud_model_provider/model/llm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from typing import Dict

from models_provider.base_model_provider import MaxKBBaseModel
from models_provider.impl.atlas_cloud_model_provider.constants import ATLAS_CLOUD_API_BASE
from models_provider.impl.base_chat_open_ai import BaseChatOpenAI


class AtlasCloudChatModel(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 AtlasCloudChatModel(
model=model_name,
openai_api_base=model_credential.get("api_base") or ATLAS_CLOUD_API_BASE,
openai_api_key=model_credential.get("api_key"),
**optional_params,
)
63 changes: 61 additions & 2 deletions apps/models_provider/tests.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,62 @@
from django.test import TestCase
from unittest import TestCase
from unittest.mock import patch

# Create your tests here.
from models_provider.impl.atlas_cloud_model_provider.atlas_cloud_model_provider import AtlasCloudModelProvider
from models_provider.impl.atlas_cloud_model_provider.constants import ATLAS_CLOUD_API_BASE
from models_provider.impl.atlas_cloud_model_provider.credential.llm import AtlasCloudLLMModelCredential
from models_provider.impl.atlas_cloud_model_provider.model.llm import AtlasCloudChatModel


class AtlasCloudModelProviderTest(TestCase):
def test_provider_metadata(self):
provider = AtlasCloudModelProvider()

self.assertIsInstance(provider, AtlasCloudModelProvider)
self.assertEqual(
provider.get_model_provide_info().to_dict(),
{"provider": "model_atlas_cloud_provider", "name": "Atlas Cloud", "icon": ""},
)

def test_provider_exposes_current_model_ids(self):
provider = AtlasCloudModelProvider()

model_names = {model["name"] for model in provider.get_model_list("LLM")}

self.assertIn("google/gemini-2.5-flash", model_names)
self.assertIn("anthropic/claude-sonnet-4.6", model_names)
self.assertIn("openai/gpt-5.4", model_names)

def test_credential_defaults_to_atlas_cloud_api(self):
credential = AtlasCloudLLMModelCredential()

self.assertEqual(credential.api_base.default_value, ATLAS_CLOUD_API_BASE)

def test_model_uses_openai_compatible_configuration(self):
factory = AtlasCloudChatModel.new_instance
with patch(
"models_provider.impl.atlas_cloud_model_provider.model.llm.AtlasCloudChatModel"
) as model_constructor:
model = factory(
"LLM",
"google/gemini-2.5-flash",
{"api_key": "test-key", "api_base": ""},
temperature=0.2,
streaming=True,
model_id="internal-id",
)

self.assertIs(model, model_constructor.return_value)
model_constructor.assert_called_once_with(
model="google/gemini-2.5-flash",
openai_api_base=ATLAS_CLOUD_API_BASE,
openai_api_key="test-key",
temperature=0.2,
)

def test_api_key_is_masked(self):
credential = AtlasCloudLLMModelCredential()

encrypted = credential.encryption_dict({"api_key": "test-secret-api-key", "api_base": ATLAS_CLOUD_API_BASE})

self.assertNotEqual(encrypted["api_key"], "test-secret-api-key")
self.assertEqual(encrypted["api_base"], ATLAS_CLOUD_API_BASE)
5 changes: 5 additions & 0 deletions ui/src/components/dynamics-form/items/model/provider-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,5 +108,10 @@ export const providerList = [
"provider": "model_minimax_provider",
"name": "MiniMax",
"icon": "<svg t=\"1776929669814\" class=\"icon\" viewBox=\"0 0 1169 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"4810\" width=\"100%\" height=\"100%\"><path d=\"M474.173841 470.682521V847.403039c-25.441562 127.572805-194.68465 94.674371-195.416638 2.192962-0.802986-116.24 0-231.750012 0-347.113027V368.697276c0-16.740712-3.654937-29.973484-18.275685-40.428305-28.512509-21.346633-62.725921 3.728936-63.456908 34.507407-1.608972 41.305289-0.804986 81.733594-1.608973 122.453893 0 32.167446 0 63.384909 0.730988 95.478357C175.164986 722.025196 3.947932 698.5576 0 581.512614V483.5493c0-32.021449 62.725921-39.551319 59.655973 8.406855-2.046965 23.759591-0.731987 48.25117-1.535973 71.791765-0.729987 42.036277 63.530907 70.32879 78.663646 1.607972 0.730987-56.658025 0.730987-113.31605 0.730988-170.486067 0-71.644767 20.32365-129.984763 96.282343-135.39467 32.898434-2.92395 54.757058 10.819814 75.738697 34.579405 8.042862 8.407855 27.049535 35.092396 27.781522 64.115897 0 26.75754 0.729987 53.368082 0.729987 80.418616 0 53.367082-0.729987 107.028158-0.729987 160.39724 0 34.579405 0.729987 68.792816 0.729987 102.568235 0 42.841263 0 86.267516-0.729987 129.180778-0.730987 55.78104 67.111845 54.977054 78.005658-0.876985 0-65.796868 0.729987-130.78875 0.729987-196.585618 0-162.078211-0.729987-324.157422-0.729987-486.163634 0-16.814711-2.33996-63.456908 6.579886-80.417617C469.274925-48.744541 613.003452 1.625592 614.319429 97.176948c2.777952 195.781631 0 393.756225 0.730988 589.975848 0 68.062829-55.269049 53.44208-58.338996 26.830538 0-204.188487 0-409.180959 0.729987-613.07745-2.703953-51.175119-78.589648-44.229239-82.976572-7.529871-1.461975 42.109275-0.729987 84.950538-1.461975 126.987815v250.025698h0.730987l0.511992 0.292995z\" fill=\"#D4367A\" p-id=\"4811\"></path><path d=\"M696.347018 467.684573v276.638239-652.848766c24.709575-128.44779 193.880664-95.038365 194.611651-2.484957 0.803986 115.437014 0 231.677014 0.803986 347.040028 0 44.303238 0 88.752473-0.730987 133.055711 0 17.545698 4.312926 29.900486 19.007673 41.159292 27.780522 20.835641 61.921935-3.654937 63.456908-34.945399 1.535974-40.501303 0.731987-81.002606 0.731987-122.527892v-94.893367c21.200635-141.315568 191.906698-117.847972 195.488637-0.803986V711.645375c0 32.166447-61.994933 39.769316-59.216981-8.334857 1.680971-24.490579 0-304.930753 0.876985-329.49433 1.461975-41.305289-63.602906-70.402789-78.663647-0.876985v169.609081c0 72.66875-20.396649 130.057762-97.013331 136.271656-72.228757 1.680971-101.253258-48.25117-103.593217-98.695302V237.250538c0-43.645249 0-86.266516 0.731987-129.107779 0.729987-55.78004-67.112845-55.78004-78.663646 0.804986v767.626792c0 16.667713 2.33996 63.383909-5.921898 80.417616-47.300186 115.363015-191.7607 64.918883-193.076678-30.559474v-90.871437c3.582938-61.190947 55.269049-46.643197 57.609009-20.762642V922.631744c2.777952 51.321117 78.663646 45.107224 82.245585 7.602869 1.534974-42.109275 1.534974-84.146552 1.534973-127.059813V467.757571h-0.219996v-0.072998z\" fill=\"#ED6D48\" p-id=\"4812\"></path></svg>"
},
{
"provider": "model_atlas_cloud_provider",
"name": "Atlas Cloud",
"icon": ""
}
]