diff --git a/.gitignore b/.gitignore index faf3ec3ce..7efec2ff8 100644 --- a/.gitignore +++ b/.gitignore @@ -137,9 +137,9 @@ celerybeat.pid # Environments .env .venv -env/ +# env/ venv/ -ENV/ +# ENV/ env.bak/ venv.bak/ diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..d70a5c3b4 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "MaxKB", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/ui/package.json b/ui/package.json index 770322189..3d5b609ad 100644 --- a/ui/package.json +++ b/ui/package.json @@ -13,8 +13,10 @@ "format": "prettier --write src/" }, "dependencies": { + "element-plus": "^2.9.7", "pinia": "^3.0.1", "vue": "^3.5.13", + "vue-i18n": "^11.1.3", "vue-router": "^4.5.0" }, "devDependencies": { @@ -30,7 +32,10 @@ "jiti": "^2.4.2", "npm-run-all2": "^7.0.2", "prettier": "3.5.3", + "sass": "^1.86.3", + "sass-loader": "^16.0.5", "typescript": "~5.8.0", + "unplugin-vue-define-options": "^3.0.0-beta.8", "vite": "^6.2.4", "vite-plugin-vue-devtools": "^7.7.2", "vue-tsc": "^2.2.8" diff --git a/ui/public/MaxKB.gif b/ui/public/MaxKB.gif new file mode 100644 index 000000000..055d49a6a Binary files /dev/null and b/ui/public/MaxKB.gif differ diff --git a/ui/public/favicon.ico b/ui/public/favicon.ico index df36fcfb7..7d9781edb 100644 Binary files a/ui/public/favicon.ico and b/ui/public/favicon.ico differ diff --git a/ui/src/App.vue b/ui/src/App.vue index 7905b0516..613fac02a 100644 --- a/ui/src/App.vue +++ b/ui/src/App.vue @@ -1,85 +1,5 @@ - + - - diff --git a/ui/src/api/type/login.ts b/ui/src/api/type/login.ts new file mode 100644 index 000000000..a6a0fe54e --- /dev/null +++ b/ui/src/api/type/login.ts @@ -0,0 +1,11 @@ +interface LoginRequest { + /** + * 用户名 + */ + username: string + /** + * 密码 + */ + password: string +} +export type { LoginRequest } diff --git a/ui/src/api/user/login.ts b/ui/src/api/user/login.ts new file mode 100644 index 000000000..e69de29bb diff --git a/ui/src/assets/base.css b/ui/src/assets/base.css deleted file mode 100644 index 8816868a4..000000000 --- a/ui/src/assets/base.css +++ /dev/null @@ -1,86 +0,0 @@ -/* color palette from */ -:root { - --vt-c-white: #ffffff; - --vt-c-white-soft: #f8f8f8; - --vt-c-white-mute: #f2f2f2; - - --vt-c-black: #181818; - --vt-c-black-soft: #222222; - --vt-c-black-mute: #282828; - - --vt-c-indigo: #2c3e50; - - --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); - --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); - --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); - --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); - - --vt-c-text-light-1: var(--vt-c-indigo); - --vt-c-text-light-2: rgba(60, 60, 60, 0.66); - --vt-c-text-dark-1: var(--vt-c-white); - --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); -} - -/* semantic color variables for this project */ -:root { - --color-background: var(--vt-c-white); - --color-background-soft: var(--vt-c-white-soft); - --color-background-mute: var(--vt-c-white-mute); - - --color-border: var(--vt-c-divider-light-2); - --color-border-hover: var(--vt-c-divider-light-1); - - --color-heading: var(--vt-c-text-light-1); - --color-text: var(--vt-c-text-light-1); - - --section-gap: 160px; -} - -@media (prefers-color-scheme: dark) { - :root { - --color-background: var(--vt-c-black); - --color-background-soft: var(--vt-c-black-soft); - --color-background-mute: var(--vt-c-black-mute); - - --color-border: var(--vt-c-divider-dark-2); - --color-border-hover: var(--vt-c-divider-dark-1); - - --color-heading: var(--vt-c-text-dark-1); - --color-text: var(--vt-c-text-dark-2); - } -} - -*, -*::before, -*::after { - box-sizing: border-box; - margin: 0; - font-weight: normal; -} - -body { - min-height: 100vh; - color: var(--color-text); - background: var(--color-background); - transition: - color 0.5s, - background-color 0.5s; - line-height: 1.6; - font-family: - Inter, - -apple-system, - BlinkMacSystemFont, - 'Segoe UI', - Roboto, - Oxygen, - Ubuntu, - Cantarell, - 'Fira Sans', - 'Droid Sans', - 'Helvetica Neue', - sans-serif; - font-size: 15px; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} diff --git a/ui/src/assets/icon_send.svg b/ui/src/assets/icon_send.svg new file mode 100644 index 000000000..79ff6425d --- /dev/null +++ b/ui/src/assets/icon_send.svg @@ -0,0 +1,4 @@ + + + + diff --git a/ui/src/assets/icon_send_colorful.svg b/ui/src/assets/icon_send_colorful.svg new file mode 100644 index 000000000..b6a1dacb6 --- /dev/null +++ b/ui/src/assets/icon_send_colorful.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/ui/src/assets/logo.svg b/ui/src/assets/logo.svg deleted file mode 100644 index 756566035..000000000 --- a/ui/src/assets/logo.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/ui/src/assets/logo/MaxKB-logo-currentColor.svg b/ui/src/assets/logo/MaxKB-logo-currentColor.svg new file mode 100644 index 000000000..94281645f --- /dev/null +++ b/ui/src/assets/logo/MaxKB-logo-currentColor.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/ui/src/assets/logo/MaxKB-logo.svg b/ui/src/assets/logo/MaxKB-logo.svg new file mode 100644 index 000000000..beb86aa51 --- /dev/null +++ b/ui/src/assets/logo/MaxKB-logo.svg @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui/src/assets/logo/logo-currentColor.svg b/ui/src/assets/logo/logo-currentColor.svg new file mode 100644 index 000000000..5f50e4cf3 --- /dev/null +++ b/ui/src/assets/logo/logo-currentColor.svg @@ -0,0 +1 @@ +MaxKB \ No newline at end of file diff --git a/ui/src/assets/logo/logo.svg b/ui/src/assets/logo/logo.svg new file mode 100644 index 000000000..2e601bb46 --- /dev/null +++ b/ui/src/assets/logo/logo.svg @@ -0,0 +1 @@ +MaxKB \ No newline at end of file diff --git a/ui/src/assets/main.css b/ui/src/assets/main.css deleted file mode 100644 index 36fb845b5..000000000 --- a/ui/src/assets/main.css +++ /dev/null @@ -1,35 +0,0 @@ -@import './base.css'; - -#app { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - font-weight: normal; -} - -a, -.green { - text-decoration: none; - color: hsla(160, 100%, 37%, 1); - transition: 0.4s; - padding: 3px; -} - -@media (hover: hover) { - a:hover { - background-color: hsla(160, 100%, 37%, 0.2); - } -} - -@media (min-width: 1024px) { - body { - display: flex; - place-items: center; - } - - #app { - display: grid; - grid-template-columns: 1fr 1fr; - padding: 0 2rem; - } -} diff --git a/ui/src/assets/theme/default.jpg b/ui/src/assets/theme/default.jpg new file mode 100644 index 000000000..162ebe925 Binary files /dev/null and b/ui/src/assets/theme/default.jpg differ diff --git a/ui/src/assets/theme/green.jpg b/ui/src/assets/theme/green.jpg new file mode 100644 index 000000000..937e8a03c Binary files /dev/null and b/ui/src/assets/theme/green.jpg differ diff --git a/ui/src/assets/theme/orange.jpg b/ui/src/assets/theme/orange.jpg new file mode 100644 index 000000000..64b4c6abe Binary files /dev/null and b/ui/src/assets/theme/orange.jpg differ diff --git a/ui/src/assets/theme/purple.jpg b/ui/src/assets/theme/purple.jpg new file mode 100644 index 000000000..843a42585 Binary files /dev/null and b/ui/src/assets/theme/purple.jpg differ diff --git a/ui/src/assets/theme/red.jpg b/ui/src/assets/theme/red.jpg new file mode 100644 index 000000000..cabf84f6f Binary files /dev/null and b/ui/src/assets/theme/red.jpg differ diff --git a/ui/src/components/HelloWorld.vue b/ui/src/components/HelloWorld.vue deleted file mode 100644 index d174cf8e1..000000000 --- a/ui/src/components/HelloWorld.vue +++ /dev/null @@ -1,41 +0,0 @@ - - - - - diff --git a/ui/src/components/TheWelcome.vue b/ui/src/components/TheWelcome.vue deleted file mode 100644 index 6092dff14..000000000 --- a/ui/src/components/TheWelcome.vue +++ /dev/null @@ -1,94 +0,0 @@ - - - diff --git a/ui/src/components/WelcomeItem.vue b/ui/src/components/WelcomeItem.vue deleted file mode 100644 index 6d7086aea..000000000 --- a/ui/src/components/WelcomeItem.vue +++ /dev/null @@ -1,87 +0,0 @@ - - - diff --git a/ui/src/components/icons/IconCommunity.vue b/ui/src/components/icons/IconCommunity.vue deleted file mode 100644 index 2dc8b0552..000000000 --- a/ui/src/components/icons/IconCommunity.vue +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/ui/src/components/icons/IconDocumentation.vue b/ui/src/components/icons/IconDocumentation.vue deleted file mode 100644 index 6d4791cfb..000000000 --- a/ui/src/components/icons/IconDocumentation.vue +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/ui/src/components/icons/IconEcosystem.vue b/ui/src/components/icons/IconEcosystem.vue deleted file mode 100644 index c3a4f078c..000000000 --- a/ui/src/components/icons/IconEcosystem.vue +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/ui/src/components/icons/IconSupport.vue b/ui/src/components/icons/IconSupport.vue deleted file mode 100644 index 7452834d3..000000000 --- a/ui/src/components/icons/IconSupport.vue +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/ui/src/components/icons/IconTooling.vue b/ui/src/components/icons/IconTooling.vue deleted file mode 100644 index 660598d7c..000000000 --- a/ui/src/components/icons/IconTooling.vue +++ /dev/null @@ -1,19 +0,0 @@ - - diff --git a/ui/src/components/index.ts b/ui/src/components/index.ts new file mode 100644 index 000000000..c6e667fad --- /dev/null +++ b/ui/src/components/index.ts @@ -0,0 +1,11 @@ +import { type App } from 'vue' +import LogoFull from './logo/LogoFull.vue' +import LogoIcon from './logo/LogoIcon.vue' +import SendIcon from './logo/SendIcon.vue' +export default { + install(app: App) { + app.component('LogoFull', LogoFull) + app.component('LogoIcon', LogoIcon) + app.component('SendIcon', SendIcon) + }, +} diff --git a/ui/src/components/logo/LogoFull.vue b/ui/src/components/logo/LogoFull.vue new file mode 100644 index 000000000..ba7933999 --- /dev/null +++ b/ui/src/components/logo/LogoFull.vue @@ -0,0 +1,95 @@ + + + diff --git a/ui/src/components/logo/LogoIcon.vue b/ui/src/components/logo/LogoIcon.vue new file mode 100644 index 000000000..51d47db82 --- /dev/null +++ b/ui/src/components/logo/LogoIcon.vue @@ -0,0 +1,59 @@ + + + diff --git a/ui/src/components/logo/SendIcon.vue b/ui/src/components/logo/SendIcon.vue new file mode 100644 index 000000000..933976c0b --- /dev/null +++ b/ui/src/components/logo/SendIcon.vue @@ -0,0 +1,44 @@ + + + diff --git a/ui/src/locales/index.ts b/ui/src/locales/index.ts new file mode 100644 index 000000000..a2c8b2e3a --- /dev/null +++ b/ui/src/locales/index.ts @@ -0,0 +1,85 @@ +import { useLocalStorage, usePreferredLanguages } from '@vueuse/core' +import { computed } from 'vue' +import { createI18n } from 'vue-i18n' + +// 导入语言文件 +const langModules = import.meta.glob('./lang/*/index.ts', { eager: true }) as Record< + string, + () => Promise<{ default: Object }> +> + +// 定义 Recordable 类型 +type Recordable = Record + +const langModuleMap = new Map() + +export const langCode: Array = [] + +export const localeConfigKey = 'MaxKB-locale' + +// 获取浏览器默认语言环境 +const languages = usePreferredLanguages() + +export function getBrowserLang() { + const browserLang = navigator.language ? navigator.language : languages.value[0] + let defaultBrowserLang = '' + if (browserLang === 'zh-HK' || browserLang === 'zh-TW') { + defaultBrowserLang = 'zh-Hant' + } else if (browserLang === 'zh-CN') { + defaultBrowserLang = 'zh-CN' + } else { + defaultBrowserLang = 'en-US' + } + return defaultBrowserLang +} + +// 生成语言模块列表 +const generateLangModuleMap = () => { + const fullPaths = Object.keys(langModules) + fullPaths.forEach((fullPath) => { + const k = fullPath.replace('./lang', '') + const startIndex = 1 + const lastIndex = k.lastIndexOf('/') + const code = k.substring(startIndex, lastIndex) + langCode.push(code) + langModuleMap.set(code, langModules[fullPath]) + }) +} + +// 导出 Message +const importMessages = computed(() => { + generateLangModuleMap() + + const message: Recordable = {} + langModuleMap.forEach((value: any, key) => { + message[key] = value.default + }) + return message +}) + +export const i18n = createI18n({ + legacy: false, + locale: useLocalStorage(localeConfigKey, getBrowserLang()).value || getBrowserLang(), + fallbackLocale: getBrowserLang(), + messages: importMessages.value, + globalInjection: true +}) + +export const langList = computed(() => { + if (langModuleMap.size === 0) generateLangModuleMap() + + const list: any = [] + langModuleMap.forEach((value: any, key) => { + list.push({ + label: value.default.lang, + value: key + }) + }) + + return list +}) + +// @ts-ignore +export const { t } = i18n.global + +export default i18n diff --git a/ui/src/locales/lang/en-US/ai-chat.ts b/ui/src/locales/lang/en-US/ai-chat.ts new file mode 100644 index 000000000..01c5c3c67 --- /dev/null +++ b/ui/src/locales/lang/en-US/ai-chat.ts @@ -0,0 +1,96 @@ +export default { + noHistory: 'No Chat History', + createChat: 'New Chat', + history: 'Chat History', + only20history: 'Showing only the last 20 chats', + question_count: 'Questions', + exportRecords: 'Export Chat History', + chatId: 'Chat ID', + userInput: 'User Input', + quote: 'Quote', + download: 'Click to Download', + passwordValidator: { + title: 'Enter Password to Access', + errorMessage1: 'Password cannot be empty', + errorMessage2: 'Incorrect password' + }, + operation: { + play: 'Play', + pause: 'Pause', + regeneration: 'Regenerate Response', + like: 'Like', + cancelLike: 'Unlike', + oppose: 'Dislike', + cancelOppose: 'Undo Dislike', + continue: 'Continue', + stopChat: 'Stop Response', + startChat: 'Start Response', + }, + tip: { + error500Message: 'Sorry, the service is currently under maintenance. Please try again later!', + errorIdentifyMessage: 'Unable to verify user identity', + errorLimitMessage: 'Sorry, you have reached the maximum number of questions. Please try again tomorrow!', + answerMessage: 'Sorry, no relevant content found. Please rephrase your question or provide more details.', + stopAnswer: 'Response Stopped', + answerLoading: 'Generating Response...', + recorderTip: `

This feature requires microphone access. Browsers block recording on insecure pages. Solutions:
+1. Enable HTTPS;
+2. If HTTPS is not available, adjust browser security settings. For Chrome:
+(1) Enter chrome://flags/#unsafely-treat-insecure-origin-as-secure in the address bar;
+(2) Add your HTTP site, e.g., http://127.0.0.1:8080.

