balibabu
commited on
Commit
·
a432686
1
Parent(s):
be98b1d
Feat: Modify the data structure of the chunk in the conversation #3909 (#3955)
Browse files### What problem does this PR solve?
Feat: Modify the data structure of the chunk in the conversation #3909
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- web/src/components/api-service/chat-api-key-modal/index.tsx +1 -1
- web/src/components/api-service/chat-overview-modal/api-content.tsx +9 -8
- web/src/components/api-service/embed-modal/index.less +4 -0
- web/src/components/api-service/embed-modal/index.tsx +32 -3
- web/src/components/api-service/hooks.ts +37 -18
- web/src/components/message-item/index.tsx +2 -3
- web/src/components/pdf-drawer/hooks.ts +5 -3
- web/src/components/pdf-drawer/index.tsx +2 -1
- web/src/components/pdf-previewer/index.tsx +4 -3
- web/src/hooks/chat-hooks.ts +7 -1
- web/src/hooks/document-hooks.ts +4 -1
- web/src/hooks/logic-hooks.ts +2 -0
- web/src/hooks/user-setting-hooks.tsx +21 -3
- web/src/interfaces/database/chat.ts +16 -3
- web/src/locales/config.ts +1 -1
- web/src/locales/en.ts +1 -0
- web/src/locales/ja.ts +15 -18
- web/src/locales/zh-traditional.ts +1 -0
- web/src/locales/zh.ts +1 -0
- web/src/pages/chat/index.tsx +18 -17
- web/src/pages/chat/markdown-content/index.tsx +9 -9
- web/src/pages/chat/share/large.tsx +23 -8
- web/src/pages/chat/shared-hooks.ts +35 -72
- web/src/pages/flow/header/index.tsx +26 -21
- web/src/pages/flow/hooks.tsx +14 -0
- web/src/utils/authorization-util.ts +3 -3
- web/src/utils/document-util.ts +8 -2
web/src/components/api-service/chat-api-key-modal/index.tsx
CHANGED
@@ -63,7 +63,7 @@ const ChatApiKeyModal = ({
|
|
63 |
<Button
|
64 |
onClick={createToken}
|
65 |
loading={creatingLoading}
|
66 |
-
disabled={tokenList
|
67 |
>
|
68 |
{t('createNewKey')}
|
69 |
</Button>
|
|
|
63 |
<Button
|
64 |
onClick={createToken}
|
65 |
loading={creatingLoading}
|
66 |
+
disabled={tokenList?.length > 0}
|
67 |
>
|
68 |
{t('createNewKey')}
|
69 |
</Button>
|
web/src/components/api-service/chat-overview-modal/api-content.tsx
CHANGED
@@ -3,8 +3,7 @@ import apiDoc from '@parent/docs/references/http_api_reference.md';
|
|
3 |
import MarkdownPreview from '@uiw/react-markdown-preview';
|
4 |
import { Button, Card, Flex, Space } from 'antd';
|
5 |
import ChatApiKeyModal from '../chat-api-key-modal';
|
6 |
-
import
|
7 |
-
import { usePreviewChat, useShowEmbedModal } from '../hooks';
|
8 |
import BackendServiceApi from './backend-service-api';
|
9 |
|
10 |
const ApiContent = ({
|
@@ -22,10 +21,10 @@ const ApiContent = ({
|
|
22 |
hideModal: hideApiKeyModal,
|
23 |
showModal: showApiKeyModal,
|
24 |
} = useSetModalState();
|
25 |
-
const { embedVisible, hideEmbedModal, showEmbedModal, embedToken } =
|
26 |
-
|
27 |
|
28 |
-
const { handlePreview } = usePreviewChat(idKey
|
29 |
|
30 |
return (
|
31 |
<div>
|
@@ -36,7 +35,9 @@ const ApiContent = ({
|
|
36 |
<Flex gap={8} vertical>
|
37 |
<Space size={'middle'}>
|
38 |
<Button onClick={handlePreview}>{t('preview')}</Button>
|
39 |
-
<Button onClick={showEmbedModal
|
|
|
|
|
40 |
</Space>
|
41 |
</Flex>
|
42 |
</Card>
|
@@ -50,13 +51,13 @@ const ApiContent = ({
|
|
50 |
idKey={idKey}
|
51 |
></ChatApiKeyModal>
|
52 |
)}
|
53 |
-
{embedVisible && (
|
54 |
<EmbedModal
|
55 |
token={embedToken}
|
56 |
visible={embedVisible}
|
57 |
hideModal={hideEmbedModal}
|
58 |
></EmbedModal>
|
59 |
-
)}
|
60 |
</div>
|
61 |
);
|
62 |
};
|
|
|
3 |
import MarkdownPreview from '@uiw/react-markdown-preview';
|
4 |
import { Button, Card, Flex, Space } from 'antd';
|
5 |
import ChatApiKeyModal from '../chat-api-key-modal';
|
6 |
+
import { usePreviewChat } from '../hooks';
|
|
|
7 |
import BackendServiceApi from './backend-service-api';
|
8 |
|
9 |
const ApiContent = ({
|
|
|
21 |
hideModal: hideApiKeyModal,
|
22 |
showModal: showApiKeyModal,
|
23 |
} = useSetModalState();
|
24 |
+
// const { embedVisible, hideEmbedModal, showEmbedModal, embedToken } =
|
25 |
+
// useShowEmbedModal(idKey);
|
26 |
|
27 |
+
const { handlePreview } = usePreviewChat(idKey);
|
28 |
|
29 |
return (
|
30 |
<div>
|
|
|
35 |
<Flex gap={8} vertical>
|
36 |
<Space size={'middle'}>
|
37 |
<Button onClick={handlePreview}>{t('preview')}</Button>
|
38 |
+
{/* <Button onClick={() => showEmbedModal(id)}>
|
39 |
+
{t('embedded')}
|
40 |
+
</Button> */}
|
41 |
</Space>
|
42 |
</Flex>
|
43 |
</Card>
|
|
|
51 |
idKey={idKey}
|
52 |
></ChatApiKeyModal>
|
53 |
)}
|
54 |
+
{/* {embedVisible && (
|
55 |
<EmbedModal
|
56 |
token={embedToken}
|
57 |
visible={embedVisible}
|
58 |
hideModal={hideEmbedModal}
|
59 |
></EmbedModal>
|
60 |
+
)} */}
|
61 |
</div>
|
62 |
);
|
63 |
};
|
web/src/components/api-service/embed-modal/index.less
CHANGED
@@ -6,3 +6,7 @@
|
|
6 |
padding: 10px;
|
7 |
background-color: #ffffff09;
|
8 |
}
|
|
|
|
|
|
|
|
|
|
6 |
padding: 10px;
|
7 |
background-color: #ffffff09;
|
8 |
}
|
9 |
+
|
10 |
+
.id {
|
11 |
+
.linkText();
|
12 |
+
}
|
web/src/components/api-service/embed-modal/index.tsx
CHANGED
@@ -1,21 +1,33 @@
|
|
1 |
import CopyToClipboard from '@/components/copy-to-clipboard';
|
2 |
import HightLightMarkdown from '@/components/highlight-markdown';
|
|
|
3 |
import { useTranslate } from '@/hooks/common-hooks';
|
4 |
import { IModalProps } from '@/interfaces/common';
|
5 |
-
import { Card, Modal, Tabs, TabsProps } from 'antd';
|
|
|
6 |
import styles from './index.less';
|
7 |
|
|
|
|
|
8 |
const EmbedModal = ({
|
9 |
visible,
|
10 |
hideModal,
|
11 |
token = '',
|
12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
const { t } = useTranslate('chat');
|
14 |
|
15 |
const text = `
|
16 |
~~~ html
|
17 |
<iframe
|
18 |
-
src="${location.origin}/chat/share?shared_id=${token}"
|
19 |
style="width: 100%; height: 100%; min-height: 600px"
|
20 |
frameborder="0"
|
21 |
>
|
@@ -63,6 +75,23 @@ const EmbedModal = ({
|
|
63 |
onCancel={hideModal}
|
64 |
>
|
65 |
<Tabs defaultActiveKey="1" items={items} onChange={onChange} />
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
66 |
</Modal>
|
67 |
);
|
68 |
};
|
|
|
1 |
import CopyToClipboard from '@/components/copy-to-clipboard';
|
2 |
import HightLightMarkdown from '@/components/highlight-markdown';
|
3 |
+
import { SharedFrom } from '@/constants/chat';
|
4 |
import { useTranslate } from '@/hooks/common-hooks';
|
5 |
import { IModalProps } from '@/interfaces/common';
|
6 |
+
import { Card, Modal, Tabs, TabsProps, Typography } from 'antd';
|
7 |
+
|
8 |
import styles from './index.less';
|
9 |
|
10 |
+
const { Paragraph, Link } = Typography;
|
11 |
+
|
12 |
const EmbedModal = ({
|
13 |
visible,
|
14 |
hideModal,
|
15 |
token = '',
|
16 |
+
form,
|
17 |
+
beta = '',
|
18 |
+
isAgent,
|
19 |
+
}: IModalProps<any> & {
|
20 |
+
token: string;
|
21 |
+
form: SharedFrom;
|
22 |
+
beta: string;
|
23 |
+
isAgent: boolean;
|
24 |
+
}) => {
|
25 |
const { t } = useTranslate('chat');
|
26 |
|
27 |
const text = `
|
28 |
~~~ html
|
29 |
<iframe
|
30 |
+
src="${location.origin}/chat/share?shared_id=${token}&from=${form}&auth=${beta}"
|
31 |
style="width: 100%; height: 100%; min-height: 600px"
|
32 |
frameborder="0"
|
33 |
>
|
|
|
75 |
onCancel={hideModal}
|
76 |
>
|
77 |
<Tabs defaultActiveKey="1" items={items} onChange={onChange} />
|
78 |
+
<div className="text-base font-medium mt-4 mb-1">
|
79 |
+
{t(isAgent ? 'flow' : 'chat', { keyPrefix: 'header' })}
|
80 |
+
<span className="ml-1 inline-block">ID</span>
|
81 |
+
</div>
|
82 |
+
<Paragraph copyable={{ text: token }} className={styles.id}>
|
83 |
+
{token}
|
84 |
+
</Paragraph>
|
85 |
+
<Link
|
86 |
+
href={
|
87 |
+
isAgent
|
88 |
+
? 'https://ragflow.io/docs/dev/http_api_reference#create-session-with-an-agent'
|
89 |
+
: 'https://ragflow.io/docs/dev/http_api_reference#create-session-with-chat-assistant'
|
90 |
+
}
|
91 |
+
target="_blank"
|
92 |
+
>
|
93 |
+
{t('howUseId')}
|
94 |
+
</Link>
|
95 |
</Modal>
|
96 |
);
|
97 |
};
|
web/src/components/api-service/hooks.ts
CHANGED
@@ -6,6 +6,7 @@ import {
|
|
6 |
} from '@/hooks/common-hooks';
|
7 |
import {
|
8 |
useCreateSystemToken,
|
|
|
9 |
useFetchSystemTokenList,
|
10 |
useRemoveSystemToken,
|
11 |
} from '@/hooks/user-setting-hooks';
|
@@ -17,9 +18,7 @@ import { useCallback } from 'react';
|
|
17 |
export const useOperateApiKey = (idKey: string, dialogId?: string) => {
|
18 |
const { removeToken } = useRemoveSystemToken();
|
19 |
const { createToken, loading: creatingLoading } = useCreateSystemToken();
|
20 |
-
const { data: tokenList, loading: listLoading } = useFetchSystemTokenList(
|
21 |
-
[idKey]: dialogId,
|
22 |
-
});
|
23 |
|
24 |
const showDeleteConfirm = useShowDeleteConfirm();
|
25 |
|
@@ -72,49 +71,68 @@ export const useShowTokenEmptyError = () => {
|
|
72 |
return { showTokenEmptyError };
|
73 |
};
|
74 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
const getUrlWithToken = (token: string, from: string = 'chat') => {
|
76 |
const { protocol, host } = window.location;
|
77 |
return `${protocol}//${host}/chat/share?shared_id=${token}&from=${from}`;
|
78 |
};
|
79 |
|
80 |
-
const useFetchTokenListBeforeOtherStep = (
|
81 |
const { showTokenEmptyError } = useShowTokenEmptyError();
|
|
|
|
|
|
|
|
|
82 |
|
83 |
-
|
84 |
-
|
85 |
-
});
|
86 |
|
87 |
-
|
|
|
|
|
|
|
|
|
|
|
88 |
Array.isArray(tokenList) && tokenList.length > 0 ? tokenList[0].token : '';
|
89 |
|
90 |
const handleOperate = useCallback(async () => {
|
91 |
-
const ret = await
|
92 |
-
const list = ret
|
93 |
if (Array.isArray(list) && list.length > 0) {
|
|
|
|
|
|
|
|
|
94 |
return list[0]?.token;
|
95 |
} else {
|
96 |
showTokenEmptyError();
|
97 |
return false;
|
98 |
}
|
99 |
-
}, [
|
100 |
|
101 |
return {
|
102 |
token,
|
|
|
103 |
handleOperate,
|
104 |
};
|
105 |
};
|
106 |
|
107 |
-
export const useShowEmbedModal = (
|
108 |
const {
|
109 |
visible: embedVisible,
|
110 |
hideModal: hideEmbedModal,
|
111 |
showModal: showEmbedModal,
|
112 |
} = useSetModalState();
|
113 |
|
114 |
-
const { handleOperate, token } = useFetchTokenListBeforeOtherStep(
|
115 |
-
idKey,
|
116 |
-
dialogId,
|
117 |
-
);
|
118 |
|
119 |
const handleShowEmbedModal = useCallback(async () => {
|
120 |
const succeed = await handleOperate();
|
@@ -128,11 +146,12 @@ export const useShowEmbedModal = (idKey: string, dialogId?: string) => {
|
|
128 |
hideEmbedModal,
|
129 |
embedVisible,
|
130 |
embedToken: token,
|
|
|
131 |
};
|
132 |
};
|
133 |
|
134 |
-
export const usePreviewChat = (idKey: string
|
135 |
-
const { handleOperate } = useFetchTokenListBeforeOtherStep(
|
136 |
|
137 |
const open = useCallback(
|
138 |
(t: string) => {
|
|
|
6 |
} from '@/hooks/common-hooks';
|
7 |
import {
|
8 |
useCreateSystemToken,
|
9 |
+
useFetchManualSystemTokenList,
|
10 |
useFetchSystemTokenList,
|
11 |
useRemoveSystemToken,
|
12 |
} from '@/hooks/user-setting-hooks';
|
|
|
18 |
export const useOperateApiKey = (idKey: string, dialogId?: string) => {
|
19 |
const { removeToken } = useRemoveSystemToken();
|
20 |
const { createToken, loading: creatingLoading } = useCreateSystemToken();
|
21 |
+
const { data: tokenList, loading: listLoading } = useFetchSystemTokenList();
|
|
|
|
|
22 |
|
23 |
const showDeleteConfirm = useShowDeleteConfirm();
|
24 |
|
|
|
71 |
return { showTokenEmptyError };
|
72 |
};
|
73 |
|
74 |
+
export const useShowBetaEmptyError = () => {
|
75 |
+
const { t } = useTranslate('chat');
|
76 |
+
|
77 |
+
const showBetaEmptyError = useCallback(() => {
|
78 |
+
message.error(t('betaError'));
|
79 |
+
}, [t]);
|
80 |
+
return { showBetaEmptyError };
|
81 |
+
};
|
82 |
+
|
83 |
const getUrlWithToken = (token: string, from: string = 'chat') => {
|
84 |
const { protocol, host } = window.location;
|
85 |
return `${protocol}//${host}/chat/share?shared_id=${token}&from=${from}`;
|
86 |
};
|
87 |
|
88 |
+
const useFetchTokenListBeforeOtherStep = () => {
|
89 |
const { showTokenEmptyError } = useShowTokenEmptyError();
|
90 |
+
const { showBetaEmptyError } = useShowBetaEmptyError();
|
91 |
+
|
92 |
+
const { data: tokenList, fetchSystemTokenList } =
|
93 |
+
useFetchManualSystemTokenList();
|
94 |
|
95 |
+
let token = '',
|
96 |
+
beta = '';
|
|
|
97 |
|
98 |
+
if (Array.isArray(tokenList) && tokenList.length > 0) {
|
99 |
+
token = tokenList[0].token;
|
100 |
+
beta = tokenList[0].beta;
|
101 |
+
}
|
102 |
+
|
103 |
+
token =
|
104 |
Array.isArray(tokenList) && tokenList.length > 0 ? tokenList[0].token : '';
|
105 |
|
106 |
const handleOperate = useCallback(async () => {
|
107 |
+
const ret = await fetchSystemTokenList();
|
108 |
+
const list = ret;
|
109 |
if (Array.isArray(list) && list.length > 0) {
|
110 |
+
if (!list[0].beta) {
|
111 |
+
showBetaEmptyError();
|
112 |
+
return false;
|
113 |
+
}
|
114 |
return list[0]?.token;
|
115 |
} else {
|
116 |
showTokenEmptyError();
|
117 |
return false;
|
118 |
}
|
119 |
+
}, [fetchSystemTokenList, showBetaEmptyError, showTokenEmptyError]);
|
120 |
|
121 |
return {
|
122 |
token,
|
123 |
+
beta,
|
124 |
handleOperate,
|
125 |
};
|
126 |
};
|
127 |
|
128 |
+
export const useShowEmbedModal = () => {
|
129 |
const {
|
130 |
visible: embedVisible,
|
131 |
hideModal: hideEmbedModal,
|
132 |
showModal: showEmbedModal,
|
133 |
} = useSetModalState();
|
134 |
|
135 |
+
const { handleOperate, token, beta } = useFetchTokenListBeforeOtherStep();
|
|
|
|
|
|
|
136 |
|
137 |
const handleShowEmbedModal = useCallback(async () => {
|
138 |
const succeed = await handleOperate();
|
|
|
146 |
hideEmbedModal,
|
147 |
embedVisible,
|
148 |
embedToken: token,
|
149 |
+
beta,
|
150 |
};
|
151 |
};
|
152 |
|
153 |
+
export const usePreviewChat = (idKey: string) => {
|
154 |
+
const { handleOperate } = useFetchTokenListBeforeOtherStep();
|
155 |
|
156 |
const open = useCallback(
|
157 |
(t: string) => {
|
web/src/components/message-item/index.tsx
CHANGED
@@ -1,8 +1,7 @@
|
|
1 |
import { ReactComponent as AssistantIcon } from '@/assets/svg/assistant.svg';
|
2 |
import { MessageType } from '@/constants/chat';
|
3 |
import { useSetModalState } from '@/hooks/common-hooks';
|
4 |
-
import { IReference } from '@/interfaces/database/chat';
|
5 |
-
import { IChunk } from '@/interfaces/database/knowledge';
|
6 |
import classNames from 'classnames';
|
7 |
import { memo, useCallback, useEffect, useMemo, useState } from 'react';
|
8 |
|
@@ -31,7 +30,7 @@ interface IProps extends Partial<IRemoveMessageById>, IRegenerateMessage {
|
|
31 |
sendLoading?: boolean;
|
32 |
nickname?: string;
|
33 |
avatar?: string;
|
34 |
-
clickDocumentButton?: (documentId: string, chunk:
|
35 |
index: number;
|
36 |
showLikeButton?: boolean;
|
37 |
}
|
|
|
1 |
import { ReactComponent as AssistantIcon } from '@/assets/svg/assistant.svg';
|
2 |
import { MessageType } from '@/constants/chat';
|
3 |
import { useSetModalState } from '@/hooks/common-hooks';
|
4 |
+
import { IReference, IReferenceChunk } from '@/interfaces/database/chat';
|
|
|
5 |
import classNames from 'classnames';
|
6 |
import { memo, useCallback, useEffect, useMemo, useState } from 'react';
|
7 |
|
|
|
30 |
sendLoading?: boolean;
|
31 |
nickname?: string;
|
32 |
avatar?: string;
|
33 |
+
clickDocumentButton?: (documentId: string, chunk: IReferenceChunk) => void;
|
34 |
index: number;
|
35 |
showLikeButton?: boolean;
|
36 |
}
|
web/src/components/pdf-drawer/hooks.ts
CHANGED
@@ -1,14 +1,16 @@
|
|
1 |
import { useSetModalState } from '@/hooks/common-hooks';
|
2 |
-
import {
|
3 |
import { useCallback, useState } from 'react';
|
4 |
|
5 |
export const useClickDrawer = () => {
|
6 |
const { visible, showModal, hideModal } = useSetModalState();
|
7 |
-
const [selectedChunk, setSelectedChunk] = useState<
|
|
|
|
|
8 |
const [documentId, setDocumentId] = useState<string>('');
|
9 |
|
10 |
const clickDocumentButton = useCallback(
|
11 |
-
(documentId: string, chunk:
|
12 |
showModal();
|
13 |
setSelectedChunk(chunk);
|
14 |
setDocumentId(documentId);
|
|
|
1 |
import { useSetModalState } from '@/hooks/common-hooks';
|
2 |
+
import { IReferenceChunk } from '@/interfaces/database/chat';
|
3 |
import { useCallback, useState } from 'react';
|
4 |
|
5 |
export const useClickDrawer = () => {
|
6 |
const { visible, showModal, hideModal } = useSetModalState();
|
7 |
+
const [selectedChunk, setSelectedChunk] = useState<IReferenceChunk>(
|
8 |
+
{} as IReferenceChunk,
|
9 |
+
);
|
10 |
const [documentId, setDocumentId] = useState<string>('');
|
11 |
|
12 |
const clickDocumentButton = useCallback(
|
13 |
+
(documentId: string, chunk: IReferenceChunk) => {
|
14 |
showModal();
|
15 |
setSelectedChunk(chunk);
|
16 |
setDocumentId(documentId);
|
web/src/components/pdf-drawer/index.tsx
CHANGED
@@ -1,11 +1,12 @@
|
|
1 |
import { IModalProps } from '@/interfaces/common';
|
|
|
2 |
import { IChunk } from '@/interfaces/database/knowledge';
|
3 |
import { Drawer } from 'antd';
|
4 |
import DocumentPreviewer from '../pdf-previewer';
|
5 |
|
6 |
interface IProps extends IModalProps<any> {
|
7 |
documentId: string;
|
8 |
-
chunk: IChunk;
|
9 |
}
|
10 |
|
11 |
export const PdfDrawer = ({
|
|
|
1 |
import { IModalProps } from '@/interfaces/common';
|
2 |
+
import { IReferenceChunk } from '@/interfaces/database/chat';
|
3 |
import { IChunk } from '@/interfaces/database/knowledge';
|
4 |
import { Drawer } from 'antd';
|
5 |
import DocumentPreviewer from '../pdf-previewer';
|
6 |
|
7 |
interface IProps extends IModalProps<any> {
|
8 |
documentId: string;
|
9 |
+
chunk: IChunk | IReferenceChunk;
|
10 |
}
|
11 |
|
12 |
export const PdfDrawer = ({
|
web/src/components/pdf-previewer/index.tsx
CHANGED
@@ -2,7 +2,9 @@ import {
|
|
2 |
useGetChunkHighlights,
|
3 |
useGetDocumentUrl,
|
4 |
} from '@/hooks/document-hooks';
|
|
|
5 |
import { IChunk } from '@/interfaces/database/knowledge';
|
|
|
6 |
import { Skeleton } from 'antd';
|
7 |
import { useEffect, useRef, useState } from 'react';
|
8 |
import {
|
@@ -13,13 +15,12 @@ import {
|
|
13 |
PdfLoader,
|
14 |
Popup,
|
15 |
} from 'react-pdf-highlighter';
|
16 |
-
|
17 |
-
import FileError from '@/pages/document-viewer/file-error';
|
18 |
import { useCatchDocumentError } from './hooks';
|
|
|
19 |
import styles from './index.less';
|
20 |
|
21 |
interface IProps {
|
22 |
-
chunk: IChunk;
|
23 |
documentId: string;
|
24 |
visible: boolean;
|
25 |
}
|
|
|
2 |
useGetChunkHighlights,
|
3 |
useGetDocumentUrl,
|
4 |
} from '@/hooks/document-hooks';
|
5 |
+
import { IReferenceChunk } from '@/interfaces/database/chat';
|
6 |
import { IChunk } from '@/interfaces/database/knowledge';
|
7 |
+
import FileError from '@/pages/document-viewer/file-error';
|
8 |
import { Skeleton } from 'antd';
|
9 |
import { useEffect, useRef, useState } from 'react';
|
10 |
import {
|
|
|
15 |
PdfLoader,
|
16 |
Popup,
|
17 |
} from 'react-pdf-highlighter';
|
|
|
|
|
18 |
import { useCatchDocumentError } from './hooks';
|
19 |
+
|
20 |
import styles from './index.less';
|
21 |
|
22 |
interface IProps {
|
23 |
+
chunk: IChunk | IReferenceChunk;
|
24 |
documentId: string;
|
25 |
visible: boolean;
|
26 |
}
|
web/src/hooks/chat-hooks.ts
CHANGED
@@ -504,11 +504,17 @@ export const useCreateNextSharedConversation = () => {
|
|
504 |
return { data, loading, createSharedConversation: mutateAsync };
|
505 |
};
|
506 |
|
507 |
-
|
|
|
|
|
|
|
508 |
const { data, isPending: loading } = useQuery({
|
509 |
queryKey: ['fetchSharedConversation'],
|
510 |
enabled: !!conversationId,
|
511 |
queryFn: async () => {
|
|
|
|
|
|
|
512 |
const { data } = await chatService.getExternalConversation(
|
513 |
null,
|
514 |
conversationId,
|
|
|
504 |
return { data, loading, createSharedConversation: mutateAsync };
|
505 |
};
|
506 |
|
507 |
+
// deprecated
|
508 |
+
export const useFetchNextSharedConversation = (
|
509 |
+
conversationId?: string | null,
|
510 |
+
) => {
|
511 |
const { data, isPending: loading } = useQuery({
|
512 |
queryKey: ['fetchSharedConversation'],
|
513 |
enabled: !!conversationId,
|
514 |
queryFn: async () => {
|
515 |
+
if (!conversationId) {
|
516 |
+
return {};
|
517 |
+
}
|
518 |
const { data } = await chatService.getExternalConversation(
|
519 |
null,
|
520 |
conversationId,
|
web/src/hooks/document-hooks.ts
CHANGED
@@ -1,3 +1,4 @@
|
|
|
|
1 |
import { IDocumentInfo } from '@/interfaces/database/document';
|
2 |
import { IChunk } from '@/interfaces/database/knowledge';
|
3 |
import { IChangeParserConfigRequestBody } from '@/interfaces/request/document';
|
@@ -32,7 +33,9 @@ export const useGetDocumentUrl = (documentId?: string) => {
|
|
32 |
return getDocumentUrl;
|
33 |
};
|
34 |
|
35 |
-
export const useGetChunkHighlights = (
|
|
|
|
|
36 |
const [size, setSize] = useState({ width: 849, height: 1200 });
|
37 |
|
38 |
const highlights: IHighlight[] = useMemo(() => {
|
|
|
1 |
+
import { IReferenceChunk } from '@/interfaces/database/chat';
|
2 |
import { IDocumentInfo } from '@/interfaces/database/document';
|
3 |
import { IChunk } from '@/interfaces/database/knowledge';
|
4 |
import { IChangeParserConfigRequestBody } from '@/interfaces/request/document';
|
|
|
33 |
return getDocumentUrl;
|
34 |
};
|
35 |
|
36 |
+
export const useGetChunkHighlights = (
|
37 |
+
selectedChunk: IChunk | IReferenceChunk,
|
38 |
+
) => {
|
39 |
const [size, setSize] = useState({ width: 849, height: 1200 });
|
40 |
|
41 |
const highlights: IHighlight[] = useMemo(() => {
|
web/src/hooks/logic-hooks.ts
CHANGED
@@ -12,6 +12,7 @@ import { PaginationProps, message } from 'antd';
|
|
12 |
import { FormInstance } from 'antd/lib';
|
13 |
import axios from 'axios';
|
14 |
import { EventSourceParserStream } from 'eventsource-parser/stream';
|
|
|
15 |
import {
|
16 |
ChangeEventHandler,
|
17 |
useCallback,
|
@@ -336,6 +337,7 @@ export const useSelectDerivedMessages = () => {
|
|
336 |
}),
|
337 |
prompt: answer.prompt,
|
338 |
audio_binary: answer.audio_binary,
|
|
|
339 |
},
|
340 |
];
|
341 |
});
|
|
|
12 |
import { FormInstance } from 'antd/lib';
|
13 |
import axios from 'axios';
|
14 |
import { EventSourceParserStream } from 'eventsource-parser/stream';
|
15 |
+
import { omit } from 'lodash';
|
16 |
import {
|
17 |
ChangeEventHandler,
|
18 |
useCallback,
|
|
|
337 |
}),
|
338 |
prompt: answer.prompt,
|
339 |
audio_binary: answer.audio_binary,
|
340 |
+
...omit(answer, 'reference'),
|
341 |
},
|
342 |
];
|
343 |
});
|
web/src/hooks/user-setting-hooks.tsx
CHANGED
@@ -169,17 +169,34 @@ export const useFetchSystemStatus = () => {
|
|
169 |
};
|
170 |
};
|
171 |
|
172 |
-
export const
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
173 |
const {
|
174 |
data,
|
175 |
isFetching: loading,
|
176 |
refetch,
|
177 |
} = useQuery<IToken[]>({
|
178 |
-
queryKey: ['fetchSystemTokenList'
|
179 |
initialData: [],
|
180 |
gcTime: 0,
|
181 |
queryFn: async () => {
|
182 |
-
const { data } = await userService.listToken(
|
183 |
|
184 |
return data?.data ?? [];
|
185 |
},
|
@@ -213,6 +230,7 @@ export const useRemoveSystemToken = () => {
|
|
213 |
|
214 |
export const useCreateSystemToken = () => {
|
215 |
const queryClient = useQueryClient();
|
|
|
216 |
const {
|
217 |
data,
|
218 |
isPending: loading,
|
|
|
169 |
};
|
170 |
};
|
171 |
|
172 |
+
export const useFetchManualSystemTokenList = () => {
|
173 |
+
const {
|
174 |
+
data,
|
175 |
+
isPending: loading,
|
176 |
+
mutateAsync,
|
177 |
+
} = useMutation({
|
178 |
+
mutationKey: ['fetchManualSystemTokenList'],
|
179 |
+
mutationFn: async () => {
|
180 |
+
const { data } = await userService.listToken();
|
181 |
+
|
182 |
+
return data?.data ?? [];
|
183 |
+
},
|
184 |
+
});
|
185 |
+
|
186 |
+
return { data, loading, fetchSystemTokenList: mutateAsync };
|
187 |
+
};
|
188 |
+
|
189 |
+
export const useFetchSystemTokenList = () => {
|
190 |
const {
|
191 |
data,
|
192 |
isFetching: loading,
|
193 |
refetch,
|
194 |
} = useQuery<IToken[]>({
|
195 |
+
queryKey: ['fetchSystemTokenList'],
|
196 |
initialData: [],
|
197 |
gcTime: 0,
|
198 |
queryFn: async () => {
|
199 |
+
const { data } = await userService.listToken();
|
200 |
|
201 |
return data?.data ?? [];
|
202 |
},
|
|
|
230 |
|
231 |
export const useCreateSystemToken = () => {
|
232 |
const queryClient = useQueryClient();
|
233 |
+
|
234 |
const {
|
235 |
data,
|
236 |
isPending: loading,
|
web/src/interfaces/database/chat.ts
CHANGED
@@ -1,5 +1,4 @@
|
|
1 |
import { MessageType } from '@/constants/chat';
|
2 |
-
import { IChunk } from './knowledge';
|
3 |
|
4 |
export interface PromptConfig {
|
5 |
empty_response: string;
|
@@ -35,7 +34,7 @@ export interface IDialog {
|
|
35 |
description: string;
|
36 |
icon: string;
|
37 |
id: string;
|
38 |
-
dialog_id
|
39 |
kb_ids: string[];
|
40 |
kb_names: string[];
|
41 |
language: string;
|
@@ -75,8 +74,21 @@ export interface Message {
|
|
75 |
audio_binary?: string;
|
76 |
}
|
77 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
78 |
export interface IReference {
|
79 |
-
chunks:
|
80 |
doc_aggs: Docagg[];
|
81 |
total: number;
|
82 |
}
|
@@ -117,6 +129,7 @@ export interface IToken {
|
|
117 |
token: string;
|
118 |
update_date?: any;
|
119 |
update_time?: any;
|
|
|
120 |
}
|
121 |
|
122 |
export interface IStats {
|
|
|
1 |
import { MessageType } from '@/constants/chat';
|
|
|
2 |
|
3 |
export interface PromptConfig {
|
4 |
empty_response: string;
|
|
|
34 |
description: string;
|
35 |
icon: string;
|
36 |
id: string;
|
37 |
+
dialog_id: string;
|
38 |
kb_ids: string[];
|
39 |
kb_names: string[];
|
40 |
language: string;
|
|
|
74 |
audio_binary?: string;
|
75 |
}
|
76 |
|
77 |
+
export interface IReferenceChunk {
|
78 |
+
id: string;
|
79 |
+
content: null;
|
80 |
+
document_id: string;
|
81 |
+
document_name: string;
|
82 |
+
dataset_id: string;
|
83 |
+
image_id: string;
|
84 |
+
similarity: number;
|
85 |
+
vector_similarity: number;
|
86 |
+
term_similarity: number;
|
87 |
+
positions: number[];
|
88 |
+
}
|
89 |
+
|
90 |
export interface IReference {
|
91 |
+
chunks: IReferenceChunk[];
|
92 |
doc_aggs: Docagg[];
|
93 |
total: number;
|
94 |
}
|
|
|
129 |
token: string;
|
130 |
update_date?: any;
|
131 |
update_time?: any;
|
132 |
+
beta: string;
|
133 |
}
|
134 |
|
135 |
export interface IStats {
|
web/src/locales/config.ts
CHANGED
@@ -2,11 +2,11 @@ import i18n from 'i18next';
|
|
2 |
import LanguageDetector from 'i18next-browser-languagedetector';
|
3 |
import { initReactI18next } from 'react-i18next';
|
4 |
|
5 |
-
import { createTranslationTable, flattenObject } from './until';
|
6 |
import translation_en from './en';
|
7 |
import translation_es from './es';
|
8 |
import translation_id from './id';
|
9 |
import translation_ja from './ja';
|
|
|
10 |
import translation_vi from './vi';
|
11 |
import translation_zh from './zh';
|
12 |
import translation_zh_traditional from './zh-traditional';
|
|
|
2 |
import LanguageDetector from 'i18next-browser-languagedetector';
|
3 |
import { initReactI18next } from 'react-i18next';
|
4 |
|
|
|
5 |
import translation_en from './en';
|
6 |
import translation_es from './es';
|
7 |
import translation_id from './id';
|
8 |
import translation_ja from './ja';
|
9 |
+
import { createTranslationTable, flattenObject } from './until';
|
10 |
import translation_vi from './vi';
|
11 |
import translation_zh from './zh';
|
12 |
import translation_zh_traditional from './zh-traditional';
|
web/src/locales/en.ts
CHANGED
@@ -432,6 +432,7 @@ The above is the content you need to summarize.`,
|
|
432 |
partialTitle: 'Partial Embed',
|
433 |
extensionTitle: 'Chrome Extension',
|
434 |
tokenError: 'Please create API Token first!',
|
|
|
435 |
searching: 'searching...',
|
436 |
parsing: 'Parsing',
|
437 |
uploading: 'Uploading',
|
|
|
432 |
partialTitle: 'Partial Embed',
|
433 |
extensionTitle: 'Chrome Extension',
|
434 |
tokenError: 'Please create API Token first!',
|
435 |
+
betaError: 'The beta field of the API Token cannot be empty!',
|
436 |
searching: 'searching...',
|
437 |
parsing: 'Parsing',
|
438 |
uploading: 'Uploading',
|
web/src/locales/ja.ts
CHANGED
@@ -33,6 +33,7 @@ export default {
|
|
33 |
pleaseSelect: '選択してください',
|
34 |
pleaseInput: '入力してください',
|
35 |
submit: '送信',
|
|
|
36 |
},
|
37 |
login: {
|
38 |
login: 'ログイン',
|
@@ -85,8 +86,7 @@ export default {
|
|
85 |
name: '名前',
|
86 |
namePlaceholder: '名前を入力してください',
|
87 |
doc: 'ドキュメント',
|
88 |
-
datasetDescription:
|
89 |
-
'😉 パースが成功すると、質問と回答が可能になります。',
|
90 |
addFile: 'ファイルを追加',
|
91 |
searchFiles: 'ファイルを検索',
|
92 |
localFiles: 'ローカルファイル',
|
@@ -157,8 +157,7 @@ export default {
|
|
157 |
topK: 'トップK',
|
158 |
topKTip: `Kチャンクがリランキングモデルに供給されます。`,
|
159 |
delimiter: `区切り文字`,
|
160 |
-
delimiterTip:
|
161 |
-
'複数文字の区切り文字をサポートしています。',
|
162 |
html4excel: 'ExcelをHTMLに変換',
|
163 |
html4excelTip: `有効にすると、スプレッドシートはHTMLテーブルとして解析されます。それ以外の場合、キーと値のペアとして解析されます。`,
|
164 |
autoKeywords: '自動キーワード',
|
@@ -182,7 +181,7 @@ export default {
|
|
182 |
embeddingModelTip:
|
183 |
'チャンクを埋め込みに変換するモデルです。一度チャンクが作成されると変更できません。',
|
184 |
permissionsTip:
|
185 |
-
|
186 |
chunkTokenNumberTip:
|
187 |
'チャンクのトークンしきい値を設定します。このしきい値を下回る段落は、次の段落と結合され、しきい値を超えた時点でチャンクが作成されます。',
|
188 |
chunkMethod: 'チャンク方法',
|
@@ -201,8 +200,7 @@ export default {
|
|
201 |
methodExamplesDescription:
|
202 |
'以下のスクリーンショットは明確な説明のために提供されています。',
|
203 |
dialogueExamplesTitle: '会話の例',
|
204 |
-
methodEmpty:
|
205 |
-
'ナレッジベースカテゴリの視覚的説明がここに表示されます',
|
206 |
book: `<p>対応ファイル形式は<b>DOCX</b>, <b>PDF</b>, <b>TXT</b>です。</p><p>
|
207 |
PDF形式の書籍では、解析時間を短縮するため、<i>ページ範囲</i>を設定してください。</p>`,
|
208 |
laws: `<p>対応ファイル形式は<b>DOCX</b>, <b>PDF</b>, <b>TXT</b>です。</p><p>
|
@@ -305,7 +303,7 @@ export default {
|
|
305 |
entityTypes: 'エンティティタイプ',
|
306 |
pageRank: 'ページランク',
|
307 |
pageRankTip: `これは関連性スコアを高めるために使用されます。すべての取得されたチャンクの関連性スコアにこの数値が加算されます。
|
308 |
-
|
309 |
},
|
310 |
chunk: {
|
311 |
chunk: 'チャンク',
|
@@ -360,8 +358,7 @@ export default {
|
|
360 |
{knowledge}
|
361 |
上記がナレッジベースです。`,
|
362 |
systemMessage: '入力してください!',
|
363 |
-
systemTip:
|
364 |
-
'LLMが質問に答える際に従う指示を設定します。',
|
365 |
topN: 'トップN',
|
366 |
topNTip: `類似度スコアがしきい値を超えるチャンクのうち、上位N件のみがLLMに供給されます。`,
|
367 |
variable: '変数',
|
@@ -406,7 +403,8 @@ export default {
|
|
406 |
quote: '引用を表示',
|
407 |
quoteTip: '元のテキストの出典を表示しますか?',
|
408 |
selfRag: 'Self-RAG',
|
409 |
-
selfRagTip:
|
|
|
410 |
overview: 'チャットID',
|
411 |
pv: 'メッセージ数',
|
412 |
uv: 'アクティブユーザー数',
|
@@ -486,7 +484,7 @@ export default {
|
|
486 |
newPassword: '新しいパスワード',
|
487 |
newPasswordMessage: 'パスワードを入力してください!',
|
488 |
newPasswordDescription:
|
489 |
-
'新しいパスワードは8文字以上でなければなりません。',
|
490 |
confirmPassword: '新しいパスワードの確認',
|
491 |
confirmPasswordMessage: 'パスワードを確認してください!',
|
492 |
confirmPasswordNonMatchMessage:
|
@@ -568,7 +566,7 @@ export default {
|
|
568 |
SparkModelNameMessage: 'Sparkモデルを選択してください',
|
569 |
addSparkAPIPassword: 'Spark APIパスワード',
|
570 |
SparkAPIPasswordMessage: 'APIパスワードを入力してください',
|
571 |
-
addSparkAPPID: 'Spark APPID',
|
572 |
SparkAPPIDMessage: 'APPIDを入力してください',
|
573 |
addSparkAPISecret: 'Spark APIシークレット',
|
574 |
SparkAPISecretMessage: 'APIシークレットを入力してください',
|
@@ -579,8 +577,7 @@ export default {
|
|
579 |
yiyanAKMessage: 'APIキーを入力してください',
|
580 |
addyiyanSK: 'yiyanシークレットキー',
|
581 |
yiyanSKMessage: 'シークレットキーを入力してください',
|
582 |
-
FishAudioModelNameMessage:
|
583 |
-
'音声合成モデルに名前を付けてください',
|
584 |
addFishAudioAK: 'Fish Audio APIキー',
|
585 |
addFishAudioAKMessage: 'APIキーを入力してください',
|
586 |
addFishAudioRefID: 'FishAudio参照ID',
|
@@ -700,7 +697,7 @@ export default {
|
|
700 |
relevantDescription: `LLMを使用して、上流の出力がユーザーの最新のクエリに関連しているかどうかを評価するコンポーネント。各判定結果に対して次のコンポーネントを指定してください。`,
|
701 |
rewriteQuestionDescription: `ナレッジベースから関連情報を取得できなかった場合にユーザーのクエリを修正するコンポーネント。定義されたループの上限に達するまでこのプロセスを繰り返します。上流が「Relevant」、下流が「Retrieval」であることを確認してください。`,
|
702 |
messageDescription:
|
703 |
-
|
704 |
keywordDescription: `ユーザーの入力からトップNの検索結果を取得するコンポーネント。使用前にTopNの値が適切に設定されていることを確認してください。`,
|
705 |
switchDescription: `前のコンポーネントの出力に基づいて条件を評価し、それに応じて実行の流れを指示するコンポーネント。ケースを定義し、各ケースのアクションまたは条件が満たされない場合のデフォルトアクションを指定することで、複雑な分岐ロジックを可能にします。`,
|
706 |
wikipediaDescription: `wikipedia.orgから検索を行うコンポーネントで、TopNを使用して検索結果の数を指定します。既存のナレッジベースを補完します。`,
|
@@ -800,7 +797,7 @@ export default {
|
|
800 |
news: 'ニュースと情報',
|
801 |
law: '法律と規制',
|
802 |
contract: '契約',
|
803 |
-
},
|
804 |
baiduSourceLangOptions: {
|
805 |
auto: '自動検出',
|
806 |
zh: '中国語',
|
@@ -1089,4 +1086,4 @@ export default {
|
|
1089 |
chat: 'チャット',
|
1090 |
},
|
1091 |
},
|
1092 |
-
};
|
|
|
33 |
pleaseSelect: '選択してください',
|
34 |
pleaseInput: '入力してください',
|
35 |
submit: '送信',
|
36 |
+
japanese: '日本語',
|
37 |
},
|
38 |
login: {
|
39 |
login: 'ログイン',
|
|
|
86 |
name: '名前',
|
87 |
namePlaceholder: '名前を入力してください',
|
88 |
doc: 'ドキュメント',
|
89 |
+
datasetDescription: '😉 パースが成功すると、質問と回答が可能になります。',
|
|
|
90 |
addFile: 'ファイルを追加',
|
91 |
searchFiles: 'ファイルを検索',
|
92 |
localFiles: 'ローカルファイル',
|
|
|
157 |
topK: 'トップK',
|
158 |
topKTip: `Kチャンクがリランキングモデルに供給されます。`,
|
159 |
delimiter: `区切り文字`,
|
160 |
+
delimiterTip: '複数文字の区切り文字をサポートしています。',
|
|
|
161 |
html4excel: 'ExcelをHTMLに変換',
|
162 |
html4excelTip: `有効にすると、スプレッドシートはHTMLテーブルとして解析されます。それ以外の場合、キーと値のペアとして解析されます。`,
|
163 |
autoKeywords: '自動キーワード',
|
|
|
181 |
embeddingModelTip:
|
182 |
'チャンクを埋め込みに変換するモデルです。一度チャンクが作成されると変更できません。',
|
183 |
permissionsTip:
|
184 |
+
'「チーム」に設定すると、全てのチームメンバーがナレッジベースを管理できます。',
|
185 |
chunkTokenNumberTip:
|
186 |
'チャンクのトークンしきい値を設定します。このしきい値を下回る段落は、次の段落と結合され、しきい値を超えた時点でチャンクが作成されます。',
|
187 |
chunkMethod: 'チャンク方法',
|
|
|
200 |
methodExamplesDescription:
|
201 |
'以下のスクリーンショットは明確な説明のために提供されています。',
|
202 |
dialogueExamplesTitle: '会話の例',
|
203 |
+
methodEmpty: 'ナレッジベースカテゴリの視覚的説明がここに表示されます',
|
|
|
204 |
book: `<p>対応ファイル形式は<b>DOCX</b>, <b>PDF</b>, <b>TXT</b>です。</p><p>
|
205 |
PDF形式の書籍では、解析時間を短縮するため、<i>ページ範囲</i>を設定してください。</p>`,
|
206 |
laws: `<p>対応ファイル形式は<b>DOCX</b>, <b>PDF</b>, <b>TXT</b>です。</p><p>
|
|
|
303 |
entityTypes: 'エンティティタイプ',
|
304 |
pageRank: 'ページランク',
|
305 |
pageRankTip: `これは関連性スコアを高めるために使用されます。すべての取得されたチャンクの関連性スコアにこの数値が加算されます。
|
306 |
+
特定のナレッジベースを最初に検索したい場合は、他のものよりも高いページランクスコアを設定してください。`,
|
307 |
},
|
308 |
chunk: {
|
309 |
chunk: 'チャンク',
|
|
|
358 |
{knowledge}
|
359 |
上記がナレッジベースです。`,
|
360 |
systemMessage: '入力してください!',
|
361 |
+
systemTip: 'LLMが質問に答える際に従う指示を設定します。',
|
|
|
362 |
topN: 'トップN',
|
363 |
topNTip: `類似度スコアがしきい値を超えるチャンクのうち、上位N件のみがLLMに供給されます。`,
|
364 |
variable: '変数',
|
|
|
403 |
quote: '引用を表示',
|
404 |
quoteTip: '元のテキストの出典を表示しますか?',
|
405 |
selfRag: 'Self-RAG',
|
406 |
+
selfRagTip:
|
407 |
+
'詳細は次を参照してください:https://huggingface.co/papers/2310.11511',
|
408 |
overview: 'チャットID',
|
409 |
pv: 'メッセージ数',
|
410 |
uv: 'アクティブユーザー数',
|
|
|
484 |
newPassword: '新しいパスワード',
|
485 |
newPasswordMessage: 'パスワードを入力してください!',
|
486 |
newPasswordDescription:
|
487 |
+
'新しいパスワードは8文字以上でなければなりません。',
|
488 |
confirmPassword: '新しいパスワードの確認',
|
489 |
confirmPasswordMessage: 'パスワードを確認してください!',
|
490 |
confirmPasswordNonMatchMessage:
|
|
|
566 |
SparkModelNameMessage: 'Sparkモデルを選択してください',
|
567 |
addSparkAPIPassword: 'Spark APIパスワード',
|
568 |
SparkAPIPasswordMessage: 'APIパスワードを入力してください',
|
569 |
+
addSparkAPPID: 'Spark APPID',
|
570 |
SparkAPPIDMessage: 'APPIDを入力してください',
|
571 |
addSparkAPISecret: 'Spark APIシークレット',
|
572 |
SparkAPISecretMessage: 'APIシークレットを入力してください',
|
|
|
577 |
yiyanAKMessage: 'APIキーを入力してください',
|
578 |
addyiyanSK: 'yiyanシークレットキー',
|
579 |
yiyanSKMessage: 'シークレットキーを入力してください',
|
580 |
+
FishAudioModelNameMessage: '音声合成モデルに名前を付けてください',
|
|
|
581 |
addFishAudioAK: 'Fish Audio APIキー',
|
582 |
addFishAudioAKMessage: 'APIキーを入力してください',
|
583 |
addFishAudioRefID: 'FishAudio参照ID',
|
|
|
697 |
relevantDescription: `LLMを使用して、上流の出力がユーザーの最新のクエリに関連しているかどうかを評価するコンポーネント。各判定結果に対して次のコンポーネントを指定してください。`,
|
698 |
rewriteQuestionDescription: `ナレッジベースから関連情報を取得できなかった場合にユーザーのクエリを修正するコンポーネント。定義されたループの上限に達するまでこのプロセスを繰り返します。上流が「Relevant」、下流が「Retrieval」であることを確認してください。`,
|
699 |
messageDescription:
|
700 |
+
'静的メッセージを送信するコンポーネント。複数のメッセージが提供されている場合は、その中からランダムに1つを選択して送信します。下流がインターフェースコンポーネント「Answer」であることを確認してください。',
|
701 |
keywordDescription: `ユーザーの入力からトップNの検索結果を取得するコンポーネント。使用前にTopNの値が適切に設定されていることを確認してください。`,
|
702 |
switchDescription: `前のコンポーネントの出力に基づいて条件を評価し、それに応じて実行の流れを指示するコンポーネント。ケースを定義し、各ケースのアクションまたは条件が満たされない場合のデフォルトアクションを指定することで、複雑な分岐ロジックを可能にします。`,
|
703 |
wikipediaDescription: `wikipedia.orgから検索を行うコンポーネントで、TopNを使用して検索結果の数を指定します。既存のナレッジベースを補完します。`,
|
|
|
797 |
news: 'ニュースと情報',
|
798 |
law: '法律と規制',
|
799 |
contract: '契約',
|
800 |
+
},
|
801 |
baiduSourceLangOptions: {
|
802 |
auto: '自動検出',
|
803 |
zh: '中国語',
|
|
|
1086 |
chat: 'チャット',
|
1087 |
},
|
1088 |
},
|
1089 |
+
};
|
web/src/locales/zh-traditional.ts
CHANGED
@@ -414,6 +414,7 @@ export default {
|
|
414 |
partialTitle: '部分嵌入',
|
415 |
extensionTitle: 'Chrome 插件',
|
416 |
tokenError: '請先創建 API Token!',
|
|
|
417 |
searching: '搜索中',
|
418 |
parsing: '解析中',
|
419 |
uploading: '上傳中',
|
|
|
414 |
partialTitle: '部分嵌入',
|
415 |
extensionTitle: 'Chrome 插件',
|
416 |
tokenError: '請先創建 API Token!',
|
417 |
+
betaError: 'API Token的beta欄位不可以為空!',
|
418 |
searching: '搜索中',
|
419 |
parsing: '解析中',
|
420 |
uploading: '上傳中',
|
web/src/locales/zh.ts
CHANGED
@@ -431,6 +431,7 @@ export default {
|
|
431 |
partialTitle: '部分嵌入',
|
432 |
extensionTitle: 'Chrome 插件',
|
433 |
tokenError: '请先创建 API Token!',
|
|
|
434 |
searching: '搜索中',
|
435 |
parsing: '解析中',
|
436 |
uploading: '上传中',
|
|
|
431 |
partialTitle: '部分嵌入',
|
432 |
extensionTitle: 'Chrome 插件',
|
433 |
tokenError: '请先创建 API Token!',
|
434 |
+
betaError: 'API Token的beta字段不可以为空!',
|
435 |
searching: '搜索中',
|
436 |
parsing: '解析中',
|
437 |
uploading: '上传中',
|
web/src/pages/chat/index.tsx
CHANGED
@@ -29,18 +29,20 @@ import {
|
|
29 |
useSelectDerivedConversationList,
|
30 |
} from './hooks';
|
31 |
|
|
|
|
|
32 |
import SvgIcon from '@/components/svg-icon';
|
33 |
import { useTheme } from '@/components/theme-provider';
|
|
|
34 |
import {
|
35 |
useClickConversationCard,
|
36 |
useClickDialogCard,
|
37 |
useFetchNextDialogList,
|
38 |
useGetChatSearchParams,
|
39 |
} from '@/hooks/chat-hooks';
|
40 |
-
import {
|
41 |
import { useSetSelectedRecord } from '@/hooks/logic-hooks';
|
42 |
import { IDialog } from '@/interfaces/database/chat';
|
43 |
-
import ChatIdModal from './chat-id-modal';
|
44 |
import styles from './index.less';
|
45 |
|
46 |
const { Text } = Typography;
|
@@ -82,13 +84,10 @@ const Chat = () => {
|
|
82 |
showDialogEditModal,
|
83 |
} = useEditDialog();
|
84 |
const { t } = useTranslate('chat');
|
85 |
-
const {
|
86 |
-
visible: overviewVisible,
|
87 |
-
hideModal: hideOverviewModal,
|
88 |
-
showModal: showOverviewModal,
|
89 |
-
} = useSetModalState();
|
90 |
const { currentRecord, setRecord } = useSetSelectedRecord<IDialog>();
|
91 |
const [controller, setController] = useState(new AbortController());
|
|
|
|
|
92 |
|
93 |
const handleAppCardEnter = (id: string) => () => {
|
94 |
handleItemEnter(id);
|
@@ -120,7 +119,7 @@ const Chat = () => {
|
|
120 |
info?.domEvent?.preventDefault();
|
121 |
info?.domEvent?.stopPropagation();
|
122 |
setRecord(dialog);
|
123 |
-
|
124 |
};
|
125 |
|
126 |
const handleRemoveConversation =
|
@@ -193,7 +192,7 @@ const Chat = () => {
|
|
193 |
label: (
|
194 |
<Space>
|
195 |
<KeyOutlined />
|
196 |
-
{t('
|
197 |
</Space>
|
198 |
),
|
199 |
},
|
@@ -374,14 +373,16 @@ const Chat = () => {
|
|
374 |
initialName={initialConversationName}
|
375 |
loading={conversationRenameLoading}
|
376 |
></RenameModal>
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
|
|
|
|
385 |
)}
|
386 |
</Flex>
|
387 |
);
|
|
|
29 |
useSelectDerivedConversationList,
|
30 |
} from './hooks';
|
31 |
|
32 |
+
import EmbedModal from '@/components/api-service/embed-modal';
|
33 |
+
import { useShowEmbedModal } from '@/components/api-service/hooks';
|
34 |
import SvgIcon from '@/components/svg-icon';
|
35 |
import { useTheme } from '@/components/theme-provider';
|
36 |
+
import { SharedFrom } from '@/constants/chat';
|
37 |
import {
|
38 |
useClickConversationCard,
|
39 |
useClickDialogCard,
|
40 |
useFetchNextDialogList,
|
41 |
useGetChatSearchParams,
|
42 |
} from '@/hooks/chat-hooks';
|
43 |
+
import { useTranslate } from '@/hooks/common-hooks';
|
44 |
import { useSetSelectedRecord } from '@/hooks/logic-hooks';
|
45 |
import { IDialog } from '@/interfaces/database/chat';
|
|
|
46 |
import styles from './index.less';
|
47 |
|
48 |
const { Text } = Typography;
|
|
|
84 |
showDialogEditModal,
|
85 |
} = useEditDialog();
|
86 |
const { t } = useTranslate('chat');
|
|
|
|
|
|
|
|
|
|
|
87 |
const { currentRecord, setRecord } = useSetSelectedRecord<IDialog>();
|
88 |
const [controller, setController] = useState(new AbortController());
|
89 |
+
const { showEmbedModal, hideEmbedModal, embedVisible, beta } =
|
90 |
+
useShowEmbedModal();
|
91 |
|
92 |
const handleAppCardEnter = (id: string) => () => {
|
93 |
handleItemEnter(id);
|
|
|
119 |
info?.domEvent?.preventDefault();
|
120 |
info?.domEvent?.stopPropagation();
|
121 |
setRecord(dialog);
|
122 |
+
showEmbedModal();
|
123 |
};
|
124 |
|
125 |
const handleRemoveConversation =
|
|
|
192 |
label: (
|
193 |
<Space>
|
194 |
<KeyOutlined />
|
195 |
+
{t('publish', { keyPrefix: 'flow' })}
|
196 |
</Space>
|
197 |
),
|
198 |
},
|
|
|
373 |
initialName={initialConversationName}
|
374 |
loading={conversationRenameLoading}
|
375 |
></RenameModal>
|
376 |
+
|
377 |
+
{embedVisible && (
|
378 |
+
<EmbedModal
|
379 |
+
visible={embedVisible}
|
380 |
+
hideModal={hideEmbedModal}
|
381 |
+
token={currentRecord.id}
|
382 |
+
form={SharedFrom.Chat}
|
383 |
+
beta={beta}
|
384 |
+
isAgent={false}
|
385 |
+
></EmbedModal>
|
386 |
)}
|
387 |
</Flex>
|
388 |
);
|
web/src/pages/chat/markdown-content/index.tsx
CHANGED
@@ -1,7 +1,6 @@
|
|
1 |
import Image from '@/components/image';
|
2 |
import SvgIcon from '@/components/svg-icon';
|
3 |
-
import { IReference } from '@/interfaces/database/chat';
|
4 |
-
import { IChunk } from '@/interfaces/database/knowledge';
|
5 |
import { getExtension } from '@/utils/document-util';
|
6 |
import { InfoCircleOutlined } from '@ant-design/icons';
|
7 |
import { Button, Flex, Popover, Space } from 'antd';
|
@@ -11,6 +10,7 @@ import Markdown from 'react-markdown';
|
|
11 |
import reactStringReplace from 'react-string-replace';
|
12 |
import SyntaxHighlighter from 'react-syntax-highlighter';
|
13 |
import rehypeKatex from 'rehype-katex';
|
|
|
14 |
import remarkGfm from 'remark-gfm';
|
15 |
import remarkMath from 'remark-math';
|
16 |
import { visitParents } from 'unist-util-visit-parents';
|
@@ -36,7 +36,7 @@ const MarkdownContent = ({
|
|
36 |
content: string;
|
37 |
loading: boolean;
|
38 |
reference: IReference;
|
39 |
-
clickDocumentButton?: (documentId: string, chunk:
|
40 |
}) => {
|
41 |
const { t } = useTranslation();
|
42 |
const { setDocumentIds, data: fileThumbnails } =
|
@@ -54,7 +54,7 @@ const MarkdownContent = ({
|
|
54 |
}, [reference, setDocumentIds]);
|
55 |
|
56 |
const handleDocumentButtonClick = useCallback(
|
57 |
-
(documentId: string, chunk:
|
58 |
if (!isPdf) {
|
59 |
return;
|
60 |
}
|
@@ -85,15 +85,15 @@ const MarkdownContent = ({
|
|
85 |
const chunks = reference?.chunks ?? [];
|
86 |
const chunkItem = chunks[chunkIndex];
|
87 |
const document = reference?.doc_aggs?.find(
|
88 |
-
(x) => x?.doc_id === chunkItem?.
|
89 |
);
|
90 |
const documentId = document?.doc_id;
|
91 |
const fileThumbnail = documentId ? fileThumbnails[documentId] : '';
|
92 |
const fileExtension = documentId ? getExtension(document?.doc_name) : '';
|
93 |
-
const imageId = chunkItem?.
|
94 |
return (
|
95 |
<Flex
|
96 |
-
key={chunkItem?.
|
97 |
gap={10}
|
98 |
className={styles.referencePopoverWrapper}
|
99 |
>
|
@@ -116,7 +116,7 @@ const MarkdownContent = ({
|
|
116 |
<Space direction={'vertical'}>
|
117 |
<div
|
118 |
dangerouslySetInnerHTML={{
|
119 |
-
__html: DOMPurify.sanitize(chunkItem?.
|
120 |
}}
|
121 |
className={styles.chunkContentText}
|
122 |
></div>
|
@@ -176,7 +176,7 @@ const MarkdownContent = ({
|
|
176 |
|
177 |
return (
|
178 |
<Markdown
|
179 |
-
rehypePlugins={[rehypeWrapReference, rehypeKatex]}
|
180 |
remarkPlugins={[remarkGfm, remarkMath]}
|
181 |
components={
|
182 |
{
|
|
|
1 |
import Image from '@/components/image';
|
2 |
import SvgIcon from '@/components/svg-icon';
|
3 |
+
import { IReference, IReferenceChunk } from '@/interfaces/database/chat';
|
|
|
4 |
import { getExtension } from '@/utils/document-util';
|
5 |
import { InfoCircleOutlined } from '@ant-design/icons';
|
6 |
import { Button, Flex, Popover, Space } from 'antd';
|
|
|
10 |
import reactStringReplace from 'react-string-replace';
|
11 |
import SyntaxHighlighter from 'react-syntax-highlighter';
|
12 |
import rehypeKatex from 'rehype-katex';
|
13 |
+
import rehypeRaw from 'rehype-raw';
|
14 |
import remarkGfm from 'remark-gfm';
|
15 |
import remarkMath from 'remark-math';
|
16 |
import { visitParents } from 'unist-util-visit-parents';
|
|
|
36 |
content: string;
|
37 |
loading: boolean;
|
38 |
reference: IReference;
|
39 |
+
clickDocumentButton?: (documentId: string, chunk: IReferenceChunk) => void;
|
40 |
}) => {
|
41 |
const { t } = useTranslation();
|
42 |
const { setDocumentIds, data: fileThumbnails } =
|
|
|
54 |
}, [reference, setDocumentIds]);
|
55 |
|
56 |
const handleDocumentButtonClick = useCallback(
|
57 |
+
(documentId: string, chunk: IReferenceChunk, isPdf: boolean) => () => {
|
58 |
if (!isPdf) {
|
59 |
return;
|
60 |
}
|
|
|
85 |
const chunks = reference?.chunks ?? [];
|
86 |
const chunkItem = chunks[chunkIndex];
|
87 |
const document = reference?.doc_aggs?.find(
|
88 |
+
(x) => x?.doc_id === chunkItem?.document_id,
|
89 |
);
|
90 |
const documentId = document?.doc_id;
|
91 |
const fileThumbnail = documentId ? fileThumbnails[documentId] : '';
|
92 |
const fileExtension = documentId ? getExtension(document?.doc_name) : '';
|
93 |
+
const imageId = chunkItem?.image_id;
|
94 |
return (
|
95 |
<Flex
|
96 |
+
key={chunkItem?.id}
|
97 |
gap={10}
|
98 |
className={styles.referencePopoverWrapper}
|
99 |
>
|
|
|
116 |
<Space direction={'vertical'}>
|
117 |
<div
|
118 |
dangerouslySetInnerHTML={{
|
119 |
+
__html: DOMPurify.sanitize(chunkItem?.content ?? ''),
|
120 |
}}
|
121 |
className={styles.chunkContentText}
|
122 |
></div>
|
|
|
176 |
|
177 |
return (
|
178 |
<Markdown
|
179 |
+
rehypePlugins={[rehypeWrapReference, rehypeKatex, rehypeRaw]}
|
180 |
remarkPlugins={[remarkGfm, remarkMath]}
|
181 |
components={
|
182 |
{
|
web/src/pages/chat/share/large.tsx
CHANGED
@@ -1,21 +1,23 @@
|
|
1 |
import MessageInput from '@/components/message-input';
|
2 |
import MessageItem from '@/components/message-item';
|
|
|
3 |
import { MessageType, SharedFrom } from '@/constants/chat';
|
4 |
-
import { useFetchNextSharedConversation } from '@/hooks/chat-hooks';
|
5 |
import { useSendButtonDisabled } from '@/pages/chat/hooks';
|
6 |
import { Flex, Spin } from 'antd';
|
7 |
import { forwardRef } from 'react';
|
8 |
import {
|
9 |
-
useCreateSharedConversationOnMount,
|
10 |
useGetSharedChatSearchParams,
|
11 |
useSendSharedMessage,
|
12 |
} from '../shared-hooks';
|
13 |
import { buildMessageItemReference } from '../utils';
|
|
|
|
|
14 |
import styles from './index.less';
|
15 |
|
16 |
const ChatContainer = () => {
|
17 |
-
const { conversationId } =
|
18 |
-
const {
|
|
|
19 |
|
20 |
const {
|
21 |
handlePressEnter,
|
@@ -25,9 +27,13 @@ const ChatContainer = () => {
|
|
25 |
loading,
|
26 |
ref,
|
27 |
derivedMessages,
|
28 |
-
|
|
|
29 |
const sendDisabled = useSendButtonDisabled(value);
|
30 |
-
|
|
|
|
|
|
|
31 |
|
32 |
return (
|
33 |
<>
|
@@ -44,7 +50,7 @@ const ChatContainer = () => {
|
|
44 |
reference={buildMessageItemReference(
|
45 |
{
|
46 |
message: derivedMessages,
|
47 |
-
reference:
|
48 |
},
|
49 |
message,
|
50 |
)}
|
@@ -54,6 +60,7 @@ const ChatContainer = () => {
|
|
54 |
derivedMessages?.length - 1 === i
|
55 |
}
|
56 |
index={i}
|
|
|
57 |
></MessageItem>
|
58 |
);
|
59 |
})}
|
@@ -65,7 +72,7 @@ const ChatContainer = () => {
|
|
65 |
<MessageInput
|
66 |
isShared
|
67 |
value={value}
|
68 |
-
disabled={
|
69 |
sendDisabled={sendDisabled}
|
70 |
conversationId={conversationId}
|
71 |
onInputChange={handleInputChange}
|
@@ -75,6 +82,14 @@ const ChatContainer = () => {
|
|
75 |
showUploadIcon={from === SharedFrom.Chat}
|
76 |
></MessageInput>
|
77 |
</Flex>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
78 |
</>
|
79 |
);
|
80 |
};
|
|
|
1 |
import MessageInput from '@/components/message-input';
|
2 |
import MessageItem from '@/components/message-item';
|
3 |
+
import { useClickDrawer } from '@/components/pdf-drawer/hooks';
|
4 |
import { MessageType, SharedFrom } from '@/constants/chat';
|
|
|
5 |
import { useSendButtonDisabled } from '@/pages/chat/hooks';
|
6 |
import { Flex, Spin } from 'antd';
|
7 |
import { forwardRef } from 'react';
|
8 |
import {
|
|
|
9 |
useGetSharedChatSearchParams,
|
10 |
useSendSharedMessage,
|
11 |
} from '../shared-hooks';
|
12 |
import { buildMessageItemReference } from '../utils';
|
13 |
+
|
14 |
+
import PdfDrawer from '@/components/pdf-drawer';
|
15 |
import styles from './index.less';
|
16 |
|
17 |
const ChatContainer = () => {
|
18 |
+
const { from, sharedId: conversationId } = useGetSharedChatSearchParams();
|
19 |
+
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
|
20 |
+
useClickDrawer();
|
21 |
|
22 |
const {
|
23 |
handlePressEnter,
|
|
|
27 |
loading,
|
28 |
ref,
|
29 |
derivedMessages,
|
30 |
+
hasError,
|
31 |
+
} = useSendSharedMessage();
|
32 |
const sendDisabled = useSendButtonDisabled(value);
|
33 |
+
|
34 |
+
if (!conversationId) {
|
35 |
+
return <div>empty</div>;
|
36 |
+
}
|
37 |
|
38 |
return (
|
39 |
<>
|
|
|
50 |
reference={buildMessageItemReference(
|
51 |
{
|
52 |
message: derivedMessages,
|
53 |
+
reference: [],
|
54 |
},
|
55 |
message,
|
56 |
)}
|
|
|
60 |
derivedMessages?.length - 1 === i
|
61 |
}
|
62 |
index={i}
|
63 |
+
clickDocumentButton={clickDocumentButton}
|
64 |
></MessageItem>
|
65 |
);
|
66 |
})}
|
|
|
72 |
<MessageInput
|
73 |
isShared
|
74 |
value={value}
|
75 |
+
disabled={hasError}
|
76 |
sendDisabled={sendDisabled}
|
77 |
conversationId={conversationId}
|
78 |
onInputChange={handleInputChange}
|
|
|
82 |
showUploadIcon={from === SharedFrom.Chat}
|
83 |
></MessageInput>
|
84 |
</Flex>
|
85 |
+
{visible && (
|
86 |
+
<PdfDrawer
|
87 |
+
visible={visible}
|
88 |
+
hideModal={hideModal}
|
89 |
+
documentId={documentId}
|
90 |
+
chunk={selectedChunk}
|
91 |
+
></PdfDrawer>
|
92 |
+
)}
|
93 |
</>
|
94 |
);
|
95 |
};
|
web/src/pages/chat/shared-hooks.ts
CHANGED
@@ -1,83 +1,41 @@
|
|
1 |
import { MessageType, SharedFrom } from '@/constants/chat';
|
2 |
-
import {
|
3 |
-
useCreateNextSharedConversation,
|
4 |
-
useFetchNextSharedConversation,
|
5 |
-
} from '@/hooks/chat-hooks';
|
6 |
import {
|
7 |
useSelectDerivedMessages,
|
8 |
useSendMessageWithSse,
|
9 |
} from '@/hooks/logic-hooks';
|
10 |
import { Message } from '@/interfaces/database/chat';
|
11 |
-
import
|
|
|
12 |
import trim from 'lodash/trim';
|
13 |
import { useCallback, useEffect, useState } from 'react';
|
14 |
import { useSearchParams } from 'umi';
|
15 |
import { v4 as uuid } from 'uuid';
|
16 |
import { useHandleMessageInputChange } from './hooks';
|
17 |
|
18 |
-
|
19 |
-
|
20 |
-
const [conversationId, setConversationId] = useState('');
|
21 |
-
|
22 |
-
const { createSharedConversation: createConversation } =
|
23 |
-
useCreateNextSharedConversation();
|
24 |
-
const sharedId = currentQueryParameters.get('shared_id');
|
25 |
-
const userId = currentQueryParameters.get('user_id');
|
26 |
-
|
27 |
-
const setConversation = useCallback(async () => {
|
28 |
-
if (sharedId) {
|
29 |
-
const data = await createConversation(userId ?? undefined);
|
30 |
-
const id = data.data?.id;
|
31 |
-
if (id) {
|
32 |
-
setConversationId(id);
|
33 |
-
}
|
34 |
-
}
|
35 |
-
}, [createConversation, sharedId, userId]);
|
36 |
-
|
37 |
-
useEffect(() => {
|
38 |
-
setConversation();
|
39 |
-
}, [setConversation]);
|
40 |
|
41 |
-
|
|
|
42 |
};
|
43 |
|
44 |
-
export const
|
45 |
-
const
|
46 |
-
|
47 |
-
const {
|
48 |
-
derivedMessages,
|
49 |
-
ref,
|
50 |
-
setDerivedMessages,
|
51 |
-
addNewestAnswer,
|
52 |
-
addNewestQuestion,
|
53 |
-
removeLatestMessage,
|
54 |
-
} = useSelectDerivedMessages();
|
55 |
-
|
56 |
-
useEffect(() => {
|
57 |
-
setDerivedMessages(data?.data?.message);
|
58 |
-
}, [setDerivedMessages, data]);
|
59 |
|
60 |
return {
|
61 |
-
|
62 |
-
|
63 |
-
addNewestQuestion,
|
64 |
-
removeLatestMessage,
|
65 |
-
loading,
|
66 |
-
ref,
|
67 |
-
setDerivedMessages,
|
68 |
};
|
69 |
};
|
70 |
|
71 |
-
export const
|
72 |
-
|
73 |
-
};
|
74 |
-
|
75 |
-
export const useSendSharedMessage = (conversationId: string) => {
|
76 |
const { createSharedConversation: setConversation } =
|
77 |
useCreateNextSharedConversation();
|
78 |
const { handleInputChange, value, setValue } = useHandleMessageInputChange();
|
79 |
const { send, answer, done } = useSendMessageWithSse(
|
80 |
-
api.
|
81 |
);
|
82 |
const {
|
83 |
derivedMessages,
|
@@ -85,24 +43,25 @@ export const useSendSharedMessage = (conversationId: string) => {
|
|
85 |
removeLatestMessage,
|
86 |
addNewestAnswer,
|
87 |
addNewestQuestion,
|
88 |
-
|
89 |
-
|
90 |
|
91 |
const sendMessage = useCallback(
|
92 |
async (message: Message, id?: string) => {
|
93 |
const res = await send({
|
94 |
conversation_id: id ?? conversationId,
|
95 |
-
quote:
|
96 |
-
|
|
|
97 |
});
|
98 |
|
99 |
-
if (
|
100 |
// cancel loading
|
101 |
setValue(message.content);
|
102 |
removeLatestMessage();
|
103 |
}
|
104 |
},
|
105 |
-
[conversationId, derivedMessages,
|
106 |
);
|
107 |
|
108 |
const handleSendMessage = useCallback(
|
@@ -120,6 +79,18 @@ export const useSendSharedMessage = (conversationId: string) => {
|
|
120 |
[conversationId, setConversation, sendMessage],
|
121 |
);
|
122 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
123 |
useEffect(() => {
|
124 |
if (answer.answer) {
|
125 |
addNewestAnswer(answer);
|
@@ -154,16 +125,8 @@ export const useSendSharedMessage = (conversationId: string) => {
|
|
154 |
value,
|
155 |
sendLoading: !done,
|
156 |
ref,
|
157 |
-
loading,
|
158 |
derivedMessages,
|
159 |
-
|
160 |
-
};
|
161 |
-
|
162 |
-
export const useGetSharedChatSearchParams = () => {
|
163 |
-
const [searchParams] = useSearchParams();
|
164 |
-
|
165 |
-
return {
|
166 |
-
from: searchParams.get('from') as SharedFrom,
|
167 |
-
sharedId: searchParams.get('shared_id'),
|
168 |
};
|
169 |
};
|
|
|
1 |
import { MessageType, SharedFrom } from '@/constants/chat';
|
2 |
+
import { useCreateNextSharedConversation } from '@/hooks/chat-hooks';
|
|
|
|
|
|
|
3 |
import {
|
4 |
useSelectDerivedMessages,
|
5 |
useSendMessageWithSse,
|
6 |
} from '@/hooks/logic-hooks';
|
7 |
import { Message } from '@/interfaces/database/chat';
|
8 |
+
import { message } from 'antd';
|
9 |
+
import { get } from 'lodash';
|
10 |
import trim from 'lodash/trim';
|
11 |
import { useCallback, useEffect, useState } from 'react';
|
12 |
import { useSearchParams } from 'umi';
|
13 |
import { v4 as uuid } from 'uuid';
|
14 |
import { useHandleMessageInputChange } from './hooks';
|
15 |
|
16 |
+
const isCompletionError = (res: any) =>
|
17 |
+
res && (res?.response.status !== 200 || res?.data?.code !== 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
|
19 |
+
export const useSendButtonDisabled = (value: string) => {
|
20 |
+
return trim(value) === '';
|
21 |
};
|
22 |
|
23 |
+
export const useGetSharedChatSearchParams = () => {
|
24 |
+
const [searchParams] = useSearchParams();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
|
26 |
return {
|
27 |
+
from: searchParams.get('from') as SharedFrom,
|
28 |
+
sharedId: searchParams.get('shared_id'),
|
|
|
|
|
|
|
|
|
|
|
29 |
};
|
30 |
};
|
31 |
|
32 |
+
export const useSendSharedMessage = () => {
|
33 |
+
const { from, sharedId: conversationId } = useGetSharedChatSearchParams();
|
|
|
|
|
|
|
34 |
const { createSharedConversation: setConversation } =
|
35 |
useCreateNextSharedConversation();
|
36 |
const { handleInputChange, value, setValue } = useHandleMessageInputChange();
|
37 |
const { send, answer, done } = useSendMessageWithSse(
|
38 |
+
`/api/v1/${from === SharedFrom.Agent ? 'agentbots' : 'chatbots'}/${conversationId}/completions`,
|
39 |
);
|
40 |
const {
|
41 |
derivedMessages,
|
|
|
43 |
removeLatestMessage,
|
44 |
addNewestAnswer,
|
45 |
addNewestQuestion,
|
46 |
+
} = useSelectDerivedMessages();
|
47 |
+
const [hasError, setHasError] = useState(false);
|
48 |
|
49 |
const sendMessage = useCallback(
|
50 |
async (message: Message, id?: string) => {
|
51 |
const res = await send({
|
52 |
conversation_id: id ?? conversationId,
|
53 |
+
quote: true,
|
54 |
+
question: message.content,
|
55 |
+
session_id: get(derivedMessages, '0.session_id'),
|
56 |
});
|
57 |
|
58 |
+
if (isCompletionError(res)) {
|
59 |
// cancel loading
|
60 |
setValue(message.content);
|
61 |
removeLatestMessage();
|
62 |
}
|
63 |
},
|
64 |
+
[send, conversationId, derivedMessages, setValue, removeLatestMessage],
|
65 |
);
|
66 |
|
67 |
const handleSendMessage = useCallback(
|
|
|
79 |
[conversationId, setConversation, sendMessage],
|
80 |
);
|
81 |
|
82 |
+
const fetchSessionId = useCallback(async () => {
|
83 |
+
const ret = await send({ question: '' });
|
84 |
+
if (isCompletionError(ret)) {
|
85 |
+
message.error(ret?.data.message);
|
86 |
+
setHasError(true);
|
87 |
+
}
|
88 |
+
}, [send]);
|
89 |
+
|
90 |
+
useEffect(() => {
|
91 |
+
fetchSessionId();
|
92 |
+
}, [fetchSessionId, send]);
|
93 |
+
|
94 |
useEffect(() => {
|
95 |
if (answer.answer) {
|
96 |
addNewestAnswer(answer);
|
|
|
125 |
value,
|
126 |
sendLoading: !done,
|
127 |
ref,
|
128 |
+
loading: false,
|
129 |
derivedMessages,
|
130 |
+
hasError,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
131 |
};
|
132 |
};
|
web/src/pages/flow/header/index.tsx
CHANGED
@@ -1,13 +1,15 @@
|
|
1 |
-
import
|
2 |
-
import {
|
|
|
|
|
3 |
import { useFetchFlow } from '@/hooks/flow-hooks';
|
4 |
import { ArrowLeftOutlined } from '@ant-design/icons';
|
5 |
import { Button, Flex, Space } from 'antd';
|
6 |
import { useCallback } from 'react';
|
7 |
import { Link, useParams } from 'umi';
|
8 |
-
import FlowIdModal from '../flow-id-modal';
|
9 |
import {
|
10 |
useGetBeginNodeDataQuery,
|
|
|
11 |
useSaveGraph,
|
12 |
useSaveGraphBeforeOpeningDebugDrawer,
|
13 |
useWatchAgentChange,
|
@@ -25,15 +27,16 @@ const FlowHeader = ({ showChatDrawer, chatDrawerVisible }: IProps) => {
|
|
25 |
const { handleRun } = useSaveGraphBeforeOpeningDebugDrawer(showChatDrawer);
|
26 |
const { data } = useFetchFlow();
|
27 |
const { t } = useTranslate('flow');
|
28 |
-
const {
|
29 |
-
visible: overviewVisible,
|
30 |
-
hideModal: hideOverviewModal,
|
31 |
-
// showModal: showOverviewModal,
|
32 |
-
} = useSetModalState();
|
33 |
-
const { visible, hideModal, showModal } = useSetModalState();
|
34 |
const { id } = useParams();
|
35 |
const time = useWatchAgentChange(chatDrawerVisible);
|
36 |
const getBeginNodeDataQuery = useGetBeginNodeDataQuery();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
|
38 |
const handleRunAgent = useCallback(() => {
|
39 |
const query: BeginQuery[] = getBeginNodeDataQuery();
|
@@ -70,23 +73,25 @@ const FlowHeader = ({ showChatDrawer, chatDrawerVisible }: IProps) => {
|
|
70 |
<Button type="primary" onClick={() => saveGraph()}>
|
71 |
<b>{t('save')}</b>
|
72 |
</Button>
|
73 |
-
|
|
|
|
|
|
|
|
|
74 |
<b>{t('publish')}</b>
|
75 |
-
</Button> */}
|
76 |
-
<Button type="primary" onClick={showModal}>
|
77 |
-
<b>Agent ID</b>
|
78 |
</Button>
|
79 |
</Space>
|
80 |
</Flex>
|
81 |
-
{
|
82 |
-
<
|
83 |
-
visible={
|
84 |
-
hideModal={
|
85 |
-
|
86 |
-
|
87 |
-
|
|
|
|
|
88 |
)}
|
89 |
-
{visible && <FlowIdModal hideModal={hideModal}></FlowIdModal>}
|
90 |
</>
|
91 |
);
|
92 |
};
|
|
|
1 |
+
import EmbedModal from '@/components/api-service/embed-modal';
|
2 |
+
import { useShowEmbedModal } from '@/components/api-service/hooks';
|
3 |
+
import { SharedFrom } from '@/constants/chat';
|
4 |
+
import { useTranslate } from '@/hooks/common-hooks';
|
5 |
import { useFetchFlow } from '@/hooks/flow-hooks';
|
6 |
import { ArrowLeftOutlined } from '@ant-design/icons';
|
7 |
import { Button, Flex, Space } from 'antd';
|
8 |
import { useCallback } from 'react';
|
9 |
import { Link, useParams } from 'umi';
|
|
|
10 |
import {
|
11 |
useGetBeginNodeDataQuery,
|
12 |
+
useGetBeginNodeDataQueryIsEmpty,
|
13 |
useSaveGraph,
|
14 |
useSaveGraphBeforeOpeningDebugDrawer,
|
15 |
useWatchAgentChange,
|
|
|
27 |
const { handleRun } = useSaveGraphBeforeOpeningDebugDrawer(showChatDrawer);
|
28 |
const { data } = useFetchFlow();
|
29 |
const { t } = useTranslate('flow');
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
const { id } = useParams();
|
31 |
const time = useWatchAgentChange(chatDrawerVisible);
|
32 |
const getBeginNodeDataQuery = useGetBeginNodeDataQuery();
|
33 |
+
const { showEmbedModal, hideEmbedModal, embedVisible, beta } =
|
34 |
+
useShowEmbedModal();
|
35 |
+
const isBeginNodeDataQueryEmpty = useGetBeginNodeDataQueryIsEmpty();
|
36 |
+
|
37 |
+
const handleShowEmbedModal = useCallback(() => {
|
38 |
+
showEmbedModal();
|
39 |
+
}, [showEmbedModal]);
|
40 |
|
41 |
const handleRunAgent = useCallback(() => {
|
42 |
const query: BeginQuery[] = getBeginNodeDataQuery();
|
|
|
73 |
<Button type="primary" onClick={() => saveGraph()}>
|
74 |
<b>{t('save')}</b>
|
75 |
</Button>
|
76 |
+
<Button
|
77 |
+
type="primary"
|
78 |
+
onClick={handleShowEmbedModal}
|
79 |
+
disabled={!isBeginNodeDataQueryEmpty}
|
80 |
+
>
|
81 |
<b>{t('publish')}</b>
|
|
|
|
|
|
|
82 |
</Button>
|
83 |
</Space>
|
84 |
</Flex>
|
85 |
+
{embedVisible && (
|
86 |
+
<EmbedModal
|
87 |
+
visible={embedVisible}
|
88 |
+
hideModal={hideEmbedModal}
|
89 |
+
token={id!}
|
90 |
+
form={SharedFrom.Agent}
|
91 |
+
beta={beta}
|
92 |
+
isAgent
|
93 |
+
></EmbedModal>
|
94 |
)}
|
|
|
95 |
</>
|
96 |
);
|
97 |
};
|
web/src/pages/flow/hooks.tsx
CHANGED
@@ -474,6 +474,20 @@ export const useGetBeginNodeDataQuery = () => {
|
|
474 |
return getBeginNodeDataQuery;
|
475 |
};
|
476 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
477 |
export const useSaveGraphBeforeOpeningDebugDrawer = (show: () => void) => {
|
478 |
const { saveGraph, loading } = useSaveGraph();
|
479 |
const { resetFlow } = useResetFlow();
|
|
|
474 |
return getBeginNodeDataQuery;
|
475 |
};
|
476 |
|
477 |
+
export const useGetBeginNodeDataQueryIsEmpty = () => {
|
478 |
+
const [isBeginNodeDataQueryEmpty, setIsBeginNodeDataQueryEmpty] =
|
479 |
+
useState(false);
|
480 |
+
const getBeginNodeDataQuery = useGetBeginNodeDataQuery();
|
481 |
+
const nodes = useGraphStore((state) => state.nodes);
|
482 |
+
|
483 |
+
useEffect(() => {
|
484 |
+
const query: BeginQuery[] = getBeginNodeDataQuery();
|
485 |
+
setIsBeginNodeDataQueryEmpty(query.length === 0);
|
486 |
+
}, [getBeginNodeDataQuery, nodes]);
|
487 |
+
|
488 |
+
return isBeginNodeDataQueryEmpty;
|
489 |
+
};
|
490 |
+
|
491 |
export const useSaveGraphBeforeOpeningDebugDrawer = (show: () => void) => {
|
492 |
const { saveGraph, loading } = useSaveGraph();
|
493 |
const { resetFlow } = useResetFlow();
|
web/src/utils/authorization-util.ts
CHANGED
@@ -47,9 +47,9 @@ const storage = {
|
|
47 |
};
|
48 |
|
49 |
export const getAuthorization = () => {
|
50 |
-
const
|
51 |
-
const authorization =
|
52 |
-
? 'Bearer ' +
|
53 |
: storage.getAuthorization() || '';
|
54 |
|
55 |
return authorization;
|
|
|
47 |
};
|
48 |
|
49 |
export const getAuthorization = () => {
|
50 |
+
const auth = getSearchValue('auth');
|
51 |
+
const authorization = auth
|
52 |
+
? 'Bearer ' + auth
|
53 |
: storage.getAuthorization() || '';
|
54 |
|
55 |
return authorization;
|
web/src/utils/document-util.ts
CHANGED
@@ -1,10 +1,12 @@
|
|
1 |
import { Images, SupportedPreviewDocumentTypes } from '@/constants/common';
|
|
|
2 |
import { IChunk } from '@/interfaces/database/knowledge';
|
3 |
import { UploadFile } from 'antd';
|
|
|
4 |
import { v4 as uuid } from 'uuid';
|
5 |
|
6 |
export const buildChunkHighlights = (
|
7 |
-
selectedChunk: IChunk,
|
8 |
size: { width: number; height: number },
|
9 |
) => {
|
10 |
return Array.isArray(selectedChunk?.positions) &&
|
@@ -24,7 +26,11 @@ export const buildChunkHighlights = (
|
|
24 |
text: '',
|
25 |
emoji: '',
|
26 |
},
|
27 |
-
content: {
|
|
|
|
|
|
|
|
|
28 |
position: {
|
29 |
boundingRect: boundingRect,
|
30 |
rects: [boundingRect],
|
|
|
1 |
import { Images, SupportedPreviewDocumentTypes } from '@/constants/common';
|
2 |
+
import { IReferenceChunk } from '@/interfaces/database/chat';
|
3 |
import { IChunk } from '@/interfaces/database/knowledge';
|
4 |
import { UploadFile } from 'antd';
|
5 |
+
import { get } from 'lodash';
|
6 |
import { v4 as uuid } from 'uuid';
|
7 |
|
8 |
export const buildChunkHighlights = (
|
9 |
+
selectedChunk: IChunk | IReferenceChunk,
|
10 |
size: { width: number; height: number },
|
11 |
) => {
|
12 |
return Array.isArray(selectedChunk?.positions) &&
|
|
|
26 |
text: '',
|
27 |
emoji: '',
|
28 |
},
|
29 |
+
content: {
|
30 |
+
text:
|
31 |
+
get(selectedChunk, 'content_with_weight') ||
|
32 |
+
get(selectedChunk, 'content', ''),
|
33 |
+
},
|
34 |
position: {
|
35 |
boundingRect: boundingRect,
|
36 |
rects: [boundingRect],
|