Skip to content

Commit e47e0e8

Browse files
feat: Add parameter configuration functionality
1 parent 9deca7e commit e47e0e8

File tree

10 files changed

+363
-89
lines changed

10 files changed

+363
-89
lines changed

backend/apps/api.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from apps.data_training.api import data_training
66
from apps.datasource.api import datasource, table_relation, recommended_problem
77
from apps.mcp import mcp
8-
from apps.system.api import login, user, aimodel, workspace, assistant
8+
from apps.system.api import login, user, aimodel, workspace, assistant, parameter
99
from apps.terminology.api import terminology
1010
from apps.settings.api import base
1111

@@ -23,5 +23,6 @@
2323
api_router.include_router(dashboard_api.router)
2424
api_router.include_router(mcp.router)
2525
api_router.include_router(table_relation.router)
26+
api_router.include_router(parameter.router)
2627

2728
api_router.include_router(recommended_problem.router)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
from fastapi import APIRouter, Request
3+
from sqlbot_xpack.config.model import SysArgModel
4+
5+
6+
from apps.system.crud.parameter_manage import get_parameter_args, save_parameter_args
7+
from common.core.deps import SessionDep
8+
9+
router = APIRouter(tags=["system/parameter"], prefix="/system/parameter")
10+
11+
@router.get("")
12+
async def get_args(session: SessionDep) -> list[SysArgModel]:
13+
return await get_parameter_args(session)
14+
15+
@router.post("", )
16+
async def save_args(session: SessionDep, request: Request):
17+
return await save_parameter_args(session = session, request = request)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from fastapi import Request
2+
from sqlbot_xpack.config.arg_manage import get_group_args, save_group_args
3+
from sqlbot_xpack.config.model import SysArgModel
4+
import json
5+
from common.core.deps import SessionDep
6+
from sqlbot_xpack.file_utils import SQLBotFileUtils
7+
8+
async def get_parameter_args(session: SessionDep) -> list[SysArgModel]:
9+
group_args = await get_group_args(session=session)
10+
return [x for x in group_args if not x.pkey.startswith('appearance.')]
11+
12+
async def save_parameter_args(session: SessionDep, request: Request):
13+
allow_file_mapping = {
14+
""" "test_logo": { "types": [".jpg", ".jpeg", ".png", ".svg"], "size": 5 * 1024 * 1024 } """
15+
}
16+
form_data = await request.form()
17+
files = form_data.getlist("files")
18+
json_text = form_data.get("data")
19+
sys_args = [
20+
SysArgModel(**{**item, "pkey": f"{item['pkey']}"})
21+
for item in json.loads(json_text)
22+
if "pkey" in item
23+
]
24+
if not sys_args:
25+
return
26+
file_mapping = None
27+
if files:
28+
file_mapping = {}
29+
for file in files:
30+
origin_file_name = file.filename
31+
file_name, flag_name = SQLBotFileUtils.split_filename_and_flag(origin_file_name)
32+
file.filename = file_name
33+
allow_limit_obj = allow_file_mapping.get(flag_name)
34+
if allow_limit_obj:
35+
SQLBotFileUtils.check_file(file=file, file_types=allow_limit_obj.get("types"), limit_file_size=allow_limit_obj.get("size"))
36+
else:
37+
raise Exception(f'The file [{file_name}] is not allowed to be uploaded!')
38+
file_id = await SQLBotFileUtils.upload(file)
39+
file_mapping[f"{flag_name}"] = file_id
40+
41+
await save_group_args(session=session, sys_args=sys_args, file_mapping=file_mapping)

frontend/src/i18n/en.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@
1414
"rows_of_data": "Limit 1000 Rows of Data",
1515
"third_party_platform_settings": "Third-Party Platform Settings",
1616
"by_third_party_platform": "Automatic User Creation by Third-Party Platform",
17-
"platform_user_organization": "Third-Party Platform User Organization",
17+
"platform_user_organization": "Third-Party Platform Workspace",
1818
"platform_user_roles": "Third-Party Platform User Roles",
1919
"excessive_data_volume": "Disabling the 1000-row data limit may cause system lag due to excessive data volume.",
2020
"prompt": "Prompt",
2121
"disabling_successfully": "Disabling Successfully",
2222
"closed_by_default": "In the Question Count window, control whether the model thinking process is expanded or closed by default.",
23-
"and_platform_integration": "Scope includes authentication settings and platform integration."
23+
"and_platform_integration": "Scope includes authentication settings and platform integration.",
24+
"login_settings": "Login Settings",
25+
"default_login": "Default Login Method"
2426
},
2527
"prompt": {
2628
"default_password": "Default password:{msg}",
@@ -816,4 +818,4 @@
816818
"modelType": {
817819
"llm": "Large Language Model"
818820
}
819-
}
821+
}