`, + recorderError: 'Recording Failed', + confirm: 'Got it', + requiredMessage: 'Please fill in all required fields', + inputParamMessage1: 'Please specify a parameter in the URL', + inputParamMessage2: 'value', + prologueMessage: 'Sorry, the service is currently under maintenance. Please try again later!' + }, + inputPlaceholder: { + speaking: 'Speaking...', + recorderLoading: 'Transcribing...', + default: 'Type your question' + }, + uploadFile: { + label: 'Upload File', + most: 'Maximum', + limit: 'files allowed, each up to', + fileType: 'File Type', + tipMessage: 'Please select allowed file types in the upload settings', + limitMessage1: 'You can upload up to', + limitMessage2: 'files', + sizeLimit: 'Each file must not exceed', + imageMessage: 'Please process the image content', + errorMessage: 'Upload Failed' + }, + executionDetails: { + title: 'Execution Details', + paramOutputTooltip: 'Each document supports previewing up to 500 characters', + audioFile: 'Audio File', + searchContent: 'Search Query', + searchResult: 'Search Results', + conditionResult: 'Condition Evaluation', + currentChat: 'Current Chat', + answer: 'AI Response', + replyContent: 'Reply Content', + textContent: 'Text Content', + input: 'Input', + output: 'Output', + rerankerContent: 'Re-ranked Content', + rerankerResult: 'Re-ranking Results', + paragraph: 'Segment', + noSubmit: 'No submission from user', + errMessage: 'Error Log' + }, + KnowledgeSource: { + title: 'Knowledge Source', + referenceParagraph: 'Cited Segment', + consume: 'Tokens', + consumeTime: 'Runtime' + }, + paragraphSource: { + title: 'Knowledge Quote', + question: 'User Question', + optimizationQuestion: 'Optimized Question' + }, + editTitle: 'Edit Title', +} diff --git a/ui/src/locales/lang/en-US/common.ts b/ui/src/locales/lang/en-US/common.ts new file mode 100644 index 000000000..b00021ee0 --- /dev/null +++ b/ui/src/locales/lang/en-US/common.ts @@ -0,0 +1,64 @@ +export default { + create: 'Create', + createSuccess: 'Successful', + copy: 'Copy', + copySuccess: 'Successful', + copyError: 'Copy Failed', + save: 'Save', + saveSuccess: 'Successful', + delete: 'Delete', + deleteSuccess: 'Successful', + setting: 'Settings', + settingSuccess: 'Successful', + submit: 'Submit', + submitSuccess: 'Successful', + edit: 'Edit', + editSuccess: 'Successful', + modify: 'Modify', + modifySuccess: 'Successful', + cancel: 'Cancel', + confirm: 'OK', + tip: 'Tips', + add: 'Add', + refresh: 'Refresh', + search: 'Search', + clear: 'Clear', + professional: 'Purchase the Professional Edition', + createDate: 'Create Date', + createTime: 'Create Time', + operation: 'Action', + character: 'characters', + export: 'Export', + exportSuccess: 'Successful', + unavailable: '(Unavailable)', + public: 'Public', + private: 'Private', + paramSetting: 'Parameter Settings', + creator: 'Creator', + author: 'Author', + debug: 'Debug', + required: 'Required', + noData: 'No data', + result: 'Result', + fileUpload: { + document: 'Documents', + image: 'Image', + audio: 'Audio', + video: 'Video' + }, + status: { + label: 'Status', + enableSuccess: 'Successful', + disableSuccess: 'Successful' + }, + param: { + outputParam: 'Output Parameters', + inputParam: 'Input Parameters', + initParam: 'Startup Parameters', + }, + + inputPlaceholder: 'Please input', + title: 'Title', + content: 'Content', + rename: 'Rename' +} diff --git a/ui/src/locales/lang/en-US/components.ts b/ui/src/locales/lang/en-US/components.ts new file mode 100644 index 000000000..7f794e1a1 --- /dev/null +++ b/ui/src/locales/lang/en-US/components.ts @@ -0,0 +1,12 @@ +export default { + quickCreatePlaceholder: 'Quickly create blank document', + quickCreateName: 'document name', + noData: 'No Data', + loading: 'Loading', + noMore: 'No more! ', + selectParagraph: { + title: 'Select Segments', + error: 'Process only the failed segments', + all: 'All Segments' + } +} diff --git a/ui/src/locales/lang/en-US/dynamics-form.ts b/ui/src/locales/lang/en-US/dynamics-form.ts new file mode 100644 index 000000000..2cfcd8058 --- /dev/null +++ b/ui/src/locales/lang/en-US/dynamics-form.ts @@ -0,0 +1,102 @@ +export default { + input_type_list: { + TextInput: 'Input', + PasswordInput: 'Password', + Slider: 'Slider', + SwitchInput: 'Switch', + SingleSelect: 'Single Select', + MultiSelect: 'Multi Select', + DatePicker: 'Date Picker', + JsonInput: 'JSON', + RadioCard: 'Radio Card', + RadioRow: 'Radio Row' + }, + default: { + label: 'Default', + placeholder: 'Please enter a default', + requiredMessage: ' is a required property', + show: 'Show Default' + }, + tip: { + requiredMessage: 'cannot be empty', + jsonMessage: 'Incorrect JSON format' + }, + searchBar: { + placeholder: 'Please enter keywords to search' + }, + paramForm: { + field: { + label: 'Parameter', + placeholder: 'Please enter a parameter', + requiredMessage: 'Parameter is a required property', + requiredMessage2: 'Only letters, numbers, and underscores are allowed' + }, + name: { + label: 'Name', + placeholder: 'Please enter a name', + requiredMessage: 'Name is a required property' + }, + tooltip: { + label: 'Tooltip', + placeholder: 'Please enter a tooltip' + }, + required: { + label: 'Required', + requiredMessage: 'Required is a required property' + }, + input_type: { + label: 'Type', + placeholder: 'Please select a type', + requiredMessage: 'Type is a required property' + } + }, + DatePicker: { + placeholder: 'Select Date', + year: 'Year', + month: 'Month', + date: 'Date', + datetime: 'Date Time', + dataType: { + label: 'Date Type', + placeholder: 'Please select a date type' + }, + format: { + label: 'Format', + placeholder: 'Please select a format' + } + }, + Select: { + label: 'Option Value', + placeholder: 'Please enter an option value' + }, + tag: { + label: 'Tag', + placeholder: 'Please enter an option label' + }, + Slider: { + showInput: { + label: 'Show Input Box' + }, + valueRange: { + label: 'Value Range', + minRequired: 'Minimum value is required', + maxRequired: 'Maximum value is required' + }, + step: { + label: 'Step Value', + requiredMessage1: 'Step value is required', + requiredMessage2: 'Step value cannot be 0' + } + }, + TextInput: { + length: { + label: 'Text Length', + minRequired: 'Minimum length is required', + maxRequired: 'Maximum length is required', + requiredMessage1: 'Length must be between', + requiredMessage2: 'and', + requiredMessage3: 'characters', + requiredMessage4: 'Text length is a required parameter' + } + } +} diff --git a/ui/src/locales/lang/en-US/index.ts b/ui/src/locales/lang/en-US/index.ts new file mode 100644 index 000000000..bf56593e2 --- /dev/null +++ b/ui/src/locales/lang/en-US/index.ts @@ -0,0 +1,17 @@ +import en from 'element-plus/es/locale/lang/en' +import components from './components' +import layout from './layout' +import views from './views' +import common from './common' +import dynamicsForm from './dynamics-form' +import chat from './ai-chat' +export default { + lang: 'English', + layout, + views, + components, + en, + common, + dynamicsForm, + chat +} diff --git a/ui/src/locales/lang/en-US/layout.ts b/ui/src/locales/lang/en-US/layout.ts new file mode 100644 index 000000000..8ceecd753 --- /dev/null +++ b/ui/src/locales/lang/en-US/layout.ts @@ -0,0 +1,34 @@ +export default { + github: 'Project Address', + wiki: 'User Manual', + forum: 'Forum For Help', + logout: 'Log Out', + apiKey: 'API Key', + apiServiceAddress: 'API Service Address', + language: 'Language', + isExpire: 'License not uploaded or expired', + about: { + title: 'About', + expiredTime: 'Expiration Date', + edition: { + label: 'Edition', + community: 'Community Edition', + professional: 'Professional Edition' + }, + version: 'Version', + serialNo: 'Serial No.', + remark: 'Remarks', + update: 'Update', + authorize: 'Authorized', + + }, + time: { + daysLater: 'days later', + hoursLater: 'hours later', + expired: 'expired', + expiringSoon: 'expiring soon' + }, + copyright: 'Copyright © 2014-2025 FIT2CLOUD, All rights reserved.', + userManualUrl: 'http://docs.maxkb.hk/', + forumUrl: 'https://github.com/1Panel-dev/MaxKB/discussions' +} diff --git a/ui/src/locales/lang/en-US/views/404.ts b/ui/src/locales/lang/en-US/views/404.ts new file mode 100644 index 000000000..0d4861a4a --- /dev/null +++ b/ui/src/locales/lang/en-US/views/404.ts @@ -0,0 +1,5 @@ +export default { + title: "404", + message: "Unable to Access APP", + operate: "Back to Home", +}; diff --git a/ui/src/locales/lang/en-US/views/application-overview.ts b/ui/src/locales/lang/en-US/views/application-overview.ts new file mode 100644 index 000000000..7580cdd53 --- /dev/null +++ b/ui/src/locales/lang/en-US/views/application-overview.ts @@ -0,0 +1,114 @@ +export default { + title: 'Overview', + appInfo: { + header: 'App Information', + publicAccessLink: 'Public URL', + openText: 'On', + closeText: 'Off', + copyLinkText: 'Copy Link', + refreshLinkText: 'Refresh Link', + demo: 'Preview', + embedInWebsite: 'Get Embed Code', + accessControl: 'Access Control', + displaySetting: 'Display Settings', + apiAccessCredentials: 'API Access Credentials', + apiKey: 'API Key', + refreshToken: { + msgConfirm1: 'Are you sure you want to regenerate the public URL?', + msgConfirm2: + 'Regenerating the Public URL will affect any existing embedded codes on third-party sites. You will need to update the embed code and re-integrate it into those sites. Proceed with caution!', + refreshSuccess: 'Successfully Refreshed' + }, + APIKeyDialog: { + saveSettings: 'Save Settings', + msgConfirm1: 'Are you sure you want to delete the API Key', + msgConfirm2: + 'This action is irreversible. Once deleted, the API Key cannot be recovered. Do you still want to proceed?', + enabledSuccess: 'Enabled', + disabledSuccess: 'Disabled' + }, + EditAvatarDialog: { + title: 'App Logo', + customizeUpload: 'Custom Upload', + upload: 'Upload', + default: 'Default Logo', + custom: 'Custom', + sizeTip: + 'Recommended size: 32×32 pixels. Supports JPG, PNG, and GIF formats. Max size: 10 MB', + fileSizeExceeded: 'File size exceeds 10 MB', + uploadImagePrompt: 'Please upload an image' + }, + EmbedDialog: { + fullscreenModeTitle: 'Fullscreen Mode', + copyInstructions: 'Copy the code below to embed', + floatingModeTitle: 'Floating Mode', + mobileModeTitle: 'Mobile Mode' + }, + LimitDialog: { + dialogTitle: 'Access Restrictions', + showSourceLabel: 'Show Knowledge Source', + clientQueryLimitLabel: 'Query Limit per Client', + authentication: 'Authentication', + authenticationValue: 'Access Password', + timesDays: 'queries per day', + whitelistLabel: 'Allowed Domains', + whitelistPlaceholder: + 'Enter allowed third-party domains, one per line. For example:\nhttp://127.0.0.1:5678\nhttps://dataease.io' + }, + SettingAPIKeyDialog: { + allowCrossDomainLabel: 'Allow Cross-Domain Access', + crossDomainPlaceholder: + 'Enter allowed cross-domain addresses. If enabled but left blank, no restrictions will apply.\nEnter one per line, e.g.:\nhttp://127.0.0.1:5678\nhttps://dataease.io' + }, + SettingDisplayDialog: { + dialogTitle: 'Display Settings', + languageLabel: 'Language', + showSourceLabel: 'Show Knowledge Source', + showExecutionDetail: 'Show Execution Details', + restoreDefault: 'Restore Default', + customThemeColor: 'Custom Theme Color', + headerTitleFontColor: 'Header Title Font Color', + default: 'Default', + askUserAvatar: 'User Avatar (Asking)', + replace: 'Replace', + imageMessage: + 'Recommended size: 32×32 pixels. Supports JPG, PNG, and GIF formats. Max size: 10 MB', + AIAvatar: 'AI Avatar', + floatIcon: 'Floating Icon', + iconDefaultPosition: 'Default Icon Position', + iconPosition: { + left: 'Left', + right: 'Right', + bottom: 'Bottom', + top: 'Top' + }, + draggablePosition: 'Draggable Position', + showHistory: 'Show Chat History', + displayGuide: 'Show Guide Image (Floating Mode)', + disclaimer: 'Disclaimer', + disclaimerValue: 'This content is AI-generated and for reference only.' + } + }, + monitor: { + monitoringStatistics: 'Monitoring Statistics', + customRange: 'Custom Range', + startDatePlaceholder: 'Start Date', + endDatePlaceholder: 'End Date', + pastDayOptions: { + past7Days: 'Last 7 Days', + past30Days: 'Last 30 Days', + past90Days: 'Last 90 Days', + past183Days: 'Last 6 Months', + other: 'Custom' + }, + charts: { + customerTotal: 'Total Users', + customerNew: 'New Users', + queryCount: 'Total Queries', + tokensTotal: 'Total Tokens Used', + userSatisfaction: 'User Feedback Metrics', + approval: 'Like', + disapproval: 'Dislike' + } + } +} diff --git a/ui/src/locales/lang/en-US/views/application-workflow.ts b/ui/src/locales/lang/en-US/views/application-workflow.ts new file mode 100644 index 000000000..6e1aa8c67 --- /dev/null +++ b/ui/src/locales/lang/en-US/views/application-workflow.ts @@ -0,0 +1,288 @@ +export default { + node: 'Node', + nodeName: 'Node Name', + baseComponent: 'Basic', + nodeSetting: 'Node Settings', + workflow: 'Workflow', + searchBar: { + placeholder: 'Search by name' + }, + info: { + previewVersion: 'Preview Version:', + saveTime: 'Last Saved:' + }, + setting: { + restoreVersion: 'Restore Previous Version"', + restoreCurrentVersion: 'Restore to This Version', + addComponent: 'Add', + public: 'Publish', + releaseHistory: 'Release History', + autoSave: 'Auto Save', + latestRelease: 'Latest Release', + copyParam: 'Copy Parameters', + debug: 'Run', + exit: 'Exit', + exitSave: 'Save & Exit', + }, + tip: { + publicSuccess: 'Published successfully', + noData: 'No related results found', + nameMessage: 'Name cannot be empty!', + onlyRight: 'Connections can only be made from the right anchor', + notRecyclable: 'Loop connections are not allowed', + onlyLeft: 'Connections can only be made to the left anchor', + applicationNodeError: 'This application is unavailable', + functionNodeError: 'This function node is unavailable', + repeatedNodeError: 'A node with this name already exists', + cannotCopy: 'Cannot be copied', + copyError: 'Node already copied', + paramErrorMessage: 'Parameter already exists: ', + saveMessage: 'Current changes have not been saved. Save before exiting?', + }, + delete: { + confirmTitle: 'Confirm to delete this node?', + deleteMessage: 'This node cannot be deleted' + }, + control: { + zoomOut: 'Zoom Out', + zoomIn: 'Zoom In', + fitView: 'Fit to Screen', + retract: 'Collapse All', + extend: 'Expand All', + beautify: 'Auto-Arrange' + }, + variable: { + label: 'Variable', + global: 'Global Variable', + Referencing: 'Referenced Variable', + ReferencingRequired: 'Referenced variable is required', + ReferencingError: 'Invalid referenced variable', + NoReferencing: 'Referenced variable does not exist', + placeholder: 'Please select a variable' + }, + condition: { + title: 'Execution Condition', + front: 'Precondition', + AND: 'All', + OR: 'Any', + text: 'After the connected node is executed, execute the current node' + }, + validate: { + startNodeRequired: 'Start node is required', + startNodeOnly: 'Only one start node is allowed', + baseNodeRequired: 'Base information node is required', + baseNodeOnly: 'Only one base information node is allowed', + notInWorkFlowNode: 'Node not in workflow', + noNextNode: 'Next node does not exist', + nodeUnavailable: 'Node unavailable', + needConnect1: 'The branch of the node needs to be connected', + cannotEndNode: 'This node cannot be used as an end node' + }, + nodes: { + startNode: { + label: 'Start', + question: 'User Question', + currentTime: 'Current Time' + }, + baseNode: { + label: 'Base Information', + appName: { + label: 'App Name' + }, + appDescription: { + label: 'App Description' + }, + fileUpload: { + label: 'File Upload', + tooltip: 'When enabled, the Q&A page will display a file upload button.' + }, + FileUploadSetting: { + title: 'File Upload Settings', + maxFiles: 'Maximum number of files per upload', + fileLimit: 'Maximum size per file (MB)', + fileUploadType: { + label: 'File types allowed for upload', + documentText: 'Requires "Document Content Extraction" node to parse document content', + imageText: 'Requires "Image Understanding" node to parse image content', + audioText: 'Requires "Speech-to-Text" node to parse audio content' + } + } + }, + aiChatNode: { + label: 'AI Chat', + text: 'Chat with an AI model', + answer: 'AI Content', + returnContent: { + label: 'Return Content', + tooltip: `If turned off, the content of this node will not be output to the user. + If you want the user to see the output of this node, please turn on the switch.` + }, + defaultPrompt: 'Known Information', + think: 'Thinking Process' + }, + searchDatasetNode: { + label: 'Knowledge Retrieval', + text: 'Allows you to query text content related to user questions from the Knowledge', + paragraph_list: 'List of retrieved segments', + is_hit_handling_method_list: 'List of segments that meet direct response criteria', + result: 'Search Result', + directly_return: 'Content of segments that meet direct response criteria', + searchParam: 'Retrieval Parameters', + searchQuestion: { + label: 'Question', + placeholder: 'Please select a search question', + requiredMessage: 'Please select a search question' + } + }, + questionNode: { + label: 'Question Optimization', + text: 'Optimize and improve the current question based on historical chat records to better match knowledge segments', + result: 'Optimized Question Result', + defaultPrompt1: `Optimize and improve the user's question based on context:`, + defaultPrompt2: `Please output an optimized question.`, + systemDefault: 'You are a question optimization expert' + }, + conditionNode: { + label: 'Conditional Branch', + text: 'Trigger different nodes based on conditions', + branch_name: 'Branch Name', + conditions: { + label: 'Conditions', + info: 'Meets the following', + requiredMessage: 'Please select conditions' + }, + valueMessage: 'Please enter a value', + addCondition: 'Add Condition', + addBranch: 'Add Branch' + }, + replyNode: { + label: 'Specified Reply', + text: 'Specify reply content, referenced variables will be converted to strings for output', + content: 'Content', + replyContent: { + label: 'Reply Content', + custom: 'Custom', + reference: 'Reference Variable' + } + }, + rerankerNode: { + label: 'Multi-path Recall', + text: 'Use a re-ranking model to refine retrieval results from multiple knowledge sources', + result_list: 'Re-ranked Results List', + result: 'Re-ranking Result', + rerankerContent: { + label: 'Re-ranking Content', + requiredMessage: 'Please select re-ranking content' + }, + higher: 'Higher', + ScoreTooltip: 'The higher the Score, the stronger the relevance.', + max_paragraph_char_number: 'Maximum Character', + reranker_model: { + label: 'Rerank', + placeholder: 'Please select a rerank' + } + }, + formNode: { + label: 'Form Input', + text: 'Collect user input during Q&A and use it in subsequent processes', + form_content_format1: 'Hello, please fill out the form below:', + form_content_format2: 'Click the [Submit] button after filling it out.', + form_data: 'All Form Content', + formContent: { + label: 'Form Output Content', + requiredMessage: + 'Please set the output content of this node, { form } is a placeholder for the form.', + tooltip: 'Define the output content of this node. { form } is a placeholder for the form' + }, + formAllContent: 'All Form Content', + formSetting: 'Form Configuration' + }, + documentExtractNode: { + label: 'Document Content Extraction', + text: 'Extract content from documents', + content: 'Document Content' + }, + imageUnderstandNode: { + label: 'Image Understanding', + text: 'Analyze images to identify objects, scenes, and provide answers', + answer: 'AI Content', + model: { + label: 'Vision Model', + requiredMessage: 'Please select a vision model' + }, + image: { + label: 'Select Image', + requiredMessage: 'Please select an image' + } + }, + variableAssignNode: { + label: 'Variable Assign', + text: 'Update the value of the global variable', + assign: 'Set Value' + }, + imageGenerateNode: { + label: 'Image Generation', + text: 'Generate images based on provided text content', + answer: 'AI Content', + model: { + label: 'Image Generation Model', + requiredMessage: 'Please select an image generation model' + }, + prompt: { + label: 'Positive Prompt', + tooltip: 'Describe elements and visual features you want in the generated image' + }, + negative_prompt: { + label: 'Negative Prompt', + tooltip: 'Describe elements you want to exclude from the generated image', + placeholder: + 'Please describe content you do not want to generate, such as color, bloody content' + } + }, + speechToTextNode: { + label: 'Speech2Text', + text: 'Convert audio to text through speech recognition model', + stt_model: { + label: 'Speech Recognition Model' + }, + audio: { + label: 'Select Audio File', + placeholder: 'Please select an audio file' + } + }, + textToSpeechNode: { + label: 'TTS', + text: 'Convert text to audio through speech synthesis model', + tts_model: { + label: 'Speech Synthesis Model' + }, + content: { + label: 'Select Text Content' + } + }, + functionNode: { + label: 'Custom Function', + text: 'Execute custom scripts to achieve data processing' + }, + applicationNode: { + label: 'APP Node' + } + }, + compare: { + is_null: 'Is null', + is_not_null: 'Is not null', + contain: 'Contains', + not_contain: 'Does not contain', + eq: 'Equal to', + ge: 'Greater than or equal to', + gt: 'Greater than', + le: 'Less than or equal to', + lt: 'Less than', + len_eq: 'Length equal to', + len_ge: 'Length greater than or equal to', + len_gt: 'Length greater than', + len_le: 'Length less than or equal to', + len_lt: 'Length less than' + }, + FileUploadSetting: {} +} diff --git a/ui/src/locales/lang/en-US/views/application.ts b/ui/src/locales/lang/en-US/views/application.ts new file mode 100644 index 000000000..ebc4ef7cd --- /dev/null +++ b/ui/src/locales/lang/en-US/views/application.ts @@ -0,0 +1,228 @@ +export default { + title: 'APP', + createApplication: 'Create APP', + importApplication: 'Import APP', + copyApplication: 'Copy APP', + workflow: 'WORKFLOW', + simple: 'SIMPLE', + searchBar: { + placeholder: 'Search by name' + }, + + setting: { + demo: 'Demo' + }, + delete: { + confirmTitle: 'Are you sure you want to delete this APP: ', + confirmMessage: + 'Deleting this APP will no longer provide its services. Please proceed with caution.' + }, + tip: { + ExportError: 'Export Failed', + professionalMessage: + 'The Community Edition supports up to 5 APP. If you need more APP, please upgrade to the Professional Edition.', + saveErrorMessage: 'Saving failed, please check your input or try again later', + loadingErrorMessage: 'Failed to load configuration, please check your input or try again later' + }, + + applicationForm: { + title: { + appTest: 'Debug Preview', + copy: 'copy' + }, + form: { + appName: { + label: 'Name', + placeholder: 'Please enter the APP name', + requiredMessage: 'APP name is required' + }, + appDescription: { + label: 'Description', + placeholder: + 'Describe the APP scenario and use, e.g.: XXX assistant answering user questions about XXX product usage' + }, + appType: { + label: 'Type', + simplePlaceholder: 'Suitable for beginners to create assistant.', + workflowPlaceholder: 'Suitable for advanced users to customize the workflow of assistant' + }, + appTemplate: { + blankApp: 'Blank APP', + assistantApp: 'Knowledge Assistant' + }, + aiModel: { + label: 'AI Model', + placeholder: 'Please select an AI model' + }, + roleSettings: { + label: 'System Role', + placeholder: 'You are xxx assistant' + }, + + prompt: { + label: 'Prompt', + noReferences: '(No references Knowledge)', + references: ' (References Knowledge)', + placeholder: 'Please enter prompt', + requiredMessage: 'Please enter prompt', + tooltip: + 'By adjusting the content of the prompt, you can guide the direction of the large model chat.', + + noReferencesTooltip: + 'By adjusting the content of the prompt, you can guide the direction of the large model chat. This prompt will be fixed at the beginning of the context. Variables used: {question} is the question posed by the user.', + referencesTooltip: + 'By adjusting the content of the prompt, you can guide the direction of the large model chat. This prompt will be fixed at the beginning of the context. Variables used: {data} carries known information from the knowledge; {question} is the question posed by the user.', + defaultPrompt: `Known information: {data} + Question: {question} + Response requirements: + - Please use concise and professional language to answer the user's question. + ` + }, + historyRecord: { + label: 'Chat History' + }, + relatedKnowledge: { + label: 'Related Knowledge', + placeholder: 'Related knowledge are displayed here' + }, + multipleRoundsDialogue: 'Multiple Rounds Dialogue', + + prologue: 'Prologue', + defaultPrologue: + 'Hello, I am XXX Assistant. You can ask me questions about using XXX.\n- What are the main features of XXX?\n- Which LLM does XXX support?\n- What document types does XXX support?', + problemOptimization: { + label: 'Questions Optimization', + tooltip: + 'Optimize the current question based on historical chat to better match knowledge points.' + }, + + voiceInput: { + label: 'Voice Input', + placeholder: 'Please select a speech recognition model', + requiredMessage: 'Please select a speech input model', + autoSend: 'Automatic Sending' + }, + voicePlay: { + label: 'Voice Playback', + placeholder: 'Please select a speech synthesis model', + requiredMessage: 'Please select a speech playback model', + autoPlay: 'Automatic Playback', + browser: 'Browser Playback (free)', + tts: 'TTS Model', + listeningTest: 'Preview' + }, + reasoningContent: { + label: 'Output Thinking', + tooltip: + "Please set the thinking label based on the model's return, and the content in the middle of the label will be recognized as the thinking process.", + start: 'Start', + end: 'End' + } + }, + buttons: { + publish: 'Save&Publish', + addModel: 'Add Model' + }, + dialog: { + addDataset: 'Add Related Knowledge', + addDatasetPlaceholder: 'The selected knowledge must use the same embedding model', + selected: 'Selected', + countDataset: 'Knowledge', + + selectSearchMode: 'Retrieval Mode', + vectorSearch: 'Vector Search', + vectorSearchTooltip: + 'Vector search is a retrieval method based on vector distance calculations, suitable for large data volumes in the knowledge.', + fullTextSearch: 'Full-text Search', + fullTextSearchTooltip: + 'Full-text search is a retrieval method based on text similarity, suitable for small data volumes in the knowledge.', + hybridSearch: 'Hybrid Search', + hybridSearchTooltip: + 'Hybrid search is a retrieval method based on both vector and text similarity, suitable for medium data volumes in the knowledge.', + similarityThreshold: 'Similarity higher than', + similarityTooltip: 'The higher the similarity, the stronger the correlation.', + topReferences: 'Top N Segments', + maxCharacters: 'Maximum Characters per Reference', + noReferencesAction: 'When there are no knowledge references', + continueQuestioning: 'Continue to ask questions to the Al model', + provideAnswer: 'Specify Reply Content', + designated_answer: + 'Hello, I am XXX Assistant. My knowledge only contains information related to XXX products. Please rephrase your question.', + defaultPrompt1: + "The content inside the parentheses () represents the user's question. Based on the context, please speculate and complete the user's question ({question}). The requirement is to output a completed question and place it", + defaultPrompt2: 'tag' + } + }, + applicationAccess: { + title: 'APP Access', + wecom: 'WeCom', + wecomTip: 'Create WeCom intelligent APP', + dingtalk: 'DingTalk', + dingtalkTip: 'Create DingTalk intelligent APP', + wechat: 'WeChat', + wechatTip: 'Create WeChat intelligent APP', + lark: 'Lark', + larkTip: 'Create Lark intelligent APP', + setting: 'Setting', + callback: 'Callback Address', + callbackTip: 'Please fill in the callback address', + wecomPlatform: 'WeCom Open Platform', + wechatPlatform: 'WeChat Open Platform', + dingtalkPlatform: 'DingTalk Open Platform', + larkPlatform: 'Lark Open Platform', + slack: 'Slack', + slackTip: 'Create Slack intelligent APP', + wecomSetting: { + title: 'WeCom Configuration', + cropId: 'Crop ID', + cropIdPlaceholder: 'Please enter crop ID', + agentIdPlaceholder: 'Please enter agent ID', + secretPlaceholder: 'Please enter secret', + tokenPlaceholder: 'Please enter token', + encodingAesKeyPlaceholder: 'Please enter EncodingAESKey', + authenticationSuccessful: 'Successful', + urlInfo: + '-APP management-Self-built-Created APP-Receive messages-Set the "URL" received by the API' + }, + dingtalkSetting: { + title: 'DingTalk Configuration', + clientIdPlaceholder: 'Please enter client ID', + clientSecretPlaceholder: 'Please enter client secret', + urlInfo: + '-On the robot page, set the "Message Receiving Mode" to HTTP mode, and fill in the above URL into the "Message Receiving Address"' + }, + wechatSetting: { + title: 'WeChat Configuration', + appId: 'APP ID', + appIdPlaceholder: 'Please enter APP ID', + appSecret: 'APP SECRET', + appSecretPlaceholder: 'Please enter APP SECRET', + token: 'TOKEN', + tokenPlaceholder: 'Please enter TOKEN', + aesKey: 'Message Encryption Key', + aesKeyPlaceholder: 'Please enter the message encryption key', + urlInfo: + '-Settings and Development-Basic Configuration-"Server Address URL" in server configuration' + }, + larkSetting: { + title: 'Lark Configuration', + appIdPlaceholder: 'Please enter APP ID', + appSecretPlaceholder: 'Please enter APP secret', + verificationTokenPlaceholder: 'Please enter verification token', + urlInfo: + '-Events and callbacks - event configuration - configure the "request address" of the subscription method' + }, + slackSetting: { + title: 'Slack Configuration', + signingSecretPlaceholder: 'Please enter signing secret', + botUserTokenPlaceholder: 'Please enter bot user token' + }, + copyUrl: 'Copy the link and fill it in' + }, + hitTest: { + title: 'Retrieval Testing', + text: 'Test the hitting effect of the Knowledge based on the given query text.', + emptyMessage1: 'Retrieval Testing results will show here', + emptyMessage2: 'No matching sections found' + } +} diff --git a/ui/src/locales/lang/en-US/views/dataset.ts b/ui/src/locales/lang/en-US/views/dataset.ts new file mode 100644 index 000000000..7764c7c54 --- /dev/null +++ b/ui/src/locales/lang/en-US/views/dataset.ts @@ -0,0 +1,86 @@ +export default { + title: 'Knowledge', + createDataset: 'Create Knowledge', + general: 'General', + web: 'Web Site', + relatedApplications: 'Linked App', + document_count: 'docs', + relatedApp_count: 'linked apps', + searchBar: { + placeholder: 'Search by name' + }, + setting: { + vectorization: 'Vectorization', + sync: 'Sync' + }, + tip: { + professionalMessage: + 'The community edition supports up to 50 knowledge. For more knowledge, please upgrade to the professional edition.', + syncSuccess: 'Sync task sent successfully', + updateModeMessage: + 'After modifying the knowledge vector model, you need to vectorize the knowledge. Do you want to continue saving?' + }, + delete: { + confirmTitle: 'Confirm deletion of knowledge:', + confirmMessage1: 'This knowledge is related with', + confirmMessage2: 'APP. Deleting it will be irreversible, please proceed with caution.' + }, + datasetForm: { + title: { + info: 'Knowledge Settings' + }, + form: { + datasetName: { + label: 'Name', + placeholder: 'Please enter the knowledge name', + requiredMessage: 'Please enter the knowledge name' + }, + datasetDescription: { + label: 'Description', + placeholder: + 'Describe the content of the knowledge. A detailed description will help AI understand the content better, improving the accuracy of content retrieval and hit rate.', + requiredMessage: 'Please enter the knowledge description' + }, + EmbeddingModel: { + label: 'Embedding Model', + placeholder: 'Please select a embedding model', + requiredMessage: 'Please select the embedding model' + }, + datasetType: { + label: 'Type', + generalInfo: 'Upload local documents', + webInfo: 'Sync text data from a web site' + }, + source_url: { + label: 'Web Root URL', + placeholder: 'Please enter the web root URL', + requiredMessage: 'Please enter the web root URL' + }, + selector: { + label: 'Selector', + placeholder: 'Default is body, can input .classname/#idname/tagname' + } + } + }, + ResultSuccess: { + title: 'Knowledge Created Successfully', + paragraph: 'Segments', + paragraph_count: 'Segments', + documentList: 'Document List', + loading: 'Importing', + buttons: { + toDataset: 'Return to Knowledge List', + toDocument: 'Go to Document' + } + }, + syncWeb: { + title: 'Sync Knowledge', + syncMethod: 'Sync Method', + replace: 'Replace Sync', + replaceText: 'Re-fetch Web site documents, replacing the documents in the local knowledge', + complete: 'Full Sync', + completeText: + 'Delete all documents in the local knowledge and re-fetch web site documents', + tip: 'Note: All syncs will delete existing data and re-fetch new data. Please proceed with caution.' + } +} diff --git a/ui/src/locales/lang/en-US/views/document.ts b/ui/src/locales/lang/en-US/views/document.ts new file mode 100644 index 000000000..bbf6e35e9 --- /dev/null +++ b/ui/src/locales/lang/en-US/views/document.ts @@ -0,0 +1,178 @@ +export default { + uploadDocument: 'Upload Document', + importDocument: 'Import Document', + syncDocument: 'Sync Document', + selected: 'Selected', + items: 'Items', + searchBar: { + placeholder: 'Search by document name' + }, + setting: { + migration: 'Move', + cancelGenerateQuestion: 'Cancel Generating Questions', + cancelVectorization: 'Cancel Vectorization', + cancelGenerate: 'Cancel Generation', + export: 'Export to' + }, + tip: { + saveMessage: 'Current changes have not been saved. Confirm exit?', + cancelSuccess: 'Successful', + sendMessage: 'Successful', + vectorizationSuccess: 'Successful', + nameMessage: 'Document name cannot be empty!', + importMessage: 'Successful', + migrationSuccess: 'Successful' + }, + upload: { + selectFile: 'Select File', + selectFiles: 'Select Folder', + uploadMessage: 'Drag and drop files here to upload or', + formats: 'Supported formats:', + requiredMessage: 'Please upload a file', + errorMessage1: 'The file size exceeds 100mb', + errorMessage2: 'Unsupported file format', + errorMessage3: 'File cannot be empty', + errorMessage4: 'Up to 50 files can be uploaded at once', + template: 'Template', + download: 'Download' + }, + + fileType: { + txt: { + label: 'Text File', + tip1: '1. It is recommended to standardize the segment markers in the file before uploading.', + tip2: '2. Up to 50 files can be uploaded at once, with each file not exceeding 100MB.' + }, + table: { + label: 'Table', + tip1: '1. Click to download the corresponding template and complete the information:', + tip2: '2. The first row must be column headers, and the column headers must be meaningful terms. Each record in the table will be treated as a segment.', + tip3: '3. Each sheet in the uploaded spreadsheet file will be treated as a document, with the sheet name as the document name.', + tip4: '4. Up to 50 files can be uploaded at once, with each file not exceeding 100MB.' + }, + QA: { + label: 'QA Pairs', + tip1: '1. Click to download the corresponding template and complete the information:', + tip2: '2. Each sheet in the uploaded spreadsheet file will be treated as a document, with the sheet name as the document name.', + tip3: '3. Up to 50 files can be uploaded at once, with each file not exceeding 100MB.' + } + }, + setRules: { + title: { + setting: 'Set Segment Rules', + preview: 'Preview' + }, + intelligent: { + label: 'Automatic Segmentation (Recommended)', + text: 'If you are unsure how to set segmentation rules, it is recommended to use automatic segmentation.' + }, + advanced: { + label: 'Advanced Segmentation', + text: 'Users can customize segmentation delimiters, segment length, and cleaning rules based on document standards.' + }, + patterns: { + label: 'Segment Delimiters', + tooltip: + 'Recursively split according to the selected symbols in order. If the split result exceeds the segment length, it will be truncated to the segment length.', + placeholder: 'Please select' + }, + limit: { + label: 'Segment Length' + }, + with_filter: { + label: 'Auto Clean', + text: 'Remove duplicate extra symbols, spaces, blank lines, and tab words.' + }, + checkedConnect: { + label: 'Add "Related Questions" section for question-based QA pairs during import.' + } + }, + buttons: { + prev: 'Previous', + next: 'Next', + import: 'Start Import', + preview: 'Apply' + }, + table: { + name: 'Document Name', + char_length: 'Character', + paragraph: 'Segment', + all: 'All', + updateTime: 'Update Time' + }, + fileStatus: { + label: 'File Status', + SUCCESS: 'Success', + FAILURE: 'Failure', + EMBEDDING: 'Indexing', + PENDING: 'Queuing', + GENERATE: 'Generating', + SYNC: 'Syncing', + REVOKE: 'Cancelling', + finish: 'Finish' + }, + enableStatus: { + label: 'Status', + enable: 'Enabled', + close: 'Disabled' + }, + sync: { + label: 'Sync', + confirmTitle: 'Confirm sync document?', + confirmMessage1: + 'Syncing will delete existing data and retrieve new data. Please proceed with caution.', + confirmMessage2: 'Cannot sync, please set the document URL first.', + successMessage: 'Successful' + }, + delete: { + confirmTitle1: 'Confirm batch deletion of', + confirmTitle2: 'documents?', + confirmMessage: + 'Segments within the selected documents will also be deleted. Please proceed with caution.', + successMessage: 'Successful', + confirmTitle3: 'Confirm deleting document:', + confirmMessage1: 'Under this document', + confirmMessage2: 'All segments will be deleted, please operate with caution. ' + }, + form: { + source_url: { + label: 'Document URL', + placeholder: 'Enter document URL, one per line. Incorrect URL will cause import failure.', + requiredMessage: 'Please enter a document URL' + }, + selector: { + label: 'Selector', + placeholder: 'Default is body, you can input .classname/#idname/tagname' + }, + hit_handling_method: { + label: 'Retrieve-Respond', + tooltip: 'When user asks a question, handle matched segments according to the set method.' + }, + similarity: { + label: 'Similarity Higher Than', + placeholder: 'Directly return segment content', + requiredMessage: 'Please enter similarity value' + } + }, + hitHandlingMethod: { + optimization: 'Model optimization', + directly_return: 'Respond directly' + }, + generateQuestion: { + title: 'Generate Questions', + successMessage: 'Successful', + tip1: 'The {data} in the prompt is a placeholder for segmented content, which is replaced by the segmented content when executed and sent to the AI model;', + tip2: 'The AI model generates relevant questions based on the segmented content. Please place the generated questions within the', + tip3: 'tags, and the system will automatically relate the questions within these tags;', + tip4: 'The generation effect depends on the selected model and prompt. Users can adjust to achieve the best effect.', + prompt1: + 'Content: {data}\n \n Please summarize the above and generate 5 questions based on the summary. \nAnswer requirements: \n - Please output only questions; \n - Please place each question in', + prompt2: 'tag.' + }, + feishu: { + selectDocument: 'Select Document', + tip1: 'Only documents and tables are supported. Documents will be segmented based on titles, and tables will be converted to Markdown format before segmentation.', + tip2: 'The system does not store the original document. Before importing the document, it is recommended to standardize the document segmentation markers.', + allCheck: 'Select All' + } +} diff --git a/ui/src/locales/lang/en-US/views/function-lib.ts b/ui/src/locales/lang/en-US/views/function-lib.ts new file mode 100644 index 000000000..1ca7103b3 --- /dev/null +++ b/ui/src/locales/lang/en-US/views/function-lib.ts @@ -0,0 +1,79 @@ +export default { + title: 'Function', + internalTitle: 'Internal Function', + added: 'Added', + createFunction: 'Create Function', + editFunction: 'Edit Function', + copyFunction: 'Copy Function', + importFunction: 'Import Function', + searchBar: { + placeholder: 'Search by function name' + }, + setting: { + disabled: 'Disabled' + }, + tip: { + saveMessage: 'Unsaved changes will be lost. Are you sure you want to exit?' + }, + delete: { + confirmTitle: 'Confirm deletion of function:', + confirmMessage: + 'Deleting this function will cause errors in APP that reference it when they are queried. Please proceed with caution.' + }, + disabled: { + confirmTitle: 'Confirm disable function:', + confirmMessage: + 'Disabling this function will cause errors in APP that reference it when they are queried. Please proceed with caution.' + }, + functionForm: { + title: { + copy: 'Copy', + baseInfo: 'Basic Information' + }, + form: { + functionName: { + label: 'Name', + placeholder: 'Please enter the function name', + requiredMessage: 'Please enter the function name' + }, + functionDescription: { + label: 'Description', + placeholder: 'Please enter a description of the function' + }, + permission_type: { + label: 'Permissions', + requiredMessage: 'Please select' + }, + paramName: { + label: 'Parameter Name', + placeholder: 'Please enter the parameter name', + requiredMessage: 'Please enter the parameter name' + }, + dataType: { + label: 'Data Type' + }, + source: { + label: 'Source', + custom: 'Custom', + reference: 'Reference Parameter' + }, + required: { + label: 'Required' + }, + param: { + paramInfo1: 'Displayed when using the function', + paramInfo2: 'Not displayed when using the function', + code: 'Content (Python)', + selectPlaceholder: 'Please select parameter', + inputPlaceholder: 'Please enter parameter values', + }, + debug: { + run: 'Run', + output: 'Output', + runResult: 'Run Result', + runSuccess: 'Successful', + runFailed: 'Run Failed' + } + } + } +} diff --git a/ui/src/locales/lang/en-US/views/index.ts b/ui/src/locales/lang/en-US/views/index.ts new file mode 100644 index 000000000..c63d40492 --- /dev/null +++ b/ui/src/locales/lang/en-US/views/index.ts @@ -0,0 +1,34 @@ +import notFound from './404' +import application from './application' +import applicationOverview from './application-overview' +import dataset from './dataset' +import system from './system' +import functionLib from './function-lib' +import user from './user' +import team from './team' +import template from './template' +import document from './document' +import paragraph from './paragraph' +import problem from './problem' +import log from './log' +import applicationWorkflow from './application-workflow' +import login from './login' +import operateLog from './operate-log' +export default { + notFound, + application, + applicationOverview, + system, + functionLib, + user, + team, + template, + dataset, + applicationWorkflow, + document, + paragraph, + problem, + log, + login, + operateLog +} diff --git a/ui/src/locales/lang/en-US/views/log.ts b/ui/src/locales/lang/en-US/views/log.ts new file mode 100644 index 000000000..9dfa40e00 --- /dev/null +++ b/ui/src/locales/lang/en-US/views/log.ts @@ -0,0 +1,41 @@ +export default { + title: 'Chat Logs', + delete: { + confirmTitle: 'Confirm deletion of question:', + confirmMessage1: 'Deleting this question will cancel the association of', + confirmMessage2: 'segments. Please proceed with caution.' + }, + buttons: { + clearStrategy: 'Cleanup Strategy', + prev: 'Previous', + next: 'Next' + }, + table: { + abstract: 'Title', + chat_record_count: 'Total Messages', + user: 'User', + feedback: { + label: 'User Feedback', + star: 'Agree', + trample: 'Disagree' + }, + mark: 'Marks', + recenTimes: 'Last Chat Time' + }, + addToDataset: 'Add to Knowledge', + daysText: 'Days ago', + selectDataset: 'Select Knowledge', + selectDatasetPlaceholder: 'Please select a knowledge', + saveToDocument: 'Save to Document', + documentPlaceholder: 'Please select a document', + editContent: 'Edit Content', + editMark: 'Edit Label', + form: { + content: { + placeholder: 'Please enter the content' + }, + title: { + placeholder: 'Please set a title for the current content for management and viewing' + } + } +} diff --git a/ui/src/locales/lang/en-US/views/login.ts b/ui/src/locales/lang/en-US/views/login.ts new file mode 100644 index 000000000..dc2edba57 --- /dev/null +++ b/ui/src/locales/lang/en-US/views/login.ts @@ -0,0 +1,24 @@ +export default { + title: 'Login', + jump_tip: 'You will be redirected to the authentication source page for authentication', + jump: 'Redirect', + resetPassword: 'Change Password', + forgotPassword: 'Forgot Password', + userRegister: 'User Registration', + buttons: { + login: 'Login', + register: 'Register', + backLogin: 'Back to Login', + checkCode: 'Verify Now' + }, + newPassword: 'New Password', + enterPassword: 'Please enter your new password', + useEmail: 'Use Email', + moreMethod: 'More Login Methods', + verificationCode: { + placeholder: 'Please enter the verification code', + getVerificationCode: 'Get Verification Code', + successMessage: 'Verification code sent successfully', + resend: 'Resend' + } +} diff --git a/ui/src/locales/lang/en-US/views/operate-log.ts b/ui/src/locales/lang/en-US/views/operate-log.ts new file mode 100644 index 000000000..1dbd8175d --- /dev/null +++ b/ui/src/locales/lang/en-US/views/operate-log.ts @@ -0,0 +1,30 @@ +export default { + title: 'Operate Logs', + table: { + menu: { + label: 'Operate menu' + }, + operate: { + label: 'Operate' + }, + user: { + label: 'Operate user' + }, + status: { + label: 'Status', + success: 'Successful', + fail: 'Failed', + all: 'All' + }, + ip_address: { + label: 'IP Address' + }, + opt: { + label: 'API Details' + }, + operateTime: { + label: 'Operate Time' + } + }, + close: 'Close' +} diff --git a/ui/src/locales/lang/en-US/views/paragraph.ts b/ui/src/locales/lang/en-US/views/paragraph.ts new file mode 100644 index 000000000..812e3ab68 --- /dev/null +++ b/ui/src/locales/lang/en-US/views/paragraph.ts @@ -0,0 +1,32 @@ +export default { + title: 'Segment', + paragraph_count: 'Segments', + editParagraph: 'Edit Segment', + addParagraph: 'Add Segment', + paragraphDetail: 'Segment Details', + character_count: 'characters', + setting: { + batchSelected: 'Batch Select', + cancelSelected: 'Cancel Selection' + }, + delete: { + confirmTitle: 'Confirm deletion of segment:', + confirmMessage: 'Deletion cannot be undone. Please proceed with caution.' + }, + relatedProblem: { + title: 'Related Questions', + placeholder: 'Please select a question' + }, + form: { + paragraphTitle: { + label: 'Title', + placeholder: 'Please enter the segment title' + }, + content: { + label: 'Content', + placeholder: 'Please enter the segment content', + requiredMessage1: 'Please enter the segment content', + requiredMessage2: 'Content must not exceed 100,000 words' + } + } +} diff --git a/ui/src/locales/lang/en-US/views/problem.ts b/ui/src/locales/lang/en-US/views/problem.ts new file mode 100644 index 000000000..cd9780b59 --- /dev/null +++ b/ui/src/locales/lang/en-US/views/problem.ts @@ -0,0 +1,37 @@ +export default { + title: 'Questions', + createProblem: 'Create Question', + detailProblem: 'Question Details', + quickCreateProblem: 'Quick Create', + quickCreateName: 'question', + tip: { + placeholder: 'Enter the question, support multiple entries, one per line.', + errorMessage: 'Question cannot be empty!', + requiredMessage: 'Please enter a question', + relatedSuccess: 'Successful' + }, + + setting: { + batchDelete: 'Bulk Delete', + cancelRelated: 'Cancel Association' + }, + searchBar: { + placeholder: 'Search by name' + }, + table: { + paragraph_count: 'Related Segments', + updateTime: 'Update Time' + }, + delete: { + confirmTitle: 'Confirm deletion of question:', + confirmMessage1: 'Deleting this question will cancel the association of', + confirmMessage2: 'segments. Please proceed with caution.' + }, + relateParagraph: { + title: 'Relate to Segment', + selectDocument: 'Select a Document', + placeholder: 'Search document by name', + selectedParagraph: 'Selected Segments', + count: 'Count' + } +} diff --git a/ui/src/locales/lang/en-US/views/system.ts b/ui/src/locales/lang/en-US/views/system.ts new file mode 100644 index 000000000..303d1175d --- /dev/null +++ b/ui/src/locales/lang/en-US/views/system.ts @@ -0,0 +1,153 @@ +export default { + title: 'System', + test: 'Test Connection', + testSuccess: 'Successful', + testFailed: 'Test connection failed', + password: 'Password', + authentication: { + title: 'Login Authentication', + ldap: { + title: 'LDAP', + address: 'LDAP Address', + serverPlaceholder: 'Please enter LDAP address', + bindDN: 'Bind DN', + bindDNPlaceholder: 'Please enter Bind DN', + ou: 'User OU', + ouPlaceholder: 'Please enter user OU', + ldap_filter: 'User Filter', + ldap_filterPlaceholder: 'Please enter user filter', + ldap_mapping: 'LDAP Attribute Mapping', + ldap_mappingPlaceholder: 'Please enter LDAP attribute mapping', + enableAuthentication: 'Enable LDAP Authentication' + }, + cas: { + title: 'CAS', + ldpUri: 'ldpUri', + ldpUriPlaceholder: 'Please enter ldpUri', + validateUrl: 'Validation Address', + validateUrlPlaceholder: 'Please enter validation address', + redirectUrl: 'Callback Address', + redirectUrlPlaceholder: 'Please enter callback address', + enableAuthentication: 'Enable CAS Authentication' + }, + oidc: { + title: 'OIDC', + authEndpoint: 'Auth Endpoint', + authEndpointPlaceholder: 'Please enter auth endpoint', + tokenEndpoint: 'Token Endpoint', + tokenEndpointPlaceholder: 'Please enter token endpoint', + userInfoEndpoint: 'User Information Endpoint', + userInfoEndpointPlaceholder: 'Please enter user information endpoint', + clientId: 'Client ID', + clientIdPlaceholder: 'Please enter client ID', + scopePlaceholder: 'Please enter scope', + clientSecret: 'Client Secret', + clientSecretPlaceholder: 'Please enter client secret', + logoutEndpoint: 'Logout Endpoint', + logoutEndpointPlaceholder: 'Please enter logout endpoint', + redirectUrl: 'Redirect URL', + redirectUrlPlaceholder: 'Please enter redirect URL', + enableAuthentication: 'Enable OIDC Authentication' + }, + + oauth2: { + title: 'OAuth2', + authEndpoint: 'Auth Endpoint', + authEndpointPlaceholder: 'Please enter auth endpoint', + tokenEndpoint: 'Token Endpoint', + tokenEndpointPlaceholder: 'Please enter token endpoint', + userInfoEndpoint: 'User Information Endpoint', + userInfoEndpointPlaceholder: 'Please enter user information endpoint', + scope: 'Scope', + scopePlaceholder: 'Please enter scope', + clientId: 'Client ID', + clientIdPlaceholder: 'Please enter client ID', + clientSecret: 'Client Secret', + clientSecretPlaceholder: 'Please enter client secret', + redirectUrl: 'Redirect URL', + redirectUrlPlaceholder: 'Please enter redirect URL', + filedMapping: 'Field Mapping', + filedMappingPlaceholder: 'Please enter field mapping', + enableAuthentication: 'Enable OAuth2 Authentication' + }, + scanTheQRCode: { + title: 'Scan the QR code', + wecom: 'WeCom', + dingtalk: 'DingTalk', + lark: 'Lark', + effective: 'Effective', + alreadyTurnedOn: 'Turned On', + notEnabled: 'Not Enabled', + validate: 'Validate', + validateSuccess: 'Successful', + validateFailed: 'Validation failed', + validateFailedTip: 'Please fill in all required fields and ensure the format is correct', + appKeyPlaceholder: 'Please enter APP key', + appSecretPlaceholder: 'Please enter APP secret', + corpIdPlaceholder: 'Please enter corp ID', + agentIdPlaceholder: 'Please enter agent ID', + callbackWarning: 'Please enter a valid URL address', + larkQrCode: 'Lark Scan Code Login', + dingtalkQrCode: 'DingTalk Scan Code Login', + setting: ' Setting', + access: 'Access' + } + }, + theme: { + title: 'Appearance Settings', + platformDisplayTheme: 'Platform Display Theme', + customTheme: 'Custom Theme', + platformLoginSettings: 'Platform Login Settings', + custom: 'Custom', + pagePreview: 'Page Preview', + default: 'Default', + restoreDefaults: 'Restore Defaults', + orange: 'Orange', + green: 'Green', + purple: 'Purple', + red: 'Red', + loginBackground: 'Login Background Image', + loginLogo: 'Login Logo', + websiteLogo: 'Website Logo', + replacePicture: 'Replace Image', + websiteLogoTip: + 'Logo displayed at the top of the website. Recommended size: 48x48. Supports JPG, PNG, GIF. Maximum size: 10MB', + loginLogoTip: + 'Logo on the right side of the login page. Recommended size: 204x52. Supports JPG, PNG, GIF. Maximum size: 10MB', + loginBackgroundTip: + 'Left-side background image. Vector graphics recommended size: 576x900; Bitmap recommended size: 1152x1800. Supports JPG, PNG, GIF. Maximum size: 10MB', + websiteName: 'Website Name', + websiteNamePlaceholder: 'Please enter the website name', + websiteNameTip: 'The platform name displayed in the web page tab', + websiteSlogan: 'Welcome Slogan', + websiteSloganPlaceholder: 'Please enter the welcome slogan', + websiteSloganTip: 'The welcome slogan below the product logo', + defaultSlogan: 'Ready-to-use, flexible RAG Chatbot', + defaultTip: 'The default is the MaxKB platform interface, supports custom settings', + logoDefaultTip: 'The default is the MaxKB login interface, supports custom settings', + platformSetting: 'Platform Settings', + showUserManual: 'Show User Manual', + showForum: 'Show Forum Support', + showProject: 'Show Project Address', + urlPlaceholder: 'Please enter the URL address', + abandonUpdate: 'Abandon Update', + saveAndApply: 'Save and Apply', + fileMessageError: 'File size exceeds 10MB', + saveSuccess: 'Appearance settings successfully applied' + }, + email: { + title: 'Email Settings', + smtpHost: 'SMTP Host', + smtpHostPlaceholder: 'Please enter SMTP host', + smtpPort: 'SMTP Port', + smtpPortPlaceholder: 'Please enter SMTP port', + smtpUser: 'SMTP User', + smtpUserPlaceholder: 'Please enter SMTP user', + sendEmail: 'Sender\'s Email', + sendEmailPlaceholder: 'Please enter the sender\'s email', + smtpPassword: 'SMTP Password', + smtpPasswordPlaceholder: 'Please enter SMTP password', + enableSSL: 'Enable SSL (if the SMTP port is 465, you usually need to enable SSL)', + enableTLS: 'Enable TLS (if the SMTP port is 587, you usually need to enable TLS)' + } +} diff --git a/ui/src/locales/lang/en-US/views/team.ts b/ui/src/locales/lang/en-US/views/team.ts new file mode 100644 index 000000000..d25df4bb3 --- /dev/null +++ b/ui/src/locales/lang/en-US/views/team.ts @@ -0,0 +1,30 @@ +export default { + title: 'Team Members', + member: 'Member', + manage: 'Owner', + permissionSetting: 'Permission Settings', + addMember: 'Add Member', + addSubTitle: 'Members can access the data you authorize after logging in.', + searchBar: { + placeholder: 'Enter username to search' + }, + delete: { + button: 'Remove', + confirmTitle: 'Confirm removal of member:', + confirmMessage: + 'Removing the member will revoke their access to knowledge and APP.' + }, + setting: { + management: 'Manage', + check: 'View' + }, + teamForm: { + form: { + userName: { + label: 'Username/Email', + placeholder: "Enter the member's username or email", + requiredMessage: 'Enter the username/email' + } + } + } +} diff --git a/ui/src/locales/lang/en-US/views/template.ts b/ui/src/locales/lang/en-US/views/template.ts new file mode 100644 index 000000000..0a89fcfb6 --- /dev/null +++ b/ui/src/locales/lang/en-US/views/template.ts @@ -0,0 +1,89 @@ +export default { + title: 'Models', + provider: 'Provider', + providerPlaceholder: 'Select Provider', + addModel: 'Add Model', + searchBar: { + placeholder: 'Search by name' + }, + delete: { + confirmTitle: 'Delete Model', + confirmMessage: 'Are you sure you want to delete the model:' + }, + tip: { + createSuccessMessage: 'Model created successfully', + createErrorMessage: 'There are errors in the basic information', + errorMessage: 'Variable already exists: ', + emptyMessage1: 'Please select the model type and base model in the basic information first', + emptyMessage2: 'The selected model does not support parameter settings', + updateSuccessMessage: 'Model updated successfully', + saveSuccessMessage: 'Model parameters saved successfully', + downloadError: 'Download failed', + noModel: 'Model does not exist in Ollama' + }, + model: { + allModel: 'All Models', + publicModel: 'Public Models', + privateModel: 'Private Models', + LLM: 'LLM', + EMBEDDING: 'Embedding Model', + RERANKER: 'Rerank', + STT: 'Speech2Text', + TTS: 'TTS', + IMAGE: 'Vision Model', + TTI: 'Image Generation' + }, + templateForm: { + title: { + baseInfo: 'Basic Information', + advancedInfo: 'Advanced Settings', + modelParams: 'Model Parameters', + editParam: 'Edit Parameter', + addParam: 'Add Parameter', + paramSetting: 'Model Parameter Settings', + apiParamPassing: 'Interface Parameters' + }, + form: { + templateName: { + label: 'Model Name', + placeholder: 'Set a name for the base model', + tooltip: 'Custom model name in MaxKB', + requiredMessage: 'Model name cannot be empty' + }, + permissionType: { + label: 'Permission', + privateDesc: 'Available only to current user', + publicDesc: 'Available to all users', + requiredMessage: 'Permission cannot be empty' + }, + model_type: { + label: 'Model Type', + placeholder: 'Select a model type', + tooltip1: + 'LLM: An inference model for AI chats in the APP.', + tooltip2: + 'Embedding Model: A model for vectorizing document content in the knowledge.', + tooltip3: 'Speech2Text: A model used for speech recognition in the APP.', + tooltip4: 'TTS: A model used for TTS in the APP.', + tooltip5: + 'Rerank: A model used to reorder candidate segments when using multi-route recall in advanced orchestration APP.', + tooltip6: + 'Vision Model: A visual model used for image understanding in advanced orchestration APP.', + tooltip7: + 'Image Generation: A visual model used for image generation in advanced orchestration APP.', + requiredMessage: 'Model type cannot be empty' + }, + base_model: { + label: 'Base Model', + tooltip: + 'For models not listed, enter the model name and press Enter', + placeholder: 'Enter the base model name and press Enter to add', + requiredMessage: 'Base model cannot be empty' + } + } + }, + download: { + downloading: 'Downloading...', + cancelDownload: 'Cancel Download' + } +} diff --git a/ui/src/locales/lang/en-US/views/user.ts b/ui/src/locales/lang/en-US/views/user.ts new file mode 100644 index 000000000..ae41fd564 --- /dev/null +++ b/ui/src/locales/lang/en-US/views/user.ts @@ -0,0 +1,70 @@ +export default { + title: 'User', + createUser: 'Create User', + editUser: 'Edit User', + setting: { + updatePwd: 'Change Password' + }, + tip: { + professionalMessage: + 'The community edition supports up to 2 users. For more users, please upgrade to the professional edition.', + updatePwdSuccess: 'User password updated successfully' + }, + delete: { + confirmTitle: 'Confirm deletion of user:', + confirmMessage: + 'Deleting this user will also delete all resources (APP, knowledge, models) created by this user. Please proceed with caution.' + }, + disabled: { + confirmTitle: 'Confirm disable function:', + confirmMessage: + 'Disabling this function will cause errors when APP that reference it are queried. Please proceed with caution.' + }, + userForm: { + form: { + username: { + label: 'Username', + placeholder: 'Please enter username', + requiredMessage: 'Please enter username', + lengthMessage: 'Length must be between 6 and 20 words' + }, + nick_name: { + label: 'Name', + placeholder: 'Please enter name' + }, + email: { + label: 'Email', + placeholder: 'Please enter email', + requiredMessage: 'Please enter email' + }, + phone: { + label: 'Phone', + placeholder: 'Please enter phone' + }, + password: { + label: 'Login Password', + placeholder: 'Please enter password', + requiredMessage: 'Please enter password', + lengthMessage: 'Length must be between 6 and 20 words' + }, + new_password: { + label: 'New Password', + placeholder: 'Please enter new password', + requiredMessage: 'Please enter new password' + }, + re_password: { + label: 'Confirm Password', + placeholder: 'Please enter confirm password', + requiredMessage: 'Please enter confirm password', + validatorMessage: 'Passwords do not match' + } + } + }, + source: { + label: 'User Type', + local: 'System User', + wecom: 'WeCom', + lark: 'Lark', + dingtalk: 'DingTalk' + } +} diff --git a/ui/src/locales/lang/zh-CN/ai-chat.ts b/ui/src/locales/lang/zh-CN/ai-chat.ts new file mode 100644 index 000000000..9277762c8 --- /dev/null +++ b/ui/src/locales/lang/zh-CN/ai-chat.ts @@ -0,0 +1,96 @@ +export default { + noHistory: '暂无历史记录', + createChat: '新建对话', + history: '历史记录', + only20history: '仅显示最近 20 条对话', + question_count: '条提问', + exportRecords: '导出聊天记录', + chatId: '对话 ID', + userInput: '用户输入', + quote: '引用', + download: '点击下载文件', + passwordValidator: { + title: '请输入密码打开链接', + errorMessage1: '密码不能为空', + errorMessage2: '密码错误' + }, + operation: { + play: '点击播放', + pause: '停止', + regeneration: '换个答案', + like: '赞同', + cancelLike: '取消赞同', + oppose: '反对', + cancelOppose: '取消反对', + continue: '继续', + stopChat: '停止回答', + startChat: '开始回答', + }, + tip: { + error500Message: '抱歉,当前正在维护,无法提供服务,请稍后再试!', + errorIdentifyMessage: '无法识别用户身份', + errorLimitMessage: '抱歉,您的提问已达到最大限制,请明天再来吧!', + answerMessage: '抱歉,没有查找到相关内容,请重新描述您的问题或提供更多信息。', + stopAnswer: '已停止回答', + answerLoading: '回答中', + recorderTip: `

