diff --git a/apps/models_provider/constants/model_provider_constants.py b/apps/models_provider/constants/model_provider_constants.py
index ae749795cb7..b2d6f643f1b 100644
--- a/apps/models_provider/constants/model_provider_constants.py
+++ b/apps/models_provider/constants/model_provider_constants.py
@@ -24,6 +24,7 @@
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
+from models_provider.impl.webwright_model_provider.webwright_model_provider import WebWrightModelProvider
class ModelProvideConstants(Enum):
@@ -48,3 +49,4 @@ class ModelProvideConstants(Enum):
model_siliconCloud_provider = SiliconCloudModelProvider()
model_regolo_provider = RegoloModelProvider()
model_minimax_provider = MiniMaxModelProvider()
+ model_webwright_provider = WebWrightModelProvider()
diff --git a/apps/models_provider/impl/webwright_model_provider/__init__.py b/apps/models_provider/impl/webwright_model_provider/__init__.py
new file mode 100644
index 00000000000..df5407d0ccc
--- /dev/null
+++ b/apps/models_provider/impl/webwright_model_provider/__init__.py
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+"""
+@Project :MaxKB
+@File :__init__.py
+@Desc :WebWright model provider package
+"""
diff --git a/apps/models_provider/impl/webwright_model_provider/credential/__init__.py b/apps/models_provider/impl/webwright_model_provider/credential/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/apps/models_provider/impl/webwright_model_provider/credential/llm.py b/apps/models_provider/impl/webwright_model_provider/credential/llm.py
new file mode 100644
index 00000000000..af0b40f640b
--- /dev/null
+++ b/apps/models_provider/impl/webwright_model_provider/credential/llm.py
@@ -0,0 +1,70 @@
+# coding=utf-8
+"""
+ @project: MaxKB
+ @file: llm.py
+ @desc: WebWright LLM credential. WebWright is OpenAI-compatible, so the
+ credential is an API base URL and an API key.
+"""
+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 WebWrightLLMModelParams(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 WebWrightLLMModelCredential(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:
+ 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://webwright.ai/v1')
+ api_key = forms.PasswordInputField('API Key', required=True)
+
+ def get_model_params_setting_form(self, model_name):
+ return WebWrightLLMModelParams()
diff --git a/apps/models_provider/impl/webwright_model_provider/icon/__init__.py b/apps/models_provider/impl/webwright_model_provider/icon/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/apps/models_provider/impl/webwright_model_provider/icon/webwright_icon_svg b/apps/models_provider/impl/webwright_model_provider/icon/webwright_icon_svg
new file mode 100644
index 00000000000..ac2ed1e9274
--- /dev/null
+++ b/apps/models_provider/impl/webwright_model_provider/icon/webwright_icon_svg
@@ -0,0 +1,31 @@
+
+
diff --git a/apps/models_provider/impl/webwright_model_provider/model/__init__.py b/apps/models_provider/impl/webwright_model_provider/model/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/apps/models_provider/impl/webwright_model_provider/model/llm.py b/apps/models_provider/impl/webwright_model_provider/model/llm.py
new file mode 100644
index 00000000000..be51710f007
--- /dev/null
+++ b/apps/models_provider/impl/webwright_model_provider/model/llm.py
@@ -0,0 +1,29 @@
+# coding=utf-8
+"""
+ @project: MaxKB
+ @file: llm.py
+ @desc: WebWright chat model. WebWright exposes an OpenAI-compatible
+ /v1/chat/completions endpoint, so this model reuses the shared
+ BaseChatOpenAI implementation.
+"""
+from typing import Dict
+
+from models_provider.base_model_provider import MaxKBBaseModel
+from models_provider.impl.base_chat_open_ai import BaseChatOpenAI
+
+
+class WebWrightChatModel(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 WebWrightChatModel(
+ model=model_name,
+ openai_api_base=model_credential.get('api_base') or 'https://webwright.ai/v1',
+ openai_api_key=model_credential.get('api_key'),
+ **optional_params,
+ )
diff --git a/apps/models_provider/impl/webwright_model_provider/webwright_model_provider.py b/apps/models_provider/impl/webwright_model_provider/webwright_model_provider.py
new file mode 100644
index 00000000000..6ef928144e5
--- /dev/null
+++ b/apps/models_provider/impl/webwright_model_provider/webwright_model_provider.py
@@ -0,0 +1,54 @@
+# coding=utf-8
+"""
+ @project: MaxKB
+ @file: webwright_model_provider.py
+ @desc: WebWright provider. WebWright serves an OpenAI-compatible chat
+ completions API at https://webwright.ai/v1 with the Wren R1 model.
+"""
+import os
+
+from common.utils.common import get_file_content
+from models_provider.base_model_provider import (
+ IModelProvider,
+ ModelProvideInfo,
+ ModelInfo,
+ ModelTypeConst,
+ ModelInfoManage,
+)
+from models_provider.impl.webwright_model_provider.credential.llm import WebWrightLLMModelCredential
+from models_provider.impl.webwright_model_provider.model.llm import WebWrightChatModel
+from maxkb.conf import PROJECT_DIR
+
+webwright_llm_model_credential = WebWrightLLMModelCredential()
+webwright_llm_list = [
+ ModelInfo('wren-r1', '', ModelTypeConst.LLM, webwright_llm_model_credential, WebWrightChatModel),
+]
+
+model_info_manage = (
+ ModelInfoManage.builder()
+ .append_model_info_list(webwright_llm_list)
+ .append_default_model_info(webwright_llm_list[0])
+ .build()
+)
+
+
+class WebWrightModelProvider(IModelProvider):
+ def get_model_info_manage(self):
+ return model_info_manage
+
+ def get_model_provide_info(self):
+ return ModelProvideInfo(
+ provider='model_webwright_provider',
+ name='WebWright',
+ icon=get_file_content(
+ os.path.join(
+ PROJECT_DIR,
+ "apps",
+ "models_provider",
+ "impl",
+ "webwright_model_provider",
+ "icon",
+ "webwright_icon_svg",
+ )
+ ),
+ )
diff --git a/ui/src/components/dynamics-form/items/model/provider-data.ts b/ui/src/components/dynamics-form/items/model/provider-data.ts
index 5e7b39b82c6..d8f0c02e7cd 100644
--- a/ui/src/components/dynamics-form/items/model/provider-data.ts
+++ b/ui/src/components/dynamics-form/items/model/provider-data.ts
@@ -108,5 +108,10 @@ export const providerList = [
"provider": "model_minimax_provider",
"name": "MiniMax",
"icon": ""
- }
+ },
+{
+ "provider": "model_webwright_provider",
+ "name": "WebWright",
+ "icon": "\n"
+}
]