feat(i18n): add internationalization support with i18next
- Add i18next and related dependencies for internationalization - Implement language switcher component with English and Chinese support - Create translation files for English and Chinese locales - Update login and home pages to use translations - Configure i18n initialization with language detection - Add dayjs locale synchronization with i18n language changes - Update tsconfig and eslint to ignore new locales directory - Remove unused App.css and simplify index.css - Update npmrc with mirror configuration
This commit is contained in:
42
src/App.css
42
src/App.css
@@ -1,42 +0,0 @@
|
||||
#root {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 6em;
|
||||
padding: 1.5em;
|
||||
will-change: filter;
|
||||
transition: filter 300ms;
|
||||
}
|
||||
.logo:hover {
|
||||
filter: drop-shadow(0 0 2em #646cffaa);
|
||||
}
|
||||
.logo.react:hover {
|
||||
filter: drop-shadow(0 0 2em #61dafbaa);
|
||||
}
|
||||
|
||||
@keyframes logo-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
a:nth-of-type(2) .logo {
|
||||
animation: logo-spin infinite 20s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 2em;
|
||||
}
|
||||
|
||||
.read-the-docs {
|
||||
color: #888;
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import { BrowserRouter } from 'react-router-dom';
|
||||
import { CssBaseline, ThemeProvider } from '@mui/material';
|
||||
import { theme } from './theme';
|
||||
import AppRoutes from './routes';
|
||||
import './locales';
|
||||
|
||||
function App() {
|
||||
return (
|
||||
|
||||
66
src/components/LanguageSwitcher.tsx
Normal file
66
src/components/LanguageSwitcher.tsx
Normal file
@@ -0,0 +1,66 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Menu, MenuItem } from '@mui/material';
|
||||
import { LanguageAbbreviation } from '../locales';
|
||||
|
||||
interface LanguageSwitcherProps {
|
||||
textColor?: string;
|
||||
}
|
||||
|
||||
const LanguageSwitcher: React.FC<LanguageSwitcherProps> = ({ textColor = '#fff' }) => {
|
||||
const { t, i18n } = useTranslation();
|
||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||
const open = Boolean(anchorEl);
|
||||
|
||||
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const handleLanguageChange = (language: "en" | "zh") => {
|
||||
i18n.changeLanguage(language);
|
||||
handleClose();
|
||||
};
|
||||
|
||||
const getCurrentLanguageLabel = () => {
|
||||
return i18n.language === LanguageAbbreviation.Zh ? '中文' : 'English';
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Button
|
||||
onClick={handleClick}
|
||||
variant="outlined"
|
||||
sx={{
|
||||
color: textColor,
|
||||
borderColor: '#fff',
|
||||
}}
|
||||
>
|
||||
{getCurrentLanguageLabel()}
|
||||
</Button>
|
||||
<Menu
|
||||
anchorEl={anchorEl}
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<MenuItem
|
||||
onClick={() => handleLanguageChange(LanguageAbbreviation.Zh)}
|
||||
selected={i18n.language === LanguageAbbreviation.Zh}
|
||||
>
|
||||
中文
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onClick={() => handleLanguageChange(LanguageAbbreviation.En)}
|
||||
selected={i18n.language === LanguageAbbreviation.En}
|
||||
>
|
||||
English
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LanguageSwitcher;
|
||||
@@ -1,68 +1,15 @@
|
||||
:root {
|
||||
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
|
||||
color-scheme: light dark;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background-color: #242424;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
color: #646cff;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
a:hover {
|
||||
color: #535bf2;
|
||||
html, body, #root {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
place-items: center;
|
||||
min-width: 320px;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3.2em;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.6em 1.2em;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
background-color: #1a1a1a;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.25s;
|
||||
}
|
||||
button:hover {
|
||||
border-color: #646cff;
|
||||
}
|
||||
button:focus,
|
||||
button:focus-visible {
|
||||
outline: 4px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
color: #213547;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
a:hover {
|
||||
color: #747bff;
|
||||
}
|
||||
button {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
a {
|
||||
text-decoration: inherit;
|
||||
}
|
||||
|
||||
426
src/locales/en.ts
Normal file
426
src/locales/en.ts
Normal file
@@ -0,0 +1,426 @@
|
||||
export default {
|
||||
translation: {
|
||||
common: {
|
||||
noResults: 'No results.',
|
||||
selectPlaceholder: 'Please select',
|
||||
selectAll: 'Select all',
|
||||
delete: 'Delete',
|
||||
deleteModalTitle: 'Are you sure to delete?',
|
||||
ok: 'Yes',
|
||||
cancel: 'No',
|
||||
total: 'Total',
|
||||
rename: 'Rename',
|
||||
name: 'Name',
|
||||
save: 'Save',
|
||||
namePlaceholder: 'Please input name',
|
||||
next: 'Next',
|
||||
create: 'Create',
|
||||
edit: 'Edit',
|
||||
upload: 'Upload',
|
||||
english: 'English',
|
||||
portugueseBr: 'Portuguese (Brazil)',
|
||||
chinese: 'Simplified Chinese',
|
||||
traditionalChinese: 'Traditional Chinese',
|
||||
language: 'Language',
|
||||
languageMessage: 'Please input language',
|
||||
languagePlaceholder: 'Please select language',
|
||||
copy: 'Copy',
|
||||
copied: 'Copied successfully',
|
||||
comingSoon: 'Coming soon',
|
||||
download: 'Download',
|
||||
close: 'Close',
|
||||
preview: 'Preview',
|
||||
move: 'Move',
|
||||
warn: 'Warn',
|
||||
action: 'Action',
|
||||
s: 's',
|
||||
pleaseSelect: 'Please select',
|
||||
pleaseInput: 'Please input',
|
||||
submit: 'Submit',
|
||||
clear: 'Clear',
|
||||
embedIntoSite: 'Embed into site',
|
||||
previousPage: 'Previous page',
|
||||
nextPage: 'Next page',
|
||||
add: 'Add',
|
||||
remove: 'Remove',
|
||||
search: 'Search',
|
||||
noDataFound: 'No data found.',
|
||||
noData: 'No data',
|
||||
promptPlaceholder: 'Please input or use / to quickly insert variables.',
|
||||
},
|
||||
login: {
|
||||
login: 'Login',
|
||||
signUp: 'Sign Up',
|
||||
loginDescription: 'Nice to see you again!',
|
||||
registerDescription: 'Nice to have you join!',
|
||||
emailLabel: 'Email',
|
||||
emailPlaceholder: 'Please enter email address',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Please enter password',
|
||||
rememberMe: 'Remember me',
|
||||
signInTip: "Don't have an account?",
|
||||
signUpTip: 'Already have an account?',
|
||||
nicknameLabel: 'Name',
|
||||
nicknamePlaceholder: 'Please enter name',
|
||||
register: 'Create account',
|
||||
continue: 'Continue',
|
||||
title: 'Start building your intelligent assistant',
|
||||
description:
|
||||
'Sign up for free to explore top-tier RAG technology. Create knowledge bases and AI to enhance your business',
|
||||
review: 'From 500+ reviews',
|
||||
},
|
||||
header: {
|
||||
knowledgeBase: 'Knowledge Base',
|
||||
chat: 'Chat',
|
||||
register: 'Register',
|
||||
signin: 'Sign In',
|
||||
home: 'Home',
|
||||
setting: 'User Settings',
|
||||
logout: 'Logout',
|
||||
fileManager: 'File Manager',
|
||||
flow: 'Agent',
|
||||
search: 'Search',
|
||||
welcome: 'Welcome to',
|
||||
dataset: 'Dataset',
|
||||
},
|
||||
knowledgeList: {
|
||||
welcome: 'Welcome back',
|
||||
description: 'Which knowledge base are we going to use today?',
|
||||
createKnowledgeBase: 'Create knowledge base',
|
||||
name: 'Name',
|
||||
namePlaceholder: 'Please input name',
|
||||
doc: 'Doc',
|
||||
searchKnowledgePlaceholder: 'Search',
|
||||
noMoreData: 'No more data',
|
||||
},
|
||||
knowledgeDetails: {
|
||||
fileSize: 'File size',
|
||||
fileType: 'File type',
|
||||
uploadedBy: 'Created by',
|
||||
notGenerated: 'Not generated',
|
||||
generatedOn: 'Generated on',
|
||||
subbarFiles: 'Files',
|
||||
generate: 'Generate',
|
||||
raptor: 'Raptor',
|
||||
processingType: 'Processing type',
|
||||
dataPipeline: 'Data pipeline',
|
||||
operations: 'Operations',
|
||||
taskId: 'Task ID',
|
||||
duration: 'Duration',
|
||||
details: 'Details',
|
||||
status: 'Status',
|
||||
task: 'Task',
|
||||
startDate: 'Start date',
|
||||
source: 'Source',
|
||||
fileName: 'File name',
|
||||
datasetLogs: 'Dataset logs',
|
||||
fileLogs: 'File logs',
|
||||
overview: 'Overview',
|
||||
success: 'Success',
|
||||
failed: 'Failed',
|
||||
completed: 'Completed',
|
||||
datasetLog: 'Dataset log',
|
||||
created: 'Created',
|
||||
learnMore: 'Learn more',
|
||||
general: 'General',
|
||||
chunkMethodTab: 'Chunk method',
|
||||
testResults: 'Test results',
|
||||
testSetting: 'Test setting',
|
||||
retrievalTesting: 'Retrieval testing',
|
||||
retrievalTestingDescription:
|
||||
'Conduct retrieval testing to check if RAGFlow can retrieve the expected content for the large language model (LLM).',
|
||||
Parse: 'Parse',
|
||||
dataset: 'Dataset',
|
||||
testing: 'Testing',
|
||||
configuration: 'Configuration',
|
||||
knowledgeGraph: 'Knowledge graph',
|
||||
files: 'files',
|
||||
name: 'Name',
|
||||
namePlaceholder: 'Please input name',
|
||||
doc: 'Doc',
|
||||
datasetDescription: 'You can only chat after parsing is successful.',
|
||||
addFile: 'Add file',
|
||||
searchFiles: 'Search files',
|
||||
localFiles: 'Local files',
|
||||
emptyFiles: 'Create empty file',
|
||||
webCrawl: 'Web crawl',
|
||||
chunkNumber: 'Chunk number',
|
||||
uploadDate: 'Upload date',
|
||||
chunkMethod: 'Chunk method',
|
||||
enabled: 'Enabled',
|
||||
disabled: 'Disabled',
|
||||
action: 'Action',
|
||||
parsingStatus: 'Parsing status',
|
||||
parsingStatusTip:
|
||||
'The time for text parsing depends on many factors. If knowledge graph, RAPTOR, automatic question extraction, automatic keyword extraction and other functions are enabled, the time will be longer. If the parsing progress bar does not update for a long time, you can also refer to these two FAQs: https://ragflow.io/docs/dev/faq#why-does-my-document-parsing-stall-at-under-one-percent.',
|
||||
processBeginAt: 'Begin at',
|
||||
processDuration: 'Duration',
|
||||
progressMsg: 'Progress',
|
||||
noTestResultsForRuned: 'No relevant results found, please try adjusting the query statement or parameters',
|
||||
noTestResultsForNotRuned: 'No test has been run yet, results will be displayed here',
|
||||
testingDescription:
|
||||
'Please complete the recall test: ensure that your configuration can recall the correct text blocks from the database. If you adjust the default settings here, such as keyword similarity weight, please note that the changes here will not be automatically saved. Please be sure to synchronize and update related settings in the chat assistant settings or recall operator settings.',
|
||||
similarityThreshold: 'Similarity threshold',
|
||||
similarityThresholdTip:
|
||||
'We use a hybrid similarity score to evaluate the distance between two lines of text. It is a weighted keyword similarity and vector cosine similarity. If the similarity between the query and the chunk is less than this threshold, the chunk will be filtered out. The default setting is 0.2, which means that the hybrid similarity score of the text chunk must be at least 20 to be recalled.',
|
||||
vectorSimilarityWeight: 'Vector similarity weight',
|
||||
vectorSimilarityWeightTip:
|
||||
'We use a hybrid similarity score to evaluate the distance between two lines of text. It is a weighted keyword similarity and vector cosine similarity or rerank score (0~1). The sum of the two weights is 1.0.',
|
||||
keywordSimilarityWeight: 'Keyword similarity weight',
|
||||
keywordSimilarityWeightTip:
|
||||
'We use a hybrid similarity score to evaluate the distance between two lines of text. It is a weighted keyword similarity and vector cosine similarity or rerank score (0~1). The sum of the two weights is 1.0.',
|
||||
testText: 'Test text',
|
||||
testTextPlaceholder: 'Please input your question!',
|
||||
testingLabel: 'Testing',
|
||||
similarity: 'Hybrid similarity',
|
||||
termSimilarity: 'Term similarity',
|
||||
vectorSimilarity: 'Vector similarity',
|
||||
hits: 'Hits',
|
||||
view: 'View',
|
||||
filesSelected: 'Files selected',
|
||||
upload: 'Upload',
|
||||
run: 'Parse',
|
||||
runningStatus0: 'Unparsed',
|
||||
runningStatus1: 'Parsing',
|
||||
runningStatus2: 'Cancel',
|
||||
runningStatus3: 'Success',
|
||||
runningStatus4: 'Failed',
|
||||
pageRanges: 'Page ranges',
|
||||
pageRangesTip:
|
||||
'Page ranges: Define the page ranges that need to be parsed. Pages not included in these ranges will be ignored.',
|
||||
fromPlaceholder: 'From',
|
||||
fromMessage: 'Missing start page number',
|
||||
toPlaceholder: 'To',
|
||||
toMessage: 'Missing end page number (exclusive)',
|
||||
layoutRecognize: 'PDF parser',
|
||||
layoutRecognizeTip:
|
||||
'Use visual models for PDF layout analysis to better identify document structure, find the location of titles, text blocks, images and tables. If you choose the Naive option, you can only get the plain text of the PDF. Please note that this function only applies to PDF documents and does not work for other documents. For more information, please refer to https://ragflow.io/docs/dev/select_pdf_parser.',
|
||||
taskPageSize: 'Task page size',
|
||||
taskPageSizeMessage: 'Please input your task page size!',
|
||||
taskPageSizeTip: `If layout recognition is used, PDF files will be divided into consecutive groups. Layout analysis will be performed in parallel between groups to improve processing speed. "Task page size" determines the size of the group. The larger the page size, the lower the chance of splitting continuous text between pages into different chunks.`,
|
||||
addPage: 'Add page',
|
||||
greaterThan: 'The current value must be greater than the starting value!',
|
||||
greaterThanPrevious: 'The current value must be greater than the previous value!',
|
||||
selectFiles: 'Select files',
|
||||
changeSpecificCategory: 'Change specific category',
|
||||
uploadTitle: 'Click or drag files to this area to upload',
|
||||
uploadDescription:
|
||||
'Support single or batch upload. For local deployment, the total file size limit for a single upload is 1GB, the number of files for a single batch upload does not exceed 32, and there is no limit on the number of files for a single account. For demo.ragflow.io: the total file size limit for each upload is 10MB, each file must not exceed 10MB, and each account can upload up to 128 files. It is strictly prohibited to upload prohibited files.',
|
||||
chunk: 'Chunk',
|
||||
bulk: 'Bulk',
|
||||
cancel: 'Cancel',
|
||||
close: 'Close',
|
||||
rerankModel: 'Rerank model',
|
||||
rerankPlaceholder: 'Please select',
|
||||
rerankTip: `Optional: If no rerank model is selected, the system will default to a hybrid query method that combines keyword similarity and vector cosine similarity; if a rerank model is set, the vector similarity part in the hybrid query will be replaced by rerank scoring. Please note: using a rerank model will be very time-consuming. If you need to use a rerank model, it is recommended to use a SaaS rerank model service; if you prefer to use a locally deployed rerank model, please make sure you start RAGFlow using docker-compose-gpu.yml.`,
|
||||
topK: 'Top-K',
|
||||
topKTip: `Used in conjunction with the Rerank model to set the number of text blocks passed to the Rerank model.`,
|
||||
delimiter: `Text segmentation delimiter`,
|
||||
delimiterTip:
|
||||
'Support multiple characters as delimiters, multiple characters are wrapped with two backticks \\`\\`. If configured as: \\n`##`; the system will first use line breaks, two # signs and semicolons to split the text, and then assemble the small text blocks according to the size set by "Suggested text block size". Please make sure you understand the above text segmentation and chunking mechanism before setting text segmentation delimiters.',
|
||||
html4excel: 'Table to HTML',
|
||||
html4excelTip: `Used in conjunction with the General chunking method. When not enabled, table files (XLSX, XLS (Excel 97-2003)) will be parsed as key-value pairs by row. When enabled, table files will be parsed as HTML tables. If the original table exceeds 12 rows, the system will automatically split it into multiple HTML tables with 12 rows each. For more details, please refer to https://ragflow.io/docs/dev/enable_excel2html.`,
|
||||
autoKeywords: 'Auto keyword extraction',
|
||||
autoKeywordsTip: `Automatically extract N keywords from each text block to improve query accuracy. Please note: This function uses the default chat model set in "System Model Settings" to extract keywords, so it will also consume more tokens. In addition, you can also manually update the generated keywords. For details, please see https://ragflow.io/docs/dev/autokeyword_autoquestion.`,
|
||||
autoQuestions: 'Auto question extraction',
|
||||
autoQuestionsTip: `Use the chat model set in "System Model Settings" to extract N questions from each text block in the knowledge base to improve its ranking score. Please note that enabling it will consume additional tokens. You can view and edit the results in the chunk list. If automatic question extraction fails, it will not hinder the entire chunking process, and only empty results will be added to the original text block. For details, please see https://ragflow.io/docs/dev/autokeyword_autoquestion.`,
|
||||
redo: 'Clear existing {{chunkNum}} chunks?',
|
||||
setMetaData: 'Set metadata',
|
||||
pleaseInputJson: 'Please input JSON',
|
||||
documentMetaTips: `<p>Metadata is in JSON format (not searchable). If any chunk of this document is included in the prompt, it will be added to the LLM's prompt.</p>
|
||||
<p>Example:</p>
|
||||
<b>Metadata is:</b><br>
|
||||
<code>
|
||||
{
|
||||
"Author": "Alex Dowson",
|
||||
"Date": "2024-11-12"
|
||||
}
|
||||
</code><br>
|
||||
<b>The prompt will be:</b><br>
|
||||
<p>Document: the_name_of_document</p>
|
||||
<p>Author: Alex Dowson</p>
|
||||
<p>Date: 2024-11-12</p>
|
||||
<p>Related segments are as follows:</p>
|
||||
<ul>
|
||||
<li> This is chunk content....</li>
|
||||
<li> This is chunk content....</li>
|
||||
</ul>
|
||||
`,
|
||||
metaData: 'Metadata',
|
||||
deleteDocumentConfirmContent:
|
||||
'This document is associated with a knowledge graph. After deletion, related node and relationship information will be deleted, but the graph will not be updated immediately. The update graph action is performed during the process of parsing new documents that carry knowledge graph extraction tasks.',
|
||||
plainText: 'Naive',
|
||||
reRankModelWaring: 'Rerank model is very time-consuming.',
|
||||
theDocumentBeingParsedCannotBeDeleted: 'The document being parsed cannot be deleted',
|
||||
},
|
||||
knowledgeConfiguration: {
|
||||
deleteGenerateModalContent: `
|
||||
<p>Deleting the generated <strong class='text-text-primary'>{{type}}</strong> results
|
||||
will remove all derived entities and relationships from this dataset.
|
||||
Your original files will remain unchanged.<p>
|
||||
<br/>
|
||||
Do you want to continue?
|
||||
`,
|
||||
extractRaptor: 'Extract Raptor from documents',
|
||||
extractKnowledgeGraph: 'Extract knowledge graph from documents',
|
||||
filterPlaceholder: 'Please input',
|
||||
fileFilterTip: '',
|
||||
fileFilter: 'Regex matching expression',
|
||||
setDefaultTip: '',
|
||||
setDefault: 'Set default',
|
||||
eidtLinkDataPipeline: 'Edit data pipeline',
|
||||
linkPipelineSetTip: 'Manage data pipeline links with this dataset',
|
||||
default: 'Default',
|
||||
dataPipeline: 'Data pipeline',
|
||||
linkDataPipeline: 'Link data pipeline',
|
||||
enableAutoGenerate: 'Enable auto generate',
|
||||
teamPlaceholder: 'Please select team',
|
||||
dataFlowPlaceholder: 'Please select data flow',
|
||||
buildItFromScratch: 'Build it from scratch',
|
||||
dataFlow: 'Data flow',
|
||||
parseType: 'Chunk method',
|
||||
manualSetup: 'Manual setup',
|
||||
builtIn: 'Built-in',
|
||||
titleDescription: 'Update your knowledge base details here, especially the chunk method.',
|
||||
name: 'Knowledge base name',
|
||||
photo: 'Knowledge base photo',
|
||||
photoTip: 'You can upload files up to 4MB',
|
||||
description: 'Description',
|
||||
language: 'Document language',
|
||||
languageMessage: 'Please input language',
|
||||
languagePlaceholder: 'Please input language',
|
||||
permissions: 'Permissions',
|
||||
embeddingModel: 'Embedding model',
|
||||
chunkTokenNumber: 'Suggested chunk size',
|
||||
chunkTokenNumberMessage: 'Chunk token number is required',
|
||||
embeddingModelTip:
|
||||
'The default embedding model used by the knowledge base. Once text chunks have been generated in the knowledge base, you will not be able to change the default embedding model unless you delete all text chunks in the knowledge base.',
|
||||
permissionsTip:
|
||||
'If the knowledge base permission is set to "Team", all team members can operate the knowledge base.',
|
||||
chunkTokenNumberTip:
|
||||
'The recommended token number threshold for generating text chunks. If the token number of the small text segment obtained by segmentation does not reach this threshold, it will continue to merge with subsequent text segments until merging the next text segment will exceed this threshold, and then a final text chunk will be generated. If the system never encounters a text segmentation delimiter when segmenting text segments, even if the token number of the text segment has exceeded this threshold, the system will not generate new text chunks.',
|
||||
chunkMethod: 'Chunk method',
|
||||
chunkMethodTip: 'The description is on the right.',
|
||||
upload: 'Upload',
|
||||
english: 'English',
|
||||
chinese: 'Chinese',
|
||||
embeddingModelPlaceholder: 'Please select embedding model',
|
||||
chunkMethodPlaceholder: 'Please select chunk method',
|
||||
save: 'Save',
|
||||
me: 'Only me',
|
||||
team: 'Team',
|
||||
cancel: 'Cancel',
|
||||
methodTitle: 'Chunk method description',
|
||||
methodExamples: 'Examples',
|
||||
methodExamplesDescription:
|
||||
'To help you understand better, we provide relevant screenshots for your reference.',
|
||||
dialogueExamplesTitle: 'Dialogue examples',
|
||||
methodEmpty: 'This will show a visual explanation of the knowledge base category',
|
||||
book: `<p>Supported file formats are <b>DOCX</b>, <b>PDF</b>, <b>TXT</b>.</p><p>
|
||||
Since a book is very long, not all parts are useful. If it is a PDF,
|
||||
please set <i>page ranges</i> for each book to eliminate negative effects and save analysis computing time.</p>`,
|
||||
laws: `<p>Supported file formats are <b>DOCX</b>, <b>PDF</b>, <b>TXT</b>.</p><p>
|
||||
Legal documents have very strict writing formats. We use text features to detect split points.
|
||||
</p><p>
|
||||
The granularity of chunks is consistent with 'ARTICLE', and all upper-level text will be included in the chunk.
|
||||
</p>`,
|
||||
manual: `<p>Only <b>PDF</b> is supported.</p><p>
|
||||
We assume that the manual has a hierarchical section structure. We use the lowest section title as the pivot for slicing the document.
|
||||
Therefore, figures and tables in the same section will not be split, and the chunk size may be large.
|
||||
</p>`,
|
||||
naive: `<p>Supported file formats are <b>MD, MDX, DOCX, XLSX, XLS (Excel 97-2003), PPT, PDF, TXT, JPEG, JPG, PNG, TIF, GIF, CSV, JSON, EML, HTML</b>.</p>
|
||||
<p>This method applies a simple approach to chunk files:</p>
|
||||
<p>
|
||||
<li>The system will use a visual detection model to split continuous text into multiple segments.</li>
|
||||
<li>Next, these continuous segments are merged into chunks with no more than "Token number" tokens.</li></p>`,
|
||||
paper: `<p>Only <b>PDF</b> files are supported.</p><p>
|
||||
If our model works well, the paper will be sliced by its sections, such as <i>Abstract, 1.1, 1.2</i>, etc.</p><p>
|
||||
The advantage of this is that the LLM can better summarize the content of relevant sections in the paper,
|
||||
produce more comprehensive answers, and help readers better understand the paper.
|
||||
The disadvantage is that it increases the context of LLM conversations and increases computational costs,
|
||||
so during the conversation, you can consider reducing the '<b>topN</b>' setting.</p>`,
|
||||
presentation: `<p>Supported file formats are <b>PDF</b>, <b>PPTX</b>.</p><p>
|
||||
Each page will be treated as a chunk. And thumbnails of each page will be stored.</p><p>
|
||||
<i>All PPT files you upload will be automatically chunked using this method, without the need to set it for each PPT file.</i></p>`,
|
||||
qa: ` <p>
|
||||
This chunk method supports <b>excel</b> and <b>csv/txt</b> file formats.
|
||||
</p>
|
||||
<li>
|
||||
If the file is in <b>excel</b> format, it should consist of two columns
|
||||
without headers: one for questions and another for answers,
|
||||
with the question column before the answer column. Multiple sheets are
|
||||
acceptable as long as the columns are correctly structured.
|
||||
</li>
|
||||
<li>
|
||||
If the file is in <b>csv/txt</b> format,
|
||||
it should be UTF-8 encoded and use TAB as the delimiter to separate questions and answers.
|
||||
</li>
|
||||
<p>
|
||||
<i>
|
||||
Text lines that fail to follow the above rules will be ignored, and
|
||||
each Q&A pair will be considered a unique chunk.
|
||||
</i>
|
||||
</p>`,
|
||||
resume: `<p>Supported file formats are <b>DOCX</b>, <b>PDF</b>, <b>TXT</b>.
|
||||
</p><p>
|
||||
Resumes come in various formats, just like a person's personality, but we often have to organize them into structured data for easy searching.
|
||||
</p><p>
|
||||
Instead of chunking resumes, we parse resumes into structured data. As an HR, you can throw away all resumes,
|
||||
and you only need to talk to <i>'RAGFlow'</i> to list all qualified candidates.
|
||||
</p>
|
||||
`,
|
||||
table: `<p>Supports <b>XLSX</b> and <b>CSV/TXT</b> format files.</p><p>
|
||||
Here are some tips:
|
||||
<ul>
|
||||
<li>For csv or txt files, the delimiter between columns is <em><b>TAB</b></em>.</li>
|
||||
<li>The first row must be column headers.</li>
|
||||
<li>Column headers must be meaningful terms so that our large language model can understand.
|
||||
When listing some synonyms, it is best to use slashes <i>'/'</i> to separate them, or even better
|
||||
to use square brackets to enumerate values, such as <i>'gender/sex(male,female)'</i>.<p>
|
||||
Here are some examples of headers:<ol>
|
||||
<li>Supplier/Vendor<b>'TAB'</b>Color(Yellow,Red,Brown)<b>'TAB'</b>Gender(Male,Female)<b>'TAB'</b>Size(M,L,XL,XXL)</li>
|
||||
<li>Name/First Name<b>'TAB'</b>Phone/Mobile/WeChat<b>'TAB'</b>Highest Education(High School,Vocational High School,Master,Bachelor,PhD,Junior High School,Technical Secondary School,Technical College,College,Undergraduate,MPA,MBA,EMBA)</li>
|
||||
</ol>
|
||||
</p>
|
||||
</li>
|
||||
<li>Each row in the table will be treated as a chunk.</li>
|
||||
</ul>`,
|
||||
picture: `
|
||||
<p>Supports image files. Video coming soon.</p><p>
|
||||
If there is text in the image, OCR is applied to extract the text as its text description.
|
||||
</p><p>
|
||||
If the text extracted by OCR is not enough, you can use visual LLM to get the description.
|
||||
</p>`,
|
||||
one: `
|
||||
<p>Supported file formats are <b>MD, MDX, DOCX, XLSX, XLS (Excel 97-2003), PPT, PDF, TXT, JPEG, JPG, PNG, TIF, GIF, CSV, JSON, EML, HTML</b>.</p>
|
||||
<p>This method treats the entire document as one chunk.</p>`,
|
||||
email: `<p>Supported file formats are <b>EML</b>.</p><p>
|
||||
Each email will be treated as a chunk.
|
||||
</p>`,
|
||||
knowledgeGraph: `<p>Supported file formats are <b>MD, MDX, DOCX, XLSX, XLS (Excel 97-2003), PPT, PDF, TXT, JPEG, JPG, PNG, TIF, GIF, CSV, JSON, EML, HTML</b>.</p>
|
||||
<p>This method will extract entities and relationships from documents and store them in a knowledge graph.</p>`,
|
||||
},
|
||||
dashboard: {
|
||||
title: 'Dashboard',
|
||||
knowledgeBaseStatus: 'Knowledge Base Status',
|
||||
documents: 'Documents',
|
||||
sources: 'Sources',
|
||||
vectors: 'Vectors',
|
||||
recentActivity: 'Recent Activity',
|
||||
noActivity: 'No activity',
|
||||
systemHealth: 'System Health',
|
||||
healthy: 'Healthy',
|
||||
warning: 'Warning',
|
||||
error: 'Error',
|
||||
},
|
||||
time: {
|
||||
justNow: 'Just now',
|
||||
minutesAgo: '{{count}} minutes ago',
|
||||
hoursAgo: '{{count}} hours ago',
|
||||
daysAgo: '{{count}} days ago',
|
||||
weeksAgo: '{{count}} weeks ago',
|
||||
monthsAgo: '{{count}} months ago',
|
||||
yearsAgo: '{{count}} years ago',
|
||||
},
|
||||
},
|
||||
};
|
||||
54
src/locales/index.ts
Normal file
54
src/locales/index.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import i18n from 'i18next';
|
||||
import LanguageDetector from 'i18next-browser-languagedetector';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
import dayjs from 'dayjs';
|
||||
import 'dayjs/locale/zh-cn';
|
||||
import 'dayjs/locale/en';
|
||||
|
||||
import en from './en';
|
||||
import zh from './zh';
|
||||
|
||||
export const LanguageAbbreviation = Object.freeze({
|
||||
En: 'en',
|
||||
Zh: 'zh',
|
||||
})
|
||||
|
||||
const resources = {
|
||||
[LanguageAbbreviation.En]: en,
|
||||
[LanguageAbbreviation.Zh]: zh,
|
||||
};
|
||||
|
||||
// 语言变更时同步更新 dayjs 语言
|
||||
const updateDayjsLocale = (lng: string) => {
|
||||
if (lng === LanguageAbbreviation.Zh) {
|
||||
dayjs.locale('zh-cn');
|
||||
} else {
|
||||
dayjs.locale('en');
|
||||
}
|
||||
};
|
||||
|
||||
i18n
|
||||
.use(initReactI18next)
|
||||
.use(LanguageDetector)
|
||||
.init({
|
||||
detection: {
|
||||
lookupLocalStorage: 'lng',
|
||||
order: ['localStorage', 'navigator', 'htmlTag'],
|
||||
caches: ['localStorage'],
|
||||
},
|
||||
supportedLngs: Object.values(LanguageAbbreviation),
|
||||
resources,
|
||||
fallbackLng: LanguageAbbreviation.En,
|
||||
defaultNS: 'translation',
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
},
|
||||
});
|
||||
|
||||
// 监听语言变更
|
||||
i18n.on('languageChanged', updateDayjsLocale);
|
||||
|
||||
// 初始化时设置 dayjs 语言
|
||||
updateDayjsLocale(i18n.language);
|
||||
|
||||
export default i18n;
|
||||
426
src/locales/zh.ts
Normal file
426
src/locales/zh.ts
Normal file
@@ -0,0 +1,426 @@
|
||||
export default {
|
||||
translation: {
|
||||
common: {
|
||||
noResults: '无结果。',
|
||||
selectPlaceholder: '请选择',
|
||||
selectAll: '全选',
|
||||
delete: '删除',
|
||||
deleteModalTitle: '确定删除吗?',
|
||||
ok: '是',
|
||||
cancel: '否',
|
||||
total: '总共',
|
||||
rename: '重命名',
|
||||
name: '名称',
|
||||
save: '保存',
|
||||
namePlaceholder: '请输入名称',
|
||||
next: '下一步',
|
||||
create: '创建',
|
||||
edit: '编辑',
|
||||
upload: '上传',
|
||||
english: '英文',
|
||||
portugueseBr: '葡萄牙语 (巴西)',
|
||||
chinese: '简体中文',
|
||||
traditionalChinese: '繁体中文',
|
||||
language: '语言',
|
||||
languageMessage: '请输入语言',
|
||||
languagePlaceholder: '请选择语言',
|
||||
copy: '复制',
|
||||
copied: '复制成功',
|
||||
comingSoon: '即将推出',
|
||||
download: '下载',
|
||||
close: '关闭',
|
||||
preview: '预览',
|
||||
move: '移动',
|
||||
warn: '提醒',
|
||||
action: '操作',
|
||||
s: '秒',
|
||||
pleaseSelect: '请选择',
|
||||
pleaseInput: '请输入',
|
||||
submit: '提交',
|
||||
clear: '清空',
|
||||
embedIntoSite: '嵌入网站',
|
||||
previousPage: '上一页',
|
||||
nextPage: '下一页',
|
||||
add: '添加',
|
||||
remove: '移除',
|
||||
search: '搜索',
|
||||
noDataFound: '没有找到数据。',
|
||||
noData: '暂无数据',
|
||||
promptPlaceholder: '请输入或使用 / 快速插入变量。',
|
||||
},
|
||||
login: {
|
||||
login: '登录',
|
||||
signUp: '注册',
|
||||
loginDescription: '很高兴再次见到您!',
|
||||
registerDescription: '很高兴您加入!',
|
||||
emailLabel: '邮箱',
|
||||
emailPlaceholder: '请输入邮箱地址',
|
||||
passwordLabel: '密码',
|
||||
passwordPlaceholder: '请输入密码',
|
||||
rememberMe: '记住我',
|
||||
signInTip: '没有帐户?',
|
||||
signUpTip: '已经有帐户?',
|
||||
nicknameLabel: '名称',
|
||||
nicknamePlaceholder: '请输入名称',
|
||||
register: '创建账户',
|
||||
continue: '继续',
|
||||
title: '开始构建您的智能助手',
|
||||
description:
|
||||
'免费注册以探索顶级 RAG 技术。 创建知识库和人工智能来增强您的业务',
|
||||
review: '来自 500 多条评论',
|
||||
},
|
||||
header: {
|
||||
knowledgeBase: '知识库',
|
||||
chat: '聊天',
|
||||
register: '注册',
|
||||
signin: '登录',
|
||||
home: '首页',
|
||||
setting: '用户设置',
|
||||
logout: '登出',
|
||||
fileManager: '文件管理',
|
||||
flow: '智能体',
|
||||
search: '搜索',
|
||||
welcome: '欢迎来到',
|
||||
dataset: '知识库',
|
||||
},
|
||||
knowledgeList: {
|
||||
welcome: '欢迎回来',
|
||||
description: '今天我们要使用哪个知识库?',
|
||||
createKnowledgeBase: '创建知识库',
|
||||
name: '名称',
|
||||
namePlaceholder: '请输入名称',
|
||||
doc: '文档',
|
||||
searchKnowledgePlaceholder: '搜索',
|
||||
noMoreData: '没有更多数据了',
|
||||
},
|
||||
knowledgeDetails: {
|
||||
fileSize: '文件大小',
|
||||
fileType: '文件类型',
|
||||
uploadedBy: '创建者',
|
||||
notGenerated: '未生成',
|
||||
generatedOn: '生成于',
|
||||
subbarFiles: '文件列表',
|
||||
generate: '生成',
|
||||
raptor: 'Raptor',
|
||||
processingType: '处理类型',
|
||||
dataPipeline: '数据管道',
|
||||
operations: '操作',
|
||||
taskId: '任务ID',
|
||||
duration: '耗时',
|
||||
details: '详情',
|
||||
status: '状态',
|
||||
task: '任务',
|
||||
startDate: '开始时间',
|
||||
source: '来源',
|
||||
fileName: '文件名',
|
||||
datasetLogs: '数据集日志',
|
||||
fileLogs: '文件日志',
|
||||
overview: '概览',
|
||||
success: '成功',
|
||||
failed: '失败',
|
||||
completed: '已完成',
|
||||
datasetLog: '知识库日志',
|
||||
created: '创建于',
|
||||
learnMore: '了解更多',
|
||||
general: '通用',
|
||||
chunkMethodTab: '切片方法',
|
||||
testResults: '测试结果',
|
||||
testSetting: '测试设置',
|
||||
retrievalTesting: '知识检索测试',
|
||||
retrievalTestingDescription:
|
||||
'进行检索测试,检查 RAGFlow 是否能够为大语言模型(LLM)恢复预期的内容。',
|
||||
Parse: '解析',
|
||||
dataset: '知识库',
|
||||
testing: '检索测试',
|
||||
configuration: '配置',
|
||||
knowledgeGraph: '知识图谱',
|
||||
files: '个文件',
|
||||
name: '名称',
|
||||
namePlaceholder: '请输入名称',
|
||||
doc: '文档',
|
||||
datasetDescription: '解析成功后才能问答哦。',
|
||||
addFile: '新增文件',
|
||||
searchFiles: '搜索文件',
|
||||
localFiles: '本地文件',
|
||||
emptyFiles: '新建空文件',
|
||||
webCrawl: '网页抓取',
|
||||
chunkNumber: '分块数',
|
||||
uploadDate: '上传日期',
|
||||
chunkMethod: '切片方法',
|
||||
enabled: '启用',
|
||||
disabled: '禁用',
|
||||
action: '动作',
|
||||
parsingStatus: '解析状态',
|
||||
parsingStatusTip:
|
||||
'文本解析的时间取决于诸多因素。如果开启了知识图谱、RAPTOR、自动问题提取、自动关键词提取等功能,时间会更长。如果解析进度条长时间不更新,也可以参考这两条 FAQ:https://ragflow.io/docs/dev/faq#why-does-my-document-parsing-stall-at-under-one-percent。',
|
||||
processBeginAt: '开始于',
|
||||
processDuration: '持续时间',
|
||||
progressMsg: '进度',
|
||||
noTestResultsForRuned: '未找到相关结果,请尝试调整查询语句或参数',
|
||||
noTestResultsForNotRuned: '尚未运行测试,结果会显示在这里',
|
||||
testingDescription:
|
||||
'请完成召回测试:确保你的配置可以从数据库召回正确的文本块。如果你调整了这里的默认设置,比如关键词相似度权重,请注意这里的改动不会被自动保存。请务必在聊天助手设置或者召回算子设置处同步更新相关设置。',
|
||||
similarityThreshold: '相似度阈值',
|
||||
similarityThresholdTip:
|
||||
'我们使用混合相似度得分来评估两行文本之间的距离。 它是加权关键词相似度和向量余弦相似度。 如果查询和块之间的相似度小于此阈值,则该块将被过滤掉。默认设置为 0.2,也就是说文本块的混合相似度得分至少 20 才会被召回。',
|
||||
vectorSimilarityWeight: '向量相似度权重',
|
||||
vectorSimilarityWeightTip:
|
||||
'我们使用混合相似性评分来评估两行文本之间的距离。它是加权关键字相似性和矢量余弦相似性或rerank得分(0〜1)。两个权重的总和为1.0。',
|
||||
keywordSimilarityWeight: '关键词相似度权重',
|
||||
keywordSimilarityWeightTip:
|
||||
'我们使用混合相似性评分来评估两行文本之间的距离。它是加权关键字相似性和矢量余弦相似性或rerank得分(0〜1)。两个权重的总和为1.0。',
|
||||
testText: '测试文本',
|
||||
testTextPlaceholder: '请输入您的问题!',
|
||||
testingLabel: '测试',
|
||||
similarity: '混合相似度',
|
||||
termSimilarity: '关键词相似度',
|
||||
vectorSimilarity: '向量相似度',
|
||||
hits: '命中数',
|
||||
view: '看法',
|
||||
filesSelected: '选定的文件',
|
||||
upload: '上传',
|
||||
run: '解析',
|
||||
runningStatus0: '未解析',
|
||||
runningStatus1: '解析中',
|
||||
runningStatus2: '取消',
|
||||
runningStatus3: '成功',
|
||||
runningStatus4: '失败',
|
||||
pageRanges: '页码范围',
|
||||
pageRangesTip:
|
||||
'页码范围:定义需要解析的页面范围。 不包含在这些范围内的页面将被忽略。',
|
||||
fromPlaceholder: '从',
|
||||
fromMessage: '缺少起始页码',
|
||||
toPlaceholder: '到',
|
||||
toMessage: '缺少结束页码(不包含)',
|
||||
layoutRecognize: 'PDF解析器',
|
||||
layoutRecognizeTip:
|
||||
'使用视觉模型进行 PDF 布局分析,以更好地识别文档结构,找到标题、文本块、图像和表格的位置。 如果选择 Naive 选项,则只能获取 PDF 的纯文本。请注意该功能只适用于 PDF 文档,对其他文档不生效。欲了解更多信息,请参阅 https://ragflow.io/docs/dev/select_pdf_parser。',
|
||||
taskPageSize: '任务页面大小',
|
||||
taskPageSizeMessage: '请输入您的任务页面大小!',
|
||||
taskPageSizeTip: `如果使用布局识别,PDF 文件将被分成连续的组。 布局分析将在组之间并行执行,以提高处理速度。 "任务页面大小"决定组的大小。 页面大小越大,将页面之间的连续文本分割成不同块的机会就越低。`,
|
||||
addPage: '新增页面',
|
||||
greaterThan: '当前值必须大于起始值!',
|
||||
greaterThanPrevious: '当前值必须大于之前的值!',
|
||||
selectFiles: '选择文件',
|
||||
changeSpecificCategory: '更改特定类别',
|
||||
uploadTitle: '点击或拖拽文件至此区域即可上传',
|
||||
uploadDescription:
|
||||
'支持单次或批量上传。本地部署的单次上传文件总大小上限为 1GB,单次批量上传文件数不超过 32,单个账户不限文件数量。对于 demo.ragflow.io:每次上传的总文件大小限制为 10MB,每个文件不得超过 10MB,每个账户最多可上传 128 个文件。严禁上传违禁文件。',
|
||||
chunk: '解析块',
|
||||
bulk: '批量',
|
||||
cancel: '取消',
|
||||
close: '关闭',
|
||||
rerankModel: 'Rerank模型',
|
||||
rerankPlaceholder: '请选择',
|
||||
rerankTip: `非必选项:若不选择 rerank 模型,系统将默认采用关键词相似度与向量余弦相似度相结合的混合查询方式;如果设置了 rerank 模型,则混合查询中的向量相似度部分将被 rerank 打分替代。请注意:采用 rerank 模型会非常耗时。如需选用 rerank 模型,建议使用 SaaS 的 rerank 模型服务;如果你倾向使用本地部署的 rerank 模型,请务必确保你使用 docker-compose-gpu.yml 启动 RAGFlow。`,
|
||||
topK: 'Top-K',
|
||||
topKTip: `与 Rerank 模型配合使用,用于设置传给 Rerank 模型的文本块数量。`,
|
||||
delimiter: `文本分段标识符`,
|
||||
delimiterTip:
|
||||
'支持多字符作为分隔符,多字符用两个反引号 \\`\\` 分隔符包裹。若配置成:\\n`##`; 系统将首先使用换行符、两个#号以及分号先对文本进行分割,随后再对分得的小文本块按照「建议文本块大小」设定的大小进行拼装。在设置文本分段标识符前请确保理解上述文本分段切片机制。',
|
||||
html4excel: '表格转HTML',
|
||||
html4excelTip: `与 General 切片方法配合使用。未开启状态下,表格文件(XLSX、XLS(Excel 97-2003))会按行解析为键值对。开启后,表格文件会被解析为 HTML 表格。若原始表格超过 12 行,系统会自动按每 12 行拆分为多个 HTML 表格。欲了解更多详情,请参阅 https://ragflow.io/docs/dev/enable_excel2html。`,
|
||||
autoKeywords: '自动关键词提取',
|
||||
autoKeywordsTip: `自动为每个文本块中提取 N 个关键词,用以提升查询精度。请注意:该功能采用"系统模型设置"中设置的默认聊天模型提取关键词,因此也会产生更多 Token 消耗。另外,你也可以手动更新生成的关键词。详情请见 https://ragflow.io/docs/dev/autokeyword_autoquestion。`,
|
||||
autoQuestions: '自动问题提取',
|
||||
autoQuestionsTip: `利用"系统模型设置"中设置的 chat model 对知识库的每个文本块提取 N 个问题以提高其排名得分。请注意,开启后将消耗额外的 token。您可以在块列表中查看、编辑结果。如果自动问题提取发生错误,不会妨碍整个分块过程,只会将空结果添加到原始文本块。详情请见 https://ragflow.io/docs/dev/autokeyword_autoquestion。`,
|
||||
redo: '是否清空已有 {{chunkNum}}个 chunk?',
|
||||
setMetaData: '设置元数据',
|
||||
pleaseInputJson: '请输入JSON',
|
||||
documentMetaTips: `<p>元数据为 Json 格式(不可搜索)。如果提示中包含此文档的任何块,它将被添加到 LLM 的提示中。</p>
|
||||
<p>示例:</p>
|
||||
<b>元数据为:</b><br>
|
||||
<code>
|
||||
{
|
||||
"作者": "Alex Dowson",
|
||||
"日期": "2024-11-12"
|
||||
}
|
||||
</code><br>
|
||||
<b>提示将为:</b><br>
|
||||
<p>文档:the_name_of_document</p>
|
||||
<p>作者:Alex Dowson</p>
|
||||
<p>日期:2024-11-12</p>
|
||||
<p>相关片段如下:</p>
|
||||
<ul>
|
||||
<li> 这是块内容....</li>
|
||||
<li> 这是块内容....</li>
|
||||
</ul>
|
||||
`,
|
||||
metaData: '元数据',
|
||||
deleteDocumentConfirmContent:
|
||||
'该文档与知识图谱相关联。删除后,相关节点和关系信息将被删除,但图不会立即更新。更新图动作是在解析承载知识图谱提取任务的新文档的过程中执行的。',
|
||||
plainText: 'Naive',
|
||||
reRankModelWaring: '重排序模型非常耗时。',
|
||||
theDocumentBeingParsedCannotBeDeleted: '正在解析的文档不能被删除',
|
||||
},
|
||||
knowledgeConfiguration: {
|
||||
deleteGenerateModalContent: `
|
||||
<p>删除生成的 <strong class='text-text-primary'>{{type}}</strong> 结果
|
||||
将从此数据集中移除所有派生实体和关系。
|
||||
您的原始文件将保持不变。<p>
|
||||
<br/>
|
||||
是否要继续?
|
||||
`,
|
||||
extractRaptor: '从文档中提取Raptor',
|
||||
extractKnowledgeGraph: '从文档中提取知识图谱',
|
||||
filterPlaceholder: '请输入',
|
||||
fileFilterTip: '',
|
||||
fileFilter: '正则匹配表达式',
|
||||
setDefaultTip: '',
|
||||
setDefault: '设置默认',
|
||||
eidtLinkDataPipeline: '编辑数据流',
|
||||
linkPipelineSetTip: '管理与此数据集的数据管道链接',
|
||||
default: '默认',
|
||||
dataPipeline: '数据流',
|
||||
linkDataPipeline: '关联数据流',
|
||||
enableAutoGenerate: '是否启用自动生成',
|
||||
teamPlaceholder: '请选择团队',
|
||||
dataFlowPlaceholder: '请选择数据流',
|
||||
buildItFromScratch: '去Scratch构建',
|
||||
dataFlow: '数据流',
|
||||
parseType: '切片方法',
|
||||
manualSetup: '手动设置',
|
||||
builtIn: '内置',
|
||||
titleDescription: '在这里更新您的知识库详细信息,尤其是切片方法。',
|
||||
name: '知识库名称',
|
||||
photo: '知识库图片',
|
||||
photoTip: '你可以上传4MB的文件',
|
||||
description: '描述',
|
||||
language: '文档语言',
|
||||
languageMessage: '请输入语言',
|
||||
languagePlaceholder: '请输入语言',
|
||||
permissions: '权限',
|
||||
embeddingModel: '嵌入模型',
|
||||
chunkTokenNumber: '建议文本块大小',
|
||||
chunkTokenNumberMessage: '块Token数是必填项',
|
||||
embeddingModelTip:
|
||||
'知识库采用的默认嵌入模型。 一旦知识库内已经产生了文本块后,你将无法更改默认的嵌入模型,除非删除知识库内的所有文本块。',
|
||||
permissionsTip:
|
||||
'如果把知识库权限设为"团队",则所有团队成员都可以操作该知识库。',
|
||||
chunkTokenNumberTip:
|
||||
'建议的生成文本块的 token 数阈值。如果切分得到的小文本段 token 数达不到这一阈值就会不断与之后的文本段合并,直至再合并下一个文本段会超过这一阈值为止,此时产生一个最终文本块。如果系统在切分文本段时始终没有遇到文本分段标识符,即便文本段 token 数已经超过这一阈值,系统也不会生成新文本块。',
|
||||
chunkMethod: '切片方法',
|
||||
chunkMethodTip: '说明位于右侧。',
|
||||
upload: '上传',
|
||||
english: '英文',
|
||||
chinese: '中文',
|
||||
embeddingModelPlaceholder: '请选择嵌入模型',
|
||||
chunkMethodPlaceholder: '请选择分块方法',
|
||||
save: '保存',
|
||||
me: '只有我',
|
||||
team: '团队',
|
||||
cancel: '取消',
|
||||
methodTitle: '分块方法说明',
|
||||
methodExamples: '示例',
|
||||
methodExamplesDescription:
|
||||
'为帮助您更好地理解,我们提供了相关截图供您参考。',
|
||||
dialogueExamplesTitle: '对话示例',
|
||||
methodEmpty: '这将显示知识库类别的可视化解释',
|
||||
book: `<p>支持的文件格式为<b>DOCX</b>、<b>PDF</b>、<b>TXT</b>。</p><p>
|
||||
由于一本书很长,并不是所有部分都有用,如果是 PDF,
|
||||
请为每本书设置<i>页面范围</i>,以消除负面影响并节省分析计算时间。</p>`,
|
||||
laws: `<p>支持的文件格式为<b>DOCX</b>、<b>PDF</b>、<b>TXT</b>。</p><p>
|
||||
法律文件有非常严格的书写格式。 我们使用文本特征来检测分割点。
|
||||
</p><p>
|
||||
chunk的粒度与'ARTICLE'一致,所有上层文本都会包含在chunk中。
|
||||
</p>`,
|
||||
manual: `<p>仅支持<b>PDF</b>。</p><p>
|
||||
我们假设手册具有分层部分结构。 我们使用最低的部分标题作为对文档进行切片的枢轴。
|
||||
因此,同一部分中的图和表不会被分割,并且块大小可能会很大。
|
||||
</p>`,
|
||||
naive: `<p>支持的文件格式为<b>MD、MDX、DOCX、XLSX、XLS (Excel 97-2003)、PPT、PDF、TXT、JPEG、JPG、PNG、TIF、GIF、CSV、JSON、EML、HTML</b>。</p>
|
||||
<p>此方法将简单的方法应用于块文件:</p>
|
||||
<p>
|
||||
<li>系统将使用视觉检测模型将连续文本分割成多个片段。</li>
|
||||
<li>接下来,这些连续的片段被合并成Token数不超过"Token数"的块。</li></p>`,
|
||||
paper: `<p>仅支持<b>PDF</b>文件。</p><p>
|
||||
如果我们的模型运行良好,论文将按其部分进行切片,例如<i>摘要、1.1、1.2</i>等。</p><p>
|
||||
这样做的好处是LLM可以更好的概括论文中相关章节的内容,
|
||||
产生更全面的答案,帮助读者更好地理解论文。
|
||||
缺点是它增加了 LLM 对话的背景并增加了计算成本,
|
||||
所以在对话过程中,你可以考虑减少'<b>topN</b>'的设置。</p>`,
|
||||
presentation: `<p>支持的文件格式为<b>PDF</b>、<b>PPTX</b>。</p><p>
|
||||
每个页面都将被视为一个块。 并且每个页面的缩略图都会被存储。</p><p>
|
||||
<i>您上传的所有PPT文件都会使用此方法自动分块,无需为每个PPT文件进行设置。</i></p>`,
|
||||
qa: ` <p>
|
||||
此块方法支持<b> excel </b>和<b> csv/txt </b>文件格式。
|
||||
</p>
|
||||
<li>
|
||||
如果文件是<b> excel </b>格式,则应由两个列组成
|
||||
没有标题:一个提出问题,另一个用于答案,
|
||||
答案列之前的问题列。多张纸是
|
||||
只要列正确结构,就可以接受。
|
||||
</li>
|
||||
<li>
|
||||
如果文件是<b> csv/txt </b>格式
|
||||
以 UTF-8 编码且用 TAB 作分开问题和答案的定界符。
|
||||
</li>
|
||||
<p>
|
||||
<i>
|
||||
未能遵循上述规则的文本行将被忽略,并且
|
||||
每个问答对将被认为是一个独特的部分。
|
||||
</i>
|
||||
</p>`,
|
||||
resume: `<p>支持的文件格式为<b>DOCX</b>、<b>PDF</b>、<b>TXT</b>。
|
||||
</p><p>
|
||||
简历有多种格式,就像一个人的个性一样,但我们经常必须将它们组织成结构化数据,以便于搜索。
|
||||
</p><p>
|
||||
我们不是将简历分块,而是将简历解析为结构化数据。 作为HR,你可以扔掉所有的简历,
|
||||
您只需与<i>'RAGFlow'</i>交谈即可列出所有符合资格的候选人。
|
||||
</p>
|
||||
`,
|
||||
table: `支持<p><b>XLSX</b>和<b>CSV/TXT</b>格式文件。</p><p>
|
||||
以下是一些提示:
|
||||
<ul>
|
||||
<li>对于 csv 或 txt 文件,列之间的分隔符为 <em><b>TAB</b></em>。</li>
|
||||
<li>第一行必须是列标题。</li>
|
||||
<li>列标题必须是有意义的术语,以便我们的大语言模型能够理解。
|
||||
列举一些同义词时最好使用斜杠<i>'/'</i>来分隔,甚至更好
|
||||
使用方括号枚举值,例如 <i>'gender/sex(male,female)'</i>.<p>
|
||||
以下是标题的一些示例:<ol>
|
||||
<li>供应商/供货商<b>'TAB'</b>颜色(黄色、红色、棕色)<b>'TAB'</b>性别(男、女)<b>'TAB'</ b>尺码(M、L、XL、XXL)</li>
|
||||
<li>姓名/名字<b>'TAB'</b>电话/手机/微信<b>'TAB'</b>最高学历(高中,职高,硕士,本科,博士,初中,中技,中 专,专科,专升本,MPA,MBA,EMBA)</li>
|
||||
</ol>
|
||||
</p>
|
||||
</li>
|
||||
<li>表中的每一行都将被视为一个块。</li>
|
||||
</ul>`,
|
||||
picture: `
|
||||
<p>支持图像文件。 视频即将推出。</p><p>
|
||||
如果图片中有文字,则应用 OCR 提取文字作为其文字描述。
|
||||
</p><p>
|
||||
如果OCR提取的文本不够,可以使用视觉LLM来获取描述。
|
||||
</p>`,
|
||||
one: `
|
||||
<p>支持的文件格式为<b>MD、MDX、DOCX、XLSX、XLS (Excel 97-2003)、PPT、PDF、TXT、JPEG、JPG、PNG、TIF、GIF、CSV、JSON、EML、HTML</b>。</p>
|
||||
<p>此方法将整个文档视为一个块。</p>`,
|
||||
email: `<p>支持的文件格式为<b>EML</b>。</p><p>
|
||||
每封电子邮件都将被视为一个块。
|
||||
</p>`,
|
||||
knowledgeGraph: `<p>支持的文件格式为<b>MD、MDX、DOCX、XLSX、XLS (Excel 97-2003)、PPT、PDF、TXT、JPEG、JPG、PNG、TIF、GIF、CSV、JSON、EML、HTML</b>。</p>
|
||||
<p>此方法将从文档中提取实体和关系,并将它们存储在知识图谱中。</p>`,
|
||||
},
|
||||
dashboard: {
|
||||
title: '仪表板',
|
||||
knowledgeBaseStatus: '知识库状态',
|
||||
documents: '文档',
|
||||
sources: '来源',
|
||||
vectors: '向量',
|
||||
recentActivity: '最近活动',
|
||||
noActivity: '暂无活动',
|
||||
systemHealth: '系统健康',
|
||||
healthy: '健康',
|
||||
warning: '警告',
|
||||
error: '错误',
|
||||
},
|
||||
time: {
|
||||
justNow: '刚刚',
|
||||
minutesAgo: '{{count}} 分钟前',
|
||||
hoursAgo: '{{count}} 小时前',
|
||||
daysAgo: '{{count}} 天前',
|
||||
weeksAgo: '{{count}} 周前',
|
||||
monthsAgo: '{{count}} 个月前',
|
||||
yearsAgo: '{{count}} 年前',
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -14,6 +14,8 @@ import {
|
||||
Typography,
|
||||
styled
|
||||
} from '@mui/material';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import LanguageSwitcher from '../components/LanguageSwitcher';
|
||||
|
||||
const StyledCard = styled(Card)({
|
||||
height: '100%',
|
||||
@@ -93,8 +95,18 @@ const recentQueries = [
|
||||
];
|
||||
|
||||
const Home = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Box className="p-6">
|
||||
{/* Header with Language Switcher */}
|
||||
<Box className="flex justify-between items-center mb-6">
|
||||
<Typography variant="h4" className="font-bold text-gray-800">
|
||||
{t('navigation.dashboard')}
|
||||
</Typography>
|
||||
<LanguageSwitcher />
|
||||
</Box>
|
||||
|
||||
<Grid container spacing={3}>
|
||||
{/* Knowledge Base Status Card */}
|
||||
<Grid size={{ xs: 12, md: 6, lg: 4 }}>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
@@ -14,8 +15,10 @@ import {
|
||||
Card,
|
||||
CardContent
|
||||
} from '@mui/material';
|
||||
import LanguageSwitcher from '../components/LanguageSwitcher';
|
||||
|
||||
const Login = () => {
|
||||
const { t } = useTranslation();
|
||||
const [email, setEmail] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [rememberEmail, setRememberEmail] = useState(false);
|
||||
@@ -24,6 +27,8 @@ const Login = () => {
|
||||
const [passwordError, setPasswordError] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
|
||||
console.log(t, t('en'), t('login'));
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -44,7 +49,7 @@ const Login = () => {
|
||||
<Box sx={{ minHeight: '100vh', width: '100vw', bgcolor: 'background.default', display: 'flex', flexDirection: 'column' }}>
|
||||
{/* 顶部栏使用主题主色 */}
|
||||
<AppBar position="static" color="primary" enableColorOnDark>
|
||||
<Toolbar sx={{ minHeight: 60 }}>
|
||||
<Toolbar sx={{ minHeight: 60, justifyContent: 'space-between' }}>
|
||||
<Box
|
||||
sx={{
|
||||
width: 40,
|
||||
@@ -62,6 +67,7 @@ const Login = () => {
|
||||
>
|
||||
T
|
||||
</Box>
|
||||
<LanguageSwitcher />
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
|
||||
@@ -69,12 +75,12 @@ const Login = () => {
|
||||
<Container maxWidth="sm" sx={{ flex: 1, display: 'flex', alignItems: 'center' }}>
|
||||
<Card sx={{ width: '100%' }}>
|
||||
<CardContent sx={{ p: 4 }}>
|
||||
<Typography variant="caption" color="text.secondary" sx={{ mb: 1, display: 'block' }}>
|
||||
Servicename
|
||||
<Typography variant="subtitle1" color="text.secondary" sx={{ mb: 1, display: 'block' }}>
|
||||
T-Systems Enterprise RAG Empowerment System
|
||||
</Typography>
|
||||
<Typography variant="h5" fontWeight={700} sx={{ mb: 2 }}>
|
||||
Enter Login
|
||||
<br /> Email & Password
|
||||
{t('login.login')}
|
||||
<br /> {t('login.emailLabel')} & {t('login.passwordLabel')}
|
||||
</Typography>
|
||||
|
||||
<Box component="form" onSubmit={handleSubmit} noValidate>
|
||||
@@ -83,7 +89,7 @@ const Login = () => {
|
||||
id="email"
|
||||
name="email"
|
||||
type="email"
|
||||
placeholder="Email"
|
||||
placeholder={t('login.emailPlaceholder')}
|
||||
autoComplete="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
@@ -97,7 +103,7 @@ const Login = () => {
|
||||
id="password"
|
||||
name="password"
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
placeholder={t('login.passwordPlaceholder')}
|
||||
autoComplete="current-password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
@@ -115,23 +121,18 @@ const Login = () => {
|
||||
id="rememberEmail"
|
||||
/>
|
||||
}
|
||||
label="Remember email"
|
||||
label={t('login.rememberMe')}
|
||||
/>
|
||||
<Link href="#" variant="caption">
|
||||
Forgot your username or password?
|
||||
</Link>
|
||||
</Box>
|
||||
|
||||
<Button type="submit" variant="contained" fullWidth disabled={isSubmitting}>
|
||||
{isSubmitting ? 'Processing...' : 'Login'}
|
||||
{isSubmitting ? 'Processing...' : t('login.login')}
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
<Box sx={{ mt: 2, textAlign: 'center' }}>
|
||||
<Link href="#">Do you need help?</Link>
|
||||
<Box mt={0.5}>
|
||||
{/* 保留说明文案,去掉社交登录 */}
|
||||
No account? <Link href="#">Sign up</Link>.
|
||||
{t('login.signInTip')} <Link href="#">{t('login.signUp')}</Link>.
|
||||
</Box>
|
||||
</Box>
|
||||
</CardContent>
|
||||
|
||||
Reference in New Issue
Block a user