diff --git a/.gitignore b/.gitignore index c6009b3ebb7298c54a771f0092561d7030575496..07765cf0e374f0ff778c48f535439167c9bfa037 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,6 @@ rag/res/deepdoc sdk/python/ragflow.egg-info/ sdk/python/build/ sdk/python/dist/ -sdk/python/ragflow_sdk.egg-info/ \ No newline at end of file +sdk/python/ragflow_sdk.egg-info/ +huggingface.co/ +nltk_data/ diff --git a/docker/docker-compose-base.yml b/docker/docker-compose-base.yml index 2d482a3ed3444656d8ac0467dd2ad40cce49ab89..48cfda0600fc72f889214e2469d88f32b82ac205 100644 --- a/docker/docker-compose-base.yml +++ b/docker/docker-compose-base.yml @@ -74,7 +74,7 @@ services: command: --max_connections=1000 --character-set-server=utf8mb4 - --collation-server=utf8mb4_general_ci + --collation-server=utf8mb4_unicode_ci --default-authentication-plugin=mysql_native_password --tls_version="TLSv1.2,TLSv1.3" --init-file /data/application/init.sql diff --git a/rag/svr/task_executor.py b/rag/svr/task_executor.py index e9ea38280642179717e305749e35379070b19495..606bb0757165c6d45b24515f5738161abf47988b 100644 --- a/rag/svr/task_executor.py +++ b/rag/svr/task_executor.py @@ -260,7 +260,7 @@ def build_chunks(task, progress_callback): def init_kb(row, vector_size: int): idxnm = search.index_name(row["tenant_id"]) - return settings.docStoreConn.createIdx(idxnm, row["kb_id"], vector_size) + return settings.docStoreConn.createIdx(idxnm, row.get("kb_id",""), vector_size) def embedding(docs, mdl, parser_config=None, callback=None): diff --git a/web/src/app.tsx b/web/src/app.tsx index 08161485c07b23b3302e089dcc4c133c15470681..bbb1d9d7b46a16986f6295c75589207b4861fb15 100644 --- a/web/src/app.tsx +++ b/web/src/app.tsx @@ -1,7 +1,7 @@ import i18n from '@/locales/config'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; -import { App, ConfigProvider, ConfigProviderProps } from 'antd'; +import { App, ConfigProvider, ConfigProviderProps, theme } from 'antd'; import enUS from 'antd/locale/en_US'; import vi_VN from 'antd/locale/vi_VN'; import zhCN from 'antd/locale/zh_CN'; @@ -14,7 +14,7 @@ import weekOfYear from 'dayjs/plugin/weekOfYear'; import weekYear from 'dayjs/plugin/weekYear'; import weekday from 'dayjs/plugin/weekday'; import React, { ReactNode, useEffect, useState } from 'react'; -import { ThemeProvider } from './components/theme-provider'; +import { ThemeProvider, useTheme } from './components/theme-provider'; import storage from './utils/authorization-util'; dayjs.extend(customParseFormat); @@ -35,7 +35,8 @@ const queryClient = new QueryClient(); type Locale = ConfigProviderProps['locale']; -const RootProvider = ({ children }: React.PropsWithChildren) => { +function Root({ children }: React.PropsWithChildren) { + const { theme: themeragflow } = useTheme(); const getLocale = (lng: string) => AntLanguageMap[lng as keyof typeof AntLanguageMap] ?? enUS; @@ -46,6 +47,28 @@ const RootProvider = ({ children }: React.PropsWithChildren) => { setLocal(getLocale(lng)); }); + return ( + <> + + {children} + + + + ); +} + +const RootProvider = ({ children }: React.PropsWithChildren) => { useEffect(() => { // Because the language is saved in the backend, a token is required to obtain the api. However, the login page cannot obtain the language through the getUserInfo api, so the language needs to be saved in localstorage. const lng = storage.getLanguage(); @@ -57,22 +80,11 @@ const RootProvider = ({ children }: React.PropsWithChildren) => { return ( - - {children} - - + {children} ); }; - export function rootContainer(container: ReactNode) { return {container}; } diff --git a/web/src/assets/icon/Icon.tsx b/web/src/assets/icon/Icon.tsx new file mode 100644 index 0000000000000000000000000000000000000000..1d20e3a84231e82e42138f943fdaf7275e8c3f6d --- /dev/null +++ b/web/src/assets/icon/Icon.tsx @@ -0,0 +1,240 @@ +import Icon from '@ant-design/icons'; +import { CustomIconComponentProps } from '@ant-design/icons/lib/components/Icon'; + +type IconComponentProps = CustomIconComponentProps; +const currentColor = 'currentColor'; +const ApiSvg = () => ( + + + +); +const TeamSvg = () => ( + + + +); +const ProfileSvg = () => ( + + + +); +const PasswordSvg = () => ( + + + +); +const LogOutSvg = () => ( + + + +); +const ModelProviderSvg = () => ( + + + +); +const PromptSvg = () => ( + + + + + + + + + + +); +const WikipediaSvg = () => ( + + + +); +const KeywordSvg = () => ( + + + + +); +const GitHubSvg = () => ( + + + +); +const QWeatherSvg = () => ( + + + +); + +export const ApiIcon = (props: Partial) => ( + +); +export const TeamIcon = (props: Partial) => ( + +); +export const ProfileIcon = (props: Partial) => ( + +); +export const PasswordIcon = (props: Partial) => ( + +); +export const LogOutIcon = (props: Partial) => ( + +); +export const ModelProviderIcon = (props: Partial) => ( + +); +export const PromptIcon = (props: Partial) => ( + +); +export const WikipediaIcon = (props: Partial) => ( + +); +export const KeywordIcon = (props: Partial) => ( + +); +export const GitHubIcon = (props: Partial) => ( + +); +export const QWeatherIcon = (props: Partial) => ( + +); diff --git a/web/src/assets/svg/api.svg b/web/src/assets/svg/api.svg index db088dd74b3f4548bba3c87e44980c03939563fc..5dd6a8584e333dbd2773a5ed08887aa16892a9c6 100644 --- a/web/src/assets/svg/api.svg +++ b/web/src/assets/svg/api.svg @@ -2,5 +2,5 @@ width="24" height="24"> + fill="#667085" p-id="4307"> \ No newline at end of file diff --git a/web/src/assets/svg/delete.svg b/web/src/assets/svg/delete.svg index 1eef9110b61f3c275ecb6459588de48b405c6614..7e1f0a015ccbd8721bb4669a245062ce575ce24e 100644 --- a/web/src/assets/svg/delete.svg +++ b/web/src/assets/svg/delete.svg @@ -1,5 +1,5 @@ + stroke="#667085" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round" /> \ No newline at end of file diff --git a/web/src/assets/svg/prompt.svg b/web/src/assets/svg/prompt.svg index 1a9388d95a5edfdab554e10e305902020c4bbc75..408c30a9506d2f5b9637f5627369649dcda30643 100644 --- a/web/src/assets/svg/prompt.svg +++ b/web/src/assets/svg/prompt.svg @@ -2,26 +2,26 @@ width="200" height="200"> + fill="#667085" p-id="4297"> + fill="#667085" p-id="4298"> + fill="#667085" p-id="4299"> + fill="#667085" p-id="4300"> + fill="#667085" p-id="4301"> + fill="#667085" p-id="4302"> + fill="#667085" p-id="4303"> + fill="#667085" p-id="4304"> \ No newline at end of file diff --git a/web/src/components/api-service/chat-overview-modal/index.less b/web/src/components/api-service/chat-overview-modal/index.less index c923c4df745fbb32b6fd39d788da47a30cdae0fb..857bb3adc0ccdba990e2c2997003736cdc5409fd 100644 --- a/web/src/components/api-service/chat-overview-modal/index.less +++ b/web/src/components/api-service/chat-overview-modal/index.less @@ -16,4 +16,5 @@ .apiLinkText { .linkText(); margin: 0 !important; + background-color: rgba(255, 255, 255, 0.1); } diff --git a/web/src/components/api-service/embed-modal/index.less b/web/src/components/api-service/embed-modal/index.less index 5e807d8526efffbc85a64b26ae96d7eb20f85488..b2c0cfbba869706acec405a45da6bb2618ea52dd 100644 --- a/web/src/components/api-service/embed-modal/index.less +++ b/web/src/components/api-service/embed-modal/index.less @@ -4,5 +4,5 @@ .codeText { padding: 10px; - background-color: #e8e8ea; + background-color: #ffffff09; } diff --git a/web/src/components/editable-cell.tsx b/web/src/components/editable-cell.tsx index 85f5610b8d6849544e889db72c47b84dec94a361..c8e53275bd8e00c93a510798233f38e1e4aa89b9 100644 --- a/web/src/components/editable-cell.tsx +++ b/web/src/components/editable-cell.tsx @@ -90,7 +90,7 @@ export const EditableCell: React.FC = ({ ) : ( -
+
{children}
); diff --git a/web/src/components/highlight-markdown/index.less b/web/src/components/highlight-markdown/index.less index cfc5f12da729cf68cf2b737188c4c1cc55d95d2c..a250e4a1c256149974fce21c0031b52218fdcf9b 100644 --- a/web/src/components/highlight-markdown/index.less +++ b/web/src/components/highlight-markdown/index.less @@ -15,5 +15,5 @@ white-space: break-spaces; background-color: rgba(129, 139, 152, 0.12); border-radius: 4px; - color: rgb(31, 35, 40); + color: var(--ant-color-text-base); } diff --git a/web/src/components/indented-tree/indented-tree.tsx b/web/src/components/indented-tree/indented-tree.tsx index fc3cc6a8603407ebb6bb118d86691ad957bd40e2..91ee361b22f770dd43cc16b95ae1a235ccf075ba 100644 --- a/web/src/components/indented-tree/indented-tree.tsx +++ b/web/src/components/indented-tree/indented-tree.tsx @@ -312,80 +312,96 @@ function fallbackRender({ error }: FallbackProps) { const IndentedTree = ({ data, show, style = {} }: IProps) => { const containerRef = useRef(null); const graphRef = useRef(null); + const assignIds = React.useCallback(function assignIds( + node: TreeData, + parentId: string = '', + index = 0, + ) { + if (!node.id) node.id = parentId ? `${parentId}-${index}` : 'root'; + if (node.children) { + node.children.forEach((child, idx) => assignIds(child, node.id, idx)); + } + }, []); - const render = useCallback(async (data: TreeData) => { - const graph: Graph = new Graph({ - container: containerRef.current!, - x: 60, - node: { - type: 'indented', - style: { - size: (d) => [d.id.length * 6 + 10, 20], - labelBackground: (datum) => datum.id === rootId, - labelBackgroundRadius: 0, - labelBackgroundFill: '#576286', - labelFill: (datum) => (datum.id === rootId ? '#fff' : '#666'), - labelText: (d) => d.style?.labelText || d.id, - labelTextAlign: (datum) => (datum.id === rootId ? 'center' : 'left'), - labelTextBaseline: 'top', - color: (datum: any) => { - const depth = graph.getAncestorsData(datum.id, 'tree').length - 1; - return COLORS[depth % COLORS.length] || '#576286'; + const render = useCallback( + async (data: TreeData) => { + const graph: Graph = new Graph({ + container: containerRef.current!, + x: 60, + node: { + type: 'indented', + style: { + size: (d) => [d.id.length * 6 + 10, 20], + labelBackground: (datum) => datum.id === rootId, + labelBackgroundRadius: 0, + labelBackgroundFill: '#576286', + labelFill: (datum) => (datum.id === rootId ? '#fff' : '#666'), + labelText: (d) => d.style?.labelText || d.id, + labelTextAlign: (datum) => + datum.id === rootId ? 'center' : 'left', + labelTextBaseline: 'top', + color: (datum: any) => { + const depth = graph.getAncestorsData(datum.id, 'tree').length - 1; + return COLORS[depth % COLORS.length] || '#576286'; + }, }, - }, - state: { - selected: { - lineWidth: 0, - labelFill: '#40A8FF', - labelBackground: true, - labelFontWeight: 'normal', - labelBackgroundFill: '#e8f7ff', - labelBackgroundRadius: 10, + state: { + selected: { + lineWidth: 0, + labelFill: '#40A8FF', + labelBackground: true, + labelFontWeight: 'normal', + labelBackgroundFill: '#e8f7ff', + labelBackgroundRadius: 10, + }, }, }, - }, - edge: { - type: 'indented', - style: { - radius: 16, - lineWidth: 2, - sourcePort: 'out', - targetPort: 'in', - stroke: (datum: any) => { - const depth = graph.getAncestorsData(datum.source, 'tree').length; - return COLORS[depth % COLORS.length] || 'black'; + edge: { + type: 'indented', + style: { + radius: 16, + lineWidth: 2, + sourcePort: 'out', + targetPort: 'in', + stroke: (datum: any) => { + const depth = graph.getAncestorsData(datum.source, 'tree').length; + return COLORS[depth % COLORS.length] || 'black'; + }, }, }, - }, - layout: { - type: 'indented', - direction: 'LR', - isHorizontal: true, - indent: 40, - getHeight: () => 20, - getVGap: () => 10, - }, - behaviors: [ - 'scroll-canvas', - 'collapse-expand-tree', - { - type: 'click-select', - enable: (event: any) => - event.targetType === 'node' && event.target.id !== rootId, + layout: { + type: 'indented', + direction: 'LR', + isHorizontal: true, + indent: 40, + getHeight: () => 20, + getVGap: () => 10, }, - ], - }); + behaviors: [ + 'scroll-canvas', + 'collapse-expand-tree', + { + type: 'click-select', + enable: (event: any) => + event.targetType === 'node' && event.target.id !== rootId, + }, + ], + }); - if (graphRef.current) { - graphRef.current.destroy(); - } + if (graphRef.current) { + graphRef.current.destroy(); + } - graphRef.current = graph; + graphRef.current = graph; - graph?.setData(treeToGraphData(data)); + assignIds(data); - graph?.render(); - }, []); + graph?.setData(treeToGraphData(data)); + + graph?.render(); + }, + [assignIds], + ); useEffect(() => { if (!isEmpty(data)) { diff --git a/web/src/components/llm-setting-items/index.tsx b/web/src/components/llm-setting-items/index.tsx index 841de4259dd1e661320a283c90e2ea34fe214284..f665aa0b176f19c659f42c11931a961f3dc0fc75 100644 --- a/web/src/components/llm-setting-items/index.tsx +++ b/web/src/components/llm-setting-items/index.tsx @@ -269,7 +269,7 @@ const LlmSettingItems = ({ prefix, formItemLayout = {} }: IProps) => { > @@ -278,7 +278,7 @@ const LlmSettingItems = ({ prefix, formItemLayout = {} }: IProps) => { diff --git a/web/src/components/message-input/index.less b/web/src/components/message-input/index.less index daf07479985904d4314ae9ee8fda2927962aa720..41f382d90da686662241623e5515f3f3ff7cbbef 100644 --- a/web/src/components/message-input/index.less +++ b/web/src/components/message-input/index.less @@ -1,6 +1,6 @@ .messageInputWrapper { margin-right: 20px; - background-color: #f5f5f8; + background-color: rgba(255, 255, 255, 0.1); border-radius: 8px; :global(.ant-input-affix-wrapper) { border-bottom-right-radius: 0; diff --git a/web/src/components/message-input/index.tsx b/web/src/components/message-input/index.tsx index e026581a3754d08bf23118ca73dbc1385c0bb939..a20147a509bd3e49833abe026b03395612200de2 100644 --- a/web/src/components/message-input/index.tsx +++ b/web/src/components/message-input/index.tsx @@ -27,6 +27,7 @@ import { } from 'antd'; import classNames from 'classnames'; import get from 'lodash/get'; +import { Paperclip } from 'lucide-react'; import { ChangeEventHandler, memo, @@ -36,7 +37,6 @@ import { useState, } from 'react'; import FileIcon from '../file-icon'; -import SvgIcon from '../svg-icon'; import styles from './index.less'; type FileType = Parameters>[0]; @@ -98,7 +98,6 @@ const MessageInput = ({ const { data: documentInfos, setDocumentIds } = useFetchDocumentInfosByIds(); const { uploadAndParseDocument } = useUploadAndParseDocument(uploadMethod); const conversationIdRef = useRef(conversationId); - const [fileList, setFileList] = useState([]); const handlePreview = async (file: UploadFile) => { @@ -225,14 +224,7 @@ const MessageInput = ({ )} diff --git a/web/src/components/message-item/group-button.tsx b/web/src/components/message-item/group-button.tsx index 2aac4f3b96fda7073611f82e5d3c081faa13bf02..7e656a0648960990eb5e62f015c949b437b88769 100644 --- a/web/src/components/message-item/group-button.tsx +++ b/web/src/components/message-item/group-button.tsx @@ -1,3 +1,4 @@ +import { PromptIcon } from '@/assets/icon/Icon'; import CopyToClipboard from '@/components/copy-to-clipboard'; import { useSetModalState } from '@/hooks/common-hooks'; import { IRemoveMessageById } from '@/hooks/logic-hooks'; @@ -12,7 +13,6 @@ import { import { Radio, Tooltip } from 'antd'; import { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; -import SvgIcon from '../svg-icon'; import FeedbackModal from './feedback-modal'; import { useRemoveMessage, useSendFeedback, useSpeech } from './hooks'; import PromptModal from './prompt-modal'; @@ -70,7 +70,7 @@ export const AssistantGroupButton = ({ )} {prompt && ( - + )} diff --git a/web/src/components/message-item/index.less b/web/src/components/message-item/index.less index a4fe17c8df73e23ee1f1935cbc66b08ae478428f..224210e0dd7e3aec21a179a74ace0ec2c09b9110 100644 --- a/web/src/components/message-item/index.less +++ b/web/src/components/message-item/index.less @@ -6,10 +6,6 @@ .messageItemSectionLeft { width: 80%; } - .messageItemSectionRight { - // width: 80%; - // max-width: 50vw; - } .messageItemContent { display: inline-flex; gap: 20px; @@ -36,10 +32,17 @@ background-color: #e6f4ff; word-break: break-all; } + .messageTextDark { + .chunkText(); + .messageTextBase(); + background-color: #1668dc; + word-break: break-all; + } + .messageUserText { .chunkText(); .messageTextBase(); - background-color: rgb(248, 247, 247); + background-color: rgba(255, 255, 255, 0.3); word-break: break-all; text-align: justify; } diff --git a/web/src/components/message-item/index.tsx b/web/src/components/message-item/index.tsx index bd2db7a4b2089709e1e59642b6f37d08d70547c1..eab098056c355394bb0b29ddeaab2c8dc75da4cd 100644 --- a/web/src/components/message-item/index.tsx +++ b/web/src/components/message-item/index.tsx @@ -18,6 +18,7 @@ import { Avatar, Button, Flex, List, Space, Typography } from 'antd'; import FileIcon from '../file-icon'; import IndentedTreeModal from '../indented-tree/modal'; import NewDocumentLink from '../new-document-link'; +import { useTheme } from '../theme-provider'; import { AssistantGroupButton, UserGroupButton } from './group-button'; import styles from './index.less'; @@ -47,6 +48,7 @@ const MessageItem = ({ regenerateMessage, showLikeButton = true, }: IProps) => { + const { theme } = useTheme(); const isAssistant = item.role === MessageType.Assistant; const isUser = item.role === MessageType.User; const { data: documentList, setDocumentIds } = useFetchDocumentInfosByIds(); @@ -139,7 +141,11 @@ const MessageItem = ({
{ // TODO: - const fileThumbnail = - documentThumbnails[item.id] || documentThumbnails[item.id]; + // const fileThumbnail = + // documentThumbnails[item.id] || documentThumbnails[item.id]; const fileExtension = getExtension(item.name); return ( diff --git a/web/src/components/retrieval-documents/index.tsx b/web/src/components/retrieval-documents/index.tsx index 50344370e1219f008fb091d07f005997f6304c9e..f73f0f709f72541aa3173d15a7b277be1565c699 100644 --- a/web/src/components/retrieval-documents/index.tsx +++ b/web/src/components/retrieval-documents/index.tsx @@ -35,7 +35,7 @@ const RetrievalDocuments = ({ > - {selectedDocumentIds.length ?? 0}/{documents.length} + {selectedDocumentIds?.length ?? 0}/{documents?.length ?? 0} {t('knowledgeDetails.filesSelected')} diff --git a/web/src/components/theme-provider.tsx b/web/src/components/theme-provider.tsx index d6b3eaa1c61c9fdfe26193b3fae102ba5c075540..5c9aa1b91a191b7e2cf620409635d13155f73ffc 100644 --- a/web/src/components/theme-provider.tsx +++ b/web/src/components/theme-provider.tsx @@ -1,6 +1,6 @@ -import { createContext, useContext, useEffect, useState } from 'react'; +import React, { createContext, useContext, useEffect, useState } from 'react'; -type Theme = 'dark' | 'light' | 'system'; +type Theme = 'dark' | 'light'; type ThemeProviderProps = { children: React.ReactNode; @@ -14,7 +14,7 @@ type ThemeProviderState = { }; const initialState: ThemeProviderState = { - theme: 'system', + theme: 'light', setTheme: () => null, }; @@ -22,7 +22,7 @@ const ThemeProviderContext = createContext(initialState); export function ThemeProvider({ children, - defaultTheme = 'system', + defaultTheme = 'light', storageKey = 'vite-ui-theme', ...props }: ThemeProviderProps) { @@ -32,32 +32,19 @@ export function ThemeProvider({ useEffect(() => { const root = window.document.documentElement; - root.classList.remove('light', 'dark'); - - if (theme === 'system') { - const systemTheme = window.matchMedia('(prefers-color-scheme: dark)') - .matches - ? 'dark' - : 'light'; - - root.classList.add(systemTheme); - return; - } - + localStorage.setItem(storageKey, theme); root.classList.add(theme); - }, [theme]); - - const value = { - theme, - setTheme: (theme: Theme) => { - localStorage.setItem(storageKey, theme); - setTheme(theme); - }, - }; + }, [storageKey, theme]); return ( - + {children} ); diff --git a/web/src/components/ui/navigation-menu.tsx b/web/src/components/ui/navigation-menu.tsx index ace41472a8c0d5f2dd814c46b2075d4c68f38d12..b2cdae8f6a909bbd1e24ffb71f63758ab46218ba 100644 --- a/web/src/components/ui/navigation-menu.tsx +++ b/web/src/components/ui/navigation-menu.tsx @@ -123,6 +123,6 @@ export { NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, - navigationMenuTriggerStyle, NavigationMenuViewport, + navigationMenuTriggerStyle, }; diff --git a/web/src/layouts/components/header/index.less b/web/src/layouts/components/header/index.less index fc72c7d36e48bbdb65e57fb40360a0790b77b80f..76f1078a1e82c2e99f00cc14b7a78d4507b4a99f 100644 --- a/web/src/layouts/components/header/index.less +++ b/web/src/layouts/components/header/index.less @@ -48,6 +48,66 @@ color: white; } } + :global(.ant-radio-button-wrapper-checked.dark) { + border-radius: 0px !important; + & a { + color: white; + } + } + :global(.ant-radio-button-wrapper-checked.dark.first) { + border-top-left-radius: 6px !important; + border-bottom-left-radius: 6px !important; + & a { + color: white; + } + } + :global(.ant-radio-button-wrapper-checked.dark.last) { + border-top-right-radius: 6px !important; + border-bottom-right-radius: 6px !important; + & a { + color: white; + } + } +} + +.radioGroupDark { + & label { + height: 40px; + line-height: 40px; + border: 0 !important; + background-color: rgba(249, 249, 249, 0.25); + font-weight: @fontWeight700; + color: rgba(29, 25, 41, 1); + &::before { + display: none !important; + } + } + :global(.ant-radio-button-wrapper-checked) { + border-radius: 6px !important; + & a { + color: white; + } + } + :global(.ant-radio-button-wrapper-checked.dark) { + border-radius: 0px !important; + & a { + color: white; + } + } + :global(.ant-radio-button-wrapper-checked.dark.first) { + border-top-left-radius: 6px !important; + border-bottom-left-radius: 6px !important; + & a { + color: white; + } + } + :global(.ant-radio-button-wrapper-checked.dark.last) { + border-top-right-radius: 6px !important; + border-bottom-right-radius: 6px !important; + & a { + color: white; + } + } } .ant-radio-button-wrapper-checked { @@ -55,6 +115,6 @@ } .radioButtonIcon { vertical-align: middle; - max-width: 16px; - max-height: 16px; + max-width: 15px; + max-height: 15px; } diff --git a/web/src/layouts/components/header/index.tsx b/web/src/layouts/components/header/index.tsx index e5a4954cab5be6434333d6ef37ae4f657699a992..87a6d3bdc5bd1ef6de42d72c706c4fa1c589f392 100644 --- a/web/src/layouts/components/header/index.tsx +++ b/web/src/layouts/components/header/index.tsx @@ -10,6 +10,7 @@ import { MouseEventHandler, useCallback, useMemo } from 'react'; import { useLocation } from 'umi'; import Toolbar from '../right-toolbar'; +import { useTheme } from '@/components/theme-provider'; import styles from './index.less'; const { Header } = Layout; @@ -22,7 +23,7 @@ const RagHeader = () => { const { pathname } = useLocation(); const { t } = useTranslate('header'); const appConf = useFetchAppConf(); - + const { theme: themeRag } = useTheme(); const tagsData = useMemo( () => [ { path: '/knowledge', name: t('knowledgeBase'), icon: KnowledgeBaseIcon }, @@ -78,11 +79,17 @@ const RagHeader = () => { - {tagsData.map((item) => ( - + {tagsData.map((item, index) => ( + { @@ -25,6 +27,8 @@ const handleGithubCLick = () => { const RightToolBar = () => { const { t } = useTranslate('common'); const changeLanguage = useChangeLanguage(); + const { setTheme, theme } = useTheme(); + const { data: { language = 'English' }, } = useFetchUserInfo(); @@ -40,6 +44,13 @@ const RightToolBar = () => { return [...pre!, { type: 'divider' }, cur]; }, []); + const onMoonClick = React.useCallback(() => { + setTheme('light'); + }, [setTheme]); + const onSunClick = React.useCallback(() => { + setTheme('dark'); + }, [setTheme]); + return (
@@ -52,9 +63,13 @@ const RightToolBar = () => { - {/* - - */} + + {theme === 'dark' ? ( + + ) : ( + + )} +
diff --git a/web/src/less/mixins.less b/web/src/less/mixins.less index 7501bdbb29c0132a2c7e525344c6a441283b02f8..078be91827ae618f2598a0ae2f532ab170c82730 100644 --- a/web/src/less/mixins.less +++ b/web/src/less/mixins.less @@ -38,7 +38,7 @@ } tr:nth-child(even) { - background-color: #f2f2f2; + background-color: #f2f2f22a; } } diff --git a/web/src/less/variable.less b/web/src/less/variable.less index 0c88307115959db4bd5f2ec05d480435e226c332..3a180347958dc52b1d4735ea5e4be7332c068c9d 100644 --- a/web/src/less/variable.less +++ b/web/src/less/variable.less @@ -1,7 +1,7 @@ @fontWeight600: 600; @fontWeight700: 700; -@grayBackground: rgba(247, 248, 250, 1); +@grayBackground: rgba(247, 248, 250, 0.1); @gray2: rgba(29, 25, 41, 1); @gray3: rgba(52, 48, 62, 1); @gray8: rgba(165, 163, 169, 1); diff --git a/web/src/locales/config.ts b/web/src/locales/config.ts index a547003f2fcc11b613928dde87a2ccbc1e815576..0da80e594df0c832ac60b67dd4e44580889d193e 100644 --- a/web/src/locales/config.ts +++ b/web/src/locales/config.ts @@ -2,6 +2,7 @@ import i18n from 'i18next'; import LanguageDetector from 'i18next-browser-languagedetector'; import { initReactI18next } from 'react-i18next'; +import { createTranslationTable, flattenObject } from './until'; import translation_en from './en'; import translation_es from './es'; import translation_id from './id'; @@ -19,7 +20,15 @@ const resources = { es: translation_es, vi: translation_vi, }; - +const enFlattened = flattenObject(translation_en); +const viFlattened = flattenObject(translation_vi); +const esFlattened = flattenObject(translation_es); +const zhFlattened = flattenObject(translation_zh); +const zh_traditionalFlattened = flattenObject(translation_zh_traditional); +export const translationTable = createTranslationTable( + [enFlattened, viFlattened, esFlattened, zhFlattened, zh_traditionalFlattened], + ['English', 'Vietnamese', 'Spanish', 'zh', 'zh-TRADITIONAL'], +); i18n .use(initReactI18next) .use(LanguageDetector) diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index 2526eb324f9268608deb16c55f453bc3eb7c1360..06ec1c56fd73243ad717609e0eb29bf102152194 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -303,9 +303,9 @@ The above is the content you need to summarize.`, randomSeed: 'Random seed', randomSeedMessage: 'Random seed is required', entityTypes: 'Entity types', + vietnamese: 'Vietamese', pageRank: 'Page rank', - pageRankTip: `This is used to boost the relevance score. The relevance score with all the retrieved chunks will plus this number. -When you want to search the given knowledge base at first place, set a higher pagerank score than others.`, + pageRankTip: `This is used to boost the relevance score. The relevance score with all the retrieved chunks will plus this number, When you want to search the given knowledge base at first place, set a higher pagerank score than others.`, }, chunk: { chunk: 'Chunk', diff --git a/web/src/locales/es.ts b/web/src/locales/es.ts index c251c494a48f2d2e57a2e9b16de7c2e7fb5043ae..680e6acf0620df1a36915b410f9a9703a0b66fda 100644 --- a/web/src/locales/es.ts +++ b/web/src/locales/es.ts @@ -277,6 +277,7 @@ export default { multiTurn: 'Optimización de múltiples turnos', multiTurnTip: 'En conversaciones de múltiples rondas, la consulta a la base de conocimiento se optimiza. El gran modelo se llamará para consumir tokens adicionales.', + description: 'Description of assistant', }, setting: { profile: 'Perfil', diff --git a/web/src/locales/id.ts b/web/src/locales/id.ts index 0ac64fd38e1eda400149bc6d95b815470c6a2a0c..2ebe7f4cfcb51630f48303f0a97d7c12eaf46502 100644 --- a/web/src/locales/id.ts +++ b/web/src/locales/id.ts @@ -449,6 +449,7 @@ export default { multiTurnTip: 'Dalam percakapan multi-putaran, kueri ke basis pengetahuan dioptimalkan. Model besar akan dipanggil untuk mengonsumsi token tambahan.', languageSelectionTip: 'Pilih bahasa yang digunakan dalam percakapan.', + description: 'Description of assistant', }, setting: { profile: 'Profil', @@ -748,7 +749,7 @@ export default { bingTip: 'Komponen ini digunakan untuk mendapatkan hasil pencarian dari https://www.bing.com/. Biasanya, ini berfungsi sebagai pelengkap basis pengetahuan. Top N dan Kunci Langganan Bing menentukan jumlah hasil pencarian yang perlu Anda sesuaikan.', apiKey: 'Kunci API', - country: 'Negara&Wilayah', + country: 'Negara', language: 'Bahasa', googleScholar: 'Google Scholar', googleScholarDescription: diff --git a/web/src/locales/until.ts b/web/src/locales/until.ts new file mode 100644 index 0000000000000000000000000000000000000000..9934a97570bf957f208770580aac024aa0de51bd --- /dev/null +++ b/web/src/locales/until.ts @@ -0,0 +1,60 @@ +type NestedObject = { + [key: string]: string | NestedObject; +}; + +type FlattenedObject = { + [key: string]: string; +}; + +export function flattenObject( + obj: NestedObject, + parentKey: string = '', +): FlattenedObject { + const result: FlattenedObject = {}; + + for (const [key, value] of Object.entries(obj)) { + const newKey = parentKey ? `${parentKey}.${key}` : key; + + if (typeof value === 'object' && value !== null) { + Object.assign(result, flattenObject(value as NestedObject, newKey)); + } else { + result[newKey] = value as string; + } + } + + return result; +} +type TranslationTableRow = { + key: string; + [language: string]: string; +}; + +/** + * Creates a translation table from multiple flattened language objects. + * @param langs - A list of flattened language objects. + * @param langKeys - A list of language identifiers (e.g., 'English', 'Vietnamese'). + * @returns An array representing the translation table. + */ +export function createTranslationTable( + langs: FlattenedObject[], + langKeys: string[], +): TranslationTableRow[] { + const keys = new Set(); + + // Collect all unique keys from the language objects + langs.forEach((lang) => { + Object.keys(lang).forEach((key) => keys.add(key)); + }); + + // Build the table + return Array.from(keys).map((key) => { + const row: TranslationTableRow = { key }; + + langs.forEach((lang, index) => { + const langKey = langKeys[index]; + row[langKey] = lang[key] || ''; // Use empty string if key is missing + }); + + return row; + }); +} diff --git a/web/src/locales/vi.ts b/web/src/locales/vi.ts index bb95ee6f61b2b75a462848a9207f9fddcd76fe0b..dad864716fa8e149012706785300b083584a6f6b 100644 --- a/web/src/locales/vi.ts +++ b/web/src/locales/vi.ts @@ -34,6 +34,7 @@ export default { pleaseInput: 'Vui lòng nhập', submit: 'Gửi', vietnamese: 'Tiếng việt', + spanish: 'Tiếng Tây Ban Nha', }, login: { login: 'Đăng nhập', @@ -76,6 +77,7 @@ export default { namePlaceholder: 'Vui lòng nhập tên!', doc: 'Tài liệu', searchKnowledgePlaceholder: 'Tìm kiếm', + noMoreData: 'Tất cả chỉ có thế, không còn gì nữa', }, knowledgeDetails: { dataset: 'Dữ liệu', @@ -162,6 +164,7 @@ export default { autoKeywordsTip: `Trích xuất N từ khóa cho mỗi khối để tăng thứ hạng của chúng cho các truy vấn chứa các từ khóa đó. Bạn có thể kiểm tra hoặc cập nhật các từ khóa đã thêm cho một khối từ danh sách khối. Lưu ý rằng các token bổ sung sẽ được tiêu thụ bởi LLM được chỉ định trong 'Cài đặt mô hình hệ thống'.`, autoQuestions: 'Câu hỏi tự động', autoQuestionsTip: `Trích xuất N câu hỏi cho mỗi khối để tăng thứ hạng của chúng cho các truy vấn chứa các câu hỏi đó. Bạn có thể kiểm tra hoặc cập nhật các câu hỏi đã thêm cho một khối từ danh sách khối. Tính năng này sẽ không làm gián đoạn quá trình phân khối nếu xảy ra lỗi, ngoại trừ việc nó có thể thêm kết quả trống vào khối gốc. Lưu ý rằng các token bổ sung sẽ được tiêu thụ bởi LLM được chỉ định trong 'Cài đặt mô hình hệ thống'.`, + delimiterTip: `Hỗ trợ nhiều ký tự phân cách, và các ký tự phân cách nhiều ký tự được bao bọc bởi dấu . Ví dụ: nếu được cấu hình như thế này: "##"; thì văn bản sẽ được phân tách bởi dấu xuống dòng, hai dấu # và dấu chấm phẩy, sau đó được lắp ráp theo kích thước của "số token".`, }, knowledgeConfiguration: { titleDescription: @@ -297,6 +300,9 @@ export default { randomSeed: 'Hạt giống ngẫu nhiên', randomSeedMessage: 'Hạt giống ngẫu nhiên là bắt buộc', entityTypes: 'Loại thực thể', + vietnamese: 'Tiếng Việt', + pageRank: 'Xếp hạng trang', + pageRankTip: `Điều này được sử dụng để tăng điểm liên quan. Điểm liên quan với tất cả các khối được truy xuất sẽ cộng với số này, Khi bạn muốn tìm kiếm cơ sở kiến ​​thức đã cho ở vị trí đầu tiên, hãy đặt điểm "Page Rank" cao hơn những điểm khác.`, }, chunk: { chunk: 'Khối', @@ -316,6 +322,9 @@ export default { ellipse: 'Elip', graph: 'Biểu đồ kiến thức', mind: 'Sơ đồ tư duy', + question: 'Câu hỏi', + questionTip: + 'Nếu có những câu hỏi được đưa ra, việc nhúng phần đó sẽ dựa trên những câu hỏi đó.', }, chat: { newConversation: 'Cuộc trò chuyện mới', @@ -593,6 +602,12 @@ export default { refuse: 'Từ chối', teamMembers: 'Thành viên nhóm', joinedTeams: 'Nhóm đã tham gia', + bedrockModelNameMessage: `Vui lòng nhập tên model của bạn!`, + sureDelete: `Bạn có chắc chắn muốn xóa thành viên này không?`, + quit: `Rời khỏi`, + sureQuit: `Bạn có chắc chắn muốn rời khỏi nhóm mà bạn đã tham gia không?`, + FishAudioAKMessage: `Vui lòng nhập KEY API`, + FishAudioRefIDMessage: `Vui lòng nhập ID của model tham chiếu (để trống để sử dụng model mặc định)`, }, message: { registered: 'Đã đăng ký!', @@ -625,8 +640,8 @@ export default { requestError: 'Lỗi yêu cầu', networkAnomalyDescription: 'Mạng của bạn có sự bất thường và bạn không thể kết nối với máy chủ.', - networkAnomaly: 'bất thường mạng', - hint: 'gợi ý', + networkAnomaly: 'Bất thường mạng', + hint: 'Gợi ý', }, fileManager: { name: 'Tên', @@ -1033,6 +1048,27 @@ export default { optional: 'Tùy chọn', pasteFileLink: 'Dán liên kết tệp', testRun: 'Chạy thử nghiệm', + template: 'Mẫu', + templateDescription: `Thành phần này được sử dụng để sắp chữ đầu ra của nhiều thành phần khác nhau.`, + arXivTip: `Thành phần này được sử dụng để lấy kết quả tìm kiếm từ https://arxiv.org/. Thông thường, nó hoạt động như một phần bổ sung cho cơ sở tri thức. Top N chỉ định số lượng kết quả tìm kiếm bạn cần điều chỉnh.`, + googleTip: `Thành phần này được sử dụng để lấy kết quả tìm kiếm từ https://www.google.com/. Thông thường, nó hoạt động như một phần bổ sung cho cơ sở tri thức. Top N và khóa API SerpApi chỉ định số lượng kết quả tìm kiếm bạn cần điều chỉnh.`, + bingTip: `Thành phần này được sử dụng để lấy kết quả tìm kiếm từ https://www.bing.com/. Thông thường, nó hoạt động như một phần bổ sung cho cơ sở tri thức. Top N và khóa đăng ký Bing chỉ định số lượng kết quả tìm kiếm bạn cần điều chỉnh.`, + gitHubDescription: `Thành phần này được sử dụng để tìm kiếm các kho lưu trữ từ https://github.com/. Top N chỉ định số lượng kết quả tìm kiếm cần điều chỉnh.`, + flow: `Quy trình làm việc`, + emailDescription: 'Gửi email đến địa chỉ đã chỉ định', + toEmail: 'Email người nhận', + smtpServerRequired: 'Vui lòng nhập địa chỉ máy chủ SMTP', + emailContent: 'Nội dung', + smtpServer: 'SMTP Server', + smtpPort: 'SMTP Port', + senderEmailRequired: 'Vui lòng nhập email người gửi', + authCodeRequired: 'Vui lòng nhập mã xác thực', + toEmailRequired: 'Vui lòng nhập email người nhận', + emailContentRequired: 'Vui lòng nhập nội dung email', + emailSentSuccess: 'Email đã được gửi thành công', + emailSentFailed: 'Không gửi được email', + jsonFormatTip: + 'Thành phần thượng nguồn phải cung cấp chuỗi JSON theo định dạng sau:', }, footer: { profile: 'All rights reserved @ React', diff --git a/web/src/locales/zh-traditional.ts b/web/src/locales/zh-traditional.ts index 81d0d5a104b6e72d71a7f536168fc6d85665ef65..8c1bcf904a45fed6dcd34261c3e79fa5a44753aa 100644 --- a/web/src/locales/zh-traditional.ts +++ b/web/src/locales/zh-traditional.ts @@ -428,6 +428,7 @@ export default { multiTurnTip: '在多輪對話的中,對去知識庫查詢的問題進行最佳化。會呼叫大模型額外消耗token。', howUseId: '如何使用聊天ID?', + description: '助理描述', }, setting: { profile: '概述', diff --git a/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-card/index.less b/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-card/index.less index 02e74426cd4b3b36bd4455e3f0c73a4bfdba41ac..127a5c790c9518682b3395dfd982a2a6cf554741 100644 --- a/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-card/index.less +++ b/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-card/index.less @@ -29,3 +29,6 @@ .cardSelected { background-color: @selectedBackgroundColor; } +.cardSelectedDark { + background-color: #ffffff2f; +} diff --git a/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-card/index.tsx b/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-card/index.tsx index 5666febc5ff6dba47b7ddd5f6b78bff7b7c5ed32..5934eb309b16d5bebd797822dd093ac0334823d7 100644 --- a/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-card/index.tsx +++ b/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-card/index.tsx @@ -5,6 +5,7 @@ import classNames from 'classnames'; import DOMPurify from 'dompurify'; import { useEffect, useState } from 'react'; +import { useTheme } from '@/components/theme-provider'; import { ChunkTextMode } from '../../constant'; import styles from './index.less'; @@ -31,6 +32,7 @@ const ChunkCard = ({ }: IProps) => { const available = Number(item.available_int); const [enabled, setEnabled] = useState(false); + const { theme } = useTheme(); const onChange = (checked: boolean) => { setEnabled(checked); @@ -56,7 +58,8 @@ const ChunkCard = ({ return ( diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/category-panel.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/category-panel.tsx index c4eb8ab6508da66416938094cab1647362516b46..ba58003c69a2800acb0b2096287ef3532d3bfbfa 100644 --- a/web/src/pages/add-knowledge/components/knowledge-setting/category-panel.tsx +++ b/web/src/pages/add-knowledge/components/knowledge-setting/category-panel.tsx @@ -37,16 +37,14 @@ const CategoryPanel = ({ chunkMethod }: { chunkMethod: string }) => { {imageList.length > 0 ? ( <> - "{item.title}" {t('methodTitle')} + {`"${item.title}" ${t('methodTitle')}`}

- - "{item.title}" {t('methodExamples')} - + {`"${item.title}" ${t('methodExamples')}`} {t('methodExamplesDescription')} {imageList.map((x) => ( diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/configuration.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/configuration.tsx index 564ce6e187de2e87298c1ebd33ef44e164f484fd..10494e45f79159bf20cecee6530807fccd345cef 100644 --- a/web/src/pages/add-knowledge/components/knowledge-setting/configuration.tsx +++ b/web/src/pages/add-knowledge/components/knowledge-setting/configuration.tsx @@ -70,6 +70,7 @@ const ConfigurationForm = ({ form }: { form: FormInstance }) => { { > - {selectedDocumentIds?.length ?? 0}/{documents.length} + {selectedDocumentIds?.length ?? 0}/{documents?.length ?? 0} {t('filesSelected')} @@ -105,7 +105,7 @@ const TestingResult = ({ handleTesting }: IProps) => { flex={1} className={styles.selectFilesCollapse} > - {chunks.map((x) => ( + {chunks?.map((x) => ( }> {x.img_id && ( diff --git a/web/src/pages/add-knowledge/index.less b/web/src/pages/add-knowledge/index.less index bd8f3ecd37711934da5dd520e3a06f6aaad6c140..dc934280cbe72ca8df431bafec00d7b9bb4df25e 100644 --- a/web/src/pages/add-knowledge/index.less +++ b/web/src/pages/add-knowledge/index.less @@ -6,13 +6,13 @@ flex: 1; overflow-x: auto; height: 100%; - background-color: rgba(247, 248, 250, 1); + background-color: rgba(255, 255, 255, 0.1); padding: 16px 20px 28px 40px; display: flex; flex-direction: column; } .content { - background-color: white; + background-color: rgba(255, 255, 255, 0.1); margin-top: 16px; flex: 1; } diff --git a/web/src/pages/chat/chat-configuration-modal/model-setting.tsx b/web/src/pages/chat/chat-configuration-modal/model-setting.tsx index aac34cd2af2f931ee3d89386d3f986784bead6f2..6c0c9d13bd15085e5e5ecb43dd444e19b676ba64 100644 --- a/web/src/pages/chat/chat-configuration-modal/model-setting.tsx +++ b/web/src/pages/chat/chat-configuration-modal/model-setting.tsx @@ -42,224 +42,6 @@ const ModelSetting = ({ })} > {visible && } - {/* -