diff --git a/src/frontend/public/locales/en/bs.json b/src/frontend/public/locales/en/bs.json index b101a7da..7c9f1d17 100644 --- a/src/frontend/public/locales/en/bs.json +++ b/src/frontend/public/locales/en/bs.json @@ -87,7 +87,9 @@ "maximum": "Up to", "perMinute": "simultaneous online sessions", "changeTime": "Modification Time", - "deleteGroup": "After deletion 【{{name}}】 will no longer exist, Do you want to delete it?" + "deleteGroup": "After deletion 【{{name}}】 will no longer exist, Do you want to delete it?", + "currentGroup": "Current UserGroup", + "defaultGroup": "DefaultGroup" }, "skills": { "manageTemplate": "Manage Skill Templates", @@ -478,7 +480,7 @@ "skillsReplaced": "Skills replaced", "allReplaced": "All replaced", "basicConfiguration": "Basic configuration", - "modelConfiguration": "AI Model configuration", + "modelConfiguration": "AI Model Configuration", "model": "Model", "temperature": "Temperature", "openingIntroduction": "Opening Introduction", @@ -522,7 +524,28 @@ "cancel": "Cancel", "confirm": "Confirm", "forBetter": "For better assistant effect, the description needs to be greater than 20 words", - "forExample": "For example, the identity of an assistant, specific methods and steps for completing tasks, tone of voice when answering questions, and what issues to pay attention to, etc" + "forExample": "For example, the identity of an assistant, specific methods and steps for completing tasks, tone of voice when answering questions, and what issues to pay attention to, etc", + "contentSecurityR": "Content Security Review", + "errors": { + "selectAtLeastOneWordType": "At least one word type must be selected", + "autoReplyNotEmpty": "Auto-reply content cannot be empty" + }, + "saveSuccess": "Saved successfully", + "contentSecurity": "Content Security", + "contentSecurityDesc": "Review session content for safety with a sensitive word list or API", + "contentSecuritySettings": "Content Security Review Settings", + "enableContentSecurityReview": "Enable Content Security Review", + "reviewType": "Review Type", + "sensitiveWordListMatch": "Sensitive Word List Match", + "modelReview": "Model Review", + "wordListType": "Word List Type", + "builtinWordList": "Built-in Word List", + "customWordList": "Custom Word List", + "autoReplyContent": "Auto-reply Content", + "useNewlineToSeparate": "Use newline to separate, each line one item", + "txtFile": "txt file", + "sensitiveWordMatch": "Sensitive Word Match", + "defaultAutoReply": "Enter the auto-reply content for when the safety review is triggered, e.g., 'The current conversation content violates relevant regulations, please modify and re-enter.'" }, "tools": { "addTool": "Add Tool", @@ -583,5 +606,24 @@ "resetButton": "Reset Password", "passwordResetSuccess": "Your password has been successfully reset.", "resetFailed": "Pwd Reset Failed" + }, + "log": { + "auditManagement": "Audit Management", + "searchButton": "Search", + "resetButton": "Reset", + "auditId": "Audit ID", + "username": "Username", + "operationTime": "Operation Time", + "systemModule": "System Module", + "operationAction": "Operation Action", + "objectType": "Operation Object Type", + "operationObject": "Operation Object", + "ipAddress": "IP Address", + "remark": "Remark", + "selectUser": "Select User", + "selectUserGroup": "Select User Group", + "startDate": "Start Date", + "endDate": "End Date", + "actionBehavior": "Action Behavior" } } \ No newline at end of file diff --git a/src/frontend/public/locales/zh/bs.json b/src/frontend/public/locales/zh/bs.json index 3af59a60..61f94c40 100644 --- a/src/frontend/public/locales/zh/bs.json +++ b/src/frontend/public/locales/zh/bs.json @@ -88,7 +88,9 @@ "maximum": "最多", "perMinute": "个同时在线会话", "changeTime": "修改时间", - "deleteGroup": "删除后 【{{name}}】 将不再存在,是否删除?" + "deleteGroup": "删除后 【{{name}}】 将不再存在,是否删除?", + "currentGroup": "当前用户组", + "defaultGroup": "默认用户组" }, "skills": { "manageTemplate": "管理技能模板", @@ -519,7 +521,28 @@ "cancel": "取消", "confirm": "确认", "forBetter": "为了更好的助手效果,描述需要大于20 个字", - "forExample": "例如助手的身份、完成任务的具体方法和步骤、回答问题时的语气以及应该注意什么问题等" + "forExample": "例如助手的身份、完成任务的具体方法和步骤、回答问题时的语气以及应该注意什么问题等", + "contentSecurityR": "内容安全审查", + "errors": { + "selectAtLeastOneWordType": "词表至少需要选择一个", + "autoReplyNotEmpty": "自动回复内容不可为空" + }, + "saveSuccess": "保存成功", + "contentSecurity": "内容安全", + "contentSecurityDesc": "通过敏感词表或 API 对会话内容进行安全审查", + "contentSecuritySettings": "内容安全审查设置", + "enableContentSecurityReview": "开启内容安全审查", + "reviewType": "审查类型", + "sensitiveWordListMatch": "敏感词表匹配", + "modelReview": "模型审查", + "wordListType": "词表类型", + "builtinWordList": "内置词表", + "customWordList": "自定义词表", + "autoReplyContent": "自动回复内容", + "useNewlineToSeparate": "使用换行符进行分隔,每行一个", + "txtFile": "txt文件", + "sensitiveWordMatch": "敏感词匹配", + "defaultAutoReply": "填写命中安全审查时的自动回复内容,例如“当前对话内容违反相关规范,请修改后重新输入。" }, "tools": { "addTool": "添加工具", @@ -580,5 +603,24 @@ "resetButton": "重置密码", "passwordResetSuccess": "您的密码已成功重置。", "resetFailed": "密码重置失败" + }, + "log": { + "auditManagement": "审计管理", + "searchButton": "查询", + "resetButton": "重置", + "auditId": "审计ID", + "username": "用户名", + "operationTime": "操作时间", + "systemModule": "系统模块", + "operationAction": "操作行为", + "objectType": "操作对象类型", + "operationObject": "操作对象", + "ipAddress": "IP地址", + "remark": "备注", + "selectUser": "选择用户", + "selectUserGroup": "选择用户组", + "startDate": "开始日期", + "endDate": "结束日期", + "actionBehavior": "操作行为" } } \ No newline at end of file diff --git a/src/frontend/src/components/Pro/security/AssistantSetting.tsx b/src/frontend/src/components/Pro/security/AssistantSetting.tsx index fce16461..c564e99d 100644 --- a/src/frontend/src/components/Pro/security/AssistantSetting.tsx +++ b/src/frontend/src/components/Pro/security/AssistantSetting.tsx @@ -12,88 +12,90 @@ import { QuestionMarkCircledIcon } from "@radix-ui/react-icons"; import { Tooltip, TooltipProvider, TooltipContent, TooltipTrigger } from "@/components/bs-ui/tooltip"; export default function AssistantSetting({ id, type }) { - - const { t } = useTranslation() + const { t } = useTranslation(); const [open, setOpen] = useState(false); - const { toast, message } = useToast() + const { toast, message } = useToast(); const [form, setForm] = useState({ isCheck: false, autoReply: "", words: "", wordsType: [], - }) + }); // load useEffect(() => { - id !== 3 && getSensitiveApi(id, type).then(res => { - const { is_check, auto_reply, words, words_type } = res - setForm({ - isCheck: !!is_check, - autoReply: auto_reply, - words, - wordsType: Array.isArray(words_type) ? words_type : [words_type], - }) - }) - }, [id]) - + if (id !== 3) { + getSensitiveApi(id, type).then(res => { + const { is_check, auto_reply, words, words_type } = res; + setForm({ + isCheck: !!is_check, + autoReply: auto_reply, + words, + wordsType: Array.isArray(words_type) ? words_type : [words_type], + }); + }); + } + }, [id, type]); const handleFormChange = async (_form) => { - const errors = [] - if (_form.wordsType.length === 0) errors.push('词表至少需要选择一个') - if (_form.autoReply === '') errors.push('自动回复内容不可为空') + const errors = []; + if (_form.wordsType.length === 0) errors.push(t('build.errors.selectAtLeastOneWordType')); + if (_form.autoReply === '') errors.push(t('build.errors.autoReplyNotEmpty')); if (errors.length) { - return toast({ title: t('prompt'), variant: 'error', description: errors }) + return toast({ title: t('prompt'), variant: 'error', description: errors.join(', ') }); } - setForm(_form) - await sensitiveSaveApi({ ..._form, id, type }) - message({ title: t('prompt'), variant: 'success', description: '保存成功' }) - } + setForm(_form); + await sensitiveSaveApi({ ..._form, id, type }); + message({ title: t('prompt'), variant: 'success', description: t('build.saveSuccess') }); + }; const onOff = (bln) => { - setForm({ ...form, isCheck: bln }) - sensitiveSaveApi({ ...form, isCheck: bln, id, type }) - if (bln) setOpen(true) - } + setForm({ ...form, isCheck: bln }); + sensitiveSaveApi({ ...form, isCheck: bln, id, type }); + if (bln) setOpen(true); + }; - return - -
-
- 内容安全审查 - - - - - - -