frontend/src/i18n/ko-KR.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@
1414
"rows_of_data": "데이터 1,000행 제한",
1515
"third_party_platform_settings": "타사 플랫폼 설정",
1616
"by_third_party_platform": "타사 플랫폼에 의한 자동 사용자 생성",
17-
"platform_user_organization": "타사 플랫폼 사용자 구성",
17+
"platform_user_organization": "제3자 플랫폼 작업 공간",
1818
"platform_user_roles": "타사 플랫폼 사용자 역할",
1919
"excessive_data_volume": "1,000행 데이터 제한을 비활성화하면 과도한 데이터 양으로 인해 시스템 지연이 발생할 수 있습니다.",
2020
"prompt": "프롬프트",
2121
"disabling_successfully": "비활성화 완료",
2222
"closed_by_default": "질문 수 창에서 모델 사고 프로세스를 기본적으로 확장할지 또는 닫을지 여부를 제어합니다.",
23-
"and_platform_integration": "범위에는 인증 설정 및 플랫폼 통합이 포함됩니다."
23+
"and_platform_integration": "범위에는 인증 설정 및 플랫폼 통합이 포함됩니다.",
24+
"login_settings": "로그인 설정",
25+
"default_login": "기본 로그인 방식"
2426
},
2527
"prompt": {
2628
"default_password:": "기본 비밀번호:{msg}",
@@ -816,4 +818,4 @@
816818
"modelType": {
817819
"llm": "대형 언어 모델"
818820
}
819-
}
821+
}

frontend/src/i18n/zh-CN.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@
1414
"rows_of_data": "限制 1000 行数据",
1515
"third_party_platform_settings": "第三方平台设置",
1616
"by_third_party_platform": "第三方自动创建用户",
17-
"platform_user_organization": "第三方平台用户组织",
17+
"platform_user_organization": "第三方平台工作空间",
1818
"platform_user_roles": "第三方平台用户角色",
1919
"excessive_data_volume": "关闭1000行的数据限制后,数据量过大,可能会造成系统卡顿",
2020
"prompt": "提示",
2121
"disabling_successfully": "关闭成功",
2222
"closed_by_default": "在问数窗口中,控制模型思考过程默认展开或者关闭",
23-
"and_platform_integration": "作用域包括认证设置和平台对接"
23+
"and_platform_integration": "作用域包括认证设置和平台对接",
24+
"login_settings": "登录设置",
25+
"default_login": "默认登录方式"
2426
},
2527
"prompt": {
2628
"default_password": "默认密码:{msg}",
@@ -817,4 +819,4 @@
817819
"modelType": {
818820
"llm": "大语言模型"
819821
}
820-
}
822+
}

