balibabu commited on
Commit
7ba250b
·
1 Parent(s): 8f4f7c1

feat: translate EmbedModal #345 (#455)

Browse files

### What problem does this PR solve?

Embed the chat window into other websites through iframe

#345

### Type of change


- [x] New Feature (non-breaking change which adds functionality)

web/src/{pages/chat/share/shared-markdown.tsx → components/highlight-markdown/index.tsx} RENAMED
@@ -2,7 +2,11 @@ import Markdown from 'react-markdown';
2
  import SyntaxHighlighter from 'react-syntax-highlighter';
3
  import remarkGfm from 'remark-gfm';
4
 
5
- const SharedMarkdown = ({ content }: { content: string }) => {
 
 
 
 
6
  return (
7
  <Markdown
8
  remarkPlugins={[remarkGfm]}
@@ -24,9 +28,9 @@ const SharedMarkdown = ({ content }: { content: string }) => {
24
  } as any
25
  }
26
  >
27
- {content}
28
  </Markdown>
29
  );
30
  };
31
 
32
- export default SharedMarkdown;
 
2
  import SyntaxHighlighter from 'react-syntax-highlighter';
3
  import remarkGfm from 'remark-gfm';
4
 
5
+ const HightLightMarkdown = ({
6
+ children,
7
+ }: {
8
+ children: string | null | undefined;
9
+ }) => {
10
  return (
11
  <Markdown
12
  remarkPlugins={[remarkGfm]}
 
28
  } as any
29
  }
30
  >
31
+ {children}
32
  </Markdown>
33
  );
34
  };
35
 
36
+ export default HightLightMarkdown;
web/src/hooks/chatHooks.ts CHANGED
@@ -4,7 +4,7 @@ import {
4
  IStats,
5
  IToken,
6
  } from '@/interfaces/database/chat';
7
- import { useCallback, useEffect, useState } from 'react';
8
  import { useDispatch, useSelector } from 'umi';
9
 
10
  export const useFetchDialogList = () => {
@@ -299,27 +299,4 @@ export const useCompleteSharedConversation = () => {
299
  return completeSharedConversation;
300
  };
301
 
302
- export const useCreatePublicUrlToken = (dialogId: string, visible: boolean) => {
303
- const [token, setToken] = useState();
304
- const createToken = useCreateToken(dialogId);
305
- const { protocol, host } = window.location;
306
-
307
- const urlWithToken = `${protocol}//${host}/chat/share?shared_id=${token}`;
308
-
309
- const createUrlToken = useCallback(async () => {
310
- if (visible) {
311
- const data = await createToken();
312
- const urlToken = data.data?.token;
313
- if (urlToken) {
314
- setToken(urlToken);
315
- }
316
- }
317
- }, [createToken, visible]);
318
-
319
- useEffect(() => {
320
- createUrlToken();
321
- }, [createUrlToken]);
322
-
323
- return { token, createUrlToken, urlWithToken };
324
- };
325
  //#endregion
 
4
  IStats,
5
  IToken,
6
  } from '@/interfaces/database/chat';
7
+ import { useCallback } from 'react';
8
  import { useDispatch, useSelector } from 'umi';
9
 
10
  export const useFetchDialogList = () => {
 
299
  return completeSharedConversation;
300
  };
301
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
302
  //#endregion
web/src/less/mixins.less CHANGED
@@ -33,3 +33,12 @@
33
  .pointerCursor() {
34
  cursor: pointer;
35
  }
 
 
 
 
 
 
 
 
 
 
33
  .pointerCursor() {
34
  cursor: pointer;
35
  }