该功能需要使用麦克风,浏览器禁止不安全页面录音,解决方案如下:
+1、可开启 https 解决;
+2、若无 https 配置则需要修改浏览器安全配置,Chrome 设置如下:
+(1) 地址栏输入chrome://flags/#unsafely-treat-insecure-origin-as-secure;
+(2) 将 http 站点配置在文本框中,例如: http://127.0.0.1:8080。

`, + recorderError: '录音失败', + confirm: '我知道了', + requiredMessage: '请填写所有必填字段', + inputParamMessage1: '请在URL中填写参数', + inputParamMessage2: '的值', + prologueMessage: '抱歉,当前正在维护,无法提供服务,请稍后再试!' + }, + inputPlaceholder: { + speaking: '说话中', + recorderLoading: '转文字中', + default: '请输入问题' + }, + uploadFile: { + label: '上传文件', + most: '最多', + limit: '个,每个文件限制', + fileType: '文件类型', + tipMessage: '请在文件上传配置中选择文件类型', + limitMessage1: '最多上传', + limitMessage2: '个文件', + sizeLimit: '单个文件大小不能超过', + imageMessage: '请解析图片内容', + errorMessage: '上传失败' + }, + executionDetails: { + title: '执行详情', + paramOutputTooltip: '每个文档仅支持预览500字', + audioFile: '语音文件', + searchContent: '检索内容', + searchResult: '检索结果', + conditionResult: '判断结果', + currentChat: '本次对话', + answer: 'AI 回答', + replyContent: '回复内容', + textContent: '文本内容', + input: '输入', + output: '输出', + rerankerContent: '重排内容', + rerankerResult: '重排结果', + paragraph: '分段', + noSubmit: '用户未提交', + errMessage: '错误日志' + }, + KnowledgeSource: { + title: '知识来源', + referenceParagraph: '引用分段', + consume: '消耗tokens', + consumeTime: '耗时' + }, + paragraphSource: { + title: '知识库引用', + question: '用户问题', + optimizationQuestion: '优化后问题' + }, + editTitle: '编辑标题', +} diff --git a/ui/src/locales/lang/zh-CN/common.ts b/ui/src/locales/lang/zh-CN/common.ts new file mode 100644 index 000000000..ba790f282 --- /dev/null +++ b/ui/src/locales/lang/zh-CN/common.ts @@ -0,0 +1,63 @@ +export default { + create: '创建', + createSuccess: '创建成功', + copy: '复制', + copySuccess: '复制成功', + copyError: '复制失败', + save: '保存', + saveSuccess: '保存成功', + delete: '删除', + deleteSuccess: '删除成功', + setting: '设置', + settingSuccess: '设置成功', + submit: '提交', + submitSuccess: '提交成功', + edit: '编辑', + editSuccess: '编辑成功', + modify: '修改', + modifySuccess: '修改成功', + cancel: '取消', + confirm: '确定', + tip: '提示', + add: '添加', + refresh: '刷新', + search: '搜索', + clear: '清空', + professional: '购买专业版', + createDate: '创建日期', + createTime: '创建时间', + operation: '操作', + character: '字符', + export: '导出', + exportSuccess: '导出成功', + unavailable: '(不可用)', + public: '公有', + private: '私有', + paramSetting: '参数设置', + creator: '创建者', + author: '作者', + debug: '调试', + required: '必填', + noData: '暂无数据', + result: '结果', + fileUpload: { + document: '文档', + image: '图片', + audio: '音频', + video: '视频' + }, + status: { + label: '状态', + enableSuccess: '启用成功', + disableSuccess: '禁用成功' + }, + inputPlaceholder: '请输入', + title: '标题', + content: '内容', + param: { + outputParam: '输出参数', + inputParam: '输入参数', + initParam: '启动参数', + }, + rename:'重命名' +} diff --git a/ui/src/locales/lang/zh-CN/components.ts b/ui/src/locales/lang/zh-CN/components.ts new file mode 100644 index 000000000..5b871daf1 --- /dev/null +++ b/ui/src/locales/lang/zh-CN/components.ts @@ -0,0 +1,12 @@ +export default { + quickCreatePlaceholder: '快速创建空白文档', + quickCreateName: '文档名称', + noData: '无匹配数据', + loading: '加载中', + noMore: '到底啦!', + selectParagraph: { + title: '选择分段', + error: '仅执行未成功分段', + all: '全部分段' + } +} diff --git a/ui/src/locales/lang/zh-CN/dynamics-form.ts b/ui/src/locales/lang/zh-CN/dynamics-form.ts new file mode 100644 index 000000000..9814c06eb --- /dev/null +++ b/ui/src/locales/lang/zh-CN/dynamics-form.ts @@ -0,0 +1,102 @@ +export default { + input_type_list: { + TextInput: '文本框', + PasswordInput: '密码框', + Slider: '滑块', + SwitchInput: '开关', + SingleSelect: '单选框', + MultiSelect: '多选框', + DatePicker: '日期', + JsonInput: 'JSON文本框', + RadioCard: '选项卡', + RadioRow: '单行选项卡' + }, + default: { + label: '默认值', + placeholder: '请输入默认值', + requiredMessage: '为必填属性', + show: '显示默认值' + }, + tip: { + requiredMessage: '不能为空', + jsonMessage: 'JSON格式不正确' + }, + searchBar: { + placeholder: '请输入关键字搜索' + }, + paramForm: { + field: { + label: '参数', + placeholder: '请输入参数', + requiredMessage: '参数 为必填属性', + requiredMessage2: '只能输入字母数字和下划线' + }, + name: { + label: '显示名称', + placeholder: '请输入显示名称', + requiredMessage: '显示名称 为必填属性' + }, + tooltip: { + label: '参数提示说明', + placeholder: '请输入参数提示说明' + }, + required: { + label: '是否必填', + requiredMessage: '是否必填 为必填属性' + }, + input_type: { + label: '组件类型', + placeholder: '请选择组件类型', + requiredMessage: '组建类型 为必填属性' + } + }, + DatePicker: { + placeholder: '选择日期', + year: '年', + month: '月', + date: '日期', + datetime: '日期时间', + dataType: { + label: '时间类型', + placeholder: '请选择时间类型' + }, + format: { + label: '格式', + placeholder: '请选择格式' + } + }, + Select: { + label: '选项值', + placeholder: '请输入选项值' + }, + tag: { + label: '标签', + placeholder: '请输入选项标签' + }, + Slider: { + showInput: { + label: '是否带输入框' + }, + valueRange: { + label: '取值范围', + minRequired: '最小值必填', + maxRequired: '最大值必填' + }, + step: { + label: '步长值', + requiredMessage1: '步长值必填', + requiredMessage2: '步长不能为0' + } + }, + TextInput: { + length: { + label: '文本长度', + minRequired: '最小长度必填', + maxRequired: '最大长度必填', + requiredMessage1: '长度在', + requiredMessage2: '到', + requiredMessage3: '个字符', + requiredMessage4: '文本长度为必填参数' + } + } +} diff --git a/ui/src/locales/lang/zh-CN/index.ts b/ui/src/locales/lang/zh-CN/index.ts new file mode 100644 index 000000000..3df42d640 --- /dev/null +++ b/ui/src/locales/lang/zh-CN/index.ts @@ -0,0 +1,17 @@ +import zhCn from 'element-plus/es/locale/lang/zh-cn' +import components from './components' +import layout from './layout' +import views from './views' +import common from './common' +import dynamicsForm from './dynamics-form' +import chat from './ai-chat' +export default { + lang: '简体中文', + layout, + views, + components, + zhCn, + common, + dynamicsForm, + chat +} diff --git a/ui/src/locales/lang/zh-CN/layout.ts b/ui/src/locales/lang/zh-CN/layout.ts new file mode 100644 index 000000000..fbf8e7e93 --- /dev/null +++ b/ui/src/locales/lang/zh-CN/layout.ts @@ -0,0 +1,33 @@ +export default { + github: '项目地址', + wiki: '用户手册', + forum: '论坛求助', + logout: '退出', + apiKey: 'API Key 管理', + apiServiceAddress: 'API 服务地址', + language: '语言', + isExpire: '未上传 License 或 License 已过期。', + about: { + title: '关于', + expiredTime: '到期时间', + edition: { + label: '版本', + community: '社区版', + professional: '专业版' + }, + version: '版本号', + serialNo: '序列号', + remark: '备注', + update: '更新', + authorize: '授权给' + }, + time: { + daysLater: '天后', + hoursLater: '小时后', + expired: '已过期', + expiringSoon: '即将到期' + }, + copyright: '版权所有 © 2014-2025 杭州飞致云信息科技有限公司', + userManualUrl: 'https://maxkb.cn/docs/', + forumUrl: 'https://bbs.fit2cloud.com/c/mk/11' +} diff --git a/ui/src/locales/lang/zh-CN/views/404.ts b/ui/src/locales/lang/zh-CN/views/404.ts new file mode 100644 index 000000000..a65dcbbd0 --- /dev/null +++ b/ui/src/locales/lang/zh-CN/views/404.ts @@ -0,0 +1,5 @@ +export default { + title: "404", + message: "无法访问应用", + operate: "返回首页", +}; diff --git a/ui/src/locales/lang/zh-CN/views/application-overview.ts b/ui/src/locales/lang/zh-CN/views/application-overview.ts new file mode 100644 index 000000000..5c23f9ee3 --- /dev/null +++ b/ui/src/locales/lang/zh-CN/views/application-overview.ts @@ -0,0 +1,112 @@ +export default { + title: '概览', + appInfo: { + header: '应用信息', + publicAccessLink: '公开访问链接', + openText: '开', + closeText: '关', + copyLinkText: '复制链接', + refreshLinkText: '刷新链接', + demo: '演示', + embedInWebsite: '嵌入第三方', + accessControl: '访问限制', + displaySetting: '显示设置', + apiAccessCredentials: 'API 访问凭据', + apiKey: 'API Key', + refreshToken: { + msgConfirm1: '是否重新生成公开访问链接?', + msgConfirm2: + '重新生成公开访问链接会影响嵌入第三方脚本变更,需要将新脚本重新嵌入第三方,请谨慎操作!', + refreshSuccess: '刷新成功' + }, + + APIKeyDialog: { + saveSettings: '保存设置', + msgConfirm1: '是否删除API Key', + msgConfirm2: '删除API Key后将无法恢复,请确认是否删除?', + enabledSuccess: '已启用', + disabledSuccess: '已禁用' + }, + EditAvatarDialog: { + title: '应用头像', + customizeUpload: '自定义上传', + upload: '上传', + default: '默认logo', + custom: '自定义', + sizeTip: '建议尺寸 32*32,支持 JPG、PNG、GIF,大小不超过 10 MB', + fileSizeExceeded: '文件大小超过 10 MB', + uploadImagePrompt: '请上传一张图片' + }, + EmbedDialog: { + fullscreenModeTitle: '全屏模式', + copyInstructions: '复制以下代码进行嵌入', + floatingModeTitle: '浮窗模式', + mobileModeTitle: '移动端模式' + }, + LimitDialog: { + showSourceLabel: '显示知识来源', + clientQueryLimitLabel: '每个客户端提问限制', + timesDays: '次/天', + authentication: '身份验证', + authenticationValue: '验证密码', + whitelistLabel: '白名单', + whitelistPlaceholder: + '请输入允许嵌入第三方的源地址,一行一个,如:\nhttp://127.0.0.1:5678\nhttps://dataease.io' + }, + SettingAPIKeyDialog: { + dialogTitle: '设置', + allowCrossDomainLabel: '允许跨域地址', + crossDomainPlaceholder: + '请输入允许的跨域地址,开启后不输入跨域地址则不限制。\n跨域地址一行一个,如:\nhttp://127.0.0.1:5678 \nhttps://dataease.io' + }, + SettingDisplayDialog: { + dialogTitle: '显示设置', + languageLabel: '语言', + showSourceLabel: '显示知识来源', + showExecutionDetail: '显示执行详情', + restoreDefault: '恢复默认', + customThemeColor: '自定义主题色', + headerTitleFontColor: '头部标题字体颜色', + default: '默认', + askUserAvatar: '提问用户头像', + replace: '替换', + imageMessage: '建议尺寸 32*32,支持 JPG、PNG、GIF,大小不超过 10 MB', + AIAvatar: 'AI 回复头像', + floatIcon: '浮窗入口图标', + iconDefaultPosition: '图标默认位置', + iconPosition: { + left: '左', + right: '右', + bottom: '下', + top: '上' + }, + draggablePosition: '可拖拽位置', + showHistory: '显示历史记录', + displayGuide: '显示引导图(浮窗模式)', + disclaimer: '免责声明', + disclaimerValue: '「以上内容均由 AI 生成,仅供参考和借鉴」' + } + }, + monitor: { + monitoringStatistics: '监控统计', + customRange: '自定义范围', + startDatePlaceholder: '开始时间', + endDatePlaceholder: '结束时间', + pastDayOptions: { + past7Days: '过去7天', + past30Days: '过去30天', + past90Days: '过去90天', + past183Days: '过去半年', + other: '自定义' + }, + charts: { + customerTotal: '用户总数', + customerNew: '用户新增数', + queryCount: '提问次数', + tokensTotal: 'Tokens 总数', + userSatisfaction: '用户满意度', + approval: '赞同', + disapproval: '反对' + } + } +} diff --git a/ui/src/locales/lang/zh-CN/views/application-workflow.ts b/ui/src/locales/lang/zh-CN/views/application-workflow.ts new file mode 100644 index 000000000..010964bb0 --- /dev/null +++ b/ui/src/locales/lang/zh-CN/views/application-workflow.ts @@ -0,0 +1,287 @@ +export default { + node: '节点', + nodeName: '节点名称', + baseComponent: '基础组件', + nodeSetting: '节点设置', + workflow: '工作流', + searchBar: { + placeholder: '按名称搜索' + }, + info: { + previewVersion: '预览版本:', + saveTime: '保存时间:' + }, + setting: { + restoreVersion: '恢复版本', + restoreCurrentVersion: '恢复此版本', + addComponent: '添加组件', + public: '发布', + releaseHistory: '发布历史', + autoSave: '自动保存', + latestRelease: '最近发布', + copyParam: '复制参数', + debug: '调试', + exit: '直接退出', + exitSave: '保存并退出', + }, + tip: { + publicSuccess: '发布成功', + noData: '没有找到相关结果', + nameMessage: '名字不能为空!', + onlyRight: '只允许从右边的锚点连出', + notRecyclable: '不可循环连线', + onlyLeft: '只允许连接左边的锚点', + applicationNodeError: '该应用不可用', + functionNodeError: '该函数不可用', + repeatedNodeError: '节点名称已存在!', + cannotCopy: '不能被复制', + copyError: '已复制节点', + paramErrorMessage: '参数已存在: ', + saveMessage: '当前的更改尚未保存,是否保存后退出?', + }, + delete: { + confirmTitle: '确定删除该节点?', + deleteMessage: '节点不允许删除' + }, + control: { + zoomOut: '缩小', + zoomIn: '放大', + fitView: '适应', + retract: '收起全部节点', + extend: '展开全部节点', + beautify: '一键美化' + }, + variable: { + label: '变量', + global: '全局变量', + Referencing: '引用变量', + ReferencingRequired: '引用变量必填', + ReferencingError: '引用变量错误', + NoReferencing: '不存在的引用变量', + placeholder: '请选择变量' + }, + condition: { + title: '执行条件', + front: '前置', + AND: '所有', + OR: '任一', + text: '连线节点执行完,执行当前节点' + }, + validate: { + startNodeRequired: '开始节点必填', + startNodeOnly: '开始节点只能有一个', + baseNodeRequired: '基本信息节点必填', + baseNodeOnly: '基本信息节点只能有一个', + notInWorkFlowNode: '未在流程中的节点', + noNextNode: '不存在的下一个节点', + nodeUnavailable: '节点不可用', + needConnect1: '节点的', + needConnect2: '分支需要连接', + cannotEndNode: '节点不能当做结束节点' + }, + nodes: { + startNode: { + label: '开始', + question: '用户问题', + currentTime: '当前时间' + }, + baseNode: { + label: '基本信息', + appName: { + label: '应用名称' + }, + appDescription: { + label: '应用描述' + }, + fileUpload: { + label: '文件上传', + tooltip: '开启后,问答页面会显示上传文件的按钮。' + }, + FileUploadSetting: { + title: '文件上传设置', + maxFiles: '单次上传最多文件数', + fileLimit: '每个文件最大(MB)', + fileUploadType: { + label: '上传的文件类型', + documentText: '需要使用“文档内容提取”节点解析文档内容', + imageText: '需要使用“视觉模型”节点解析图片内容', + audioText: '需要使用“语音转文本”节点解析音频内容' + } + } + }, + aiChatNode: { + label: 'AI 对话', + text: '与 AI 大模型进行对话', + answer: 'AI 回答内容', + returnContent: { + label: '返回内容', + tooltip: `关闭后该节点的内容则不输出给用户。 + 如果你想让用户看到该节点的输出内容,请打开开关。` + }, + defaultPrompt: '已知信息', + think: '思考过程' + }, + searchDatasetNode: { + label: '知识库检索', + text: '关联知识库,查找与问题相关的分段', + paragraph_list: '检索结果的分段列表', + is_hit_handling_method_list: '满足直接回答的分段列表', + result: '检索结果', + directly_return: '满足直接回答的分段内容', + searchParam: '检索参数', + searchQuestion: { + label: '检索问题', + placeholder: '请选择检索问题', + requiredMessage: '请选择检索问题' + } + }, + questionNode: { + label: '问题优化', + text: '根据历史聊天记录优化完善当前问题,更利于匹配知识库分段', + result: '问题优化结果', + defaultPrompt1: `根据上下文优化和完善用户问题`, + defaultPrompt2: `请输出一个优化后的问题。`, + systemDefault: '你是一个问题优化大师' + }, + conditionNode: { + label: '判断器', + text: '根据不同条件执行不同的节点', + branch_name: '分支名称', + conditions: { + label: '条件', + info: '符合以下', + requiredMessage: '请选择条件' + }, + valueMessage: '请输入值', + addCondition: '添加条件', + addBranch: '添加分支' + }, + replyNode: { + label: '指定回复', + text: '指定回复内容,引用变量会转换为字符串进行输出', + content: '内容', + replyContent: { + label: '回复内容', + custom: '自定义', + reference: '引用变量' + } + }, + rerankerNode: { + label: '多路召回', + text: '使用重排模型对多个知识库的检索结果进行二次召回', + result_list: '重排结果列表', + result: '重排结果', + rerankerContent: { + label: '重排内容', + requiredMessage: '请选择重排内容' + }, + higher: '高于', + ScoreTooltip: 'Score越高相关性越强。', + max_paragraph_char_number: '最大引用字符数', + reranker_model: { + label: '重排模型', + placeholder: '请选择重排模型' + } + }, + formNode: { + label: '表单收集', + text: '在问答过程中用于收集用户信息,可以根据收集到表单数据执行后续流程', + form_content_format1: '你好,请先填写下面表单内容:', + form_content_format2: '填写后请点击【提交】按钮进行提交。', + form_data: '表单全部内容', + formContent: { + label: '表单输出内容', + requiredMessage: '请表单输出内容', + tooltip: '设置执行该节点输出的内容,{ form } 为表单的占位符。' + }, + formAllContent: '表单全部内容', + formSetting: '表单配置' + }, + documentExtractNode: { + label: '文档内容提取', + text: '提取文档中的内容', + content: '文档内容' + }, + imageUnderstandNode: { + label: '图片理解', + text: '识别出图片中的对象、场景等信息回答用户问题', + answer: 'AI 回答内容', + model: { + label: '视觉模型', + requiredMessage: '请选择视觉模型' + }, + image: { + label: '选择图片', + requiredMessage: '请选择图片' + } + }, + variableAssignNode: { + label: '变量赋值', + text: '更新全局变量的值', + assign: '赋值' + }, + imageGenerateNode: { + label: '图片生成', + text: '根据提供的文本内容生成图片', + answer: 'AI 回答内容', + model: { + label: '图片生成模型', + requiredMessage: '请选择图片生成模型' + }, + prompt: { + label: '提示词(正向)', + tooltip: '正向提示词,用来描述生成图像中期望包含的元素和视觉特点' + }, + negative_prompt: { + label: '提示词(负向)', + tooltip: '反向提示词,用来描述不希望在画面中看到的内容,可以对画面进行限制。', + placeholder: '请描述不想生成的图片内容,比如:颜色、血腥内容' + } + }, + speechToTextNode: { + label: '语音转文本', + text: '将音频通过语音识别模型转换为文本', + stt_model: { + label: '语音识别模型' + }, + audio: { + label: '选择语音文件', + placeholder: '请选择语音文件' + } + }, + textToSpeechNode: { + label: '文本转语音', + text: '将文本通过语音合成模型转换为音频', + tts_model: { + label: '语音识别模型' + }, + content: { + label: '选择文本内容' + } + }, + functionNode: { + label: '自定义函数', + text: '通过执行自定义脚本,实现数据处理' + }, + applicationNode: { + label: '应用节点' + } + }, + compare: { + is_null: '为空', + is_not_null: '不为空', + contain: '包含', + not_contain: '不包含', + eq: '等于', + ge: '大于等于', + gt: '大于', + le: '小于等于', + lt: '小于', + len_eq: '长度等于', + len_ge: '长度大于等于', + len_gt: '长度大于', + len_le: '长度小于等于', + len_lt: '长度小于' + }, + FileUploadSetting: {} +} diff --git a/ui/src/locales/lang/zh-CN/views/application.ts b/ui/src/locales/lang/zh-CN/views/application.ts new file mode 100644 index 000000000..b818827e3 --- /dev/null +++ b/ui/src/locales/lang/zh-CN/views/application.ts @@ -0,0 +1,215 @@ +export default { + title: '应用', + createApplication: '创建应用', + importApplication: '导入应用', + copyApplication: '复制应用', + workflow: '高级编排', + simple: '简单配置', + searchBar: { + placeholder: '按名称搜索' + }, + setting: { + demo: '演示' + }, + delete: { + confirmTitle: '是否删除应用:', + confirmMessage: '删除后该应用将不再提供服务,请谨慎操作。' + }, + tip: { + ExportError: '导出失败', + professionalMessage: '社区版最多支持 5 个应用,如需拥有更多应用,请升级为专业版。', + saveErrorMessage: '保存失败,请检查输入或稍后再试', + loadingErrorMessage: '加载配置失败,请检查输入或稍后再试' + }, + applicationForm: { + title: { + appTest: '调试预览', + copy: '副本' + }, + form: { + appName: { + label: '名称', + placeholder: '请输入应用名称', + requiredMessage: '请输入应用名称' + }, + appDescription: { + label: '描述', + placeholder: '描述该应用的应用场景及用途,如:XXX 小助手回答用户提出的 XXX 产品使用问题' + }, + appType: { + label: '类型', + simplePlaceholder: '适合新手创建小助手', + workflowPlaceholder: '适合高级用户自定义小助手的工作流' + }, + appTemplate: { + blankApp: '空白应用', + assistantApp: '知识库问答助手' + }, + aiModel: { + label: 'AI 模型', + placeholder: '请选择 AI 模型' + }, + roleSettings: { + label: '系统角色', + placeholder: '你是 xxx 小助手' + }, + prompt: { + label: '提示词', + noReferences: ' (无引用知识库)', + references: ' (引用知识库)', + placeholder: '请输入提示词', + requiredMessage: '请输入提示词', + tooltip: + '通过调整提示词内容,可以引导大模型聊天方向,该提示词会被固定在上下文的开头,可以使用变量。', + noReferencesTooltip: + '通过调整提示词内容,可以引导大模型聊天方向,该提示词会被固定在上下文的开头。可以使用变量:{question} 是用户提出问题的占位符。', + referencesTooltip: + '通过调整提示词内容,可以引导大模型聊天方向,该提示词会被固定在上下文的开头。可以使用变量:{data} 是引用知识库中分段的占位符;{question} 是用户提出问题的占位符。', + defaultPrompt: `已知信息:{data} +用户问题:{question} +回答要求: + - 请使用中文回答用户问题` + }, + historyRecord: { + label: '历史聊天记录' + }, + relatedKnowledge: { + label: '关联知识库', + placeholder: '关联的知识库展示在这里' + }, + multipleRoundsDialogue: '多轮对话', + + prologue: '开场白', + defaultPrologue: + '您好,我是 XXX 小助手,您可以向我提出 XXX 使用问题。\n- XXX 主要功能有什么?\n- XXX 如何收费?\n- 需要转人工服务', + + problemOptimization: { + label: '问题优化', + tooltip: '根据历史聊天优化完善当前问题,更利于匹配知识点。' + }, + voiceInput: { + label: '语音输入', + placeholder: '请选择语音识别模型', + requiredMessage: '请选择语音输入模型', + autoSend: '自动发送' + }, + voicePlay: { + label: '语音播放', + placeholder: '请选择语音合成模型', + requiredMessage: '请选择语音播放模型', + autoPlay: '自动播放', + browser: '浏览器播放(免费)', + tts: 'TTS模型', + listeningTest: '试听' + }, + reasoningContent: { + label: '输出思考', + tooltip: '请根据模型返回的思考标签设置,标签中间的内容将会认定为思考过程', + start: '开始', + end: '结束' + } + }, + buttons: { + publish: '保存并发布', + + addModel: '添加模型' + }, + + dialog: { + addDataset: '添加关联知识库', + addDatasetPlaceholder: '所选知识库必须使用相同的 Embedding 模型', + selected: '已选', + countDataset: '个知识库', + + selectSearchMode: '检索模式', + vectorSearch: '向量检索', + vectorSearchTooltip: '向量检索是一种基于向量相似度的检索方式,适用于知识库中的大数据量场景。', + fullTextSearch: '全文检索', + fullTextSearchTooltip: + '全文检索是一种基于文本相似度的检索方式,适用于知识库中的小数据量场景。', + hybridSearch: '混合检索', + hybridSearchTooltip: + '混合检索是一种基于向量和文本相似度的检索方式,适用于知识库中的中等数据量场景。', + similarityThreshold: '相似度高于', + similarityTooltip: '相似度越高相关性越强。', + topReferences: '引用分段数 TOP', + maxCharacters: '最多引用字符数', + noReferencesAction: '无引用知识库分段时', + continueQuestioning: '继续向 AI 模型提问', + provideAnswer: '指定回答内容', + designated_answer: + '你好,我是 XXX 小助手,我的知识库只包含了 XXX 产品相关知识,请重新描述您的问题。', + defaultPrompt1: + '()里面是用户问题,根据上下文回答揣测用户问题({question}) 要求: 输出一个补全问题,并且放在', + defaultPrompt2: '标签中' + } + }, + applicationAccess: { + title: '应用接入', + wecom: '企业微信应用', + wecomTip: '打造企业微信智能应用', + dingtalk: '钉钉应用', + dingtalkTip: '打造钉钉智能应用', + wechat: '公众号', + wechatTip: '打造公众号智能应用', + lark: '飞书应用', + larkTip: '打造飞书智能应用', + slack: 'Slack', + slackTip: '打造 Slack 智能应用', + setting: '配置', + callback: '回调地址', + callbackTip: '请输入回调地址', + wecomPlatform: '企业微信后台', + wechatPlatform: '微信公众平台', + dingtalkPlatform: '钉钉开放平台', + larkPlatform: '飞书开放平台', + wecomSetting: { + title: '企业微信应用配置', + cropId: '企业 ID', + cropIdPlaceholder: '请输入企业 ID', + agentIdPlaceholder: '请输入Agent ID', + secretPlaceholder: '请输入Secret', + tokenPlaceholder: '请输入Token', + encodingAesKeyPlaceholder: '请输入EncodingAESKey', + authenticationSuccessful: '认证成功', + urlInfo: '-应用管理-自建-创建的应用-接收消息-设置 API 接收的 "URL" 中' + }, + dingtalkSetting: { + title: '钉钉应用配置', + clientIdPlaceholder: '请输入Client ID', + clientSecretPlaceholder: '请输入Client Secret', + urlInfo: '-机器人页面,设置 "消息接收模式" 为 HTTP模式 ,并把上面URL填写到"消息接收地址"中' + }, + wechatSetting: { + title: '公众号应用配置', + appId: '开发者ID (APP ID)', + appIdPlaceholder: '请输入开发者ID (APP ID)', + appSecret: '开发者密钥 (APP SECRET)', + appSecretPlaceholder: '请输入开发者密钥 (APP SECRET)', + token: '令牌 (TOKEN)', + tokenPlaceholder: '请输入令牌 (TOKEN)', + aesKey: '消息加解密密钥', + aesKeyPlaceholder: '请输入消息加解密密钥', + urlInfo: '-设置与开发-基本配置-服务器配置的 "服务器地址URL" 中' + }, + larkSetting: { + title: '飞书应用配置', + appIdPlaceholder: '请输入App ID', + appSecretPlaceholder: '请输入App Secret', + verificationTokenPlaceholder: '请输入Verification Token', + urlInfo: '-事件与回调-事件配置-配置订阅方式的 "请求地址" 中' + }, + slackSetting: { + title: 'Slack 应用配置', + signingSecretPlaceholder: '请输入 Signing Secret', + botUserTokenPlaceholder: '请输入 Bot User Token' + }, + copyUrl: '复制链接填入到' + }, + hitTest: { + title: '命中测试', + text: '针对用户提问调试段落匹配情况,保障回答效果。', + emptyMessage1: '命中段落显示在这里', + emptyMessage2: '没有命中的分段' + } +} diff --git a/ui/src/locales/lang/zh-CN/views/dataset.ts b/ui/src/locales/lang/zh-CN/views/dataset.ts new file mode 100644 index 000000000..5ca010525 --- /dev/null +++ b/ui/src/locales/lang/zh-CN/views/dataset.ts @@ -0,0 +1,84 @@ +export default { + title: '知识库', + createDataset: '创建知识库', + general: '通用型', + web: 'web 站点', + relatedApplications: '关联应用', + document_count: '文档数', + relatedApp_count: '关联应用', + searchBar: { + placeholder: '按名称搜索' + }, + setting: { + vectorization: '向量化', + sync: '同步' + }, + tip: { + professionalMessage: '社区版最多支持 50 个知识库,如需拥有更多知识库,请升级为专业版。', + syncSuccess: '同步任务发送成功', + updateModeMessage: '修改知识库向量模型后,需要对知识库向量化,是否继续保存?' + }, + delete: { + confirmTitle: '是否删除知识库:', + confirmMessage1: '此知识库关联', + confirmMessage2: '个应用,删除后无法恢复,请谨慎操作。' + }, + + datasetForm: { + title: { + info: '基本信息' + }, + form: { + datasetName: { + label: '知识库名称', + placeholder: '请输入知识库名称', + requiredMessage: '请输入应用名称' + }, + datasetDescription: { + label: '知识库描述', + placeholder: + '描述知识库的内容,详尽的描述将帮助AI能深入理解该知识库的内容,能更准确的检索到内容,提高该知识库的命中率。', + requiredMessage: '请输入知识库描述' + }, + EmbeddingModel: { + label: '向量模型', + placeholder: '请选择向量模型', + requiredMessage: '请输入Embedding模型' + }, + datasetType: { + label: '知识库类型', + generalInfo: '上传本地文档', + webInfo: '同步Web网站文本数据' + }, + source_url: { + label: 'Web 根地址', + placeholder: '请输入 Web 根地址', + requiredMessage: ' 请输入 Web 根地址' + }, + selector: { + label: '选择器', + placeholder: '默认为 body,可输入 .classname/#idname/tagname' + } + } + }, + ResultSuccess: { + title: '知识库创建成功', + paragraph: '分段', + paragraph_count: '个分段', + documentList: '文档列表', + loading: '导入中', + buttons: { + toDataset: '返回知识库列表', + toDocument: '前往文档' + } + }, + syncWeb: { + title: '同步知识库', + syncMethod: '同步方式', + replace: '替换同步', + replaceText: '重新获取 Web 站点文档,覆盖替换本地知识库中的文档', + complete: '整体同步', + completeText: '先删除本地知识库所有文档,重新获取 Web 站点文档', + tip: '注意:所有同步都会删除已有数据重新获取新数据,请谨慎操作。' + } +} diff --git a/ui/src/locales/lang/zh-CN/views/document.ts b/ui/src/locales/lang/zh-CN/views/document.ts new file mode 100644 index 000000000..154ca5745 --- /dev/null +++ b/ui/src/locales/lang/zh-CN/views/document.ts @@ -0,0 +1,174 @@ +export default { + uploadDocument: '上传文档', + importDocument: '导入文档', + syncDocument: '同步文档', + selected: '已选', + items: '项', + searchBar: { + placeholder: '按 文档名称 搜索' + }, + setting: { + migration: '迁移', + cancelGenerateQuestion: '取消生成问题', + cancelVectorization: '取消向量化', + cancelGenerate: '取消生成', + export: '导出' + }, + tip: { + saveMessage: '当前的更改尚未保存,确认退出吗?', + cancelSuccess: '批量取消成功', + sendMessage: '发送成功', + vectorizationSuccess: '批量向量化成功', + nameMessage: '文件名称不能为空!', + importMessage: '导入成功', + migrationSuccess: '迁移成功' + }, + upload: { + selectFile: '选择文件', + selectFiles: '选择文件夹', + uploadMessage: '拖拽文件至此上传或', + formats: '支持格式:', + requiredMessage: '请上传文件', + errorMessage1: '文件大小超过 100MB', + errorMessage2: '文件格式不支持', + errorMessage3: '文件不能为空', + errorMessage4: '每次最多上传50个文件', + template: '模版', + download: '下载' + }, + + fileType: { + txt: { + label: '文本文件', + tip1: '1、文件上传前,建议规范文件的分段标识', + tip2: '2、每次最多上传 50 个文件,每个文件不超过 100MB' + }, + table: { + label: '表格', + tip1: '1、点击下载对应模版并完善信息:', + tip2: '2、第一行必须是列标题,且列标题必须是有意义的术语,表中每条记录将作为一个分段', + tip3: '3、上传的表格文件中每个 sheet 会作为一个文档,sheet名称为文档名称', + tip4: '4、每次最多上传 50 个文件,每个文件不超过 100MB' + }, + QA: { + label: 'QA 问答对', + tip1: '1、点击下载对应模版并完善信息', + tip2: '2、上传的表格文件中每个 sheet 会作为一个文档,sheet名称为文档名称', + tip3: '3、每次最多上传 50 个文件,每个文件不超过 100MB' + } + }, + setRules: { + title: { + setting: '设置分段规则', + preview: '分段预览' + }, + intelligent: { + label: '智能分段(推荐)', + text: '不了解如何设置分段规则推荐使用智能分段' + }, + advanced: { + label: '高级分段', + text: '用户可根据文档规范自行设置分段标识符、分段长度以及清洗规则' + }, + patterns: { + label: '分段标识', + tooltip: '按照所选符号先后顺序做递归分割,分割结果超出分段长度将截取至分段长度。', + placeholder: '请选择' + }, + limit: { + label: '分段长度' + }, + with_filter: { + label: '自动清洗', + text: '去掉重复多余符号空格、空行、制表符' + }, + checkedConnect: { + label: '导入时添加分段标题为关联问题(适用于标题为问题的问答对)' + } + }, + buttons: { + prev: '上一步', + next: '下一步', + import: '开始导入', + preview: '生成预览' + }, + table: { + name: '文件名称', + char_length: '字符数', + paragraph: '分段', + all: '全部', + updateTime: '更新时间' + }, + fileStatus: { + label: '文件状态', + SUCCESS: '成功', + FAILURE: '失败', + EMBEDDING: '索引中', + PENDING: '排队中', + GENERATE: '生成中', + SYNC: '同步中', + REVOKE: '取消中', + finish: '完成' + }, + enableStatus: { + label: '启用状态', + enable: '开启', + close: '关闭' + }, + sync: { + label: '同步', + confirmTitle: '确认同步文档?', + confirmMessage1: '同步将删除已有数据重新获取新数据,请谨慎操作。', + confirmMessage2: '无法同步,请先去设置文档 URL地址', + successMessage: '同步文档成功' + }, + delete: { + confirmTitle1: '是否批量删除', + confirmTitle2: '个文档?', + confirmMessage: '所选文档中的分段会跟随删除,请谨慎操作。', + successMessage: '批量删除成功', + confirmTitle3: '是否删除文档:', + confirmMessage1: '此文档下的', + confirmMessage2: '个分段都会被删除,请谨慎操作。' + }, + form: { + source_url: { + label: '文档地址', + placeholder: '请输入文档地址,一行一个,地址不正确文档会导入失败。', + requiredMessage: '请输入文档地址' + }, + selector: { + label: '选择器', + placeholder: '默认为 body,可输入 .classname/#idname/tagname' + }, + hit_handling_method: { + label: '命中处理方式', + tooltip: '用户提问时,命中文档下的分段时按照设置的方式进行处理。' + }, + similarity: { + label: '相似度高于', + placeholder: '直接返回分段内容', + requiredMessage: '请输入相似度' + } + }, + hitHandlingMethod: { + optimization: '模型优化', + directly_return: '直接回答' + }, + generateQuestion: { + title: '生成问题', + successMessage: '生成问题成功', + tip1: '提示词中的 {data} 为分段内容的占位符,执行时替换为分段内容发送给 AI 模型;', + tip2: 'AI 模型根据分段内容生成相关问题,请将生成的问题放至', + tip3: '标签中,系统会自动关联标签中的问题;', + tip4: '生成效果依赖于所选模型和提示词,用户可自行调整至最佳效果。', + prompt1: `内容:{data}\n\n请总结上面的内容,并根据内容总结生成 5 个问题。\n回答要求:\n- 请只输出问题;\n- 请将每个问题放置`, + prompt2: `标签中。` + }, + feishu: { + selectDocument: '选择文档', + tip1: '仅支持文档和表格类型,文档会根据标题分段,表格会转为Markdown格式后再分段。', + tip2: '系统不存储原始文档,导入文档前,建议规范文档的分段标识。', + allCheck: '全选' + } +} diff --git a/ui/src/locales/lang/zh-CN/views/function-lib.ts b/ui/src/locales/lang/zh-CN/views/function-lib.ts new file mode 100644 index 000000000..b0767b644 --- /dev/null +++ b/ui/src/locales/lang/zh-CN/views/function-lib.ts @@ -0,0 +1,77 @@ +export default { + title: '函数库', + internalTitle: '内置函数', + added: '已添加', + createFunction: '创建函数', + editFunction: '编辑函数', + copyFunction: '复制函数', + importFunction: '导入函数', + searchBar: { + placeholder: '按函数名称搜索' + }, + setting: { + disabled: '禁用' + }, + tip: { + saveMessage: '当前的更改尚未保存,确认退出吗?' + }, + delete: { + confirmTitle: '是否删除函数:', + confirmMessage: '删除后,引用了该函数的应用提问时会报错 ,请谨慎操作。' + }, + disabled: { + confirmTitle: '是否禁用函数:', + confirmMessage: '禁用后,引用了该函数的应用提问时会报错 ,请谨慎操作。' + }, + functionForm: { + title: { + copy: '副本', + baseInfo: '基础信息' + }, + form: { + functionName: { + label: '名称', + placeholder: '请输入函数名称', + requiredMessage: '请输入函数名称' + }, + functionDescription: { + label: '描述', + placeholder: '请输入函数的描述' + }, + permission_type: { + label: '权限', + requiredMessage: '请选择' + }, + paramName: { + label: '参数名', + placeholder: '请输入参数名', + requiredMessage: '请输入参数名' + }, + dataType: { + label: '数据类型' + }, + source: { + label: '来源', + custom: '自定义', + reference: '引用参数' + }, + required: { + label: '是否必填' + }, + param: { + paramInfo1: '使用函数时显示', + paramInfo2: '使用函数时不显示', + code: '函数内容(Python)', + selectPlaceholder: '请选择参数', + inputPlaceholder: '请输入参数值', + }, + debug: { + run: '运行', + output: '输出', + runResult: '运行结果', + runSuccess: '运行成功', + runFailed: '运行失败' + } + } + } +} diff --git a/ui/src/locales/lang/zh-CN/views/index.ts b/ui/src/locales/lang/zh-CN/views/index.ts new file mode 100644 index 000000000..b8c85b031 --- /dev/null +++ b/ui/src/locales/lang/zh-CN/views/index.ts @@ -0,0 +1,34 @@ +import notFound from './404' +import application from './application' +import applicationOverview from './application-overview' +import dataset from './dataset' +import system from './system' +import functionLib from './function-lib' +import user from './user' +import team from './team' +import template from './template' +import document from './document' +import paragraph from './paragraph' +import problem from './problem' +import log from './log' +import applicationWorkflow from './application-workflow' +import login from './login' +import operateLog from './operate-log' +export default { + notFound, + application, + applicationOverview, + dataset, + system, + functionLib, + user, + team, + template, + document, + paragraph, + problem, + log, + applicationWorkflow, + login, + operateLog +} diff --git a/ui/src/locales/lang/zh-CN/views/log.ts b/ui/src/locales/lang/zh-CN/views/log.ts new file mode 100644 index 000000000..c866a9551 --- /dev/null +++ b/ui/src/locales/lang/zh-CN/views/log.ts @@ -0,0 +1,41 @@ +export default { + title: '对话日志', + delete: { + confirmTitle: '是否删除问题:', + confirmMessage1: '删除问题关联的', + confirmMessage2: '个分段会被取消关联,请谨慎操作。' + }, + buttons: { + clearStrategy: '清除策略', + prev: '上一条', + next: '下一条' + }, + table: { + abstract: '摘要', + chat_record_count: '对话提问数', + user: '用户', + feedback: { + label: '用户反馈', + star: '赞同', + trample: '反对' + }, + mark: '改进标注', + recenTimes: '最近对话时间' + }, + addToDataset: '添加至知识库', + daysText: '天之前的对话记录', + selectDataset: '选择知识库', + selectDatasetPlaceholder: '请选择知识库', + saveToDocument: '保存至文档', + documentPlaceholder: '请选择文档', + editContent: '修改内容', + editMark: '修改标注', + form: { + content: { + placeholder: '请输入内容' + }, + title: { + placeholder: '请给当前内容设置一个标题,以便管理查看' + } + } +} diff --git a/ui/src/locales/lang/zh-CN/views/login.ts b/ui/src/locales/lang/zh-CN/views/login.ts new file mode 100644 index 000000000..c3ccf725e --- /dev/null +++ b/ui/src/locales/lang/zh-CN/views/login.ts @@ -0,0 +1,24 @@ +export default { + title: '普通登录', + jump_tip: '即将跳转至认证源页面进行认证', + jump: '跳转', + resetPassword: '修改密码', + forgotPassword: '忘记密码', + userRegister: '用户注册', + buttons: { + login: '登录', + register: '注册', + backLogin: '返回登录', + checkCode: '立即验证' + }, + newPassword: '新密码', + enterPassword: '请输入修改密码', + useEmail: '使用邮箱', + moreMethod: '更多登录方式', + verificationCode: { + placeholder: '请输入验证码', + getVerificationCode: '获取验证码', + successMessage: '验证码发送成功', + resend: '重新发送' + } +} diff --git a/ui/src/locales/lang/zh-CN/views/operate-log.ts b/ui/src/locales/lang/zh-CN/views/operate-log.ts new file mode 100644 index 000000000..880623057 --- /dev/null +++ b/ui/src/locales/lang/zh-CN/views/operate-log.ts @@ -0,0 +1,30 @@ +export default { + title: '操作日志', + table: { + menu: { + label: '操作菜单' + }, + operate: { + label: '操作' + }, + user: { + label: '操作用户' + }, + status: { + label: '状态', + success: '成功', + fail: '失败', + all: '全部' + }, + ip_address: { + label: 'IP地址' + }, + opt: { + label: 'API详情' + }, + operateTime: { + label: '操作时间' + } + }, + close: '关闭' +} diff --git a/ui/src/locales/lang/zh-CN/views/paragraph.ts b/ui/src/locales/lang/zh-CN/views/paragraph.ts new file mode 100644 index 000000000..cf38b908f --- /dev/null +++ b/ui/src/locales/lang/zh-CN/views/paragraph.ts @@ -0,0 +1,32 @@ +export default { + title: '段落', + paragraph_count: '段落', + editParagraph: '编辑分段', + addParagraph: '添加分段', + paragraphDetail: '分段详情', + character_count: '个字符', + setting: { + batchSelected: '批量选择', + cancelSelected: '取消选择' + }, + delete: { + confirmTitle: '是否删除段落:', + confirmMessage: '删除后无法恢复,请谨慎操作。' + }, + relatedProblem: { + title: '关联问题', + placeholder: '请选择问题' + }, + form: { + paragraphTitle: { + label: '分段标题', + placeholder: '请输入分段标题' + }, + content: { + label: '分段内容', + placeholder: '请输入分段内容', + requiredMessage1: '请输入分段内容', + requiredMessage2: '内容最多不超过 100000 个字' + } + } +} diff --git a/ui/src/locales/lang/zh-CN/views/problem.ts b/ui/src/locales/lang/zh-CN/views/problem.ts new file mode 100644 index 000000000..bb53275aa --- /dev/null +++ b/ui/src/locales/lang/zh-CN/views/problem.ts @@ -0,0 +1,37 @@ +export default { + title: '问题', + createProblem: '创建问题', + detailProblem: '问题详情', + quickCreateProblem: '快速创建问题', + quickCreateName: '问题', + tip: { + placeholder: '请输入问题,支持输入多个,一行一个。', + errorMessage: '问题不能为空!', + requiredMessage: '请输入问题', + relatedSuccess:'批量关联分段成功' + }, + + setting: { + batchDelete: '批量删除', + cancelRelated: '取消关联' + }, + searchBar: { + placeholder: '按名称搜索' + }, + table: { + paragraph_count: '关联分段数', + updateTime: '更新时间' + }, + delete: { + confirmTitle: '是否删除问题:', + confirmMessage1: '删除问题关联的', + confirmMessage2: '个分段会被取消关联,请谨慎操作。' + }, + relateParagraph: { + title: '关联分段', + selectDocument: '选择文档', + placeholder: '按 文档名称 搜索', + selectedParagraph: '已选分段', + count: '个' + }, +} diff --git a/ui/src/locales/lang/zh-CN/views/system.ts b/ui/src/locales/lang/zh-CN/views/system.ts new file mode 100644 index 000000000..9ce23d90d --- /dev/null +++ b/ui/src/locales/lang/zh-CN/views/system.ts @@ -0,0 +1,151 @@ +export default { + title: '系统设置', + test: '测试连接', + testSuccess: '测试连接成功', + testFailed: '测试连接失败', + password: '密码', + authentication: { + title: '登录认证', + ldap: { + title: 'LDAP', + address: 'LDAP 地址', + serverPlaceholder: '请输入LDAP 地址', + bindDN: '绑定DN', + bindDNPlaceholder: '请输入绑定 DN', + ou: '用户OU', + ouPlaceholder: '请输入用户 OU', + ldap_filter: '用户过滤器', + ldap_filterPlaceholder: '请输入用户过滤器', + ldap_mapping: 'LDAP 属性映射', + ldap_mappingPlaceholder: '请输入 LDAP 属性映射', + enableAuthentication: '启用 LDAP 认证' + }, + cas: { + title: 'CAS', + ldpUri: 'ldpUri', + ldpUriPlaceholder: '请输入ldpUri', + validateUrl: '验证地址', + validateUrlPlaceholder: '请输入验证地址', + redirectUrl: '回调地址', + redirectUrlPlaceholder: '请输入回调地址', + enableAuthentication: '启用 CAS 认证' + }, + oidc: { + title: 'OIDC', + authEndpoint: '授权端地址', + authEndpointPlaceholder: '请输入授权端地址', + tokenEndpoint: 'Token端地址', + tokenEndpointPlaceholder: '请输入 Token 端地址', + userInfoEndpoint: '用户信息端地址', + userInfoEndpointPlaceholder: '请输入用户信息端地址', + scopePlaceholder: '请输入连接范围', + clientId: '客户端 ID', + clientIdPlaceholder: '请输入客户端 ID', + clientSecret: '客户端密钥', + clientSecretPlaceholder: '请输入客户端密钥', + logoutEndpoint: '注销端地址', + logoutEndpointPlaceholder: '请输入注销端地址', + redirectUrl: '回调地址', + redirectUrlPlaceholder: '请输入回调地址', + enableAuthentication: '启用 OIDC 认证' + }, + + oauth2: { + title: 'OAuth2', + authEndpoint: '授权端地址', + authEndpointPlaceholder: '请输入授权端地址', + tokenEndpoint: 'Token 端地址', + tokenEndpointPlaceholder: '请输入 Token 端地址', + userInfoEndpoint: '用户信息端地址', + userInfoEndpointPlaceholder: '请输入用户信息端地址', + scope: '连接范围', + scopePlaceholder: '请输入连接范围', + clientId: '客户端 ID', + clientIdPlaceholder: '请输入客户端 ID', + clientSecret: '客户端密钥', + clientSecretPlaceholder: '请输入客户端密钥', + redirectUrl: '回调地址', + redirectUrlPlaceholder: '请输入回调地址', + filedMapping: '字段映射', + filedMappingPlaceholder: '请输入字段映射', + enableAuthentication: '启用 OAuth2 认证' + }, + scanTheQRCode: { + title: '扫码登录', + wecom: '企业微信', + dingtalk: '钉钉', + lark: '飞书', + effective: '有效', + alreadyTurnedOn: '已开启', + notEnabled: '未开启', + validate: '校验', + validateSuccess: '校验成功', + validateFailed: '校验失败', + validateFailedTip: '请填写所有必填项并确保格式正确', + appKeyPlaceholder: '请输入 App Key', + appSecretPlaceholder: '请输入 App Secret', + corpIdPlaceholder: '请输入 Corp Id', + agentIdPlaceholder: '请输入 Agent Id', + callbackWarning: '请输入有效的 URL 地址', + larkQrCode: '飞书扫码登录', + dingtalkQrCode: '钉钉扫码登录', + setting: '设置', + access: '接入' + } + }, + theme: { + title: '外观设置', + platformDisplayTheme: '平台显示主题', + customTheme: '自定义主题', + platformLoginSettings: '平台登录设置', + custom: '自定义', + pagePreview: '页面预览', + default: '默认', + restoreDefaults: '恢复默认', + orange: '活力橙', + green: '松石绿', + purple: '神秘紫', + red: '胭脂红', + loginBackground: '登录背景图', + loginLogo: '登录 Logo', + websiteLogo: '网站 Logo', + replacePicture: '替换图片', + websiteLogoTip: '顶部网站显示的 Logo,建议尺寸 48*48,支持 JPG、PNG、GIF,大小不超过 10MB', + loginLogoTip: '登录页面右侧 Logo,建议尺寸 204*52,支持 JPG、PNG、GIF,大小不超过 10 MB', + loginBackgroundTip: + '左侧背景图,矢量图建议尺寸 576*900,位图建议尺寸 1152*1800;支持 JPG、PNG、GIF,大小不超过 10 MB', + websiteName: '网站名称', + websiteNamePlaceholder: '请输入网站名称', + websiteNameTip: '显示在网页 Tab 的平台名称', + websiteSlogan: '欢迎语', + websiteSloganPlaceholder: '请输入欢迎语', + websiteSloganTip: '产品 Logo 下的欢迎语', + defaultSlogan: '欢迎使用 MaxKB 智能知识库问答系统', + logoDefaultTip: '默认为 MaxKB 登录界面,支持自定义设置', + defaultTip: '默认为 MaxKB 平台界面,支持自定义设置', + platformSetting: '平台设置', + showUserManual: '显示用户手册', + showForum: '显示论坛求助', + showProject: '显示项目地址', + urlPlaceholder: '请输入 URL 地址', + abandonUpdate: '放弃更新', + saveAndApply: '保存并应用', + fileMessageError: '文件大小超过 10M', + saveSuccess: '外观设置成功' + }, + email: { + title: '邮箱设置', + smtpHost: 'SMTP Host', + smtpHostPlaceholder: '请输入 SMTP Host', + smtpPort: 'SMTP Port', + smtpPortPlaceholder: '请输入 SMTP Port', + smtpUser: 'SMTP 账户', + smtpUserPlaceholder: '请输入 SMTP 账户', + sendEmail: '发件人邮箱', + sendEmailPlaceholder: '请输入发件人邮箱', + smtpPassword: '发件人密码', + smtpPasswordPlaceholder: '请输入发件人密码', + enableSSL: '启用 SSL(如果 SMTP 端口是 465,通常需要启用 SSL)', + enableTLS: '启用 TLS(如果 SMTP 端口是 587,通常需要启用 TLS)' + } +} diff --git a/ui/src/locales/lang/zh-CN/views/team.ts b/ui/src/locales/lang/zh-CN/views/team.ts new file mode 100644 index 000000000..58a2bc30c --- /dev/null +++ b/ui/src/locales/lang/zh-CN/views/team.ts @@ -0,0 +1,31 @@ +export default { + title: '团队成员', + member: '成员', + manage: '所有者', + permissionSetting: '权限设置', + addMember: '添加成员', + addSubTitle: '成员登录后可以访问到您授权的数据。', + searchBar: { + placeholder: '请输入用户名搜索' + }, + delete: { + button: '移除', + confirmTitle: '是否移除成员:', + confirmMessage: '移除后将会取消成员拥有的知识库和应用权限。' + }, + setting: { + management: '管理', + check: '查看' + }, + teamForm: { + form: { + userName: { + label: '用户名/邮箱', + placeholder: '请输入成员的用户名或邮箱', + requiredMessage: '请输入用户名/邮箱' + }, + + }, + + } +} diff --git a/ui/src/locales/lang/zh-CN/views/template.ts b/ui/src/locales/lang/zh-CN/views/template.ts new file mode 100644 index 000000000..84241990d --- /dev/null +++ b/ui/src/locales/lang/zh-CN/views/template.ts @@ -0,0 +1,83 @@ +export default { + title: '模型设置', + provider: '供应商', + providerPlaceholder: '选择供应商', + addModel: '添加模型', + searchBar: { + placeholder: '按名称搜索' + }, + delete: { + confirmTitle: '删除模型', + confirmMessage: '是否删除模型:' + }, + tip: { + createSuccessMessage: '创建模型成功', + createErrorMessage: '基础信息有填写错误', + errorMessage: '变量已存在: ', + emptyMessage1: '请先选择基础信息的模型类型和基础模型', + emptyMessage2: '所选模型不支持参数设置', + updateSuccessMessage: '修改模型成功', + saveSuccessMessage: '模型参数保存成功', + downloadError: '下载失败', + noModel: '模型在Ollama不存在' + }, + model: { + allModel: '全部模型', + publicModel: '公有模型', + privateModel: '私有模型', + LLM: '大语言模型', + EMBEDDING: '向量模型', + RERANKER: '重排模型', + STT: '语音识别', + TTS: '语音合成', + IMAGE: '视觉模型', + TTI: '图片生成' + }, + templateForm: { + title: { + baseInfo: '基础信息', + advancedInfo: '高级设置', + modelParams: '模型参数', + editParam: '编辑参数', + addParam: '添加参数', + paramSetting: '模型参数设置', + apiParamPassing: '接口传参' + }, + form: { + templateName: { + label: '模型名称', + placeholder: '请给基础模型设置一个名称', + tooltip: 'MaxKB 中自定义的模型名称', + requiredMessage: '模型名称不能为空' + }, + permissionType: { + label: '权限', + privateDesc: '仅当前用户使用', + publicDesc: '所有用户都可使用', + requiredMessage: '权限不能为空' + }, + model_type: { + label: '模型类型', + placeholder: '请选择模型类型', + tooltip1: '大语言模型:在应用中与AI对话的推理模型。', + tooltip2: '向量模型:在知识库中对文档内容进行向量化的模型。', + tooltip3: '语音识别:在应用中开启语音识别后用于语音转文字的模型。', + tooltip4: '语音合成:在应用中开启语音播放后用于文字转语音的模型。', + tooltip5: '重排模型:在高级编排应用中使用多路召回时,对候选分段进行重新排序的模型。', + tooltip6: '视觉模型:在高级编排应用中用于图片理解的视觉模型。', + tooltip7: '图片生成:在高级编排应用中用于图片生成的视觉模型。', + requiredMessage: '模型类型不能为空' + }, + base_model: { + label: '基础模型', + tooltip: '列表中未列出的模型,直接输入模型名称,回车即可添加', + placeholder: '自定义输入基础模型后回车即可', + requiredMessage: '基础模型不能为空' + } + } + }, + download: { + downloading: '正在下载中', + cancelDownload: '取消下载' + } +} diff --git a/ui/src/locales/lang/zh-CN/views/user.ts b/ui/src/locales/lang/zh-CN/views/user.ts new file mode 100644 index 000000000..4e2a8760f --- /dev/null +++ b/ui/src/locales/lang/zh-CN/views/user.ts @@ -0,0 +1,68 @@ +export default { + title: '用户管理', + createUser: '创建用户', + editUser: '编辑用户', + setting: { + updatePwd: '修改用户密码' + }, + tip: { + professionalMessage: '社区版最多支持 2 个用户,如需拥有更多用户,请升级为专业版。', + updatePwdSuccess: '修改用户密码成功' + }, + delete: { + confirmTitle: '是否删除用户:', + confirmMessage: '删除用户,该用户创建的资源(应用、知识库、模型)都会删除,请谨慎操作。' + }, + disabled: { + confirmTitle: '是否禁用函数:', + confirmMessage: '禁用后,引用了该函数的应用提问时会报错 ,请谨慎操作。' + }, + userForm: { + form: { + username: { + label: '用户名', + placeholder: '请输入用户名', + requiredMessage: '请输入用户名', + lengthMessage: '长度在 6 到 20 个字符' + }, + nick_name: { + label: '姓名', + placeholder: '请输入姓名' + }, + email: { + label: '邮箱', + placeholder: '请输入邮箱', + requiredMessage: '请输入邮箱', + validatorEmail: '请输入有效邮箱格式!', + }, + phone: { + label: '手机号', + placeholder: '请输入手机号' + }, + password: { + label: '登录密码', + placeholder: '请输入密码', + requiredMessage: '请输入密码', + lengthMessage: '长度在 6 到 20 个字符' + }, + new_password: { + label: '新密码', + placeholder: '请输入新密码', + requiredMessage: '请输入新密码', + }, + re_password: { + label: '确认密码', + placeholder: '请输入确认密码', + requiredMessage: '请输入确认密码', + validatorMessage: '密码不一致', + } + } + }, + source: { + label: '用户类型', + local: '系统用户', + wecom: '企业微信', + lark: '飞书', + dingtalk: '钉钉' + } +} diff --git a/ui/src/locales/lang/zh-Hant/ai-chat.ts b/ui/src/locales/lang/zh-Hant/ai-chat.ts new file mode 100644 index 000000000..df43dd6f8 --- /dev/null +++ b/ui/src/locales/lang/zh-Hant/ai-chat.ts @@ -0,0 +1,96 @@ +export default { + noHistory: '暫無歷史記錄', + createChat: '新建對話', + history: '歷史記錄', + only20history: '僅顯示最近 20 條對話', + question_count: '條提問', + exportRecords: '導出聊天記錄', + chatId: '對話 ID', + userInput: '用戶輸入', + quote: '引用', + download: '點擊下載文件', + passwordValidator: { + title: '請輸入密碼打開連結', + errorMessage1: '密碼不能為空', + errorMessage2: '密碼錯誤' + }, + operation: { + play: '點擊播放', + pause: '停止', + regeneration: '換個答案', + like: '贊同', + cancelLike: '取消贊同', + oppose: '反對', + cancelOppose: '取消反對', + continue: '繼續', + stopChat: '停止回答', + startChat: '開始回答', + }, + tip: { + error500Message: '抱歉,當前正在維護,無法提供服務,請稍後再試!', + errorIdentifyMessage: '無法識別用戶身份', + errorLimitMessage: '抱歉,您的提問已達最大限制,請明天再來吧!', + answerMessage: '抱歉,沒有查找到相關內容,請重新描述您的問題或提供更多資訊。', + stopAnswer: '已停止回答', + answerLoading: '回答中', + recorderTip: `

