Compare commits

...

18 Commits

Author SHA1 Message Date
wxg0103 847755b1c2 feat: add response body schemas for various API endpoints 2025-08-19 15:15:46 +08:00
wxg0103 b57455d0ee refactor: expand permissions for application access token
--bug=1060032 --user=王孝刚 【桂物智慧】 api 调用客户端修改对话摘要接口,报错403,没有访问权限 https://www.tapd.cn/57709429/s/1757188
2025-08-19 11:06:36 +08:00
maninhill 2a257edff9
chore: Update README.md (#3587)
Some checks are pending
sync2gitee / repo-sync (push) Waiting to run
Typos Check / Spell Check with Typos (push) Waiting to run
2025-07-14 17:49:32 +08:00
maninhill d47699331c
chore: Update README_CN.md (#3585) 2025-07-14 17:28:34 +08:00
maninhill 90c64d77dd
chore: Update README.md (#3584) 2025-07-14 17:27:02 +08:00
liqiang-fit2cloud e1ada3ffe2
Update build-and-push.yml
Some checks failed
sync2gitee / repo-sync (push) Has been cancelled
Typos Check / Spell Check with Typos (push) Has been cancelled
2025-07-10 17:37:21 +08:00
wangdan-fit2cloud b62c79fda6 fix: text bug
Some checks are pending
sync2gitee / repo-sync (push) Waiting to run
Typos Check / Spell Check with Typos (push) Waiting to run
2025-07-10 11:37:44 +08:00
wangdan-fit2cloud 3d9e7dd4b1 feat: optimization 2025-07-10 11:37:44 +08:00
CaptainB 8ff15865a7 fix: remove redundant import of pickle in function_code.py
Some checks are pending
sync2gitee / repo-sync (push) Waiting to run
Typos Check / Spell Check with Typos (push) Waiting to run
2025-07-09 15:02:06 +08:00
wanghe-fit2cloud 48899d55d1 docs: Add some badges
Some checks failed
sync2gitee / repo-sync (push) Has been cancelled
Typos Check / Spell Check with Typos (push) Has been cancelled
2025-07-07 13:15:57 +08:00
CaptainB 1cc4107bfe chore: remove ignore rule for pymupdf dependency in dependabot configuration
Some checks failed
sync2gitee / repo-sync (push) Has been cancelled
Typos Check / Spell Check with Typos (push) Has been cancelled
2025-07-04 11:38:01 +08:00
CaptainB b13cd03706 fix: prevent usage of 'stdio' in MCP server configuration
Some checks failed
sync2gitee / repo-sync (push) Has been cancelled
Typos Check / Spell Check with Typos (push) Has been cancelled
2025-06-24 11:46:53 +08:00
liuchang_cloud 69f024492b
fix(documet):upgrade document updatetime when upgrade document_char_length (#3211)
Some checks failed
sync2gitee / repo-sync (push) Has been cancelled
Typos Check / Spell Check with Typos (push) Has been cancelled
fixed #2942
2025-06-20 10:17:25 +08:00
Mr.zhao a9c46cd7e0
fix: Reorganize the model cache (#3315)
Some checks are pending
sync2gitee / repo-sync (push) Waiting to run
Typos Check / Spell Check with Typos (push) Waiting to run
2025-06-19 18:01:45 +08:00
CaptainB a9e9f5b085 chore: add ignore rule for pymupdf dependency in dependabot configuration
Some checks failed
sync2gitee / repo-sync (push) Has been cancelled
Typos Check / Spell Check with Typos (push) Has been cancelled
2025-06-16 13:07:33 +08:00
wxg0103 e12b1fe14e refactor: gemini
Some checks failed
sync2gitee / repo-sync (push) Has been cancelled
Typos Check / Spell Check with Typos (push) Has been cancelled
2025-06-05 09:11:06 +08:00
shaohuzhang1 7ce66a7bf3
perf: Function library execution (#3175)
Some checks failed
sync2gitee / repo-sync (push) Has been cancelled
Typos Check / Spell Check with Typos (push) Has been cancelled
2025-05-30 18:56:01 +08:00
zhangshaohu decd3395db build: Sensitive directory permissions 2025-05-22 21:59:06 +08:00
27 changed files with 272 additions and 97 deletions

View File

@ -11,4 +11,7 @@ updates:
python-dependencies:
patterns:
- "*"
# ignore:
# - dependency-name: "pymupdf"
# versions: ["*"]

View File

@ -64,7 +64,7 @@ jobs:
TAG_NAME=${{ github.event.inputs.dockerImageTag }}
TAG_NAME_WITH_LATEST=${{ github.event.inputs.dockerImageTagWithLatest }}
if [[ ${TAG_NAME_WITH_LATEST} == 'true' ]]; then
DOCKER_IMAGE_TAGS="--tag ${DOCKER_IMAGE}:${TAG_NAME} --tag ${DOCKER_IMAGE}:latest"
DOCKER_IMAGE_TAGS="--tag ${DOCKER_IMAGE}:${TAG_NAME} --tag ${DOCKER_IMAGE}:${TAG_NAME%%.*}"
else
DOCKER_IMAGE_TAGS="--tag ${DOCKER_IMAGE}:${TAG_NAME}"
fi
@ -122,7 +122,7 @@ jobs:
TAG_NAME=${{ github.event.inputs.dockerImageTag }}
TAG_NAME_WITH_LATEST=${{ github.event.inputs.dockerImageTagWithLatest }}
if [[ ${TAG_NAME_WITH_LATEST} == 'true' ]]; then
DOCKER_IMAGE_TAGS="--tag ${DOCKER_IMAGE}:${TAG_NAME} --tag ${DOCKER_IMAGE}:latest"
DOCKER_IMAGE_TAGS="--tag ${DOCKER_IMAGE}:${TAG_NAME} --tag ${DOCKER_IMAGE}:${TAG_NAME%%.*}"
else
DOCKER_IMAGE_TAGS="--tag ${DOCKER_IMAGE}:${TAG_NAME}"
fi

View File

@ -1,5 +1,6 @@
<p align="center"><img src= "https://github.com/1Panel-dev/maxkb/assets/52996290/c0694996-0eed-40d8-b369-322bf2a380bf" alt="MaxKB" width="300" /></p>
<h3 align="center">An Open-Source AI Assistant for Enterprise</h3>
<h3 align="center">Open-source platform for building enterprise-grade agents</h3>
<h3 align="center">强大易用的企业级智能体平台</h3>
<p align="center"><a href="https://trendshift.io/repositories/9113" target="_blank"><img src="https://trendshift.io/api/badge/repositories/9113" alt="1Panel-dev%2FMaxKB | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a></p>
<p align="center">
<a href="https://www.gnu.org/licenses/gpl-3.0.html#license-text"><img src="https://img.shields.io/github/license/1Panel-dev/maxkb?color=%231890FF" alt="License: GPL v3"></a>
@ -10,7 +11,7 @@
</p>
<hr/>
MaxKB = Max Knowledge Brain, it is a powerful and easy-to-use AI assistant that integrates Retrieval-Augmented Generation (RAG) pipelines, supports robust workflows, and provides advanced MCP tool-use capabilities. MaxKB is widely applied in scenarios such as intelligent customer service, corporate internal knowledge bases, academic research, and education.
MaxKB = Max Knowledge Brain, it is an open-source platform for building enterprise-grade agents. MaxKB integrates Retrieval-Augmented Generation (RAG) pipelines, supports robust workflows, and provides advanced MCP tool-use capabilities. MaxKB is widely applied in scenarios such as intelligent customer service, corporate internal knowledge bases, academic research, and education.
- **RAG Pipeline**: Supports direct uploading of documents / automatic crawling of online documents, with features for automatic text splitting, vectorization. This effectively reduces hallucinations in large models, providing a superior smart Q&A interaction experience.
- **Agentic Workflow**: Equipped with a powerful workflow engine, function library and MCP tool-use, enabling the orchestration of AI processes to meet the needs of complex business scenarios.
@ -55,8 +56,6 @@ Access MaxKB web interface at `http://your_server_ip:8080` with default admin cr
## Feature Comparison
MaxKB is positioned as an Ready-to-use RAG (Retrieval-Augmented Generation) intelligent Q&A application, rather than a middleware platform for building large model applications. The following table is merely a comparison from a functional perspective.
<table style="width: 100%;">
<tr>
<th align="center">Feature</th>

View File

@ -1,19 +1,20 @@
<p align="center"><img src= "https://github.com/1Panel-dev/maxkb/assets/52996290/c0694996-0eed-40d8-b369-322bf2a380bf" alt="MaxKB" width="300" /></p>
<h3 align="center">强大易用的企业级 AI 助手</h3>
<h3 align="center">强大易用的企业级智能体平台</h3>
<p align="center">
<a href="https://trendshift.io/repositories/9113" target="_blank"><img src="https://trendshift.io/api/badge/repositories/9113" alt="1Panel-dev%2FMaxKB | Trendshift" style="width: 250px; height: auto;" /></a>
<a href="https://market.aliyun.com/products/53690006/cmjj00067609.html?userCode=kmemb8jp" target="_blank"><img src="https://img.alicdn.com/imgextra/i2/O1CN01H5JIwY1rZ0OobDjnJ_!!6000000005644-2-tps-1000-216.png" alt="1Panel-dev%2FMaxKB | Aliyun" style="width: 250px; height: auto;" /></a>
</p>
<p align="center">
<a href="README_EN.md"><img src="https://img.shields.io/badge/English_README-blue" alt="English README"></a>
<a href="https://www.gnu.org/licenses/gpl-3.0.html#license-text"><img src="https://img.shields.io/github/license/1Panel-dev/maxkb" alt="License: GPL v3"></a>
<a href="https://www.gnu.org/licenses/gpl-3.0.html#license-text"><img src="https://img.shields.io/github/license/1Panel-dev/maxkb?color=%231890FF" alt="License: GPL v3"></a>
<a href="https://github.com/1Panel-dev/maxkb/releases/latest"><img src="https://img.shields.io/github/v/release/1Panel-dev/maxkb" alt="Latest release"></a>
<a href="https://github.com/1Panel-dev/maxkb"><img src="https://img.shields.io/github/stars/1Panel-dev/maxkb?style=flat-square" alt="Stars"></a>
<a href="https://hub.docker.com/r/1panel/maxkb"><img src="https://img.shields.io/docker/pulls/1panel/maxkb?label=downloads" alt="Download"></a>
<a href="https://github.com/1Panel-dev/maxkb"><img src="https://img.shields.io/github/stars/1Panel-dev/maxkb?style=flat-square" alt="Stars"></a>
<a href="https://hub.docker.com/r/1panel/maxkb"><img src="https://img.shields.io/docker/pulls/1panel/maxkb?label=downloads" alt="Download"></a>
<a href="https://gitee.com/fit2cloud-feizhiyun/MaxKB"><img src="https://gitee.com/fit2cloud-feizhiyun/MaxKB/badge/star.svg?theme=gvp" alt="Gitee Stars"></a>
<a href="https://gitcode.com/feizhiyun/MaxKB"><img src="https://gitcode.com/feizhiyun/MaxKB/star/badge.svg" alt="GitCode Stars"></a>
</p>
<hr/>
MaxKB = Max Knowledge Brain是一款强大易用的企业级 AI 助手,支持 RAG 检索增强生成、工作流编排、MCP 工具调用能力。MaxKB 支持对接各种主流大语言模型,广泛应用于智能客服、企业内部知识库问答、员工助手、学术研究与教育等场景。
MaxKB = Max Knowledge Brain是一款强大易用的企业级智能体平台,支持 RAG 检索增强生成、工作流编排、MCP 工具调用能力。MaxKB 支持对接各种主流大语言模型,广泛应用于智能客服、企业内部知识库问答、员工助手、学术研究与教育等场景。
- **RAG 检索增强生成**:高效搭建本地 AI 知识库,支持直接上传文档 / 自动爬取在线文档,支持文本自动拆分、向量化,有效减少大模型幻觉,提升问答效果;
- **灵活编排**:内置强大的工作流引擎、函数库和 MCP 工具调用能力,支持编排 AI 工作过程,满足复杂业务场景下的需求;

View File

@ -219,7 +219,7 @@ class BaseChatNode(IChatNode):
message_list = self.generate_message_list(system, prompt, history_message)
self.context['message_list'] = message_list
if mcp_enable and mcp_servers is not None:
if mcp_enable and mcp_servers is not None and '"stdio"' not in mcp_servers:
r = mcp_response_generator(chat_model, message_list, mcp_servers)
return NodeResult(
{'result': r, 'chat_model': chat_model, 'message_list': message_list,

View File

@ -1325,6 +1325,8 @@ class ApplicationSerializer(serializers.Serializer):
def get_mcp_servers(self, with_valid=True):
if with_valid:
self.is_valid(raise_exception=True)
if '"stdio"' in self.data.get('mcp_servers'):
raise AppApiException(500, _('stdio is not supported'))
servers = json.loads(self.data.get('mcp_servers'))
async def get_mcp_tools(servers):

View File

@ -38,6 +38,15 @@ class ApplicationApi(ApiMixin):
}
)
@staticmethod
def get_response_body_api():
return openapi.Schema(
type=openapi.TYPE_STRING,
title=_("Application authentication token"),
description=_("Application authentication token"),
default="token"
)
@staticmethod
def get_response_body_api():
return openapi.Schema(
@ -133,6 +142,27 @@ class ApplicationApi(ApiMixin):
}
)
@staticmethod
def get_response_body_api():
return openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
'id': openapi.Schema(type=openapi.TYPE_STRING, title=_("Primary key id"),
description=_("Primary key id")),
'secret_key': openapi.Schema(type=openapi.TYPE_STRING, title=_("Secret key"),
description=_("Secret key")),
'is_active': openapi.Schema(type=openapi.TYPE_BOOLEAN, title=_("Is activation"),
description=_("Is activation")),
'application_id': openapi.Schema(type=openapi.TYPE_STRING, title=_("Application ID"),
description=_("Application ID")),
'allow_cross_domain': openapi.Schema(type=openapi.TYPE_BOOLEAN,
title=_("Is cross-domain allowed"),
description=_("Is cross-domain allowed")),
'cross_domain_list': openapi.Schema(type=openapi.TYPE_ARRAY, title=_('Cross-domain list'),
items=openapi.Schema(type=openapi.TYPE_STRING))
}
)
class AccessToken(ApiMixin):
@staticmethod
def get_request_params_api():
@ -171,6 +201,37 @@ class ApplicationApi(ApiMixin):
}
)
@staticmethod
def get_response_body_api():
return openapi.Schema(
type=openapi.TYPE_OBJECT,
required=[],
properties={
'id': openapi.Schema(type=openapi.TYPE_STRING, title=_("Primary key id"),
description=_("Primary key id")),
'access_token': openapi.Schema(type=openapi.TYPE_STRING, title=_("Access Token"),
description=_("Access Token")),
'access_token_reset': openapi.Schema(type=openapi.TYPE_BOOLEAN, title=_("Reset Token"),
description=_("Reset Token")),
'is_active': openapi.Schema(type=openapi.TYPE_BOOLEAN, title=_("Is activation"),
description=_("Is activation")),
'access_num': openapi.Schema(type=openapi.TYPE_NUMBER, title=_("Number of visits"),
description=_("Number of visits")),
'white_active': openapi.Schema(type=openapi.TYPE_BOOLEAN, title=_("Whether to enable whitelist"),
description=_("Whether to enable whitelist")),
'white_list': openapi.Schema(type=openapi.TYPE_ARRAY,
items=openapi.Schema(type=openapi.TYPE_STRING), title=_("Whitelist"),
description=_("Whitelist")),
'show_source': openapi.Schema(type=openapi.TYPE_BOOLEAN,
title=_("Whether to display knowledge sources"),
description=_("Whether to display knowledge sources")),
'language': openapi.Schema(type=openapi.TYPE_STRING,
title=_("language"),
description=_("language"))
}
)
class Edit(ApiMixin):
@staticmethod
def get_request_body_api():
@ -367,6 +428,56 @@ class ApplicationApi(ApiMixin):
}
)
@staticmethod
def get_response_body_api():
return openapi.Schema(
type=openapi.TYPE_OBJECT,
required=['id', 'name', 'desc', 'model_id', 'dialogue_number', 'dataset_setting', 'model_setting',
'problem_optimization', 'stt_model_enable', 'stt_model_enable', 'tts_type',
'work_flow'],
properties={
'id': openapi.Schema(type=openapi.TYPE_STRING, title=_("Primary key id"),
description=_("Primary key id")),
'name': openapi.Schema(type=openapi.TYPE_STRING, title=_("Application Name"),
description=_("Application Name")),
'desc': openapi.Schema(type=openapi.TYPE_STRING, title=_("Application Description"),
description=_("Application Description")),
'model_id': openapi.Schema(type=openapi.TYPE_STRING, title=_("Model id"),
description=_("Model id")),
"dialogue_number": openapi.Schema(type=openapi.TYPE_NUMBER,
title=_("Number of multi-round conversations"),
description=_("Number of multi-round conversations")),
'prologue': openapi.Schema(type=openapi.TYPE_STRING, title=_("Opening remarks"),
description=_("Opening remarks")),
'dataset_id_list': openapi.Schema(type=openapi.TYPE_ARRAY,
items=openapi.Schema(type=openapi.TYPE_STRING),
title=_("List of associated knowledge base IDs"),
description=_("List of associated knowledge base IDs")),
'dataset_setting': ApplicationApi.DatasetSetting.get_request_body_api(),
'model_setting': ApplicationApi.ModelSetting.get_request_body_api(),
'problem_optimization': openapi.Schema(type=openapi.TYPE_BOOLEAN, title=_("Problem Optimization"),
description=_("Problem Optimization"), default=True),
'type': openapi.Schema(type=openapi.TYPE_STRING, title=_("Application Type"),
description=_("Application Type SIMPLE | WORK_FLOW")),
'problem_optimization_prompt': openapi.Schema(type=openapi.TYPE_STRING,
title=_('Question optimization tips'),
description=_("Question optimization tips"),
default=_(
"() contains the user's question. Answer the guessed user's question based on the context ({question}) Requirement: Output a complete question and put it in the <data></data> tag")),
'tts_model_id': openapi.Schema(type=openapi.TYPE_STRING, title=_("Text-to-speech model ID"),
description=_("Text-to-speech model ID")),
'stt_model_id': openapi.Schema(type=openapi.TYPE_STRING, title=_("Speech-to-text model id"),
description=_("Speech-to-text model id")),
'stt_model_enable': openapi.Schema(type=openapi.TYPE_STRING, title=_("Is speech-to-text enabled"),
description=_("Is speech-to-text enabled")),
'tts_model_enable': openapi.Schema(type=openapi.TYPE_STRING, title=_("Is text-to-speech enabled"),
description=_("Is text-to-speech enabled")),
'tts_type': openapi.Schema(type=openapi.TYPE_STRING, title=_("Text-to-speech type"),
description=_("Text-to-speech type")),
'work_flow': ApplicationApi.WorkFlow.get_request_body_api(),
}
)
class Query(ApiMixin):
@staticmethod
def get_request_params_api():