通过敏感词表或 API 对会话内容进行安全审查

-
-
-
-
-
- setOpen(bln)}> - - {form.isCheck && { e.stopPropagation(); setOpen(!open) }} className="w-[32px] h-[32px]" />} - - e.stopPropagation()}> - 内容安全审查设置 - setOpen(false)} onCancel={() => setOpen(false)} /> - - - e.stopPropagation()} - checked={form.isCheck} - onCheckedChange={onOff} - /> + return ( + + +
+
+ {t('build.contentSecurityR')} + + + + + + +

{t('build.contentSecurityDesc')}

+
+
+
+
+
+ setOpen(bln)}> + + {form.isCheck && { e.stopPropagation(); setOpen(!open) }} className="w-[32px] h-[32px]" />} + + e.stopPropagation()}> + {t('build.contentSecuritySettings')} + setOpen(false)} onCancel={() => setOpen(false)} /> + + + e.stopPropagation()} + checked={form.isCheck} + onCheckedChange={onOff} + /> +
-
- - - {form.isCheck && } - - -}; + + + {form.isCheck && } + + + ); +} diff --git a/src/frontend/src/components/Pro/security/FlowSetting.tsx b/src/frontend/src/components/Pro/security/FlowSetting.tsx index 1c15f558..6079eb2b 100644 --- a/src/frontend/src/components/Pro/security/FlowSetting.tsx +++ b/src/frontend/src/components/Pro/security/FlowSetting.tsx @@ -11,17 +11,16 @@ import FormSet from "./FormSet"; import FormView from "./FormView"; export default function FlowSetting({ id, type, isOnline }) { - - const { t } = useTranslation() + const { t } = useTranslation(); const [open, setOpen] = useState(false); - const { toast, message } = useToast() + const { toast, message } = useToast(); const [form, setForm] = useState({ isCheck: false, autoReply: "", words: "", wordsType: [], - }) + }); // load useEffect(() => { @@ -37,62 +36,64 @@ export default function FlowSetting({ id, type, isOnline }) { }, [id]) const handleFormChange = async (_form) => { - const errors = [] - if (_form.wordsType.length === 0) errors.push('词表至少需要选择一个') - if (_form.autoReply === '') errors.push('自动回复内容不可为空') + const errors = []; + if (_form.wordsType.length === 0) errors.push(t('build.errors.selectAtLeastOneWordType')); + if (_form.autoReply === '') errors.push(t('build.errors.autoReplyNotEmpty')); if (errors.length) { - return toast({ title: t('prompt'), variant: 'error', description: errors }) + return toast({ title: t('build.prompt'), variant: 'error', description: errors.join(', ') }); } - setForm(_form) - if (isOnline) return // 在线状态不允许修改 - await sensitiveSaveApi({ ..._form, id, type }) - message({ title: t('prompt'), variant: 'success', description: '保存成功' }) - } + setForm(_form); + if (isOnline) return; // 在线状态不允许修改 + await sensitiveSaveApi({ ..._form, id, type }); + message({ title: t('build.prompt'), variant: 'success', description: t('build.saveSuccess') }); + }; const onOff = (bln) => { - setForm({ ...form, isCheck: bln }) - if (bln) setOpen(true) - if (isOnline) return // 在线状态不允许修改 - sensitiveSaveApi({ ...form, isCheck: bln, id, type }) - } + setForm({ ...form, isCheck: bln }); + if (bln) setOpen(true); + if (isOnline) return; // 在线状态不允许修改 + sensitiveSaveApi({ ...form, isCheck: bln, id, type }); + }; - return
-
+ return ( +
+
{/* 开启内容安全审查 */} -
- 开启内容安全审查 - - - - - - -

通过敏感词表或 API 对会话内容进行安全审查

-
-
-
+
+ {t('build.enableContentSecurityReview')} + + + + + + +

{t('build.contentSecurityDesc')}

+
+
+
+
+
+ setOpen(bln)}> + + {form.isCheck && { e.stopPropagation(); setOpen(!open) }} className="w-[32px] h-[32px]" />} + + e.stopPropagation()}> + {t('build.contentSecuritySettings')} + setOpen(false)} onCancel={() => setOpen(false)} /> + + + e.stopPropagation()} + checked={form.isCheck} + onCheckedChange={onOff} + /> +
-
- setOpen(bln)}> - - {form.isCheck && { e.stopPropagation(); setOpen(!open) }} className="w-[32px] h-[32px]" />} - - e.stopPropagation()}> - 内容安全审查设置 - setOpen(false)} onCancel={() => setOpen(false)} /> - - - e.stopPropagation()} - checked={form.isCheck} - onCheckedChange={onOff} - /> +
+ {form.isCheck && }
-
- {form.isCheck && } -
-
-}; + ); +} diff --git a/src/frontend/src/components/Pro/security/FormSet.tsx b/src/frontend/src/components/Pro/security/FormSet.tsx index 70742210..4289008f 100644 --- a/src/frontend/src/components/Pro/security/FormSet.tsx +++ b/src/frontend/src/components/Pro/security/FormSet.tsx @@ -46,31 +46,31 @@ export default function FormSet({ data, onChange, onSave, onCancel }) { } return <>
- 审查类型 + {t('build.reviewType')}
-
{/* 后期更新 */} - 词表类型 +
+ {t('build.wordListType')}
handleCheckboxChange(val, 1)} + id="c1" + value="1" + checked={form.wordsType?.includes(1)} + onCheckedChange={(val) => handleCheckboxChange(val, 1)} /> - +
handleCheckboxChange(val, 2)} /> - +
+ placeholder={t('build.useNewlineToSeparate')}>
document.querySelector('#fileUpload').click()}> - +
- 自动回复内容 + {t('build.autoReplyContent')}
+ placeholder={t('build.defaultAutoReply')}>
diff --git a/src/frontend/src/components/Pro/security/FormView.tsx b/src/frontend/src/components/Pro/security/FormView.tsx index 1af0cb18..d97a9914 100644 --- a/src/frontend/src/components/Pro/security/FormView.tsx +++ b/src/frontend/src/components/Pro/security/FormView.tsx @@ -1,22 +1,29 @@ +import { useTranslation } from "react-i18next" export default function FormView({ data }) { - const map = { '1': '内置词表', '2': '自定义词表' } + const { t } = useTranslation(); + const map = { + '1': t('build.builtinWordList'), + '2': t('build.customWordList') + }; - return
-
- 审查类型: - 敏感词匹配 -
-
- 词表类型: -
- {data.wordsType?.map(v => {map[v]})} + return ( +
+
+ {t('build.reviewType')}: + {t('build.sensitiveWordMatch')} +
+
+ {t('build.wordListType')}: +
+ {data.wordsType?.map((v, index) => {map[v]})} +
+
+ {t('build.autoReplyContent')}: +
+

+ {data.autoReply || t('build.defaultAutoReply')}

- 自动回复内容: -
-

- {data.autoReply || '填写命中安全审查时的自动回复内容,例如“当前对话内容违反相关规范,请修改后重新输入'}

-
-
+ ); } \ No newline at end of file diff --git a/src/frontend/src/pages/LogPage/index.tsx b/src/frontend/src/pages/LogPage/index.tsx index e0c08a10..0163e5ce 100644 --- a/src/frontend/src/pages/LogPage/index.tsx +++ b/src/frontend/src/pages/LogPage/index.tsx @@ -73,77 +73,81 @@ export default function index() { return
-
- setKeys({...keys,userIds:values})} - > -
-
- -
-
- setKeys({...keys,start:t})} /> -
-
- setKeys({...keys,end:t})} /> -
-
- -
-
- -
+
+ setKeys({...keys,userIds:values})} + > +
+
+ +
+
+ setKeys({...keys,start:t})} /> +
+
+ setKeys({...keys,end:t})} /> +
+
+ +
+
+ +
- - + +
{/* 用户列表. */} - 审计ID - 用户名 - 操作时间 - 系统模块 - 操作行为 - 操作对象类型 - 操作对象 - IP地址 - 备注 + {t('log.auditId')} + {t('log.username')} + {t('log.operationTime')} + {t('log.systemModule')} + {t('log.operationAction')} + {t('log.objectType')} + {t('log.operationObject')} + {t('log.ipAddress')} + {t('log.remark')} @@ -164,7 +168,7 @@ export default function index() { {/* 分页 */} {/* */}
-

审计管理

+

{t('log.auditManagement')}

- +