該功能需要使用麥克風,瀏覽器禁止不安全頁面錄音,解決方案如下:
+1、可開啟 https 解決;
+2、若無 https 配置則需要修改瀏覽器安全配置,Chrome 設定如下:
+(1) 地址欄輸入 chrome://flags/#unsafely-treat-insecure-origin-as-secure;
+(2) 將 http 站點配置在文字框中,例如: http://127.0.0.1:8080。

`, + recorderError: '錄音失敗', + confirm: '我知道了', + requiredMessage: '請填寫所有必填欄位', + inputParamMessage1: '請在 URL 中填寫參數', + inputParamMessage2: '的值', + prologueMessage: '抱歉,當前正在維護,無法提供服務,請稍後再試!' + }, + inputPlaceholder: { + speaking: '說話中', + recorderLoading: '轉文字中', + default: '請輸入問題' + }, + uploadFile: { + label: '上傳文件', + most: '最多', + limit: '個,每個文件限制', + fileType: '文件類型', + tipMessage: '請在文件上傳配置中選擇文件類型', + limitMessage1: '最多上傳', + limitMessage2: '個文件', + sizeLimit: '單個文件大小不能超過', + imageMessage: '請解析圖片內容', + errorMessage: '上傳失敗' + }, + executionDetails: { + title: '執行詳細', + paramOutputTooltip: '每個文件僅支持預覽 500 字', + audioFile: '語音文件', + searchContent: '檢索內容', + searchResult: '檢索結果', + conditionResult: '判斷結果', + currentChat: '本次對話', + answer: 'AI 回答', + replyContent: '回覆內容', + textContent: '文本內容', + input: '輸入', + output: '輸出', + rerankerContent: '重排內容', + rerankerResult: '重排結果', + paragraph: '段落', + noSubmit: '用戶未提交', + errMessage: '錯誤日誌' + }, + KnowledgeSource: { + title: '知識來源', + referenceParagraph: '引用段落', + consume: '消耗tokens', + consumeTime: '耗時' + }, + paragraphSource: { + title: '知識庫引用', + question: '用戶問題', + optimizationQuestion: '優化後問題' + }, + editTitle: '編輯標題', +} diff --git a/ui/src/locales/lang/zh-Hant/common.ts b/ui/src/locales/lang/zh-Hant/common.ts new file mode 100644 index 000000000..5775f5813 --- /dev/null +++ b/ui/src/locales/lang/zh-Hant/common.ts @@ -0,0 +1,63 @@ +export default { + create: '創建', + createSuccess: '創建成功', + copy: '複製', + copySuccess: '複製成功', + copyError: '複製失敗', + save: '儲存', + saveSuccess: '儲存成功', + delete: '刪除', + deleteSuccess: '刪除成功', + setting: '設定', + settingSuccess: '設定成功', + submit: '提交', + submitSuccess: '提交成功', + edit: '編輯', + editSuccess: '編輯成功', + modify: '修改', + modifySuccess: '修改成功', + cancel: '取消', + confirm: '確認', + tip: '提示', + add: '新增', + refresh: '重新整理', + search: '搜尋', + clear: '清除', + professional: '購買專業版', + createDate: '創建日期', + createTime: '創建時間', + operation: '操作', + character: '字符', + export: '匯出', + exportSuccess: '匯出成功', + unavailable: '(不可用)', + public: '公有', + private: '私有', + paramSetting: '參數設定', + creator: '建立者', + author: '作者', + debug: '調試', + required: '必填', + noData: '暂无数据', + result: '結果', + fileUpload: { + document: '文檔', + image: '圖片', + audio: '音頻', + video: '視頻' + }, + status: { + label: '狀態', + enableSuccess: '啟用成功', + disableSuccess: '停用成功' + }, + inputPlaceholder: '請輸入', + title: '標題', + content: '内容', + param: { + outputParam: '輸出參數', + inputParam: '輸入參數', + initParam: '啟動參數', + }, + rename: '重命名' +} diff --git a/ui/src/locales/lang/zh-Hant/components.ts b/ui/src/locales/lang/zh-Hant/components.ts new file mode 100644 index 000000000..da25a3709 --- /dev/null +++ b/ui/src/locales/lang/zh-Hant/components.ts @@ -0,0 +1,12 @@ +export default { + quickCreatePlaceholder: '快速創建空白文檔', + quickCreateName: '文檔名稱', + noData: '無匹配数据', + loading: '加載中', + noMore: '到底啦!', + selectParagraph: { + title: '選擇分段', + error: '僅執行未成功分段', + all: '全部分段' + } +} diff --git a/ui/src/locales/lang/zh-Hant/dynamics-form.ts b/ui/src/locales/lang/zh-Hant/dynamics-form.ts new file mode 100644 index 000000000..e75c2393d --- /dev/null +++ b/ui/src/locales/lang/zh-Hant/dynamics-form.ts @@ -0,0 +1,102 @@ +export default { + input_type_list: { + TextInput: '文字框', + PasswordInput: '密文框', + Slider: '滑桿', + SwitchInput: '開關', + SingleSelect: '單選框', + MultiSelect: '多選框', + DatePicker: '日期選擇器', + JsonInput: 'JSON文字框', + RadioCard: '選項卡', + RadioRow: '單行選項卡' + }, + default: { + label: '預設值', + placeholder: '請輸入預設值', + requiredMessage: '為必填屬性', + show: '顯示預設值' + }, + tip: { + requiredMessage: '不能為空', + jsonMessage: 'JSON格式不正確' + }, + searchBar: { + placeholder: '請輸入關鍵字搜索' + }, + paramForm: { + field: { + label: '參數', + placeholder: '請輸入參數', + requiredMessage: '參數 為必填屬性', + requiredMessage2: '只能輸入字母、數字和底線' + }, + name: { + label: '顯示名稱', + placeholder: '請輸入顯示名稱', + requiredMessage: '顯示名稱 為必填屬性' + }, + tooltip: { + label: '參數提示說明', + placeholder: '請輸入參數提示說明' + }, + required: { + label: '是否必填', + requiredMessage: '是否必填 為必填屬性' + }, + input_type: { + label: '組件類型', + placeholder: '請選擇組件類型', + requiredMessage: '組件類型 為必填屬性' + } + }, + DatePicker: { + placeholder: '選擇日期', + year: '年', + month: '月', + date: '日期', + datetime: '日期時間', + dataType: { + label: '時間類型', + placeholder: '請選擇時間類型' + }, + format: { + label: '格式', + placeholder: '請選擇格式' + } + }, + Select: { + label: '選項值', + placeholder: '請輸入選項值' + }, + tag: { + label: '標籤', + placeholder: '請輸入選項標籤' + }, + Slider: { + showInput: { + label: '是否帶輸入框' + }, + valueRange: { + label: '取值範圍', + minRequired: '最小值必填', + maxRequired: '最大值必填' + }, + step: { + label: '步長值', + requiredMessage1: '步長值必填', + requiredMessage2: '步長不能為0' + } + }, + TextInput: { + length: { + label: '文字長度', + minRequired: '最小長度必填', + maxRequired: '最大長度必填', + requiredMessage1: '長度在', + requiredMessage2: '到', + requiredMessage3: '個字元', + requiredMessage4: '文字長度為必填參數' + } + } +} diff --git a/ui/src/locales/lang/zh-Hant/index.ts b/ui/src/locales/lang/zh-Hant/index.ts new file mode 100644 index 000000000..eb809475d --- /dev/null +++ b/ui/src/locales/lang/zh-Hant/index.ts @@ -0,0 +1,17 @@ +import zhTw from 'element-plus/es/locale/lang/zh-tw' +import components from './components' +import layout from './layout' +import views from './views' +import common from './common' +import dynamicsForm from './dynamics-form' +import chat from './ai-chat' +export default { + lang: '繁體中文', + layout, + common, + views, + components, + zhTw, + dynamicsForm, + chat +} diff --git a/ui/src/locales/lang/zh-Hant/layout.ts b/ui/src/locales/lang/zh-Hant/layout.ts new file mode 100644 index 000000000..2f8662f84 --- /dev/null +++ b/ui/src/locales/lang/zh-Hant/layout.ts @@ -0,0 +1,34 @@ +export default { + github: '項目地址', + wiki: '使用者手冊', + forum: '論壇求助', + logout: '退出', + + apiKey: 'API Key 管理', + apiServiceAddress: 'API 服務地址', + language: '語言', + isExpire: '未上傳 License 或 License 已過期。', + about: { + title: '關於', + expiredTime: '到期時間', + edition: { + label: '版本', + community: '社群版', + professional: '專業版' + }, + version: '版本號', + serialNo: '序列號', + remark: '備註', + update: '更新', + authorize: '授權給' + }, + time: { + daysLater: '天後', + hoursLater: '小時後', + expired: '已過期', + expiringSoon: '即將到期' + }, + copyright: '版權所有 © 2014-2025 杭州飛致雲信息科技有限公司', + userManualUrl:'https://maxkb.cn/docs/', + forumUrl: 'https://github.com/1Panel-dev/MaxKB/discussions' +} diff --git a/ui/src/locales/lang/zh-Hant/views/404.ts b/ui/src/locales/lang/zh-Hant/views/404.ts new file mode 100644 index 000000000..e85fc2206 --- /dev/null +++ b/ui/src/locales/lang/zh-Hant/views/404.ts @@ -0,0 +1,5 @@ +export default { + title: '404', + message: '無法訪問應用', + operate: '返回首頁' +} diff --git a/ui/src/locales/lang/zh-Hant/views/application-overview.ts b/ui/src/locales/lang/zh-Hant/views/application-overview.ts new file mode 100644 index 000000000..c402d9de3 --- /dev/null +++ b/ui/src/locales/lang/zh-Hant/views/application-overview.ts @@ -0,0 +1,112 @@ +export default { + title: '概覽', + appInfo: { + header: '應用資訊', + publicAccessLink: '公開訪問連結', + openText: '開', + closeText: '關', + copyLinkText: '複製連結', + refreshLinkText: '重新整理連結', + demo: '示範', + embedInWebsite: '嵌入第三方', + accessControl: '訪問限制', + displaySetting: '顯示設定', + apiAccessCredentials: 'API 存取憑證', + apiKey: 'API Key', + refreshToken: { + msgConfirm1: '是否重新產生公開訪問連結?', + msgConfirm2: + '重新產生公開訪問連結會影響嵌入第三方腳本變更,需要將新腳本重新嵌入第三方,請謹慎操作!', + refreshSuccess: '重新整理成功' + }, + APIKeyDialog: { + saveSettings: '儲存設定', + msgConfirm1: '是否刪除API Key', + msgConfirm2: '刪除API Key後將無法恢復,請確認是否刪除?', + enabledSuccess: '已啟用', + disabledSuccess: '已停用' + }, + EditAvatarDialog: { + title: '應用頭像', + customizeUpload: '自訂上傳', + upload: '上傳', + default: '預設logo', + custom: '自訂', + sizeTip: '建議尺寸 32*32,支援 JPG、PNG、GIF,大小不超過 10 MB', + fileSizeExceeded: '檔案大小超過 10 MB', + uploadImagePrompt: '請上傳一張圖片' + }, + EmbedDialog: { + fullscreenModeTitle: '全螢幕模式', + copyInstructions: '複製以下程式碼進行嵌入', + floatingModeTitle: '浮窗模式', + mobileModeTitle: '移動端模式' + }, + LimitDialog: { + dialogTitle: '訪問限制', + showSourceLabel: '顯示知識來源', + clientQueryLimitLabel: '每個用戶端提問限制', + timesDays: '次/天', + authentication: '身份驗證', + authenticationValue: '驗證密碼', + whitelistLabel: '白名單', + whitelistPlaceholder: + '請輸入允許嵌入第三方的來源位址,一行一個,如:\nhttp://127.0.0.1:5678\nhttps://dataease.io' + }, + SettingAPIKeyDialog: { + dialogTitle: '設定', + allowCrossDomainLabel: '允許跨域位址', + crossDomainPlaceholder: + '請輸入允許的跨域位址,開啟後不輸入跨域位址則不限制。\n跨域位址一行一個,如:\nhttp://127.0.0.1:5678 \nhttps://dataease.io' + }, + SettingDisplayDialog: { + dialogTitle: '顯示設定', + languageLabel: '語言', + showSourceLabel: '顯示知識來源', + showExecutionDetail: '顯示執行細節', + restoreDefault: '恢復預設', + customThemeColor: '自訂主題色', + headerTitleFontColor: '標頭標題字體顏色', + default: '預設', + askUserAvatar: '提問用戶頭像', + replace: '取代', + imageMessage: '建議尺寸 32*32,支援 JPG、PNG、GIF,大小不超過 10 MB', + AIAvatar: 'AI 回覆頭像', + floatIcon: '浮窗入口圖示', + iconDefaultPosition: '圖示預設位置', + iconPosition: { + left: '左', + right: '右', + bottom: '下', + top: '上' + }, + draggablePosition: '可拖曳位置', + showHistory: '顯示歷史紀錄', + displayGuide: '顯示引導圖(浮窗模式)', + disclaimer: '免責聲明', + disclaimerValue: '「以上內容均由 AI 生成,僅供參考和借鏡」' + } + }, + monitor: { + monitoringStatistics: '監控統計', + customRange: '自訂範圍', + startDatePlaceholder: '開始時間', + endDatePlaceholder: '結束時間', + pastDayOptions: { + past7Days: '過去7天', + past30Days: '過去30天', + past90Days: '過去90天', + past183Days: '過去半年', + other: '自訂义' + }, + charts: { + customerTotal: '用戶總數', + customerNew: '用戶新增數', + queryCount: '提問次數', + tokensTotal: 'Tokens 總數', + userSatisfaction: '用戶滿意度', + approval: '贊同', + disapproval: '反對' + } + } +} diff --git a/ui/src/locales/lang/zh-Hant/views/application-workflow.ts b/ui/src/locales/lang/zh-Hant/views/application-workflow.ts new file mode 100644 index 000000000..b8cf46469 --- /dev/null +++ b/ui/src/locales/lang/zh-Hant/views/application-workflow.ts @@ -0,0 +1,287 @@ +export default { + node: '節點', + nodeName: '節點名稱', + baseComponent: '基礎組件', + nodeSetting: '節點設置', + workflow: '工作流', + searchBar: { + placeholder: '按名稱搜索' + }, + info: { + previewVersion: '預覽版本:', + saveTime: '保存時間:' + }, + setting: { + restoreVersion: '恢復版本', + restoreCurrentVersion: '恢復此版本', + addComponent: '添加組件', + public: '發布', + releaseHistory: '發布歷史', + autoSave: '自動保存', + latestRelease: '最近發布', + copyParam: '複製參數', + debug: '調試', + exit: '直接退出', + exitSave: '保存並退出', + }, + tip: { + publicSuccess: '發布成功', + noData: '沒有找到相關結果', + nameMessage: '名字不能為空!', + onlyRight: '只允許從右邊的錨點連出', + notRecyclable: '不可循環連線', + onlyLeft: '只允許連接左邊的錨點', + applicationNodeError: '該應用不可用', + functionNodeError: '該函數不可用', + repeatedNodeError: '節點名稱已存在!', + cannotCopy: '不能被複製', + copyError: '已複製節點', + paramErrorMessage: '參數已存在: ', + saveMessage: '當前修改未保存,是否保存後退出?', + }, + delete: { + confirmTitle: '確定刪除該節點?', + deleteMessage: '節點不允許刪除' + }, + control: { + zoomOut: '縮小', + zoomIn: '放大', + fitView: '適應', + retract: '收起全部節點', + extend: '展開全部節點', + beautify: '一鍵美化' + }, + variable: { + label: '變量', + global: '全局變量', + Referencing: '引用變量', + ReferencingRequired: '引用變量必填', + ReferencingError: '引用變量錯誤', + NoReferencing: '不存在的引用變量', + placeholder: '請選擇變量' + }, + condition: { + title: '執行條件', + front: '前置', + AND: '所有', + OR: '任一', + text: '連線節點執行完,執行當前節點' + }, + validate: { + startNodeRequired: '開始節點必填', + startNodeOnly: '開始節點只能有一個', + baseNodeRequired: '基本信息節點必填', + baseNodeOnly: '基本信息節點只能有一個', + notInWorkFlowNode: '未在流程中的節點', + noNextNode: '不存在的下一個節點', + nodeUnavailable: '節點不可用', + needConnect1: '節點的', + needConnect2: '分支需要連接', + cannotEndNode: '節點不能當做結束節點' + }, + nodes: { + startNode: { + label: '開始', + question: '用戶問題', + currentTime: '當前時間' + }, + baseNode: { + label: '基本信息', + appName: { + label: '應用名稱' + }, + appDescription: { + label: '應用描述' + }, + fileUpload: { + label: '文件上傳', + tooltip: '開啟後,問答頁面會顯示上傳文件的按鈕。' + }, + FileUploadSetting: { + title: '文件上傳設置', + maxFiles: '單次上傳最多文件數', + fileLimit: '每個文件最大(MB)', + fileUploadType: { + label: '上傳的文件類型', + documentText: '需要使用「文檔內容提取」節點解析文檔內容', + imageText: '需要使用「圖片理解」節點解析圖片內容', + audioText: '需要使用「語音轉文本」節點解析音頻內容' + } + } + }, + aiChatNode: { + label: 'AI 對話', + text: '與 AI 大模型進行對話', + answer: 'AI 回答內容', + returnContent: { + label: '返回內容', + tooltip: `關閉後該節點的內容則不輸出給用戶。 + 如果你想讓用戶看到該節點的輸出內容,請打開開關。` + }, + defaultPrompt: '已知信息', + think: '思考過程' + }, + searchDatasetNode: { + label: '知識庫檢索', + text: '關聯知識庫,查找與問題相關的分段', + paragraph_list: '檢索結果的分段列表', + is_hit_handling_method_list: '滿足直接回答的分段列表', + result: '檢索結果', + directly_return: '滿足直接回答的分段內容', + searchParam: '檢索參數', + searchQuestion: { + label: '檢索問題', + placeholder: '請選擇檢索問題', + requiredMessage: '請選擇檢索問題' + } + }, + questionNode: { + label: '問題優化', + text: '根據歷史聊天記錄優化完善當前問題,更利於匹配知識庫分段', + result: '問題優化結果', + defaultPrompt1: `根據上下文優化和完善用戶問題:`, + defaultPrompt2: `請輸出一個優化後的問題。`, + systemDefault: '你是一個問題優化大師' + }, + conditionNode: { + label: '判斷器', + text: '根據不同條件執行不同的節點', + branch_name: '分支名稱', + conditions: { + label: '條件', + info: '符合以下', + requiredMessage: '請選擇條件' + }, + valueMessage: '請輸入值', + addCondition: '添加條件', + addBranch: '添加分支' + }, + replyNode: { + label: '指定回覆', + text: '指定回覆內容,引用變量會轉換為字符串進行輸出', + content: '內容', + replyContent: { + label: '回覆內容', + custom: '自定義', + reference: '引用變量' + } + }, + rerankerNode: { + label: '多路召回', + text: '使用重排模型對多個知識庫的檢索結果進行二次召回', + result_list: '重排結果列表', + result: '重排結果', + rerankerContent: { + label: '重排內容', + requiredMessage: '請選擇重排內容' + }, + higher: '高於', + ScoreTooltip: 'Score越高相關性越強。', + max_paragraph_char_number: '最大引用字符數', + reranker_model: { + label: '重排模型', + placeholder: '請選擇重排模型' + } + }, + formNode: { + label: '表單收集', + text: '在問答過程中用於收集用戶信息,可以根據收集到表單數據執行後續流程', + form_content_format1: '你好,請先填寫下面表單內容:', + form_content_format2: '填寫後請點擊【提交】按鈕進行提交。', + form_data: '表單全部內容', + formContent: { + label: '表單輸出內容', + requiredMessage: '請表單輸出內容', + tooltip: '設置執行該節點輸出的內容,{ form } 為表單的佔位符。' + }, + formAllContent: '表單全部內容', + formSetting: '表單配置' + }, + documentExtractNode: { + label: '文檔內容提取', + text: '提取文檔中的內容', + content: '文檔內容' + }, + imageUnderstandNode: { + label: '圖片理解', + text: '識別出圖片中的物件、場景等信息回答用戶問題', + answer: 'AI 回答內容', + model: { + label: '圖片理解模型', + requiredMessage: '請選擇圖片理解模型' + }, + image: { + label: '選擇圖片', + requiredMessage: '請選擇圖片' + } + }, + variableAssignNode: { + label: '變數賦值', + text: '更新全域變數的值', + assign: '賦值' + }, + imageGenerateNode: { + label: '圖片生成', + text: '根據提供的文本內容生成圖片', + answer: 'AI 回答內容', + model: { + label: '圖片生成模型', + requiredMessage: '請選擇圖片生成模型' + }, + prompt: { + label: '提示詞(正向)', + tooltip: '正向提示詞,用來描述生成圖像中期望包含的元素和視覺特點' + }, + negative_prompt: { + label: '提示詞(負向)', + tooltip: '反向提示詞,用來描述不希望在畫面中看到的內容,可以對畫面進行限制。', + placeholder: '請描述不想生成的圖片內容,比如:顏色、血腥內容' + } + }, + speechToTextNode: { + label: '語音轉文本', + text: '將音頻通過語音識別模型轉換為文本', + stt_model: { + label: '語音識別模型' + }, + audio: { + label: '選擇語音文件', + placeholder: '請選擇語音文件' + } + }, + textToSpeechNode: { + label: '文本轉語音', + text: '將文本通過語音合成模型轉換為音頻', + tts_model: { + label: '語音合成模型' + }, + content: { + label: '選擇文本內容' + } + }, + functionNode: { + label: '自定義函數', + text: '通過執行自定義腳本,實現數據處理' + }, + applicationNode: { + label: '應用節點' + } + }, + compare: { + is_null: '為空', + is_not_null: '不為空', + contain: '包含', + not_contain: '不包含', + eq: '等於', + ge: '大於等於', + gt: '大於', + le: '小於等於', + lt: '小於', + len_eq: '長度等於', + len_ge: '長度大於等於', + len_gt: '長度大於', + len_le: '長度小於等於', + len_lt: '長度小於' + }, + FileUploadSetting: {} +} diff --git a/ui/src/locales/lang/zh-Hant/views/application.ts b/ui/src/locales/lang/zh-Hant/views/application.ts new file mode 100644 index 000000000..192a6958f --- /dev/null +++ b/ui/src/locales/lang/zh-Hant/views/application.ts @@ -0,0 +1,214 @@ +export default { + title: '應用', + createApplication: '建立應用', + importApplication: '匯入應用', + copyApplication: '複製應用', + workflow: '進階編排', + simple: '簡單配置', + searchBar: { + placeholder: '按名稱搜尋' + }, + setting: { + demo: '示範' + }, + delete: { + confirmTitle: '是否刪除應用:', + confirmMessage: '刪除後該應用將不再提供服務,請謹慎操作。' + }, + tip: { + ExportError: '匯出失敗', + professionalMessage: '社群版最多支援 5 個應用,如需擁有更多應用,請升級為專業版。', + saveErrorMessage: '儲存失敗,請檢查輸入或稍後再試', + loadingErrorMessage: '載入配置失敗,請檢查輸入或稍後再試' + }, + applicationForm: { + title: { + appTest: '調試預覽', + copy: '副本' + }, + form: { + appName: { + label: '名稱', + placeholder: '請輸入應用名稱', + requiredMessage: '請輸入應用名稱' + }, + appDescription: { + label: '描述', + placeholder: '描述該應用的應用場景及用途,如:XXX 小助手回答用戶提出的 XXX 產品使用問題' + }, + appType: { + label: '類型', + simplePlaceholder: '適合新手建立小助手', + workflowPlaceholder: '適合高階用戶自訂小助手的工作流程' + }, + appTemplate: { + blankApp: '空白應用', + assistantApp: '知識庫問答助手' + }, + aiModel: { + label: 'AI 模型', + placeholder: '請選擇 AI 模型' + }, + roleSettings: { + label: '角色設定', + placeholder: '你是 xxx 小助手' + }, + prompt: { + label: '提示詞', + noReferences: ' (無引用知識庫)', + references: ' (引用知識庫)', + placeholder: '請輸入提示詞', + requiredMessage: '請輸入提示詞', + tooltip:'透過調整提示詞內容,可以引導大模型對話方向,該提示詞會被固定在上下文的開頭。', + + noReferencesTooltip: + '透過調整提示詞內容,可以引導大模型對話方向,該提示詞會被固定在上下文的開頭。可以使用變數:{question} 是用戶提出問題的佔位符。', + referencesTooltip: + '透過調整提示詞內容,可以引導大模型對話方向,該提示詞會被固定在上下文的開頭。可以使用變數:{data} 是引用知識庫中分段的佔位符;{question} 是用戶提出問題的佔位符。', + defaultPrompt: `已知資訊:{data} +用戶問題:{question} +回答要求: + - 請使用中文回答用戶問題` + }, + historyRecord: { + label: '歷史對話紀錄' + }, + relatedKnowledge: { + label: '關聯知識庫', + placeholder: '關聯的知識庫展示在這裡' + }, + multipleRoundsDialogue: '多輪對話', + + prologue: '開場白', + defaultPrologue: + '您好,我是 XXX 小助手,您可以向我提出 XXX 使用問題。\n- XXX 主要功能有什麼?\n- XXX 如何收費?\n- 需要轉人工服務', + + problemOptimization: { + label: '問題優化', + tooltip: '根據歷史對話優化完善當前問題,更利於匹配知識點。' + }, + voiceInput: { + label: '語音輸入', + placeholder: '請選擇語音辨識模型', + requiredMessage: '請選擇語音輸入模型', + autoSend: '自動發送' + }, + voicePlay: { + label: '語音播放', + placeholder: '請選擇語音合成模型', + requiredMessage: '請選擇語音播放模型', + autoPlay: '自動播放', + browser: '瀏覽器播放(免費)', + tts: 'TTS模型', + listeningTest: '試聽' + }, + reasoningContent: { + label: '輸出思考', + tooltip:'請根據模型返回的思考標簽設置,標簽中間的內容將會認定爲思考過程', + start: '開始', + end: '結束', + } + }, + buttons: { + publish: '儲存並發佈', + addModel: '新增模型' + }, + + dialog: { + addDataset: '新增關聯知識庫', + addDatasetPlaceholder: '所選知識庫必須使用相同的 Embedding 模型', + selected: '已選', + countDataset: '個知識庫', + + selectSearchMode: '檢索模式', + vectorSearch: '向量檢索', + vectorSearchTooltip: '向量檢索是一種基於向量相似度的檢索方式,適用於知識庫中的大數據量場景。', + fullTextSearch: '全文檢索', + fullTextSearchTooltip: + '全文檢索是一種基於文本相似度的檢索方式,適用於知識庫中的小數據量場景。', + hybridSearch: '混合檢索', + hybridSearchTooltip: + '混合檢索是一種基於向量和文本相似度的檢索方式,適用於知識庫中的中等數據量場景。', + similarityThreshold: '相似度高於', + similarityTooltip: '相似度越高相關性越強。', + topReferences: '引用分段數 TOP', + maxCharacters: '最多引用字元數', + noReferencesAction: '無引用知識庫分段時', + continueQuestioning: '繼續向 AI 模型提問', + provideAnswer: '指定回答內容', + designated_answer: + '你好,我是 XXX 小助手,我的知識庫只包含了 XXX 產品相關知識,請重新描述您的問題。', + defaultPrompt1: + '()裡面是用戶問題,根據上下文回答揣測用戶問題({question}) 要求: 輸出一個補全問題,並且放在', + defaultPrompt2: '標籤中' + } + }, + applicationAccess: { + title: '應用接入', + wecom: '企業微信應用', + wecomTip: '打造企業微信智慧應用', + dingtalk: '釘釘應用', + dingtalkTip: '打造釘釘智慧應用', + wechat: '公眾號', + wechatTip: '打造公眾號智慧應用', + lark: '飛書應用', + larkTip: '打造飛書智慧應用', + slack: 'Slack', + slackTip: '打造 Slack 智慧應用', + setting: '配置', + callback: '回呼位址', + callbackTip: '請輸入回呼位址', + wecomPlatform: '企業微信後台', + wechatPlatform: '微信公众平台', + dingtalkPlatform: '釘釘開放平台', + larkPlatform: '飛書開放平台', + wecomSetting: { + title: '企業微信應用配置', + cropId: '企業 ID', + cropIdPlaceholder: '請輸入企業 ID', + agentIdPlaceholder: '請輸入Agent ID', + secretPlaceholder: '請輸入Secret', + tokenPlaceholder: '請輸入Token', + encodingAesKeyPlaceholder: '請輸入EncodingAESKey', + authenticationSuccessful: '認證成功', + urlInfo: '-應用管理-自建-建立的應用-接收消息-設定 API 接收的 "URL" 中' + }, + dingtalkSetting: { + title: '釘釘應用配置', + clientIdPlaceholder: '請輸入Client ID', + clientSecretPlaceholder: '請輸入Client Secret', + urlInfo: '-機器人頁面,設定 "消息接收模式" 為 HTTP模式 ,並把上面URL填寫到"消息接收位址"中' + }, + wechatSetting: { + title: '公眾號應用配置', + appId: '開發者ID (APP ID)', + appIdPlaceholder: '請輸入開發者ID (APP ID)', + appSecret: '開發者密鑰 (APP SECRET)', + appSecretPlaceholder: '請輸入開發者密鑰 (APP SECRET)', + token: '權杖 (TOKEN)', + tokenPlaceholder: '請輸入權杖 (TOKEN)', + aesKey: '消息加解密密鑰', + aesKeyPlaceholder: '請輸入消息加解密密鑰', + urlInfo: '-設定與開發-基本配置-伺服器配置的 "伺服器位址URL" 中' + }, + larkSetting: { + title: '飛書應用配置', + appIdPlaceholder: '請輸入App ID', + appSecretPlaceholder: '請輸入App Secret', + verificationTokenPlaceholder: '請輸入Verification Token', + urlInfo: '-事件與回呼-事件配置-配置訂閱方式的 "請求位址" 中' + }, + slackSetting: { + title: 'Slack 應用配置', + signingSecretPlaceholder: '請輸入 Signing Secret', + botUserTokenPlaceholder: '請輸入 Bot User Token', + }, + copyUrl: '複製連結填入到' + }, + hitTest: { + title: '命中測試', + text: '針對用戶提問調試段落匹配情況,保障回答效果。', + emptyMessage1: '命中的段落顯示在這裡', + emptyMessage2: '沒有命中的分段' + } +} diff --git a/ui/src/locales/lang/zh-Hant/views/dataset.ts b/ui/src/locales/lang/zh-Hant/views/dataset.ts new file mode 100644 index 000000000..0eace754b --- /dev/null +++ b/ui/src/locales/lang/zh-Hant/views/dataset.ts @@ -0,0 +1,83 @@ +export default { + title: '知識庫', + createDataset: '建立知識庫', + general: '通用型', + web: 'Web 站點', + relatedApplications: '關聯應用', + document_count: '文檔數', + relatedApp_count: '關聯應用', + searchBar: { + placeholder: '按名稱搜尋' + }, + setting: { + vectorization: '向量化', + sync: '同步' + }, + tip: { + professionalMessage: '社群版最多支援 50 個知識庫,如需擁有更多知識庫,請升級為專業版。', + syncSuccess: '同步任務發送成功', + updateModeMessage: '修改知識庫向量模型後,需要對知識庫向量化,是否繼續保存?' + }, + delete: { + confirmTitle: '是否刪除知識庫:', + confirmMessage1: '此知識庫關聯', + confirmMessage2: '個應用,刪除後無法恢復,請謹慎操作。' + }, + datasetForm: { + title: { + info: '基本資訊' + }, + form: { + datasetName: { + label: '知識庫名稱', + placeholder: '請輸入知識庫名稱', + requiredMessage: '請輸入應用名稱' + }, + datasetDescription: { + label: '知識庫描述', + placeholder: + '描述知識庫的內容,詳盡的描述將幫助AI能深入理解該知識庫的內容,能更準確的檢索到內容,提高該知識庫的命中率。', + requiredMessage: '請輸入知識庫描述' + }, + EmbeddingModel: { + label: '向量模型', + placeholder: '請選擇向量模型', + requiredMessage: '請輸入Embedding模型' + }, + datasetType: { + label: '知識庫類型', + generalInfo: '上傳本地檔案', + webInfo: '同步Web網站文字資料' + }, + source_url: { + label: 'Web 根位址', + placeholder: '請輸入 Web 根位址', + requiredMessage: '請輸入 Web 根位址' + }, + selector: { + label: '選擇器', + placeholder: '預設為 body,可輸入 .classname/#idname/tagname' + } + } + }, + ResultSuccess: { + title: '知識庫建立成功', + paragraph: '段落', + paragraph_count: '個段落', + documentList: '文件列表', + loading: '正在導入', + buttons: { + toDataset: '返回知識庫列表', + toDocument: '前往文件' + } + }, + syncWeb: { + title: '同步知識庫', + syncMethod: '同步方式', + replace: '替換同步', + replaceText: '重新獲取 Web 站點文件,覆蓋替換本地知識庫中的文件', + complete: '完整同步', + completeText: '先刪除本地知識庫所有文件,重新獲取 Web 站點文件', + tip: '注意:所有同步都會刪除現有數據並重新獲取新數據,請謹慎操作。' + } +} diff --git a/ui/src/locales/lang/zh-Hant/views/document.ts b/ui/src/locales/lang/zh-Hant/views/document.ts new file mode 100644 index 000000000..dc3d80407 --- /dev/null +++ b/ui/src/locales/lang/zh-Hant/views/document.ts @@ -0,0 +1,174 @@ +export default { + uploadDocument: '上傳文檔', + importDocument: '導入文檔', + syncDocument: '同步文檔', + selected: '已選', + items: '項', + searchBar: { + placeholder: '按 文檔名稱 搜索' + }, + setting: { + migration: '遷移', + cancelGenerateQuestion: '取消生成問題', + cancelVectorization: '取消向量化', + cancelGenerate: '取消生成', + export: '匯出', + }, + tip: { + saveMessage: '當前的更改尚未保存,確認退出嗎?', + cancelSuccess: '批量取消成功', + sendMessage: '發送成功', + vectorizationSuccess: '批量向量化成功', + nameMessage: '文件名稱不能为空!', + importMessage: '導入成功', + migrationSuccess: '遷移成功' + }, + upload: { + selectFile: '選擇文件', + selectFiles: '選擇文件夾', + uploadMessage: '拖拽文件至此上傳或', + formats: '支持格式:', + requiredMessage: '請上傳文件', + errorMessage1: '文件大小超過 100MB', + errorMessage2: '文件格式不支持', + errorMessage3: '文件不能为空', + errorMessage4: '每次最多上傳50個文件', + template: '模板', + download: '下載' + }, + + fileType: { + txt: { + label: '文本文件', + tip1: '1、文件上傳前,建議規範文件的分段標識', + tip2: '2、每次最多上傳 50 個文件,每個文件不超过 100MB' + }, + table: { + label: '表格', + tip1: '1、點擊下載對應模板並完善信息:', + tip2: '2、第一行必須是列標題,且列標題必須是有意義的術語,表中每條記錄將作為一個分段', + tip3: '3、上傳的表格文件中每個 sheet 會作為一個文檔,sheet 名稱為文檔名稱', + tip4: '4、每次最多上傳 50 個文件,每個文件不超过 100MB' + }, + QA: { + label: 'QA 問答對', + tip1: '1、點擊下載對應模板並完善信息', + tip2: '2、上傳的表格文件中每個 sheet 會作為一個文檔,sheet 名稱為文檔名稱', + tip3: '3、每次最多上傳 50 個文件,每個文件不超过 100MB' + } + }, + setRules: { + title: { + setting: '設置分段規則', + preview: '分段預覽' + }, + intelligent: { + label: '智能分段(推薦)', + text: '不了解如何設置分段規則推薦使用智能分段' + }, + advanced: { + label: '高級分段', + text: '用戶可根據文檔規範自行設置分段標識符、分段長度以及清洗規則' + }, + patterns: { + label: '分段標識', + tooltip: '按照所選符號先後順序做遞歸分割,分割結果超出分段長度將截取至分段長度。', + placeholder: '請選擇' + }, + limit: { + label: '分段長度' + }, + with_filter: { + label: '自動清洗', + text: '去掉重複多餘符號空格、空行、制表符' + }, + checkedConnect: { + label: '導入時添加分段標題為關聯問題(適用於標題為問題的問答對)' + } + }, + buttons: { + prev: '上一步', + next: '下一步', + import: '開始導入', + preview: '生成預覽' + }, + table: { + name: '文件名稱', + char_length: '字符數', + paragraph: '分段', + all: '全部', + updateTime: '更新時間' + }, + fileStatus: { + label: '文件狀態', + SUCCESS: '成功', + FAILURE: '失敗', + EMBEDDING: '索引中', + PENDING: '排隊中', + GENERATE: '生成中', + SYNC: '同步中', + REVOKE: '取消中', + finish: '完圓' + }, + enableStatus: { + label: '啟用狀態', + enable: '開啟', + close: '關閉' + }, + sync: { + label: '同步', + confirmTitle: '確認同步文檔?', + confirmMessage1: '同步將刪除已有數據重新獲取新數據,請謹慎操作。', + confirmMessage2: '無法同步,請先去設置文檔 URL地址', + successMessage: '同步文檔成功' + }, + delete: { + confirmTitle1: '是否批量刪除', + confirmTitle2: '個文檔?', + confirmMessage: '所選文檔中的分段會跟隨刪除,請謹慎操作。', + successMessage: '批量刪除成功', + confirmTitle3: '是否刪除文檔:', + confirmMessage1: '此文檔下的', + confirmMessage2: '個分段都會被刪除,請謹慎操作。' + }, + form: { + source_url: { + label: '文檔地址', + placeholder: '請輸入文檔地址,一行一個,地址不正確文檔會導入失敗。', + requiredMessage: '請輸入文檔地址' + }, + selector: { + label: '選擇器', + placeholder: '默認為 body,可輸入 .classname/#idname/tagname' + }, + hit_handling_method: { + label: '命中處理方式', + tooltip: '用戶提問時,命中文檔下的分段時按照設置的方式進行處理。' + }, + similarity: { + label: '相似度高于', + placeholder: '直接返回分段内容', + requiredMessage: '请输入相似度' + }, + }, + hitHandlingMethod: { + optimization: '模型優化', + directly_return: '直接回答' + }, + generateQuestion: { + title: '生成問題', + successMessage: '生成問題成功', + tip1: '提示詞中的 {data} 為分段內容的佔位符,執行時替換為分段內容並發送給 AI 模型;', + tip2: 'AI 模型根據分段內容生成相關問題,請將生成的問題放置於', + tip3: '標籤中,系統會自動關聯標籤中的問題;', + tip4: '生成效果取決於所選模型和提示詞,用戶可自行調整至最佳效果。', + prompt1: `內容:{data}\n\n請總結上面的內容,並根據內容總結生成 5 個問題。\n回答要求:\n - 請只輸出問題;\n - 請將每個問題放置在`, + prompt2: `標籤中。`, + }, + feishu: { + selectDocument: '選擇文檔', + tip1: '僅支持文檔和表格類型,文檔會根據標題分段,表格會轉為Markdown格式後再分段。', + tip2: '系統不存儲原始文檔,導入文檔前,建議規範文檔的分段標識。', + allCheck: '全選' + } +} diff --git a/ui/src/locales/lang/zh-Hant/views/function-lib.ts b/ui/src/locales/lang/zh-Hant/views/function-lib.ts new file mode 100644 index 000000000..789cbf0ec --- /dev/null +++ b/ui/src/locales/lang/zh-Hant/views/function-lib.ts @@ -0,0 +1,77 @@ +export default { + title: '函數庫', + internalTitle: '內置函數', + added: '已新增', + createFunction: '建立函數', + editFunction: '編輯函數', + copyFunction: '複製函數', + importFunction: '匯入函數', + searchBar: { + placeholder: '按函數名稱搜尋' + }, + setting: { + disabled: '停用' + }, + tip: { + saveMessage: '當前的更改尚未保存,確認退出嗎?' + }, + delete: { + confirmTitle: '是否刪除函數:', + confirmMessage: '刪除後,引用該函數的應用在查詢時會報錯,請謹慎操作。' + }, + disabled: { + confirmTitle: '是否停用函數:', + confirmMessage: '停用後,引用該函數的應用在查詢時會報錯,請謹慎操作。' + }, + functionForm: { + title: { + copy: '副本', + baseInfo: '基礎信息' + }, + form: { + functionName: { + label: '名稱', + placeholder: '請輸入函數名稱', + requiredMessage: '請輸入函數名稱' + }, + functionDescription: { + label: '描述', + placeholder: '請輸入函數的描述' + }, + permission_type: { + label: '權限', + requiredMessage: '請選擇' + }, + paramName: { + label: '參數名', + placeholder: '請輸入參數名', + requiredMessage: '請輸入參數名' + }, + dataType: { + label: '數據類型' + }, + source: { + label: '來源', + custom: '自定義', + reference: '引用參數' + }, + required: { + label: '是否必填' + }, + param: { + paramInfo1: '使用函數時顯示', + paramInfo2: '使用函數時不顯示', + code: '函数内容(Python)', + selectPlaceholder: '請选择參數', + inputPlaceholder: '請輸入參數值', + }, + debug: { + run: '運行', + output: '輸出', + runResult: '運行結果', + runSuccess: '運行成功', + runFailed: '運行失敗' + } + } + } +} diff --git a/ui/src/locales/lang/zh-Hant/views/index.ts b/ui/src/locales/lang/zh-Hant/views/index.ts new file mode 100644 index 000000000..c63d40492 --- /dev/null +++ b/ui/src/locales/lang/zh-Hant/views/index.ts @@ -0,0 +1,34 @@ +import notFound from './404' +import application from './application' +import applicationOverview from './application-overview' +import dataset from './dataset' +import system from './system' +import functionLib from './function-lib' +import user from './user' +import team from './team' +import template from './template' +import document from './document' +import paragraph from './paragraph' +import problem from './problem' +import log from './log' +import applicationWorkflow from './application-workflow' +import login from './login' +import operateLog from './operate-log' +export default { + notFound, + application, + applicationOverview, + system, + functionLib, + user, + team, + template, + dataset, + applicationWorkflow, + document, + paragraph, + problem, + log, + login, + operateLog +} diff --git a/ui/src/locales/lang/zh-Hant/views/log.ts b/ui/src/locales/lang/zh-Hant/views/log.ts new file mode 100644 index 000000000..5e84a698d --- /dev/null +++ b/ui/src/locales/lang/zh-Hant/views/log.ts @@ -0,0 +1,41 @@ +export default { + title: '對話日誌', + delete: { + confirmTitle: '是否刪除問題:', + confirmMessage1: '刪除問題關聯的', + confirmMessage2: '個分段會被取消關聯,請謹慎操作。' + }, + buttons: { + clearStrategy: '清除策略', + prev: '上一條', + next: '下一條' + }, + table: { + abstract: '摘要', + chat_record_count: '對話提問數', + user: '用戶', + feedback: { + label: '用戶反饋', + star: '贊同', + trample: '反對' + }, + mark: '改進標註', + recenTimes: '最近對話時間' + }, + addToDataset: '添加至知識庫', + daysText: '天之前的對話記錄', + selectDataset: '選擇知識庫', + selectDatasetPlaceholder: '請選擇知識庫', + saveToDocument: '保存至文件', + documentPlaceholder: '請選擇文件', + editContent: '修改內容', + editMark: '修改標註', + form: { + content: { + placeholder: '請輸入內容' + }, + title: { + placeholder: '請給當前內容設定一個標題,以便管理查看' + } + } +} diff --git a/ui/src/locales/lang/zh-Hant/views/login.ts b/ui/src/locales/lang/zh-Hant/views/login.ts new file mode 100644 index 000000000..dded54730 --- /dev/null +++ b/ui/src/locales/lang/zh-Hant/views/login.ts @@ -0,0 +1,24 @@ +export default { + title: '普通登錄', + jump_tip: '即將跳轉至認證源頁面進行認證', + jump: '跳轉', + resetPassword: '修改密碼', + forgotPassword: '忘記密碼', + userRegister: '用戶註冊', + buttons: { + login: '登錄', + register: '註冊', + backLogin: '返回登錄', + checkCode: '立即驗證' + }, + newPassword: '新密碼', + enterPassword: '請輸入新密碼', + useEmail: '使用電子郵箱', + moreMethod: '更多登錄方式', + verificationCode: { + placeholder: '請輸入驗證碼', + getVerificationCode: '獲取驗證碼', + successMessage: '驗證碼發送成功', + resend: '重新發送' + } +} diff --git a/ui/src/locales/lang/zh-Hant/views/operate-log.ts b/ui/src/locales/lang/zh-Hant/views/operate-log.ts new file mode 100644 index 000000000..510ab21dc --- /dev/null +++ b/ui/src/locales/lang/zh-Hant/views/operate-log.ts @@ -0,0 +1,30 @@ +export default { + title: '操作日誌', + table: { + menu: { + label: '操作菜單' + }, + operate: { + label: '操作' + }, + user: { + label: '操作用戶' + }, + status: { + label: '狀態', + success: '成功', + fail: '失敗', + all: '全部' + }, + ip_address: { + label: 'IP地址' + }, + opt: { + label: 'API詳情' + }, + operateTime: { + label: '操作時間' + } + }, + close: '關閉' +} diff --git a/ui/src/locales/lang/zh-Hant/views/paragraph.ts b/ui/src/locales/lang/zh-Hant/views/paragraph.ts new file mode 100644 index 000000000..a5b4b3317 --- /dev/null +++ b/ui/src/locales/lang/zh-Hant/views/paragraph.ts @@ -0,0 +1,32 @@ +export default { + title: '段落', + paragraph_count: '段落', + editParagraph: '編輯分段', + addParagraph: '添加分段', + paragraphDetail: '分段詳情', + character_count: '個字符', + setting: { + batchSelected: '批量選擇', + cancelSelected: '取消選擇' + }, + delete: { + confirmTitle: '是否刪除段落:', + confirmMessage: '刪除後無法恢復,請謹慎操作。' + }, + relatedProblem: { + title: '關聯問題', + placeholder: '請選擇問題' + }, + form: { + paragraphTitle: { + label: '分段標題', + placeholder: '請輸入分段標題' + }, + content: { + label: '分段內容', + placeholder: '請輸入分段內容', + requiredMessage1: '請輸入分段內容', + requiredMessage2: '內容最多不超過 100000 個字' + } + } +} diff --git a/ui/src/locales/lang/zh-Hant/views/problem.ts b/ui/src/locales/lang/zh-Hant/views/problem.ts new file mode 100644 index 000000000..12cb86020 --- /dev/null +++ b/ui/src/locales/lang/zh-Hant/views/problem.ts @@ -0,0 +1,37 @@ +export default { + title: '問題', + createProblem: '建立問題', + detailProblem: '問題詳情', + quickCreateProblem: '快速建立問題', + quickCreateName: '問題', + tip: { + placeholder: '請輸入問題,支持輸入多個,一行一個。', + errorMessage: '問題不能為空!', + requiredMessage: '請輸入問題', + relatedSuccess: '批量關聯分段成功' + }, + + setting: { + batchDelete: '批量刪除', + cancelRelated: '取消關聯' + }, + searchBar: { + placeholder: '按名稱搜尋' + }, + table: { + paragraph_count: '關聯分段數', + updateTime: '更新時間' + }, + delete: { + confirmTitle: '是否刪除問題:', + confirmMessage1: '刪除問題關聯的', + confirmMessage2: '個分段會被取消關聯,請謹慎操作。' + }, + relateParagraph: { + title: '關聯分段', + selectDocument: '選擇文件', + placeholder: '按 文件名稱 搜尋', + selectedParagraph: '已選分段', + count: '個' + }, +} diff --git a/ui/src/locales/lang/zh-Hant/views/system.ts b/ui/src/locales/lang/zh-Hant/views/system.ts new file mode 100644 index 000000000..10259390b --- /dev/null +++ b/ui/src/locales/lang/zh-Hant/views/system.ts @@ -0,0 +1,152 @@ +export default { + title: '系統設置', + test: '測試連線', + testSuccess: '測試連線成功', + testFailed: '測試連線失敗', + password: '密碼', + authentication: { + title: '登入認證', + ldap: { + title: 'LDAP', + address: 'LDAP 位址', + serverPlaceholder: '請輸入LDAP 位址', + bindDN: '綁定DN', + bindDNPlaceholder: '請輸入綁定 DN', + + ou: '使用者OU', + ouPlaceholder: '請輸入使用者 OU', + ldap_filter: '使用者過濾器', + ldap_filterPlaceholder: '請輸入使用者過濾器', + ldap_mapping: 'LDAP 屬性對應', + ldap_mappingPlaceholder: '請輸入 LDAP 屬性對應', + enableAuthentication: '啟用 LDAP 認證' + }, + cas: { + title: 'CAS', + ldpUri: 'ldpUri', + ldpUriPlaceholder: '請輸入ldpUri', + validateUrl: '驗證位址', + validateUrlPlaceholder: '請輸入驗證位址', + redirectUrl: '回呼位址', + redirectUrlPlaceholder: '請輸入回呼位址', + enableAuthentication: '啟用 CAS 認證' + }, + oidc: { + title: 'OIDC', + authEndpoint: '授權端位址', + authEndpointPlaceholder: '請輸入授權端位址', + tokenEndpoint: 'Token端位址', + tokenEndpointPlaceholder: '請輸入 Token 端位址', + userInfoEndpoint: '使用者資訊端位址', + userInfoEndpointPlaceholder: '請輸入使用者資訊端位址', + clientId: '用戶端 ID', + scopePlaceholder: '請輸入連線範圍', + clientIdPlaceholder: '請輸入用戶端 ID', + clientSecret: '用戶端密鑰', + clientSecretPlaceholder: '請輸入用戶端密鑰', + logoutEndpoint: '登出端位址', + logoutEndpointPlaceholder: '請輸入登出端位址', + redirectUrl: '回呼位址', + redirectUrlPlaceholder: '請輸入回呼位址', + enableAuthentication: '啟用 OIDC 認證' + }, + + oauth2: { + title: 'OAuth2', + authEndpoint: '授權端位址', + authEndpointPlaceholder: '請輸入授權端位址', + tokenEndpoint: 'Token 端位址', + tokenEndpointPlaceholder: '請輸入 Token 端位址', + userInfoEndpoint: '使用者資訊端位址', + userInfoEndpointPlaceholder: '請輸入使用者資訊端位址', + scope: '連線範圍', + scopePlaceholder: '請輸入連線範圍', + clientId: '用戶端 ID', + clientIdPlaceholder: '請輸入用戶端 ID', + clientSecret: '用戶端密鑰', + clientSecretPlaceholder: '請輸入用戶端密鑰', + redirectUrl: '回呼位址', + redirectUrlPlaceholder: '請輸入回呼位址', + filedMapping: '欄位對應', + filedMappingPlaceholder: '請輸入欄位對應', + enableAuthentication: '啟用 OAuth2 認證' + }, + scanTheQRCode: { + title: '掃碼登入', + wecom: '企業微信', + dingtalk: '釘釘', + lark: '飛書', + effective: '有效', + alreadyTurnedOn: '已開啟', + notEnabled: '未開啟', + validate: '驗證', + validateSuccess: '驗證成功', + validateFailed: '驗證失敗', + validateFailedTip: '請填寫所有必填項並確保格式正確', + appKeyPlaceholder: '請輸入 App Key', + appSecretPlaceholder: '請輸入 App Secret', + corpIdPlaceholder: '請輸入 Corp Id', + agentIdPlaceholder: '請輸入 Agent Id', + callbackWarning: '請輸入有效的 URL 位址', + larkQrCode: '飛書掃碼登錄', + dingtalkQrCode: '釘釘掃碼登錄', + setting: '設置', + access: '接入' + } + }, + theme: { + title: '外觀設置', + platformDisplayTheme: '平台顯示主題', + customTheme: '自定義主題', + platformLoginSettings: '平台登錄設置', + custom: '自定義', + pagePreview: '頁面預覽', + default: '默認', + restoreDefaults: '恢復默認', + orange: '活力橙', + green: '松石綠', + purple: '神秘紫', + red: '胭脂紅', + loginBackground: '登錄背景圖', + loginLogo: '登錄 Logo', + websiteLogo: '網站 Logo', + replacePicture: '替換圖片', + websiteLogoTip: '頂部網站顯示的 Logo,建議尺寸 48*48,支持 JPG、PNG、GIF,大小不超過 10MB', + loginLogoTip: '登錄頁面右側 Logo,建議尺寸 204*52,支持 JPG、PNG、GIF,大小不超過 10 MB', + loginBackgroundTip: + '左側背景圖,矢量圖建議尺寸 576*900,位圖建議尺寸 1152*1800;支持 JPG、PNG、GIF,大小不超過 10 MB', + websiteName: '網站名稱', + websiteNamePlaceholder: '請輸入網站名稱', + websiteNameTip: '顯示在網頁 Tab 的平台名稱', + websiteSlogan: '歡迎語', + websiteSloganPlaceholder: '請輸入歡迎語', + websiteSloganTip: '產品 Logo 下的歡迎語', + logoDefaultTip: '默认为 MaxKB 登錄界面,支持自定义设置', + defaultSlogan: '歡迎使用 MaxKB 智能知識庫問答系統', + defaultTip: '默認為 MaxKB 平台界面,支持自定義設置', + platformSetting: '平台設置', + showUserManual: '顯示用戶手冊', + showForum: '顯示論壇求助', + showProject: '顯示項目地址', + urlPlaceholder: '請輸入 URL 地址', + abandonUpdate: '放棄更新', + saveAndApply: '保存並應用', + fileMessageError: '文件大小超過 10M', + saveSuccess: '外觀設置成功' + }, + email: { + title: '郵箱設置', + smtpHost: 'SMTP Host', + smtpHostPlaceholder: '請輸入 SMTP Host', + smtpPort: 'SMTP Port', + smtpPortPlaceholder: '請輸入 SMTP Port', + smtpUser: 'SMTP 帳戶', + smtpUserPlaceholder: '請輸入 SMTP 帳戶', + sendEmail: '發件人信箱', + sendEmailPlaceholder: '請輸入發件人信箱', + smtpPassword: '發件人密碼', + smtpPasswordPlaceholder: '請輸入發件人密碼', + enableSSL: '啟用 SSL(如果 SMTP 端口是 465,通常需要啟用 SSL)', + enableTLS: '啟用 TLS(如果 SMTP 端口是 587,通常需要啟用 TLS)' + } +} diff --git a/ui/src/locales/lang/zh-Hant/views/team.ts b/ui/src/locales/lang/zh-Hant/views/team.ts new file mode 100644 index 000000000..1b1fb4192 --- /dev/null +++ b/ui/src/locales/lang/zh-Hant/views/team.ts @@ -0,0 +1,29 @@ +export default { + title: '團隊成員', + member: '成員', + manage: '所有者', + permissionSetting: '權限設定', + addMember: '新增成員', + addSubTitle: '成員登入後可以存取您授權的資料。', + searchBar: { + placeholder: '請輸入使用者名稱搜尋' + }, + delete: { + button: '移除', + confirmTitle: '是否移除成員:', + confirmMessage: '移除後將會取消成員擁有之知識庫和應用程式權限。' + }, + setting: { + management: '管理', + check: '查看' + }, + teamForm: { + form: { + userName: { + label: '使用者名稱/電子郵件', + placeholder: '請輸入成員的使用者名稱或電子郵件', + requiredMessage: '請輸入使用者名稱/電子郵件' + } + } + } +} diff --git a/ui/src/locales/lang/zh-Hant/views/template.ts b/ui/src/locales/lang/zh-Hant/views/template.ts new file mode 100644 index 000000000..241f9d8c5 --- /dev/null +++ b/ui/src/locales/lang/zh-Hant/views/template.ts @@ -0,0 +1,83 @@ +export default { + title: '模型設定', + provider: '供應商', + providerPlaceholder: '選擇供應商', + addModel: '新增模型', + searchBar: { + placeholder: '按名稱搜尋' + }, + delete: { + confirmTitle: '刪除模型', + confirmMessage: '是否刪除模型:' + }, + tip: { + createSuccessMessage: '創建模型成功', + createErrorMessage: '基礎資訊有填寫錯誤', + errorMessage: '變數已存在: ', + emptyMessage1: '請先選擇基礎資訊的模型類型和基礎模型', + emptyMessage2: '所選模型不支援參數設定', + updateSuccessMessage: '修改模型成功', + saveSuccessMessage: '模型參數儲存成功', + downloadError: '下載失敗', + noModel: '模型在Ollama不存在' + }, + model: { + allModel: '全部模型', + publicModel: '公有模型', + privateModel: '私有模型', + LLM: '大語言模型', + EMBEDDING: '向量模型', + RERANKER: '重排模型', + STT: '語音辨識', + TTS: '語音合成', + IMAGE: '圖片理解', + TTI: '圖片生成' + }, + templateForm: { + title: { + baseInfo: '基礎資訊', + advancedInfo: '進階設定', + modelParams: '模型參數', + editParam: '編輯參數', + addParam: '新增參數', + paramSetting: '模型參數設定', + apiParamPassing: '接口傳參' + }, + form: { + templateName: { + label: '模型名稱', + placeholder: '請給基礎模型設定一個名稱', + tooltip: 'MaxKB 中自訂的模型名稱', + requiredMessage: '模型名稱不能為空' + }, + permissionType: { + label: '權限', + privateDesc: '僅當前使用者使用', + publicDesc: '所有使用者都可使用', + requiredMessage: '權限不能為空' + }, + model_type: { + label: '模型類型', + placeholder: '請選擇模型類型', + tooltip1: '大語言模型:在應用中與AI對話的推理模型。', + tooltip2: '向量模型:在知識庫中對文件內容進行向量化化的模型。', + tooltip3: '語音辨識:在應用中開啟語音辨識後用於語音轉文字的模型。', + tooltip4: '語音合成:在應用中開啟語音播放後用於文字轉語音的模型。', + tooltip5: '重排模型:在高階編排應用中使用多路召回時,對候選分段進行重新排序的模型。', + tooltip6: '圖片理解:在高階編排應用中用於圖片理解的視覺模型。', + tooltip7: '圖片生成:在高階編排應用中用於圖片生成的視覺模型。', + requiredMessage: '模型類型不能為空' + }, + base_model: { + label: '基礎模型', + tooltip: '列表中未列出的模型,直接輸入模型名稱,按 Enter 即可新增', + placeholder: '自訂輸入基礎模型後按 Enter 即可', + requiredMessage: '基礎模型不能為空' + } + } + }, + download: { + downloading: '正在下載中', + cancelDownload: '取消下載' + } +} diff --git a/ui/src/locales/lang/zh-Hant/views/user.ts b/ui/src/locales/lang/zh-Hant/views/user.ts new file mode 100644 index 000000000..18ea3326a --- /dev/null +++ b/ui/src/locales/lang/zh-Hant/views/user.ts @@ -0,0 +1,68 @@ +export default { + title: '使用者管理', + createUser: '建立使用者', + editUser: '編輯使用者', + setting: { + updatePwd: '修改使用者密碼' + }, + tip: { + professionalMessage: '社群版最多支援 2 個使用者,如需擁有更多使用者,請升級為專業版。', + updatePwdSuccess: '使用者密碼修改成功' + }, + delete: { + confirmTitle: '是否刪除該使用者?', + confirmMessage: + '刪除該使用者後,該使用者建立的所有資源(應用、知識庫、模型)都會被刪除,請謹慎操作。' + }, + disabled: { + confirmTitle: '是否停用函數?', + confirmMessage: '停用後,引用該函數的應用在查詢時會報錯,請謹慎操作。' + }, + userForm: { + form: { + username: { + label: '使用者名稱', + placeholder: '請輸入使用者名稱', + requiredMessage: '請輸入使用者名稱', + lengthMessage: '長度須介於 6 到 20 個字元之間' + }, + nick_name: { + label: '姓名', + placeholder: '請輸入姓名' + }, + email: { + label: '電子信箱', + placeholder: '請輸入電子信箱', + requiredMessage: '請輸入電子信箱' + }, + phone: { + label: '手機號碼', + placeholder: '請輸入手機號碼' + }, + password: { + label: '登入密碼', + placeholder: '請輸入密碼', + requiredMessage: '請輸入密碼', + lengthMessage: '長度須介於 6 到 20 個字元之間' + }, + new_password: { + label: '新密碼', + placeholder: '請輸入新密碼', + requiredMessage: '請輸入新密碼' + }, + re_password: { + label: '確認密碼', + placeholder: '請輸入確認密碼', + requiredMessage: '請輸入確認密碼', + validatorMessage: '密碼不一致' + } + } + }, + source: { + label: '使用者類型', + local: '系統使用者', + wecom: '企業微信', + lark: '飛書', + dingtalk: '釘釘' + } +} diff --git a/ui/src/locales/useLocale.ts b/ui/src/locales/useLocale.ts new file mode 100644 index 000000000..d01ec8643 --- /dev/null +++ b/ui/src/locales/useLocale.ts @@ -0,0 +1,28 @@ +import { useLocalStorage } from '@vueuse/core'; +import { computed } from 'vue'; +import { useI18n } from 'vue-i18n'; +import { i18n, langCode, localeConfigKey } from '@/locales/index'; + +export function useLocale() { + const { locale } = useI18n({ useScope: 'global' }); + function changeLocale(lang: string) { + // 如果切换的语言不在对应语言文件里则默认为简体中文 + if (!langCode.includes(lang)) { + lang = 'en-US'; + } + + locale.value = lang; + useLocalStorage(localeConfigKey, 'en-US').value = lang; + } + + const getComponentsLocale = computed(() => { + const localeMessage = i18n.global.getLocaleMessage(locale.value) as Record; + return localeMessage.componentsLocale; + }); + + return { + changeLocale, + getComponentsLocale, + locale, + }; +} diff --git a/ui/src/main.ts b/ui/src/main.ts index 5dcad83c3..b47fbf0cf 100644 --- a/ui/src/main.ts +++ b/ui/src/main.ts @@ -1,14 +1,29 @@ -import './assets/main.css' - +import '@/styles/index.scss' +import ElementPlus from 'element-plus' +import * as ElementPlusIcons from '@element-plus/icons-vue' +import zhCn from 'element-plus/es/locale/lang/zh-cn' +import enUs from 'element-plus/es/locale/lang/en' +import zhTW from 'element-plus/es/locale/lang/zh-tw' import { createApp } from 'vue' import { createPinia } from 'pinia' - import App from './App.vue' -import router from './router' - +import router from '@/router' +import i18n from '@/locales' +import Components from '@/components' const app = createApp(App) - app.use(createPinia()) +for (const [key, component] of Object.entries(ElementPlusIcons)) { + app.component(key, component) +} +const locale_map: any = { + 'zh-CN': zhCn, + 'zh-Hant': zhTW, + 'en-US': enUs +} +app.use(ElementPlus, { + locale: locale_map[localStorage.getItem('MaxKB-locale') || navigator.language || 'en-US'] +}) app.use(router) - +app.use(i18n) +app.use(Components) app.mount('#app') diff --git a/ui/src/router/index.ts b/ui/src/router/index.ts index 3e49915ca..40f33d09e 100644 --- a/ui/src/router/index.ts +++ b/ui/src/router/index.ts @@ -1,23 +1,9 @@ import { createRouter, createWebHistory } from 'vue-router' -import HomeView from '../views/HomeView.vue' +import { routes } from '@/router/routes' const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), - routes: [ - { - path: '/', - name: 'home', - component: HomeView, - }, - { - path: '/about', - name: 'about', - // route level code-splitting - // this generates a separate chunk (About.[hash].js) for this route - // which is lazy-loaded when the route is visited. - component: () => import('../views/AboutView.vue'), - }, - ], + routes: routes, }) export default router diff --git a/ui/src/router/routes.ts b/ui/src/router/routes.ts new file mode 100644 index 000000000..e32cf4b1f --- /dev/null +++ b/ui/src/router/routes.ts @@ -0,0 +1,32 @@ +import type { RouteRecordRaw } from 'vue-router' +// const modules: any = import.meta.glob('./modules/*.ts', { eager: true }) +// const rolesRoutes: RouteRecordRaw[] = [...Object.keys(modules).map((key) => modules[key].default)] + +export const routes: Array = [ + { + path: '/', + name: 'home', + component: () => import('@/views/HomeView.vue'), + }, + + { + path: '/login', + name: 'login', + component: () => import('@/views/login/index.vue'), + }, + { + path: '/forget_password', + name: 'ForgetPassword', + component: () => import('@/views/login/ForgetPassword.vue') + }, + { + path: '/reset_password/:code/:email', + name: 'ResetPassword', + component: () => import('@/views/login/ResetPassword.vue') + }, + // { + // path: '/:pathMatch(.*)', + // name: '404', + // component: () => import('@/views/404/index.vue') + // } +] diff --git a/ui/src/stores/counter.ts b/ui/src/stores/counter.ts deleted file mode 100644 index b6757ba57..000000000 --- a/ui/src/stores/counter.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ref, computed } from 'vue' -import { defineStore } from 'pinia' - -export const useCounterStore = defineStore('counter', () => { - const count = ref(0) - const doubleCount = computed(() => count.value * 2) - function increment() { - count.value++ - } - - return { count, doubleCount, increment } -}) diff --git a/ui/src/stores/index.ts b/ui/src/stores/index.ts new file mode 100644 index 000000000..9f0d07740 --- /dev/null +++ b/ui/src/stores/index.ts @@ -0,0 +1,9 @@ +import useLoginStore from './modules/login' +import useUserStore from './modules/user' + +const useStore = () => ({ + login: useLoginStore(), + user: useUserStore(), +}) + +export default useStore diff --git a/ui/src/stores/modules/login.ts b/ui/src/stores/modules/login.ts new file mode 100644 index 000000000..c116db2c9 --- /dev/null +++ b/ui/src/stores/modules/login.ts @@ -0,0 +1,210 @@ +import { defineStore } from 'pinia' +import { type Ref } from 'vue' +// import type { User } from '@/api/type/user' +// import { cloneDeep } from 'lodash' +// import UserApi from '@/api/user' +// import ThemeApi from '@/api/theme' +// import { useElementPlusTheme } from 'use-element-plus-theme' +// import { defaultPlatformSetting } from '@/utils/theme' +import { useLocalStorage } from '@vueuse/core' +import { localeConfigKey, getBrowserLang } from '@/locales/index' +export interface userStateTypes { + userType: number // 1 系统操作者 2 对话用户 + // userInfo: User | null + token: any + version?: string + userAccessToken?: string + XPACK_LICENSE_IS_VALID: false + isXPack: false + themeInfo: any +} + +const useLoginStore = defineStore('login',{ + state: (): userStateTypes => ({ + userType: 1, + // userInfo: null, + token: '', + version: '', + userAccessToken: '', + XPACK_LICENSE_IS_VALID: false, + isXPack: false, + themeInfo: null + }), + actions: { + // getLanguage() { + // return this.userType === 1 + // ? localStorage.getItem('MaxKB-locale') || getBrowserLang() + // : sessionStorage.getItem('language') || getBrowserLang() + // }, + // showXpack() { + // return this.isXPack + // }, + // isDefaultTheme() { + // return !this.themeInfo?.theme || this.themeInfo?.theme === '#3370FF' + // }, + // setTheme(data: any) { + // const { changeTheme } = useElementPlusTheme(this.themeInfo?.theme) + // changeTheme(data?.['theme']) + // this.themeInfo = cloneDeep(data) + // }, + // isExpire() { + // return this.isXPack && !this.XPACK_LICENSE_IS_VALID + // }, + // isEnterprise() { + // return this.isXPack && this.XPACK_LICENSE_IS_VALID + // }, + // getToken(): String | null { + // if (this.token) { + // return this.token + // } + // return this.userType === 1 ? localStorage.getItem('token') : this.getAccessToken() + // }, + // getAccessToken() { + // const token = sessionStorage.getItem(`${this.userAccessToken}-accessToken`) + // if (token) { + // return token + // } + // const local_token = localStorage.getItem(`${token}-accessToken`) + // if (local_token) { + // return local_token + // } + // return localStorage.getItem(`accessToken`) + // }, + + // getPermissions() { + // if (this.userInfo) { + // return this.isXPack && this.XPACK_LICENSE_IS_VALID + // ? [...this.userInfo?.permissions, 'x-pack'] + // : this.userInfo?.permissions + // } else { + // return [] + // } + // }, + // getRole() { + // if (this.userInfo) { + // return this.userInfo?.role + // } else { + // return '' + // } + // }, + // changeUserType(num: number, token?: string) { + // this.userType = num + // this.userAccessToken = token + // }, + + // async asyncGetProfile() { + // return new Promise((resolve, reject) => { + // UserApi.getProfile() + // .then(async (ok) => { + // this.version = ok.data?.version || '-' + // this.isXPack = ok.data?.IS_XPACK + // this.XPACK_LICENSE_IS_VALID = ok.data?.XPACK_LICENSE_IS_VALID + + // if (this.isEnterprise()) { + // await this.theme() + // } else { + // this.themeInfo = { + // ...defaultPlatformSetting + // } + // } + // resolve(ok) + // }) + // .catch((error) => { + // reject(error) + // }) + // }) + // }, + + // async theme(loading?: Ref) { + // return await ThemeApi.getThemeInfo(loading).then((ok) => { + // this.setTheme(ok.data) + // // window.document.title = this.themeInfo['title'] || 'MaxKB' + // // const link = document.querySelector('link[rel="icon"]') as any + // // if (link) { + // // link['href'] = this.themeInfo['icon'] || '/favicon.ico' + // // } + // }) + // }, + + // async profile() { + // return UserApi.profile().then(async (ok) => { + // this.userInfo = ok.data + // useLocalStorage(localeConfigKey, 'en-US').value = ok.data?.language || this.getLanguage() + // return this.asyncGetProfile() + // }) + // }, + + // async login(auth_type: string, username: string, password: string) { + // return UserApi.login(auth_type, { username, password }).then((ok) => { + // this.token = ok.data + // localStorage.setItem('token', ok.data) + // return this.profile() + // }) + // }, + // async dingCallback(code: string) { + // return UserApi.getDingCallback(code).then((ok) => { + // this.token = ok.data + // localStorage.setItem('token', ok.data) + // return this.profile() + // }) + // }, + // async dingOauth2Callback(code: string) { + // return UserApi.getDingOauth2Callback(code).then((ok) => { + // this.token = ok.data + // localStorage.setItem('token', ok.data) + // return this.profile() + // }) + // }, + // async wecomCallback(code: string) { + // return UserApi.getWecomCallback(code).then((ok) => { + // this.token = ok.data + // localStorage.setItem('token', ok.data) + // return this.profile() + // }) + // }, + // async larkCallback(code: string) { + // return UserApi.getlarkCallback(code).then((ok) => { + // this.token = ok.data + // localStorage.setItem('token', ok.data) + // return this.profile() + // }) + // }, + + // async logout() { + // return UserApi.logout().then(() => { + // localStorage.removeItem('token') + // return true + // }) + // }, + // async getAuthType() { + // return UserApi.getAuthType().then((ok) => { + // return ok.data + // }) + // }, + // async getQrType() { + // return UserApi.getQrType().then((ok) => { + // return ok.data + // }) + // }, + // async getQrSource() { + // return UserApi.getQrSource().then((ok) => { + // return ok.data + // }) + // }, + // async postUserLanguage(lang: string, loading?: Ref) { + // return new Promise((resolve, reject) => { + // UserApi.postLanguage({ language: lang }, loading) + // .then(async (ok) => { + // useLocalStorage(localeConfigKey, 'en-US').value = lang + // window.location.reload() + // resolve(ok) + // }) + // .catch((error) => { + // reject(error) + // }) + // }) + // } + } +}) + +export default useLoginStore diff --git a/ui/src/stores/modules/user.ts b/ui/src/stores/modules/user.ts new file mode 100644 index 000000000..08ce5910b --- /dev/null +++ b/ui/src/stores/modules/user.ts @@ -0,0 +1,210 @@ +import { defineStore } from 'pinia' +import { type Ref } from 'vue' +// import type { User } from '@/api/type/user' +import { cloneDeep } from 'lodash' +// import UserApi from '@/api/user' +// import ThemeApi from '@/api/theme' +// import { useElementPlusTheme } from 'use-element-plus-theme' +// import { defaultPlatformSetting } from '@/utils/theme' +import { useLocalStorage } from '@vueuse/core' +import { localeConfigKey, getBrowserLang } from '@/locales/index' +export interface userStateTypes { + userType: number // 1 系统操作者 2 对话用户 + // userInfo: User | null + token: any + version?: string + userAccessToken?: string + XPACK_LICENSE_IS_VALID: false + isXPack: false + themeInfo: any +} + +const useLoginStore = defineStore('user', { + state: (): userStateTypes => ({ + userType: 1, + // userInfo: null, + token: '', + version: '', + userAccessToken: '', + XPACK_LICENSE_IS_VALID: false, + isXPack: false, + themeInfo: null + }), + actions: { + getLanguage() { + return this.userType === 1 + ? localStorage.getItem('MaxKB-locale') || getBrowserLang() + : sessionStorage.getItem('language') || getBrowserLang() + }, + // showXpack() { + // return this.isXPack + // }, + isDefaultTheme() { + return !this.themeInfo?.theme || this.themeInfo?.theme === '#3370FF' + }, + // setTheme(data: any) { + // const { changeTheme } = useElementPlusTheme(this.themeInfo?.theme) + // changeTheme(data?.['theme']) + // this.themeInfo = cloneDeep(data) + // }, + // isExpire() { + // return this.isXPack && !this.XPACK_LICENSE_IS_VALID + // }, + // isEnterprise() { + // return this.isXPack && this.XPACK_LICENSE_IS_VALID + // }, + // getToken(): String | null { + // if (this.token) { + // return this.token + // } + // return this.userType === 1 ? localStorage.getItem('token') : this.getAccessToken() + // }, + // getAccessToken() { + // const token = sessionStorage.getItem(`${this.userAccessToken}-accessToken`) + // if (token) { + // return token + // } + // const local_token = localStorage.getItem(`${token}-accessToken`) + // if (local_token) { + // return local_token + // } + // return localStorage.getItem(`accessToken`) + // }, + + // getPermissions() { + // if (this.userInfo) { + // return this.isXPack && this.XPACK_LICENSE_IS_VALID + // ? [...this.userInfo?.permissions, 'x-pack'] + // : this.userInfo?.permissions + // } else { + // return [] + // } + // }, + // getRole() { + // if (this.userInfo) { + // return this.userInfo?.role + // } else { + // return '' + // } + // }, + // changeUserType(num: number, token?: string) { + // this.userType = num + // this.userAccessToken = token + // }, + + // async asyncGetProfile() { + // return new Promise((resolve, reject) => { + // UserApi.getProfile() + // .then(async (ok) => { + // this.version = ok.data?.version || '-' + // this.isXPack = ok.data?.IS_XPACK + // this.XPACK_LICENSE_IS_VALID = ok.data?.XPACK_LICENSE_IS_VALID + + // if (this.isEnterprise()) { + // await this.theme() + // } else { + // this.themeInfo = { + // ...defaultPlatformSetting + // } + // } + // resolve(ok) + // }) + // .catch((error) => { + // reject(error) + // }) + // }) + // }, + + // async theme(loading?: Ref) { + // return await ThemeApi.getThemeInfo(loading).then((ok) => { + // this.setTheme(ok.data) + // // window.document.title = this.themeInfo['title'] || 'MaxKB' + // // const link = document.querySelector('link[rel="icon"]') as any + // // if (link) { + // // link['href'] = this.themeInfo['icon'] || '/favicon.ico' + // // } + // }) + // }, + + // async profile() { + // return UserApi.profile().then(async (ok) => { + // this.userInfo = ok.data + // useLocalStorage(localeConfigKey, 'en-US').value = ok.data?.language || this.getLanguage() + // return this.asyncGetProfile() + // }) + // }, + + // async login(auth_type: string, username: string, password: string) { + // return UserApi.login(auth_type, { username, password }).then((ok) => { + // this.token = ok.data + // localStorage.setItem('token', ok.data) + // return this.profile() + // }) + // }, + // async dingCallback(code: string) { + // return UserApi.getDingCallback(code).then((ok) => { + // this.token = ok.data + // localStorage.setItem('token', ok.data) + // return this.profile() + // }) + // }, + // async dingOauth2Callback(code: string) { + // return UserApi.getDingOauth2Callback(code).then((ok) => { + // this.token = ok.data + // localStorage.setItem('token', ok.data) + // return this.profile() + // }) + // }, + // async wecomCallback(code: string) { + // return UserApi.getWecomCallback(code).then((ok) => { + // this.token = ok.data + // localStorage.setItem('token', ok.data) + // return this.profile() + // }) + // }, + // async larkCallback(code: string) { + // return UserApi.getlarkCallback(code).then((ok) => { + // this.token = ok.data + // localStorage.setItem('token', ok.data) + // return this.profile() + // }) + // }, + + // async logout() { + // return UserApi.logout().then(() => { + // localStorage.removeItem('token') + // return true + // }) + // }, + // async getAuthType() { + // return UserApi.getAuthType().then((ok) => { + // return ok.data + // }) + // }, + // async getQrType() { + // return UserApi.getQrType().then((ok) => { + // return ok.data + // }) + // }, + // async getQrSource() { + // return UserApi.getQrSource().then((ok) => { + // return ok.data + // }) + // }, + // async postUserLanguage(lang: string, loading?: Ref) { + // return new Promise((resolve, reject) => { + // UserApi.postLanguage({ language: lang }, loading) + // .then(async (ok) => { + // useLocalStorage(localeConfigKey, 'en-US').value = lang + // window.location.reload() + // resolve(ok) + // }) + // .catch((error) => { + // reject(error) + // }) + // }) + // } + } +}) + +export default useLoginStore diff --git a/ui/src/styles/app.scss b/ui/src/styles/app.scss new file mode 100644 index 000000000..9d1e80bb5 --- /dev/null +++ b/ui/src/styles/app.scss @@ -0,0 +1,374 @@ +@font-face { + font-family: AlibabaPuHuiTi; + src: + url('./font/AlibabaPuHuiTi-3-55-Regular.woff') format('woff'), + url('./font/AlibabaPuHuiTi-3-55-Regular.ttf') format('truetype'), + url('./font/AlibabaPuHuiTi-3-55-Regular.eot') format('eot'), + url('./font/AlibabaPuHuiTi-3-55-Regular.otf') format('opentype'), + url('./font/AlibabaPuHuiTi-3-55-Regular.woff2') format('woff2'); +} +* { + margin: 0; + padding: 0; +} + +html { + height: 100%; + box-sizing: border-box; + font-size: 100%; +} + +body { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + font-family: 'PingFang SC', AlibabaPuHuiTi !important; + font-size: 14px; + font-style: normal; + font-weight: 500; + height: 100%; + margin: 0; + padding: 0; + color: var(--app-text-color); +} + +#app { + height: 100%; +} + +:focus { + outline: none; +} + +a:active { + outline: none; +} + +a, +a:focus, +a:hover { + cursor: pointer; + color: inherit; + text-decoration: none; +} + +div:focus { + outline: none; +} + +ul { + list-style: none; + margin: 0; + padding: 0; +} + +/* 滚动条整体部分 */ +::-webkit-scrollbar { + width: 6px; // 纵向滚动条宽度 + height: 6px; // 横向滚动条高度 +} + +/* 滑块 */ +::-webkit-scrollbar-thumb { + border-radius: 5px; +} + +/* 轨道 */ +::-webkit-scrollbar-track { + border-radius: 5px; + background-color: transparent; +} + +.clearfix:after { + content: ''; + display: block; + clear: both; +} + +h1 { + font-size: 24px; +} + +h2 { + font-size: 20px; + font-weight: 500; +} + +h3 { + font-size: 18px; +} + +h4 { + font-size: 16px; +} + +h5 { + font-size: 14px; + font-weight: 500; +} + +.bold { + font-weight: 600; +} +.lighter { + font-weight: 400; +} + +.w-full { + width: 100%; +} +.h-full { + height: 100%; +} +.w-120 { + width: 120px; +} +.w-240 { + width: 240px; +} +.w-280 { + width: 280px; +} +.w-500 { + width: 500px; +} +.max-w-200 { + max-width: 200px; +} +.max-w-350 { + max-width: 350px; +} + +.mt-4 { + margin-top: calc(var(--app-base-px) - 4px); +} + +.mt-8 { + margin-top: var(--app-base-px); +} +.mt-12 { + margin-top: calc(var(--app-base-px) + 4px); +} +.mt-16 { + margin-top: calc(var(--app-base-px) * 2); +} +.mt-20 { + margin-top: calc(var(--app-base-px) * 2 + 4px); +} +.mt-24 { + margin-top: calc(var(--app-base-px) * 3); +} + +.mb-4 { + margin-bottom: calc(var(--app-base-px) - 4px); +} +.mb-8 { + margin-bottom: var(--app-base-px); +} +.mb-12 { + margin-bottom: calc(var(--app-base-px) + 4px); +} +.mb-16 { + margin-bottom: calc(var(--app-base-px) * 2); +} +.mb-24 { + margin-bottom: calc(var(--app-base-px) * 3); +} +.ml-4 { + margin-left: calc(var(--app-base-px) - 4px); +} +.ml-8 { + margin-left: var(--app-base-px); +} +.ml-12 { + margin-left: calc(var(--app-base-px) + 4px); +} +.ml-16 { + margin-left: calc(var(--app-base-px) * 2); +} +.ml-24 { + margin-left: calc(var(--app-base-px) * 3); +} +.mr-4 { + margin-right: calc(var(--app-base-px) - 4px); +} +.mr-8 { + margin-right: var(--app-base-px); +} +.mr-12 { + margin-right: calc(var(--app-base-px) + 4px); +} +.mr-16 { + margin-right: calc(var(--app-base-px) * 2); +} +.mr-24 { + margin-right: calc(var(--app-base-px) * 3); +} +.p-8 { + padding: var(--app-base-px); +} +.p-16 { + padding: calc(var(--app-base-px) * 2); +} +.p-24 { + padding: calc(var(--app-base-px) * 3); +} +.p-8-12 { + padding: calc(var(--app-base-px)) calc(var(--app-base-px) + 4px); +} +.p-12-16 { + padding: calc(var(--app-base-px) + 4px) calc(var(--app-base-px) * 2); +} +.p-12-24 { + padding: calc(var(--app-base-px) + 4px) calc(var(--app-base-px) * 3); +} +.p-16-24 { + padding: calc(var(--app-base-px) * 2) calc(var(--app-base-px) * 3); +} + +.pt-0 { + padding-top: 0; +} +.pb-0 { + padding-bottom: 0; +} + +.float-right { + float: right; +} + +.flex { + display: flex; +} + +.flex-center { + display: flex; + align-items: center; + justify-content: center; +} + +.flex-between { + display: flex; + justify-content: space-between; + align-items: center; +} + +.flex-wrap { + display: flex; + flex-wrap: wrap; + align-content: space-between; +} + +.align-center { + align-items: center; +} + +.align-baseline { + align-items: baseline; +} + +.justify-center { + justify-content: center; +} + +.text-left { + text-align: left; +} +.text-center { + text-align: center; +} +.text-right { + text-align: right; +} + +.vertical-middle { + vertical-align: middle; +} + +.line-height-22 { + line-height: 22px; +} + +.border { + border: 1px solid var(--el-border-color); +} + +.border-l { + border-left: 1px solid var(--el-border-color); +} + +.border-b { + border-bottom: 1px solid var(--el-border-color); +} +.border-r { + border-right: 1px solid var(--el-border-color); +} +.border-t { + border-top: 1px solid var(--el-border-color); +} + +.border-b-light { + border-bottom: 1px solid var(--el-border-color-lighter); +} +.border-r-4 { + border-radius: 4px; +} +.border-r-8 { + border-radius: 8px; +} + +.border-t-dashed { + border-top: 1px dashed var(--el-border-color); +} +.border-primary { + border: 1px solid var(--el-color-primary); + color: var(--el-color-primary); +} + +.border-none { + border: none; +} + +.cursor { + cursor: pointer; +} +.notAllowed { + cursor: not-allowed; +} + +/* + 超出省略号 +*/ + +.ellipsis { + display: inline-block; + max-width: 130px; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; +} + +/* + 双行超出省略号,其他行数自定义 -webkit-line-clamp +*/ +.ellipsis-2 { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + overflow: hidden; +} + +.ellipsis-1 { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 1; + overflow: hidden; +} + +.break-all { + word-break: break-all; +} + +.pre-wrap { + white-space: pre-wrap; +} + diff --git a/ui/src/styles/element-plus.scss b/ui/src/styles/element-plus.scss new file mode 100644 index 000000000..e6e06542d --- /dev/null +++ b/ui/src/styles/element-plus.scss @@ -0,0 +1,11 @@ +:root { + --el-color-primary: #3370ff; + // --el-menu-item-height: 45px; + // --el-box-shadow-light: 0px 2px 4px 0px rgba(31, 35, 41, 0.12); + // --el-border-color: #dee0e3; + // --el-text-color-regular: #1f2329; + // --el-color-info: #8f959e !important; + // --el-disabled-bg-color: #eff0f1 !important; + // --el-text-color-primary: #1f2329; + // --el-font-line-height-primary: 22px; +} diff --git a/ui/src/styles/font/AlibabaPuHuiTi-3-55-Regular.eot b/ui/src/styles/font/AlibabaPuHuiTi-3-55-Regular.eot new file mode 100644 index 000000000..82f27fd78 Binary files /dev/null and b/ui/src/styles/font/AlibabaPuHuiTi-3-55-Regular.eot differ diff --git a/ui/src/styles/font/AlibabaPuHuiTi-3-55-Regular.otf b/ui/src/styles/font/AlibabaPuHuiTi-3-55-Regular.otf new file mode 100644 index 000000000..541e3c108 Binary files /dev/null and b/ui/src/styles/font/AlibabaPuHuiTi-3-55-Regular.otf differ diff --git a/ui/src/styles/font/AlibabaPuHuiTi-3-55-Regular.ttf b/ui/src/styles/font/AlibabaPuHuiTi-3-55-Regular.ttf new file mode 100644 index 000000000..a6eaf3613 Binary files /dev/null and b/ui/src/styles/font/AlibabaPuHuiTi-3-55-Regular.ttf differ diff --git a/ui/src/styles/font/AlibabaPuHuiTi-3-55-Regular.woff b/ui/src/styles/font/AlibabaPuHuiTi-3-55-Regular.woff new file mode 100644 index 000000000..f57637654 Binary files /dev/null and b/ui/src/styles/font/AlibabaPuHuiTi-3-55-Regular.woff differ diff --git a/ui/src/styles/font/AlibabaPuHuiTi-3-55-Regular.woff2 b/ui/src/styles/font/AlibabaPuHuiTi-3-55-Regular.woff2 new file mode 100644 index 000000000..4b574fbd8 Binary files /dev/null and b/ui/src/styles/font/AlibabaPuHuiTi-3-55-Regular.woff2 differ diff --git a/ui/src/styles/index.scss b/ui/src/styles/index.scss new file mode 100644 index 000000000..43afaf395 --- /dev/null +++ b/ui/src/styles/index.scss @@ -0,0 +1,4 @@ +@use 'element-plus/dist/index.css'; +@use './element-plus.scss'; +@use './variables.scss'; +@use './app.scss'; diff --git a/ui/src/styles/variables.scss b/ui/src/styles/variables.scss new file mode 100644 index 000000000..f2c2a0ade --- /dev/null +++ b/ui/src/styles/variables.scss @@ -0,0 +1,53 @@ +:root { + --app-base-px: 8px; + --app-layout-bg-color: #f5f6f7; + --app-text-color: #1f2329; + --app-text-color-light-1: rgba(31, 35, 41, 0.1); + --app-text-color-secondary: #646a73; + --app-text-color-disable: #bbbfc4; + --app-input-color-placeholder: #8f959e; + --app-view-padding: 24px; + --app-view-bg-color: #ffffff; + --app-border-color-dark: #bbbfc4; + --md-bk-hover-color:var(--el-border-color-hover); + /** header 组件 */ + --app-header-height: 56px; + --app-header-padding: 0 20px; + --app-header-bg-color: linear-gradient(90deg, #ebf1ff 24.34%, #e5fbf8 56.18%, #f2ebfe 90.18%); + --app-logo-color: linear-gradient(180deg, #3370FF 0%, #7f3bf5 100%); + --app-avatar-gradient-color: linear-gradient(270deg, #9258f7 0%, #3370FF 100%); + + /* 计算高度 */ + --app-main-height: calc(100vh - var(--app-header-height) - var(--app-view-padding) * 2 - 40px); + + /** sidebar 组件 */ + --sidebar-bg-color: #ffffff; + --sidebar-width: 240px; + /** tag */ + --tag-default-bg: rgba(51, 112, 255, 0.2); + --tag-default-color: #2b5fd9; + --tag-success-bg: rgba(52, 199, 36, 0.2); + --tag-success-color: #2ca91f; + --tag-warning-bg: rgba(255, 136, 0, 0.2); + --tag-warning-color: #d97400; + --tag-danger-bg: rgba(245, 74, 69, 0.2); + + /** card */ + --card-width: 330px; + --card-min-height: 166px; + --card-min-width: 220px; + + /** setting */ + --setting-left-width: 280px; + + /** dataset */ + --create-dataset-height: calc(var(--app-main-height) - 70px); + + /** ai-chat */ + --dialog-bg-gradient-color: linear-gradient( + 188deg, + rgba(235, 241, 255, 0.2) 39.6%, + rgba(231, 249, 255, 0.2) 94.3% + ), + #eff0f1; +} diff --git a/ui/src/utils/theme.ts b/ui/src/utils/theme.ts new file mode 100644 index 000000000..067bf3a4a --- /dev/null +++ b/ui/src/utils/theme.ts @@ -0,0 +1,65 @@ +import { t } from '@/locales' + +export const themeList = [ + { + label: t('views.system.theme.default'), + value: '#3370FF', + loginBackground: 'default', + }, + { + label: t('views.system.theme.orange'), + value: '#FF8800', + loginBackground: 'orange', + }, + { + label: t('views.system.theme.green'), + value: '#00B69D', + loginBackground: 'green', + }, + { + label: t('views.system.theme.purple'), + value: '#7F3BF5', + loginBackground: 'purple', + }, + { + label: t('views.system.theme.red'), + value: '#F01D94', + loginBackground: 'red', + }, +] + +export function getThemeImg(val: string) { + if (!val) return 'default' + return themeList.filter((v) => v.value === val)?.[0]?.loginBackground || 'default' +} + +export const defaultSetting = { + icon: '', + loginLogo: '', + loginImage: '', + title: 'MaxKB', + slogan: t('views.system.theme.defaultSlogan'), +} + +export const defaultPlatformSetting = { + showUserManual: true, + userManualUrl: t('layout.userManualUrl'), + showForum: true, + forumUrl: t('layout.forumUrl'), + showProject: true, + projectUrl: 'https://github.com/1Panel-dev/MaxKB', +} + +export function hexToRgba(hex?: string, alpha?: number) { + // 将16进制颜色值的两个字符一起转换成十进制 + if (!hex) { + return '' + } else { + const r = parseInt(hex.slice(1, 3), 16) + const g = parseInt(hex.slice(3, 5), 16) + const b = parseInt(hex.slice(5, 7), 16) + + // 返回RGBA格式的字符串 + return `rgba(${r}, ${g}, ${b}, ${alpha})` + } +} diff --git a/ui/src/views/AboutView.vue b/ui/src/views/AboutView.vue deleted file mode 100644 index 756ad2a17..000000000 --- a/ui/src/views/AboutView.vue +++ /dev/null @@ -1,15 +0,0 @@ - - - diff --git a/ui/src/views/HomeView.vue b/ui/src/views/HomeView.vue index d5c0217e4..197bae0e3 100644 --- a/ui/src/views/HomeView.vue +++ b/ui/src/views/HomeView.vue @@ -1,9 +1,3 @@ - + - + diff --git a/ui/src/views/login/ForgetPassword.vue b/ui/src/views/login/ForgetPassword.vue new file mode 100644 index 000000000..2c2ff0257 --- /dev/null +++ b/ui/src/views/login/ForgetPassword.vue @@ -0,0 +1,135 @@ + + + diff --git a/ui/src/views/login/ResetPassword.vue b/ui/src/views/login/ResetPassword.vue new file mode 100644 index 000000000..2c2ff0257 --- /dev/null +++ b/ui/src/views/login/ResetPassword.vue @@ -0,0 +1,135 @@ + + + diff --git a/ui/src/views/login/components/LoginContainer.vue b/ui/src/views/login/components/LoginContainer.vue new file mode 100644 index 000000000..0415bdc96 --- /dev/null +++ b/ui/src/views/login/components/LoginContainer.vue @@ -0,0 +1,37 @@ + + + diff --git a/ui/src/views/login/components/LoginLayout.vue b/ui/src/views/login/components/LoginLayout.vue new file mode 100644 index 000000000..e176cc943 --- /dev/null +++ b/ui/src/views/login/components/LoginLayout.vue @@ -0,0 +1,108 @@ + + + diff --git a/ui/src/views/login/index.vue b/ui/src/views/login/index.vue new file mode 100644 index 000000000..875bd4288 --- /dev/null +++ b/ui/src/views/login/index.vue @@ -0,0 +1,128 @@ + + + diff --git a/ui/vite.config.ts b/ui/vite.config.ts index d49d70842..00e2415ab 100644 --- a/ui/vite.config.ts +++ b/ui/vite.config.ts @@ -1,20 +1,52 @@ import { fileURLToPath, URL } from 'node:url' - -import { defineConfig } from 'vite' +import type { ProxyOptions } from 'vite' +import { defineConfig, loadEnv } from 'vite' import vue from '@vitejs/plugin-vue' import vueJsx from '@vitejs/plugin-vue-jsx' -import vueDevTools from 'vite-plugin-vue-devtools' +import DefineOptions from 'unplugin-vue-define-options/vite' +// import vueDevTools from 'vite-plugin-vue-devtools' +const envDir = './env' // https://vite.dev/config/ -export default defineConfig({ - plugins: [ - vue(), - vueJsx(), - vueDevTools(), - ], - resolve: { - alias: { - '@': fileURLToPath(new URL('./src', import.meta.url)) +export default defineConfig(({ mode }) => { + const ENV = loadEnv(mode, envDir) + const prefix = process.env.VITE_DYNAMIC_PREFIX || ENV.VITE_BASE_PATH + const proxyConf: Record = {} + proxyConf['/api'] = { + target: 'http://127.0.0.1:8080', + changeOrigin: true, + rewrite: (path) => path.replace(ENV.VITE_BASE_PATH, '/'), + } + proxyConf['/doc'] = { + target: 'http://127.0.0.1:8080', + changeOrigin: true, + rewrite: (path) => path.replace(ENV.VITE_BASE_PATH, '/'), + } + proxyConf['/static'] = { + target: 'http://127.0.0.1:8080', + changeOrigin: true, + rewrite: (path) => path.replace(ENV.VITE_BASE_PATH, '/'), + } + return { + preflight: false, + lintOnSave: false, + base: prefix, + envDir: envDir, + plugins: [vue(), vueJsx(), DefineOptions()], + server: { + cors: true, + host: '0.0.0.0', + port: Number(ENV.VITE_APP_PORT), + strictPort: true, + proxy: proxyConf, }, - }, + build: { + outDir: 'dist/ui', + }, + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)), + }, + }, + } })