View File

@ -319,6 +319,15 @@ class ChatApi(ApiMixin):
}
)
@staticmethod
def get_response_body_api():
return openapi.Schema(
type=openapi.TYPE_STRING,
title=_("Conversation ID"),
description=_("Conversation ID"),
default="chat_id"
)
@staticmethod
def get_request_params_api():
return [openapi.Parameter(name='application_id',

View File

@ -373,7 +373,8 @@ class Application(APIView):
operation_id=_("Modify application API_KEY"),
tags=[_('Application/API_KEY')],
manual_parameters=ApplicationApi.ApiKey.Operate.get_request_params_api(),
request_body=ApplicationApi.ApiKey.Operate.get_request_body_api())
request_body=ApplicationApi.ApiKey.Operate.get_request_body_api(),
responses=result.get_api_response(ApplicationApi.ApiKey.Operate.get_response_body_api()))
@has_permissions(ViewPermission(
[RoleConstants.ADMIN, RoleConstants.USER],
[lambda r, keywords: Permission(group=Group.APPLICATION, operate=Operate.MANAGE,
@ -415,7 +416,8 @@ class Application(APIView):
operation_id=_("Modify Application AccessToken"),
tags=[_('Application/Public Access')],
manual_parameters=ApplicationApi.AccessToken.get_request_params_api(),
request_body=ApplicationApi.AccessToken.get_request_body_api())
request_body=ApplicationApi.AccessToken.get_request_body_api(),
responses=result.get_api_response(ApplicationApi.AccessToken.get_response_body_api()))
@has_permissions(ViewPermission(
[RoleConstants.ADMIN, RoleConstants.USER],
[lambda r, keywords: Permission(group=Group.APPLICATION, operate=Operate.MANAGE,
@ -455,6 +457,7 @@ class Application(APIView):
@swagger_auto_schema(operation_summary=_("Application Certification"),
operation_id=_("Application Certification"),
request_body=ApplicationApi.Authentication.get_request_body_api(),
responses=result.get_api_response(ApplicationApi.Authentication.get_response_body_api()),
tags=[_("Application/Certification")],
security=[])
def post(self, request: Request):
@ -472,6 +475,7 @@ class Application(APIView):
@swagger_auto_schema(operation_summary=_("Create an application"),
operation_id=_("Create an application"),
request_body=ApplicationApi.Create.get_request_body_api(),
responses=result.get_api_response(ApplicationApi.Create.get_response_body_api()),
tags=[_('Application')])
@has_permissions(PermissionConstants.APPLICATION_CREATE, compare=CompareConstants.AND)
@log(menu='Application', operate="Create an application",

View File

@ -94,6 +94,7 @@ class ChatView(APIView):
@swagger_auto_schema(operation_summary=_("Get the workflow temporary session id"),
operation_id=_("Get the workflow temporary session id"),
request_body=ChatApi.OpenWorkFlowTemp.get_request_body_api(),
responses=result.get_api_response(ChatApi.OpenTempChat.get_response_body_api()),
tags=[_("Application/Chat")])
def post(self, request: Request):
return result.success(ChatSerializers.OpenWorkFlowChat(
@ -106,6 +107,7 @@ class ChatView(APIView):
@swagger_auto_schema(operation_summary=_("Get a temporary session id"),
operation_id=_("Get a temporary session id"),
request_body=ChatApi.OpenTempChat.get_request_body_api(),
responses=result.get_api_response(ChatApi.OpenTempChat.get_response_body_api()),
tags=[_("Application/Chat")])
@has_permissions(RoleConstants.ADMIN, RoleConstants.USER)
def post(self, request: Request):
@ -239,9 +241,10 @@ class ChatView(APIView):
@swagger_auto_schema(operation_summary=_("Client modifies dialogue summary"),
operation_id=_("Client modifies dialogue summary"),
request_body=ChatClientHistoryApi.Operate.ReAbstract.get_request_body_api(),
responses=result.get_default_response(),
tags=[_("Application/Conversation Log")])
@has_permissions(ViewPermission(
[RoleConstants.APPLICATION_ACCESS_TOKEN],
[RoleConstants.APPLICATION_ACCESS_TOKEN, RoleConstants.ADMIN, RoleConstants.USER],
[lambda r, keywords: Permission(group=Group.APPLICATION, operate=Operate.USE,
dynamic_tag=keywords.get('application_id'))],
compare=CompareConstants.AND),
@ -418,6 +421,7 @@ class ChatView(APIView):
operation_id=_("Add to Knowledge Base"),
manual_parameters=ImproveApi.get_request_params_api_post(),
request_body=ImproveApi.get_request_body_api_post(),
responses=result.get_default_response(),
tags=[_("Application/Conversation Log/Add to Knowledge Base")]
)
@has_permissions(

View File

@ -7,13 +7,12 @@
@desc:
"""
import os
import pickle
import subprocess
import sys
import uuid
from textwrap import dedent
from diskcache import Cache
from smartdoc.const import BASE_DIR
from smartdoc.const import PROJECT_DIR
@ -37,6 +36,8 @@ class FunctionExecutor:
old_mask = os.umask(0o077)
try:
os.makedirs(self.sandbox_path, 0o700, exist_ok=True)
os.makedirs(os.path.join(self.sandbox_path, 'execute'), 0o700, exist_ok=True)
os.makedirs(os.path.join(self.sandbox_path, 'result'), 0o700, exist_ok=True)
finally:
os.umask(old_mask)
@ -44,10 +45,11 @@ class FunctionExecutor:
_id = str(uuid.uuid1())
success = '{"code":200,"msg":"成功","data":exec_result}'
err = '{"code":500,"msg":str(e),"data":None}'
path = r'' + self.sandbox_path + ''
result_path = f'{self.sandbox_path}/result/{_id}.result'
_exec_code = f"""
try:
import os
import pickle
env = dict(os.environ)
for key in list(env.keys()):
if key in os.environ and (key.startswith('MAXKB') or key.startswith('POSTGRES') or key.startswith('PG')):
@ -60,13 +62,11 @@ try:
for local in locals_v:
globals_v[local] = locals_v[local]
exec_result=f(**keywords)
from diskcache import Cache
cache = Cache({path!a})
cache.set({_id!a},{success})
with open({result_path!a}, 'wb') as file:
file.write(pickle.dumps({success}))
except Exception as e:
from diskcache import Cache
cache = Cache({path!a})
cache.set({_id!a},{err})
with open({result_path!a}, 'wb') as file:
file.write(pickle.dumps({err}))
"""
if self.sandbox:
subprocess_result = self._exec_sandbox(_exec_code, _id)
@ -74,18 +74,18 @@ except Exception as e:
subprocess_result = self._exec(_exec_code)
if subprocess_result.returncode == 1:
raise Exception(subprocess_result.stderr)
cache = Cache(self.sandbox_path)
result = cache.get(_id)
cache.delete(_id)
with open(result_path, 'rb') as file:
result = pickle.loads(file.read())
os.remove(result_path)
if result.get('code') == 200:
return result.get('data')
raise Exception(result.get('msg'))
def _exec_sandbox(self, _code, _id):
exec_python_file = f'{self.sandbox_path}/{_id}.py'
exec_python_file = f'{self.sandbox_path}/execute/{_id}.py'
with open(exec_python_file, 'w') as file:
file.write(_code)
os.system(f"chown {self.user}:{self.user} {exec_python_file}")
os.system(f"chown {self.user}:root {exec_python_file}")
kwargs = {'cwd': BASE_DIR}
subprocess_result = subprocess.run(
['su', '-s', python_directory, '-c', "exec(open('" + exec_python_file + "').read())", self.user],

View File

@ -2,6 +2,7 @@ UPDATE "document"
SET "char_length" = ( SELECT CASE WHEN
"sum" ( "char_length" ( "content" ) ) IS NULL THEN
0 ELSE "sum" ( "char_length" ( "content" ) )
END FROM paragraph WHERE "document_id" = %s )
END FROM paragraph WHERE "document_id" = %s ),
"update_time" = CURRENT_TIMESTAMP
WHERE
"id" = %s

View File

@ -181,6 +181,7 @@ class Dataset(APIView):
@swagger_auto_schema(operation_summary=_('Generate related'), operation_id=_('Generate related'),
manual_parameters=DataSetSerializers.Operate.get_request_params_api(),
request_body=GenerateRelatedSerializer.get_request_body_api(),
responses=result.get_default_response(),
tags=[_('Knowledge Base')]
)
@log(menu='document', operate="Generate related documents",

View File

@ -195,6 +195,53 @@ class FunctionLibApi(ApiMixin):
}
)
@staticmethod
def get_response_body_api():
return openapi.Schema(
type=openapi.TYPE_OBJECT,
required=['id', 'name', 'code', 'input_field_list', 'permission_type'],
properties={
'id': openapi.Schema(type=openapi.TYPE_STRING, title="", description=_('ID')),
'name': openapi.Schema(type=openapi.TYPE_STRING, title=_('function name'),
description=_('function name')),
'desc': openapi.Schema(type=openapi.TYPE_STRING, title=_('function description'),
description=_('function description')),
'code': openapi.Schema(type=openapi.TYPE_STRING, title=_('function content'),
description=_('function content')),
'permission_type': openapi.Schema(type=openapi.TYPE_STRING, title=_('permission'),
description=_('permission')),
'is_active': openapi.Schema(type=openapi.TYPE_BOOLEAN, title=_('Is active'),
description=_('Is active')),
'input_field_list': openapi.Schema(type=openapi.TYPE_ARRAY,
description=_('Input variable list'),
items=openapi.Schema(type=openapi.TYPE_OBJECT,
required=['name', 'is_required', 'source'],
properties={
'name': openapi.Schema(
type=openapi.TYPE_STRING,
title=_('variable name'),
description=_('variable name')),
'is_required': openapi.Schema(
type=openapi.TYPE_BOOLEAN,
title=_('required'),
description=_('required')),
'type': openapi.Schema(
type=openapi.TYPE_STRING,
title=_('type'),
description=_(
'Field type string|int|dict|array|float')
),
'source': openapi.Schema(
type=openapi.TYPE_STRING,
title=_('source'),
description=_(
'The source only supports custom|reference')),
}))
}
)
class Export(ApiMixin):
@staticmethod
def get_request_params_api():
@ -214,4 +261,4 @@ class FunctionLibApi(ApiMixin):
type=openapi.TYPE_FILE,
required=True,
description=_('Upload image files'))
]
]

View File

@ -44,6 +44,7 @@ class FunctionLibView(APIView):
@swagger_auto_schema(operation_summary=_('Create function'),
operation_id=_('Create function'),
request_body=FunctionLibApi.Create.get_request_body_api(),
responses=result.get_api_response(FunctionLibApi.Create.get_response_body_api()),
tags=[_('Function')])
@has_permissions(RoleConstants.ADMIN, RoleConstants.USER)
@log(menu='Function', operate="Create function",
@ -58,6 +59,7 @@ class FunctionLibView(APIView):
@swagger_auto_schema(operation_summary=_('Debug function'),
operation_id=_('Debug function'),
request_body=FunctionLibApi.Debug.get_request_body_api(),
responses=result.get_default_response(),
tags=[_('Function')])
@has_permissions(RoleConstants.ADMIN, RoleConstants.USER)
def post(self, request: Request):
@ -72,6 +74,7 @@ class FunctionLibView(APIView):
@swagger_auto_schema(operation_summary=_('Update function'),
operation_id=_('Update function'),
request_body=FunctionLibApi.Edit.get_request_body_api(),
responses=result.get_api_response(FunctionLibApi.Edit.get_request_body_api()),
tags=[_('Function')])
@has_permissions(RoleConstants.ADMIN, RoleConstants.USER)
@log(menu='Function', operate="Update function",
@ -84,6 +87,7 @@ class FunctionLibView(APIView):
@action(methods=['DELETE'], detail=False)
@swagger_auto_schema(operation_summary=_('Delete function'),
operation_id=_('Delete function'),
responses=result.get_default_response(),
tags=[_('Function')])
@has_permissions(RoleConstants.ADMIN, RoleConstants.USER)
@log(menu='Function', operate="Delete function",

View File

@ -26,6 +26,7 @@ class PyLintView(APIView):
@swagger_auto_schema(operation_summary=_('Check code'),
operation_id=_('Check code'),
request_body=PyLintApi.get_request_body_api(),
responses=result.get_api_response(PyLintApi.get_request_body_api()),
tags=[_('Function')])
@has_permissions(RoleConstants.ADMIN, RoleConstants.USER)
def post(self, request: Request):

View File

@ -13,7 +13,7 @@ from google.ai.generativelanguage_v1beta.types import (
Tool as GoogleTool,
)
from langchain_core.callbacks import CallbackManagerForLLMRun
from langchain_core.messages import BaseMessage
from langchain_core.messages import BaseMessage, get_buffer_string
from langchain_core.outputs import ChatGenerationChunk
from langchain_google_genai import ChatGoogleGenerativeAI
from langchain_google_genai._function_utils import _ToolConfigDict, _ToolDict
@ -22,6 +22,8 @@ from langchain_google_genai.chat_models import _chat_with_retry, _response_to_re
from langchain_google_genai._common import (
SafetySettingDict,
)
from common.config.tokenizer_manage_config import TokenizerManage
from setting.models_provider.base_model_provider import MaxKBBaseModel
@ -46,10 +48,18 @@ class GeminiChatModel(MaxKBBaseModel, ChatGoogleGenerativeAI):
return self.__dict__.get('_last_generation_info')
def get_num_tokens_from_messages(self, messages: List[BaseMessage]) -> int:
return self.get_last_generation_info().get('input_tokens', 0)
try:
return self.get_last_generation_info().get('input_tokens', 0)
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:
return self.get_last_generation_info().get('output_tokens', 0)
try:
return self.get_last_generation_info().get('output_tokens', 0)
except Exception as e:
tokenizer = TokenizerManage.get_tokenizer()
return len(tokenizer.encode(text))
def _stream(
self,

View File

@ -22,6 +22,9 @@ class XInferenceReranker(MaxKBBaseModel, BaseDocumentCompressor):
"""UID of the launched model"""
api_key: Optional[str]
@staticmethod
def is_cache_model():
return False
@staticmethod
def new_instance(model_type, model_name, model_credential: Dict[str, object], **model_kwargs):
return XInferenceReranker(server_url=model_credential.get('server_url'), model_uid=model_name,

View File

@ -171,6 +171,24 @@ class TeamMemberSerializer(ApiMixin, serializers.Serializer):
}
)
@staticmethod
def get_response_body_api():
return openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
'id': openapi.Schema(type=openapi.TYPE_STRING, title=_('user id'), description=_('user id')),
'username': openapi.Schema(type=openapi.TYPE_STRING, title=_('Username'), description=_('Username')),
'email': openapi.Schema(type=openapi.TYPE_STRING, title=_('Email'), description=_('Email')),
'role': openapi.Schema(type=openapi.TYPE_STRING, title=_('Role'), description=_('Role')),
'is_active': openapi.Schema(type=openapi.TYPE_STRING, title=_('Is active'),
description=_('Is active')),
'team_id': openapi.Schema(type=openapi.TYPE_STRING, title=_('team id'), description=_('team id')),
'user_id': openapi.Schema(type=openapi.TYPE_STRING, title=_('user id'), description=_('user id')),
'type': openapi.Schema(type=openapi.TYPE_STRING, title=_('member type'),
description=_('member type manage|member')),
}
)
@transaction.atomic
def batch_add_member(self, user_id_list: List[str], with_valid=True):
"""

View File

@ -38,6 +38,7 @@ class TeamMember(APIView):
@swagger_auto_schema(operation_summary=_('Add member'),
operation_id=_('Add member'),
request_body=TeamMemberSerializer().get_request_body_api(),
responses=result.get_default_response(),
tags=[_('Team')])
@has_permissions(PermissionConstants.TEAM_CREATE)
@log(menu='Team', operate='Add member',
@ -53,6 +54,7 @@ class TeamMember(APIView):
@swagger_auto_schema(operation_summary=_('Add members in batches'),
operation_id=_('Add members in batches'),
request_body=TeamMemberSerializer.get_bach_request_body_api(),
responses=result.get_api_array_response(TeamMemberSerializer.get_response_body_api()),
tags=[_('Team')])
@has_permissions(PermissionConstants.TEAM_CREATE)
@log(menu='Team', operate='Add members in batches',
@ -78,6 +80,7 @@ class TeamMember(APIView):
@swagger_auto_schema(operation_summary=_('Update team member permissions'),
operation_id=_('Update team member permissions'),
request_body=UpdateTeamMemberPermissionSerializer().get_request_body_api(),
responses=result.get_default_response(),
manual_parameters=TeamMemberSerializer.Operate.get_request_params_api(),
tags=[_('Team')]
)
@ -93,6 +96,7 @@ class TeamMember(APIView):
@swagger_auto_schema(operation_summary=_('Remove member'),
operation_id=_('Remove member'),
manual_parameters=TeamMemberSerializer.Operate.get_request_params_api(),
responses=result.get_default_response(),
tags=[_('Team')]
)
@has_permissions(PermissionConstants.TEAM_DELETE)

View File

@ -31,7 +31,8 @@ class Model(APIView):
@action(methods=['POST'], detail=False)
@swagger_auto_schema(operation_summary=_('Create model'),
operation_id=_('Create model'),
request_body=ModelCreateApi.get_request_body_api()
request_body=ModelCreateApi.get_request_body_api(),
manual_parameters=result.get_api_response(ModelCreateApi.get_request_body_api())
, tags=[_('model')])
@has_permissions(PermissionConstants.MODEL_CREATE)
@log(menu='model', operate='Create model',
@ -45,7 +46,8 @@ class Model(APIView):
@action(methods=['PUT'], detail=False)
@swagger_auto_schema(operation_summary=_('Download model, trial only with Ollama platform'),
operation_id=_('Download model, trial only with Ollama platform'),
request_body=ModelCreateApi.get_request_body_api()
request_body=ModelCreateApi.get_request_body_api(),
responses=result.get_api_response(ModelCreateApi.get_request_body_api())
, tags=[_('model')])
@has_permissions(PermissionConstants.MODEL_CREATE)
def put(self, request: Request):
@ -123,7 +125,8 @@ class Model(APIView):
@action(methods=['PUT'], detail=False)
@swagger_auto_schema(operation_summary=_('Update model'),
operation_id=_('Update model'),
request_body=ModelEditApi.get_request_body_api()
request_body=ModelEditApi.get_request_body_api(),
responses=result.get_api_response(ModelEditApi.get_request_body_api())
, tags=[_('model')])
@has_permissions(PermissionConstants.MODEL_CREATE)
@log(menu='model', operate='Update model',
@ -166,7 +169,8 @@ class Provide(APIView):
@swagger_auto_schema(operation_summary=_('Call the supplier function to obtain form data'),
operation_id=_('Call the supplier function to obtain form data'),
manual_parameters=ProvideApi.get_request_params_api(),
request_body=ProvideApi.get_request_body_api()
request_body=ProvideApi.get_request_body_api(),
responses=result.get_api_response(ProvideApi.get_request_body_api())
, tags=[_('model')])
@has_permissions(PermissionConstants.MODEL_READ)
@log(menu='model', operate='Call the supplier function to obtain form data')

View File

@ -84,7 +84,7 @@ class SwitchUserLanguageView(APIView):
description=_("language")),
}
),
responses=RePasswordSerializer().get_response_body_api(),
responses=result.get_default_response(),
tags=[_("User management")])
@log(menu='User management', operate='Switch Language',
get_operation_object=lambda r, k: {'name': r.user.username})
@ -111,7 +111,7 @@ class ResetCurrentUserPasswordView(APIView):
description=_("Password"))
}
),
responses=RePasswordSerializer().get_response_body_api(),
responses=result.get_default_response(),
tags=[_("User management")])
@log(menu='User management', operate='Modify current user password',
get_operation_object=lambda r, k: {'name': r.user.username},

View File

@ -71,7 +71,7 @@ RUN chmod 755 /opt/maxkb/app/installer/run-maxkb.sh && \
chown -R sandbox:root /opt/maxkb/app/sandbox && \
chmod g-x /usr/local/bin/* /usr/bin/* /bin/* /usr/sbin/* /sbin/* /usr/lib/postgresql/15/bin/* && \
chmod g+x /usr/local/bin/python* && \
chmod g-rx /etc
find /etc/ -type f ! -path '/etc/resolv.conf' ! -path '/etc/hosts' | xargs chmod g-rx
EXPOSE 8080

View File

@ -36,7 +36,7 @@ const getMemberPermissions: (member_id: String) => Promise<Result<any>> = (membe
}
/**
*
*
* @param member_id
* @param {
"team_member_permission_list": [

View File

@ -266,7 +266,7 @@ export default {
label: '文本转语音',
text: '将文本通过语音合成模型转换为音频',
tts_model: {
label: '语音识别模型'
label: '语音合成模型'
},
content: {
label: '选择文本内容'

View File

@ -135,51 +135,4 @@ onMounted(() => {
})
</script>
<style lang="scss" scoped>
.p-16-24 {
padding: 16px 24px;
}
.mb-16 {
margin-bottom: 16px;
}
.flex-between {
display: flex;
justify-content: space-between;
align-items: center;
}
.flex {
display: flex;
}
.align-center {
align-items: center;
}
.ml-8 {
margin-left: 8px;
}
.mr-8 {
margin-right: 8px;
}
.ml-12 {
margin-left: 12px;
}
.mr-4 {
margin-right: 4px;
}
.cursor {
cursor: pointer;
}
.icon {
width: 32px; //
height: 32px; //
}
</style>
<style lang="scss" scoped></style>

View File

@ -214,8 +214,4 @@ onMounted(() => {
getList()
})
</script>
<style lang="scss" scoped>
.log-table tr {
cursor: pointer;
}
</style>
<style lang="scss" scoped></style>