frontend/src/router/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ export const routes = [
9595
},
9696
{
9797
path: '/set',
98+
name: 'set',
9899
component: LayoutDsl,
99100
redirect: '/set/member',
100101
meta: { title: t('workspace.set'), iconActive: 'set', iconDeActive: 'noSet' },
@@ -145,6 +146,7 @@ export const routes = [
145146
},
146147
{
147148
path: '/system',
149+
name: 'system',
148150
component: LayoutDsl,
149151
redirect: '/system/user',
150152
meta: { hidden: true },

frontend/src/utils/utils.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,3 +263,22 @@ export const getSQLBotAddr = (portEnd?: boolean) => {
263263
}
264264
return addr.substring(0, addr.length - 1)
265265
}
266+
267+
export const formatArg = (text: string) => {
268+
if (!text) {
269+
return false
270+
}
271+
const mappingArray = ['true', 'false', '1', '0']
272+
const match = mappingArray.some((item: string) => {
273+
return item === text.toLocaleLowerCase()
274+
})
275+
if (!match) {
276+
return text
277+
}
278+
try {
279+
return JSON.parse(text)
280+
} catch (e: any) {
281+
console.warn(e)
282+
return text
283+
}
284+
}

frontend/src/views/system/parameter/index.vue

Lines changed: 57 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,63 @@
11
<script lang="ts" setup>
2-
import { ref, shallowRef } from 'vue'
2+
import { onMounted, provide, reactive, unref } from 'vue'
33
import icon_info_outlined_1 from '@/assets/svg/icon_info_outlined_1.svg'
44
import { useI18n } from 'vue-i18n'
5-
5+
import PlatformParam from './xpack/PlatformParam.vue'
6+
import { request } from '@/utils/request'
7+
import { formatArg } from '@/utils/utils'
68
const { t } = useI18n()
79
8-
const chatSetting = ref({
9-
modelThinkingProcess: false,
10-
rows_of_data: false,
10+
const state = reactive({
11+
parameterForm: reactive<any>({
12+
'chat.enable_model_thinking': false,
13+
'chat.rows_of_data': false,
14+
}),
1115
})
12-
13-
const platform = ref({
14-
organization: false,
15-
modelThinkingProcess: false,
16-
roles: [],
16+
provide('parameterForm', state.parameterForm)
17+
const loadData = () => {
18+
request.get('/system/parameter').then((res: any) => {
19+
if (res) {
20+
res.forEach((item: any) => {
21+
if (
22+
item.pkey?.startsWith('chat') ||
23+
item.pkey?.startsWith('login') ||
24+
item.pkey?.startsWith('platform')
25+
) {
26+
state.parameterForm[item.pkey] = formatArg(item.pval)
27+
}
28+
})
29+
console.log(state.parameterForm)
30+
}
31+
})
32+
}
33+
const buildParam = () => {
34+
const changedItemArray = Object.keys(state.parameterForm).map((key: string) => {
35+
return {
36+
pkey: key,
37+
pval: Object.prototype.hasOwnProperty.call(state.parameterForm, 'key')
38+
? state.parameterForm[key].toString()
39+
: state.parameterForm[key],
40+
}
41+
})
42+
const formData = new FormData()
43+
formData.append('data', JSON.stringify(unref(changedItemArray)))
44+
return formData
45+
}
46+
const saveHandler = () => {
47+
const param = buildParam()
48+
request
49+
.post('/system/parameter', param, {
50+
headers: {
51+
'Content-Type': 'multipart/form-data',
52+
},
53+
})
54+
.then(() => {
55+
ElMessage.success(t('common.save_success'))
56+
})
57+
}
58+
onMounted(() => {
59+
loadData()
1760
})
18-
19-
const organizations = shallowRef<any[]>([])
20-
const roles = shallowRef<any[]>([])
2161
</script>
2262

2363
<template>
@@ -41,7 +81,7 @@ const roles = shallowRef<any[]>([])
4181
</el-tooltip>
4282
</div>
4383
<div class="value">
44-
<el-switch v-model="chatSetting.modelThinkingProcess" />
84+
<el-switch v-model="state.parameterForm['chat.enable_model_thinking']" />
4585
</div>
4686
</div>
4787

@@ -59,77 +99,15 @@ const roles = shallowRef<any[]>([])
5999
</el-tooltip>
60100
</div>
61101
<div class="value">
62-
<el-switch v-model="chatSetting.rows_of_data" />
102+
<el-switch v-model="state.parameterForm['chat.rows_of_data']" />
63103
</div>
64104
</div>
65105
</div>
66106

67-
<div class="card">
68-
<div class="card-title">
69-
{{ t('parameter.third_party_platform_settings') }}
70-
</div>
71-
<div class="card-item" style="width: 100%">
72-
<div class="label">
73-
{{ t('parameter.by_third_party_platform') }}
74-
</div>
75-
<div class="value">
76-
<el-switch v-model="platform.modelThinkingProcess" />
77-
</div>
78-
</div>
79-
<div class="card-item">
80-
<div class="label">
81-
{{ t('parameter.platform_user_organization') }}
82-
<span class="require"></span>
83-
<el-tooltip
84-
effect="dark"
85-
:content="t('parameter.and_platform_integration')"
86-
placement="top"
87-
>
88-
<el-icon size="16">
89-
<icon_info_outlined_1></icon_info_outlined_1>
90-
</el-icon>
91-
</el-tooltip>
92-
</div>
93-
<div class="value">
94-
<el-select filterable v-model="platform.organization">
95-
<el-option
96-
v-for="item in organizations"
97-
:key="item.value"
98-
:label="item.label"
99-
:value="item.value"
100-
/>
101-
</el-select>
102-
</div>
103-
</div>
104-
<div class="card-item" style="margin-left: 16px">
105-
<div class="label">
106-
{{ t('parameter.platform_user_roles') }}
107-
<span class="require"></span>
108-
<el-tooltip
109-
effect="dark"
110-
:content="t('parameter.and_platform_integration')"
111-
placement="top"
112-
>
113-
<el-icon size="16">
114-
<icon_info_outlined_1></icon_info_outlined_1>
115-
</el-icon>
116-
</el-tooltip>
117-
</div>
118-
<div class="value">
119-
<el-select multiple filterable v-model="platform.roles">
120-
<el-option
121-
v-for="item in roles"
122-
:key="item.value"
123-
:label="item.label"
124-
:value="item.value"
125-
/>
126-
</el-select>
127-
</div>
128-
</div>
129-
</div>
107+
<platform-param />
130108
</div>
131109
<div class="save" style="margin-top: 16px">
132-
<el-button type="primary">{{ t('common.save') }}</el-button>
110+
<el-button type="primary" @click="saveHandler">{{ t('common.save') }}</el-button>
133111
</div>
134112
</div>
135113
</template>

0 commit comments

Comments
 (0)