36
+
37
+ .clearCardBody() {
38
+ :global {
39
+ .ant-card-body {
40
+ padding: 0;
41
+ margin: 0;
42
+ }
43
+ }
44
+ }
web/src/locales/en.ts CHANGED
@@ -349,7 +349,7 @@ export default {
349
  'This sets the maximum length of the model’s output, measured in the number of tokens (words or pieces of words).',
350
  quote: 'Show Quote',
351
  quoteTip: 'Should the source of the original text be displayed?',
352
- overview: 'Overview',
353
  pv: 'Number of messages',
354
  uv: 'Active user number',
355
  speed: 'Token output speed',
@@ -367,6 +367,14 @@ export default {
367
  createNewKey: 'Create new key',
368
  created: 'Created',
369
  action: 'Action',
 
 
 
 
 
 
 
 
370
  },
371
  setting: {
372
  profile: 'Profile',
 
349
  'This sets the maximum length of the model’s output, measured in the number of tokens (words or pieces of words).',
350
  quote: 'Show Quote',
351
  quoteTip: 'Should the source of the original text be displayed?',
352
+ overview: 'API',
353
  pv: 'Number of messages',
354
  uv: 'Active user number',
355
  speed: 'Token output speed',
 
367
  createNewKey: 'Create new key',
368
  created: 'Created',
369
  action: 'Action',
370
+ embedModalTitle: 'Embed into website',
371
+ comingSoon: 'Coming Soon',
372
+ fullScreenTitle: 'Full Embed',
373
+ fullScreenDescription:
374
+ 'Embed the following iframe into your website at the desired location',
375
+ partialTitle: 'Partial Embed',
376
+ extensionTitle: 'Chrome Extension',
377
+ tokenError: 'Please create API Token first!',
378
  },
379
  setting: {
380
  profile: 'Profile',
web/src/locales/zh-traditional.ts CHANGED
@@ -321,7 +321,7 @@ export default {
321
  '這設置了模型輸出的最大長度,以標記(單詞或單詞片段)的數量來衡量。',
322
  quote: '顯示引文',
323
  quoteTip: '是否應該顯示原文出處?',
324
- overview: '概覽',
325
  pv: '消息數',
326
  uv: '活躍用戶數',
327
  speed: 'Token 輸出速度',
@@ -339,6 +339,13 @@ export default {
339
  createNewKey: '創建新密鑰',
340
  created: '創建於',
341
  action: '操作',
 
 
 
 
 
 
 
342
  },
343
  setting: {
344
  profile: '概述',
 
321
  '這設置了模型輸出的最大長度,以標記(單詞或單詞片段)的數量來衡量。',
322
  quote: '顯示引文',
323
  quoteTip: '是否應該顯示原文出處?',
324
+ overview: 'API',
325
  pv: '消息數',
326
  uv: '活躍用戶數',
327
  speed: 'Token 輸出速度',
 
339
  createNewKey: '創建新密鑰',
340
  created: '創建於',
341
  action: '操作',
342
+ embedModalTitle: '嵌入網站',
343
+ comingSoon: '即將推出',
344
+ fullScreenTitle: '全屏嵌入',
345
+ fullScreenDescription: '將以下iframe嵌入您的網站處於所需位置',
346
+ partialTitle: '部分嵌入',
347
+ extensionTitle: 'Chrome 插件',
348
+ tokenError: '請先創建 Api Token!',
349
  },
350
  setting: {
351
  profile: '概述',
web/src/locales/zh.ts CHANGED
@@ -338,7 +338,7 @@ export default {
338
  '这设置了模型输出的最大长度,以标记(单词或单词片段)的数量来衡量。',
339
  quote: '显示引文',
340
  quoteTip: '是否应该显示原文出处?',
341
- overview: '概览',
342
  pv: '消息数',
343
  uv: '活跃用户数',
344
  speed: 'Token 输出速度',
@@ -356,6 +356,13 @@ export default {
356
  createNewKey: '创建新密钥',
357
  created: '创建于',
358
  action: '操作',
 
 
 
 
 
 
 
359
  },
360
  setting: {
361
  profile: '概要',
 
338
  '这设置了模型输出的最大长度,以标记(单词或单词片段)的数量来衡量。',
339
  quote: '显示引文',
340
  quoteTip: '是否应该显示原文出处?',
341
+ overview: 'API',
342
  pv: '消息数',
343
  uv: '活跃用户数',
344
  speed: 'Token 输出速度',
 
356
  createNewKey: '创建新密钥',
357
  created: '创建于',
358
  action: '操作',
359
+ embedModalTitle: '嵌入网站',
360
+ comingSoon: '即将推出',
361
+ fullScreenTitle: '全屏嵌入',
362
+ fullScreenDescription: '将以下iframe嵌入您的网站处于所需位置',
363
+ partialTitle: '部分嵌入',
364
+ extensionTitle: 'Chrome 插件',
365
+ tokenError: '请先创建 Api Token!',
366
  },
367
  setting: {
368
  profile: '概要',
web/src/pages/chat/chat-overview-modal/index.tsx CHANGED
@@ -1,17 +1,19 @@
1
- import CopyToClipboard from '@/components/copy-to-clipboard';
2
  import LineChart from '@/components/line-chart';
3
- import { useCreatePublicUrlToken } from '@/hooks/chatHooks';
4
  import { useSetModalState, useTranslate } from '@/hooks/commonHooks';
5
  import { IModalProps } from '@/interfaces/common';
6
  import { IDialog, IStats } from '@/interfaces/database/chat';
7
- import { ReloadOutlined } from '@ant-design/icons';
8
  import { Button, Card, DatePicker, Flex, Modal, Space, Typography } from 'antd';
9
  import { RangePickerProps } from 'antd/es/date-picker';
10
  import dayjs from 'dayjs';
11
  import camelCase from 'lodash/camelCase';
12
- import { Link } from 'umi';
13
  import ChatApiKeyModal from '../chat-api-key-modal';
14
- import { useFetchStatsOnMount, useSelectChartStatsList } from '../hooks';
 
 
 
 
 
 
15
  import styles from './index.less';
16
 
17
  const { Paragraph } = Typography;
@@ -24,16 +26,18 @@ const ChatOverviewModal = ({
24
  }: IModalProps<any> & { dialog: IDialog }) => {
25
  const { t } = useTranslate('chat');
26
  const chartList = useSelectChartStatsList();
27
- const { urlWithToken, createUrlToken, token } = useCreatePublicUrlToken(
28
- dialog.id,
29
- visible,
30
- );
31
-
32
  const {
33
  visible: apiKeyVisible,
34
  hideModal: hideApiKeyModal,
35
  showModal: showApiKeyModal,
36
  } = useSetModalState();
 
 
 
 
 
 
 
37
 
38
  const { pickerValue, setPickerValue } = useFetchStatsOnMount(visible);
39
 
@@ -41,6 +45,8 @@ const ChatOverviewModal = ({
41
  return current && current > dayjs().endOf('day');
42
  };
43
 
 
 
44
  return (
45
  <>
46
  <Modal
@@ -50,36 +56,41 @@ const ChatOverviewModal = ({
50
  width={'100vw'}
51
  >
52
  <Flex vertical gap={'middle'}>
53
- <Card title={dialog.name}>
54
- <Flex gap={8} vertical>
55
- {t('publicUrl')}
56
- <Flex className={styles.linkText} gap={10}>
57
- <span>{urlWithToken}</span>
58
- <CopyToClipboard text={urlWithToken}></CopyToClipboard>
59
- <ReloadOutlined onClick={createUrlToken} />
60
- </Flex>
61
- <Space size={'middle'}>
62
- <Button>
63
- <Link to={`/chat/share?shared_id=${token}`} target="_blank">
64
- {t('preview')}
65
- </Link>
66
- </Button>
67
- <Button>{t('embedded')}</Button>
68
- </Space>
69
- </Flex>
70
- </Card>
71
  <Card title={t('backendServiceApi')}>
72
  <Flex gap={8} vertical>
73
  {t('serviceApiEndpoint')}
74
  <Paragraph copyable className={styles.linkText}>
75
- This is a copyable text.
76
  </Paragraph>
77
  </Flex>
78
  <Space size={'middle'}>
79
  <Button onClick={showApiKeyModal}>{t('apiKey')}</Button>
80
- <Button>{t('apiReference')}</Button>
 
 
 
 
 
 
 
 
81
  </Space>
82
  </Card>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  <Space>
84
  <b>{t('dateRange')}</b>
85
  <RangePicker
@@ -103,6 +114,13 @@ const ChatOverviewModal = ({
103
  hideModal={hideApiKeyModal}
104
  dialogId={dialog.id}
105
  ></ChatApiKeyModal>
 
 
 
 
 
 
 
106
  </Modal>
107
  </>
108
  );
 
 
1
  import LineChart from '@/components/line-chart';
 
2
  import { useSetModalState, useTranslate } from '@/hooks/commonHooks';
3
  import { IModalProps } from '@/interfaces/common';
4
  import { IDialog, IStats } from '@/interfaces/database/chat';
 
5
  import { Button, Card, DatePicker, Flex, Modal, Space, Typography } from 'antd';
6
  import { RangePickerProps } from 'antd/es/date-picker';
7
  import dayjs from 'dayjs';
8
  import camelCase from 'lodash/camelCase';
 
9
  import ChatApiKeyModal from '../chat-api-key-modal';
10
+ import EmbedModal from '../embed-modal';
11
+ import {
12
+ useFetchStatsOnMount,
13
+ usePreviewChat,
14
+ useSelectChartStatsList,
15
+ useShowEmbedModal,
16
+ } from '../hooks';
17
  import styles from './index.less';
18
 
19
  const { Paragraph } = Typography;
 
26
  }: IModalProps<any> & { dialog: IDialog }) => {
27
  const { t } = useTranslate('chat');
28
  const chartList = useSelectChartStatsList();
 
 
 
 
 
29
  const {
30
  visible: apiKeyVisible,
31
  hideModal: hideApiKeyModal,
32
  showModal: showApiKeyModal,
33
  } = useSetModalState();
34
+ const {
35
+ embedVisible,
36
+ hideEmbedModal,
37
+ showEmbedModal,
38
+ embedToken,
39
+ errorContextHolder,
40
+ } = useShowEmbedModal(dialog.id);
41
 
42
  const { pickerValue, setPickerValue } = useFetchStatsOnMount(visible);
43
 
 
45
  return current && current > dayjs().endOf('day');
46
  };
47
 
48
+ const { handlePreview, contextHolder } = usePreviewChat(dialog.id);
49
+
50
  return (
51
  <>
52
  <Modal
 
56
  width={'100vw'}
57
  >
58
  <Flex vertical gap={'middle'}>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  <Card title={t('backendServiceApi')}>
60
  <Flex gap={8} vertical>
61
  {t('serviceApiEndpoint')}
62
  <Paragraph copyable className={styles.linkText}>
63
+ https://demo.ragflow.io/v1/api/
64
  </Paragraph>
65
  </Flex>
66
  <Space size={'middle'}>
67
  <Button onClick={showApiKeyModal}>{t('apiKey')}</Button>
68
+ <a
69
+ href={
70
+ 'https://github.com/infiniflow/ragflow/blob/main/docs/conversation_api.md'
71
+ }
72
+ target="_blank"
73
+ rel="noreferrer"
74
+ >
75
+ <Button>{t('apiReference')}</Button>
76
+ </a>
77
  </Space>
78
  </Card>
79
+ <Card title={dialog.name}>
80
+ <Flex gap={8} vertical>
81
+ {t('publicUrl')}
82
+ {/* <Flex className={styles.linkText} gap={10}>
83
+ <span>{urlWithToken}</span>
84
+ <CopyToClipboard text={urlWithToken}></CopyToClipboard>
85
+ <ReloadOutlined onClick={createUrlToken} />
86
+ </Flex> */}
87
+ <Space size={'middle'}>
88
+ <Button onClick={handlePreview}>{t('preview')}</Button>
89
+ <Button onClick={showEmbedModal}>{t('embedded')}</Button>
90
+ </Space>
91
+ </Flex>
92
+ </Card>
93
+
94
  <Space>
95
  <b>{t('dateRange')}</b>
96
  <RangePicker
 
114
  hideModal={hideApiKeyModal}
115
  dialogId={dialog.id}
116
  ></ChatApiKeyModal>
117
+ <EmbedModal
118
+ token={embedToken}
119
+ visible={embedVisible}
120
+ hideModal={hideEmbedModal}
121
+ ></EmbedModal>
122
+ {contextHolder}
123
+ {errorContextHolder}
124
  </Modal>
125
  </>
126
  );
web/src/pages/chat/embed-modal/index.less ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ .codeCard {
2
+ .clearCardBody();
3
+ }
4
+
5
+ .codeText {
6
+ padding: 10px;
7
+ background-color: #e8e8ea;
8
+ }
web/src/pages/chat/embed-modal/index.tsx ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import CopyToClipboard from '@/components/copy-to-clipboard';
2
+ import HightLightMarkdown from '@/components/highlight-markdown';
3
+ import { useTranslate } from '@/hooks/commonHooks';
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
+ }: IModalProps<any> & { token: string }) => {
13
+ const { t } = useTranslate('chat');
14
+
15
+ const text = `
16
+ ~~~ html
17
+ <iframe
18
+ src="https://demo.ragflow.io/chat/share?shared_id=${token}"
19
+ style="width: 100%; height: 100%; min-height: 600px"
20
+ frameborder="0"
21
+ >
22
+ </iframe>
23
+ ~~~
24
+ `;
25
+
26
+ const items: TabsProps['items'] = [
27
+ {
28
+ key: '1',
29
+ label: t('fullScreenTitle'),
30
+ children: (
31
+ <Card
32
+ title={t('fullScreenDescription')}
33
+ extra={<CopyToClipboard text={text}></CopyToClipboard>}
34
+ className={styles.codeCard}
35
+ >
36
+ <HightLightMarkdown>{text}</HightLightMarkdown>
37
+ </Card>
38
+ ),
39
+ },
40
+ {
41
+ key: '2',
42
+ label: t('partialTitle'),
43
+ children: t('comingSoon'),
44
+ },
45
+ {
46
+ key: '3',
47
+ label: t('extensionTitle'),
48
+ children: t('comingSoon'),
49
+ },
50
+ ];
51
+
52
+ const onChange = (key: string) => {
53
+ console.log(key);
54
+ };
55
+
56
+ return (
57
+ <Modal
58
+ title={t('embedModalTitle')}
59
+ open={visible}
60
+ style={{ top: 300 }}
61
+ width={'50vw'}
62
+ onOk={hideModal}
63
+ onCancel={hideModal}
64
+ >
65
+ <Tabs defaultActiveKey="1" items={items} onChange={onChange} />
66
+ </Modal>
67
+ );
68
+ };
69
+
70
+ export default EmbedModal;
web/src/pages/chat/hooks.ts CHANGED
@@ -14,15 +14,21 @@ import {
14
  useRemoveToken,
15
  useSelectConversationList,
16
  useSelectDialogList,
 
17
  useSelectTokenList,
18
  useSetDialog,
19
  useUpdateConversation,
20
  } from '@/hooks/chatHooks';
21
- import { useSetModalState, useShowDeleteConfirm } from '@/hooks/commonHooks';
 
 
 
 
22
  import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
23
  import { IConversation, IDialog, IStats } from '@/interfaces/database/chat';
24
  import { IChunk } from '@/interfaces/database/knowledge';
25
  import { getFileExtension } from '@/utils';
 
26
  import dayjs, { Dayjs } from 'dayjs';
27
  import omit from 'lodash/omit';
28
  import {
@@ -777,35 +783,35 @@ type ChartStatsType = {
777
  };
778
 
779
  export const useSelectChartStatsList = (): ChartStatsType => {
780
- // const stats: IStats = useSelectStats();
781
- const stats = {
782
- pv: [
783
- ['2024-06-01', 1],
784
- ['2024-07-24', 3],
785
- ['2024-09-01', 10],
786
- ],
787
- uv: [
788
- ['2024-02-01', 0],
789
- ['2024-03-01', 99],
790
- ['2024-05-01', 3],
791
- ],
792
- speed: [
793
- ['2024-09-01', 2],
794
- ['2024-09-01', 3],
795
- ],
796
- tokens: [
797
- ['2024-09-01', 1],
798
- ['2024-09-01', 3],
799
- ],
800
- round: [
801
- ['2024-09-01', 0],
802
- ['2024-09-01', 3],
803
- ],
804
- thumb_up: [
805
- ['2024-09-01', 3],
806
- ['2024-09-01', 9],
807
- ],
808
- };
809
 
810
  return Object.keys(stats).reduce((pre, cur) => {
811
  const item = stats[cur as keyof IStats];
@@ -819,4 +825,93 @@ export const useSelectChartStatsList = (): ChartStatsType => {
819
  }, {} as ChartStatsType);
820
  };
821
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
822
  //#endregion
 
14
  useRemoveToken,
15
  useSelectConversationList,
16
  useSelectDialogList,
17
+ useSelectStats,
18
  useSelectTokenList,
19
  useSetDialog,
20
  useUpdateConversation,
21
  } from '@/hooks/chatHooks';
22
+ import {
23
+ useSetModalState,
24
+ useShowDeleteConfirm,
25
+ useTranslate,
26
+ } from '@/hooks/commonHooks';
27
  import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
28
  import { IConversation, IDialog, IStats } from '@/interfaces/database/chat';
29
  import { IChunk } from '@/interfaces/database/knowledge';
30
  import { getFileExtension } from '@/utils';
31
+ import { message } from 'antd';
32
  import dayjs, { Dayjs } from 'dayjs';
33
  import omit from 'lodash/omit';
34
  import {
 
783
  };
784
 
785
  export const useSelectChartStatsList = (): ChartStatsType => {
786
+ const stats: IStats = useSelectStats();
787
+ // const stats = {
788
+ // pv: [
789
+ // ['2024-06-01', 1],
790
+ // ['2024-07-24', 3],
791
+ // ['2024-09-01', 10],
792
+ // ],
793
+ // uv: [
794
+ // ['2024-02-01', 0],
795
+ // ['2024-03-01', 99],
796
+ // ['2024-05-01', 3],
797
+ // ],
798
+ // speed: [
799
+ // ['2024-09-01', 2],
800
+ // ['2024-09-01', 3],
801
+ // ],
802
+ // tokens: [
803
+ // ['2024-09-01', 1],
804
+ // ['2024-09-01', 3],
805
+ // ],
806
+ // round: [
807
+ // ['2024-09-01', 0],
808
+ // ['2024-09-01', 3],
809
+ // ],
810
+ // thumb_up: [
811
+ // ['2024-09-01', 3],
812
+ // ['2024-09-01', 9],
813
+ // ],
814
+ // };
815
 
816
  return Object.keys(stats).reduce((pre, cur) => {
817
  const item = stats[cur as keyof IStats];
 
825
  }, {} as ChartStatsType);
826
  };
827
 
828
+ export const useShowTokenEmptyError = () => {
829
+ const [messageApi, contextHolder] = message.useMessage();
830
+ const { t } = useTranslate('chat');
831
+
832
+ const showTokenEmptyError = useCallback(() => {
833
+ messageApi.error(t('tokenError'));
834
+ }, [messageApi, t]);
835
+ return { showTokenEmptyError, contextHolder };
836
+ };
837
+
838
+ const getUrlWithToken = (token: string) => {
839
+ const { protocol, host } = window.location;
840
+ return `${protocol}//${host}/chat/share?shared_id=${token}`;
841
+ };
842
+
843
+ const useFetchTokenListBeforeOtherStep = (dialogId: string) => {
844
+ const { showTokenEmptyError, contextHolder } = useShowTokenEmptyError();
845
+
846
+ const listToken = useListToken();
847
+ const tokenList = useSelectTokenList();
848
+
849
+ const token =
850
+ Array.isArray(tokenList) && tokenList.length > 0 ? tokenList[0].token : '';
851
+
852
+ const handleOperate = useCallback(async () => {
853
+ const data = await listToken(dialogId);
854
+ const list = data.data;
855
+ if (data.retcode === 0 && Array.isArray(list) && list.length > 0) {
856
+ return list[0]?.token;
857
+ } else {
858
+ showTokenEmptyError();
859
+ return false;
860
+ }
861
+ }, [dialogId, listToken, showTokenEmptyError]);
862
+
863
+ return {
864
+ token,
865
+ contextHolder,
866
+ handleOperate,
867
+ };
868
+ };
869
+
870
+ export const useShowEmbedModal = (dialogId: string) => {
871
+ const {
872
+ visible: embedVisible,
873
+ hideModal: hideEmbedModal,
874
+ showModal: showEmbedModal,
875
+ } = useSetModalState();
876
+
877
+ const { handleOperate, token, contextHolder } =
878
+ useFetchTokenListBeforeOtherStep(dialogId);
879
+
880
+ const handleShowEmbedModal = useCallback(async () => {
881
+ const succeed = await handleOperate();
882
+ if (succeed) {
883
+ showEmbedModal();
884
+ }
885
+ }, [handleOperate, showEmbedModal]);
886
+
887
+ return {
888
+ showEmbedModal: handleShowEmbedModal,
889
+ hideEmbedModal,
890
+ embedVisible,
891
+ embedToken: token,
892
+ errorContextHolder: contextHolder,
893
+ };
894
+ };
895
+
896
+ export const usePreviewChat = (dialogId: string) => {
897
+ const { handleOperate, contextHolder } =
898
+ useFetchTokenListBeforeOtherStep(dialogId);
899
+
900
+ const open = useCallback((t: string) => {
901
+ window.open(getUrlWithToken(t), '_blank');
902
+ }, []);
903
+
904
+ const handlePreview = useCallback(async () => {
905
+ const token = await handleOperate();
906
+ if (token) {
907
+ open(token);
908
+ }
909
+ }, [handleOperate, open]);
910
+
911
+ return {
912
+ handlePreview,
913
+ contextHolder,
914
+ };
915
+ };
916
+
917
  //#endregion
web/src/pages/chat/index.tsx CHANGED
@@ -1,6 +1,11 @@
1
  import { ReactComponent as ChatAppCube } from '@/assets/svg/chat-app-cube.svg';
2
  import RenameModal from '@/components/rename-modal';
3
- import { DeleteOutlined, EditOutlined, FormOutlined } from '@ant-design/icons';
 
 
 
 
 
4
  import {
5
  Avatar,
6
  Button,
@@ -185,16 +190,16 @@ const Chat = () => {
185
  ),
186
  },
187
  { type: 'divider' },
188
- // {
189
- // key: '3',
190
- // onClick: handleShowOverviewModal(dialog),
191
- // label: (
192
- // <Space>
193
- // <ProfileOutlined />
194
- // {t('overview')}
195
- // </Space>
196
- // ),
197
- // },
198
  ];
199
 
200
  return appItems;
 
1
  import { ReactComponent as ChatAppCube } from '@/assets/svg/chat-app-cube.svg';
2
  import RenameModal from '@/components/rename-modal';
3
+ import {
4
+ CloudOutlined,
5
+ DeleteOutlined,
6
+ EditOutlined,
7
+ FormOutlined,
8
+ } from '@ant-design/icons';
9
  import {
10
  Avatar,
11
  Button,
 
190
  ),
191
  },
192
  { type: 'divider' },
193
+ {
194
+ key: '3',
195
+ onClick: handleShowOverviewModal(dialog),
196
+ label: (
197
+ <Space>
198
+ <CloudOutlined />
199
+ {t('overview')}
200
+ </Space>
201
+ ),
202
+ },
203
  ];
204
 
205
  return appItems;
web/src/pages/chat/model.ts CHANGED
@@ -202,7 +202,7 @@ const model: DvaModel<ChatModelState> = {
202
  payload: data.data,
203
  });
204
  }
205
- return data.retcode;
206
  },
207
  *removeToken({ payload }, { call, put }) {
208
  const { data } = yield call(
 
202
  payload: data.data,
203
  });
204
  }
205
+ return data;
206
  },
207
  *removeToken({ payload }, { call, put }) {
208
  const { data } = yield call(
web/src/pages/chat/share/large.tsx CHANGED
@@ -6,10 +6,10 @@ import { Avatar, Button, Flex, Input, Skeleton, Spin } from 'antd';
6
  import classNames from 'classnames';
7
  import { useSelectConversationLoading } from '../hooks';
8
 
 
9
  import React, { ChangeEventHandler, forwardRef } from 'react';
10
  import { IClientConversation } from '../interface';
11
  import styles from './index.less';
12
- import SharedMarkdown from './shared-markdown';
13
 
14
  const MessageItem = ({ item }: { item: Message }) => {
15
  const isAssistant = item.role === MessageType.Assistant;
@@ -46,7 +46,7 @@ const MessageItem = ({ item }: { item: Message }) => {
46
  <b>{isAssistant ? '' : 'You'}</b>
47
  <div className={styles.messageText}>
48
  {item.content !== '' ? (
49
- <SharedMarkdown content={item.content}></SharedMarkdown>
50
  ) : (
51
  <Skeleton active className={styles.messageEmpty} />
52
  )}
 
6
  import classNames from 'classnames';
7
  import { useSelectConversationLoading } from '../hooks';
8
 
9
+ import HightLightMarkdown from '@/components/highlight-markdown';
10
  import React, { ChangeEventHandler, forwardRef } from 'react';
11
  import { IClientConversation } from '../interface';
12
  import styles from './index.less';
 
13
 
14
  const MessageItem = ({ item }: { item: Message }) => {
15
  const isAssistant = item.role === MessageType.Assistant;
 
46
  <b>{isAssistant ? '' : 'You'}</b>
47
  <div className={styles.messageText}>
48
  {item.content !== '' ? (
49
+ <HightLightMarkdown>{item.content}</HightLightMarkdown>
50
  ) : (
51
  <Skeleton active className={styles.messageEmpty} />
52
  )}
web/src/utils/request.ts CHANGED
@@ -98,8 +98,8 @@ request.interceptors.request.use((url: string, options: any) => {
98
  url,
99
  options: {
100
  ...options,
101
- // data,
102
- // params,
103
  headers: {
104
  ...(options.skipToken ? undefined : { [Authorization]: authorization }),
105
  ...options.headers,
 
98
  url,
99
  options: {
100
  ...options,
101
+ data,
102
+ params,
103
  headers: {
104
  ...(options.skipToken ? undefined : { [Authorization]: authorization }),
105
  ...options.headers,