balibabu
		
	commited on
		
		
					Commit 
							
							Β·
						
						5743e5f
	
1
								Parent(s):
							
							4a78f27
								
feat: Expose the agent's chat window to third parties #1842 (#1897)
Browse files### What problem does this PR solve?
feat: Expose the agent's chat window to third parties #1842
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- web/src/{pages/chat β components/api-service}/chat-api-key-modal/index.tsx +4 -4
- web/src/{pages/chat β components/api-service}/chat-overview-modal/index.less +0 -0
- web/src/{pages/chat β components/api-service}/chat-overview-modal/index.tsx +17 -13
- web/src/{pages/chat β components/api-service}/embed-modal/index.less +0 -0
- web/src/{pages/chat β components/api-service}/embed-modal/index.tsx +0 -0
- web/src/components/api-service/hooks.ts +151 -0
- web/src/hooks/chat-hooks.ts +83 -51
- web/src/locales/en.ts +1 -0
- web/src/locales/zh-traditional.ts +1 -0
- web/src/locales/zh.ts +1 -0
- web/src/pages/chat/hooks.ts +1 -213
- web/src/pages/chat/index.tsx +10 -6
- web/src/pages/chat/model.ts +1 -69
- web/src/pages/flow/header/index.tsx +20 -2
    	
        web/src/{pages/chat β components/api-service}/chat-api-key-modal/index.tsx
    RENAMED
    
    | @@ -9,12 +9,12 @@ import { Button, Modal, Space, Table } from 'antd'; | |
| 9 | 
             
            import { useOperateApiKey } from '../hooks';
         | 
| 10 |  | 
| 11 | 
             
            const ChatApiKeyModal = ({
         | 
| 12 | 
            -
              visible,
         | 
| 13 | 
             
              dialogId,
         | 
| 14 | 
             
              hideModal,
         | 
| 15 | 
            -
             | 
|  | |
| 16 | 
             
              const { createToken, removeToken, tokenList, listLoading, creatingLoading } =
         | 
| 17 | 
            -
                useOperateApiKey( | 
| 18 | 
             
              const { t } = useTranslate('chat');
         | 
| 19 |  | 
| 20 | 
             
              const columns: TableProps<IToken>['columns'] = [
         | 
| @@ -48,7 +48,7 @@ const ChatApiKeyModal = ({ | |
| 48 | 
             
                <>
         | 
| 49 | 
             
                  <Modal
         | 
| 50 | 
             
                    title={t('apiKey')}
         | 
| 51 | 
            -
                    open | 
| 52 | 
             
                    onCancel={hideModal}
         | 
| 53 | 
             
                    cancelButtonProps={{ style: { display: 'none' } }}
         | 
| 54 | 
             
                    style={{ top: 300 }}
         | 
|  | |
| 9 | 
             
            import { useOperateApiKey } from '../hooks';
         | 
| 10 |  | 
| 11 | 
             
            const ChatApiKeyModal = ({
         | 
|  | |
| 12 | 
             
              dialogId,
         | 
| 13 | 
             
              hideModal,
         | 
| 14 | 
            +
              idKey,
         | 
| 15 | 
            +
            }: IModalProps<any> & { dialogId: string; idKey: string }) => {
         | 
| 16 | 
             
              const { createToken, removeToken, tokenList, listLoading, creatingLoading } =
         | 
| 17 | 
            +
                useOperateApiKey(dialogId, idKey);
         | 
| 18 | 
             
              const { t } = useTranslate('chat');
         | 
| 19 |  | 
| 20 | 
             
              const columns: TableProps<IToken>['columns'] = [
         | 
|  | |
| 48 | 
             
                <>
         | 
| 49 | 
             
                  <Modal
         | 
| 50 | 
             
                    title={t('apiKey')}
         | 
| 51 | 
            +
                    open
         | 
| 52 | 
             
                    onCancel={hideModal}
         | 
| 53 | 
             
                    cancelButtonProps={{ style: { display: 'none' } }}
         | 
| 54 | 
             
                    style={{ top: 300 }}
         | 
    	
        web/src/{pages/chat β components/api-service}/chat-overview-modal/index.less
    RENAMED
    
    | 
            File without changes
         | 
    	
        web/src/{pages/chat β components/api-service}/chat-overview-modal/index.tsx
    RENAMED
    
    | @@ -1,7 +1,8 @@ | |
| 1 | 
             
            import LineChart from '@/components/line-chart';
         | 
|  | |
| 2 | 
             
            import { useSetModalState, useTranslate } from '@/hooks/common-hooks';
         | 
| 3 | 
             
            import { IModalProps } from '@/interfaces/common';
         | 
| 4 | 
            -
            import {  | 
| 5 | 
             
            import { formatDate } from '@/utils/date';
         | 
| 6 | 
             
            import { Button, Card, DatePicker, Flex, Modal, Space, Typography } from 'antd';
         | 
| 7 | 
             
            import { RangePickerProps } from 'antd/es/date-picker';
         | 
| @@ -10,7 +11,6 @@ import camelCase from 'lodash/camelCase'; | |
| 10 | 
             
            import ChatApiKeyModal from '../chat-api-key-modal';
         | 
| 11 | 
             
            import EmbedModal from '../embed-modal';
         | 
| 12 | 
             
            import {
         | 
| 13 | 
            -
              useFetchStatsOnMount,
         | 
| 14 | 
             
              usePreviewChat,
         | 
| 15 | 
             
              useSelectChartStatsList,
         | 
| 16 | 
             
              useShowEmbedModal,
         | 
| @@ -40,8 +40,10 @@ const StatsLineChart = ({ statsType }: { statsType: keyof IStats }) => { | |
| 40 | 
             
            const ChatOverviewModal = ({
         | 
| 41 | 
             
              visible,
         | 
| 42 | 
             
              hideModal,
         | 
| 43 | 
            -
               | 
| 44 | 
            -
             | 
|  | |
|  | |
| 45 | 
             
              const { t } = useTranslate('chat');
         | 
| 46 | 
             
              const {
         | 
| 47 | 
             
                visible: apiKeyVisible,
         | 
| @@ -54,15 +56,15 @@ const ChatOverviewModal = ({ | |
| 54 | 
             
                showEmbedModal,
         | 
| 55 | 
             
                embedToken,
         | 
| 56 | 
             
                errorContextHolder,
         | 
| 57 | 
            -
              } = useShowEmbedModal( | 
| 58 |  | 
| 59 | 
            -
              const { pickerValue, setPickerValue } =  | 
| 60 |  | 
| 61 | 
             
              const disabledDate: RangePickerProps['disabledDate'] = (current) => {
         | 
| 62 | 
             
                return current && current > dayjs().endOf('day');
         | 
| 63 | 
             
              };
         | 
| 64 |  | 
| 65 | 
            -
              const { handlePreview, contextHolder } = usePreviewChat( | 
| 66 |  | 
| 67 | 
             
              return (
         | 
| 68 | 
             
                <>
         | 
| @@ -97,7 +99,7 @@ const ChatOverviewModal = ({ | |
| 97 | 
             
                          </a>
         | 
| 98 | 
             
                        </Space>
         | 
| 99 | 
             
                      </Card>
         | 
| 100 | 
            -
                      <Card title={`${ | 
| 101 | 
             
                        <Flex gap={8} vertical>
         | 
| 102 | 
             
                          <Space size={'middle'}>
         | 
| 103 | 
             
                            <Button onClick={handlePreview}>{t('preview')}</Button>
         | 
| @@ -124,11 +126,13 @@ const ChatOverviewModal = ({ | |
| 124 | 
             
                        <StatsLineChart statsType={'uv'}></StatsLineChart>
         | 
| 125 | 
             
                      </div>
         | 
| 126 | 
             
                    </Flex>
         | 
| 127 | 
            -
                     | 
| 128 | 
            -
                       | 
| 129 | 
            -
             | 
| 130 | 
            -
             | 
| 131 | 
            -
             | 
|  | |
|  | |
| 132 | 
             
                    <EmbedModal
         | 
| 133 | 
             
                      token={embedToken}
         | 
| 134 | 
             
                      visible={embedVisible}
         | 
|  | |
| 1 | 
             
            import LineChart from '@/components/line-chart';
         | 
| 2 | 
            +
            import { useFetchNextStats } from '@/hooks/chat-hooks';
         | 
| 3 | 
             
            import { useSetModalState, useTranslate } from '@/hooks/common-hooks';
         | 
| 4 | 
             
            import { IModalProps } from '@/interfaces/common';
         | 
| 5 | 
            +
            import { IStats } from '@/interfaces/database/chat';
         | 
| 6 | 
             
            import { formatDate } from '@/utils/date';
         | 
| 7 | 
             
            import { Button, Card, DatePicker, Flex, Modal, Space, Typography } from 'antd';
         | 
| 8 | 
             
            import { RangePickerProps } from 'antd/es/date-picker';
         | 
|  | |
| 11 | 
             
            import ChatApiKeyModal from '../chat-api-key-modal';
         | 
| 12 | 
             
            import EmbedModal from '../embed-modal';
         | 
| 13 | 
             
            import {
         | 
|  | |
| 14 | 
             
              usePreviewChat,
         | 
| 15 | 
             
              useSelectChartStatsList,
         | 
| 16 | 
             
              useShowEmbedModal,
         | 
|  | |
| 40 | 
             
            const ChatOverviewModal = ({
         | 
| 41 | 
             
              visible,
         | 
| 42 | 
             
              hideModal,
         | 
| 43 | 
            +
              id,
         | 
| 44 | 
            +
              name = '',
         | 
| 45 | 
            +
              idKey,
         | 
| 46 | 
            +
            }: IModalProps<any> & { id: string; name?: string; idKey: string }) => {
         | 
| 47 | 
             
              const { t } = useTranslate('chat');
         | 
| 48 | 
             
              const {
         | 
| 49 | 
             
                visible: apiKeyVisible,
         | 
|  | |
| 56 | 
             
                showEmbedModal,
         | 
| 57 | 
             
                embedToken,
         | 
| 58 | 
             
                errorContextHolder,
         | 
| 59 | 
            +
              } = useShowEmbedModal(id, idKey);
         | 
| 60 |  | 
| 61 | 
            +
              const { pickerValue, setPickerValue } = useFetchNextStats();
         | 
| 62 |  | 
| 63 | 
             
              const disabledDate: RangePickerProps['disabledDate'] = (current) => {
         | 
| 64 | 
             
                return current && current > dayjs().endOf('day');
         | 
| 65 | 
             
              };
         | 
| 66 |  | 
| 67 | 
            +
              const { handlePreview, contextHolder } = usePreviewChat(id, idKey);
         | 
| 68 |  | 
| 69 | 
             
              return (
         | 
| 70 | 
             
                <>
         | 
|  | |
| 99 | 
             
                          </a>
         | 
| 100 | 
             
                        </Space>
         | 
| 101 | 
             
                      </Card>
         | 
| 102 | 
            +
                      <Card title={`${name} Web App`}>
         | 
| 103 | 
             
                        <Flex gap={8} vertical>
         | 
| 104 | 
             
                          <Space size={'middle'}>
         | 
| 105 | 
             
                            <Button onClick={handlePreview}>{t('preview')}</Button>
         | 
|  | |
| 126 | 
             
                        <StatsLineChart statsType={'uv'}></StatsLineChart>
         | 
| 127 | 
             
                      </div>
         | 
| 128 | 
             
                    </Flex>
         | 
| 129 | 
            +
                    {apiKeyVisible && (
         | 
| 130 | 
            +
                      <ChatApiKeyModal
         | 
| 131 | 
            +
                        hideModal={hideApiKeyModal}
         | 
| 132 | 
            +
                        dialogId={id}
         | 
| 133 | 
            +
                        idKey={idKey}
         | 
| 134 | 
            +
                      ></ChatApiKeyModal>
         | 
| 135 | 
            +
                    )}
         | 
| 136 | 
             
                    <EmbedModal
         | 
| 137 | 
             
                      token={embedToken}
         | 
| 138 | 
             
                      visible={embedVisible}
         | 
    	
        web/src/{pages/chat β components/api-service}/embed-modal/index.less
    RENAMED
    
    | 
            File without changes
         | 
    	
        web/src/{pages/chat β components/api-service}/embed-modal/index.tsx
    RENAMED
    
    | 
            File without changes
         | 
    	
        web/src/components/api-service/hooks.ts
    ADDED
    
    | @@ -0,0 +1,151 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            import {
         | 
| 2 | 
            +
              useCreateNextToken,
         | 
| 3 | 
            +
              useFetchNextStats,
         | 
| 4 | 
            +
              useFetchTokenList,
         | 
| 5 | 
            +
              useRemoveNextToken,
         | 
| 6 | 
            +
            } from '@/hooks/chat-hooks';
         | 
| 7 | 
            +
            import {
         | 
| 8 | 
            +
              useSetModalState,
         | 
| 9 | 
            +
              useShowDeleteConfirm,
         | 
| 10 | 
            +
              useTranslate,
         | 
| 11 | 
            +
            } from '@/hooks/common-hooks';
         | 
| 12 | 
            +
            import { IStats } from '@/interfaces/database/chat';
         | 
| 13 | 
            +
            import { message } from 'antd';
         | 
| 14 | 
            +
            import { useCallback } from 'react';
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            export const useOperateApiKey = (dialogId: string, idKey: string) => {
         | 
| 17 | 
            +
              const { removeToken } = useRemoveNextToken();
         | 
| 18 | 
            +
              const { createToken, loading: creatingLoading } = useCreateNextToken();
         | 
| 19 | 
            +
              const { data: tokenList, loading: listLoading } = useFetchTokenList({
         | 
| 20 | 
            +
                [idKey]: dialogId,
         | 
| 21 | 
            +
              });
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              const showDeleteConfirm = useShowDeleteConfirm();
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              const onRemoveToken = (token: string, tenantId: string) => {
         | 
| 26 | 
            +
                showDeleteConfirm({
         | 
| 27 | 
            +
                  onOk: () => removeToken({ dialogId, tokens: [token], tenantId }),
         | 
| 28 | 
            +
                });
         | 
| 29 | 
            +
              };
         | 
| 30 | 
            +
             | 
| 31 | 
            +
              const onCreateToken = useCallback(() => {
         | 
| 32 | 
            +
                createToken({ [idKey]: dialogId });
         | 
| 33 | 
            +
              }, [createToken, idKey, dialogId]);
         | 
| 34 | 
            +
             | 
| 35 | 
            +
              return {
         | 
| 36 | 
            +
                removeToken: onRemoveToken,
         | 
| 37 | 
            +
                createToken: onCreateToken,
         | 
| 38 | 
            +
                tokenList,
         | 
| 39 | 
            +
                creatingLoading,
         | 
| 40 | 
            +
                listLoading,
         | 
| 41 | 
            +
              };
         | 
| 42 | 
            +
            };
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            type ChartStatsType = {
         | 
| 45 | 
            +
              [k in keyof IStats]: Array<{ xAxis: string; yAxis: number }>;
         | 
| 46 | 
            +
            };
         | 
| 47 | 
            +
             | 
| 48 | 
            +
            export const useSelectChartStatsList = (): ChartStatsType => {
         | 
| 49 | 
            +
              const { data: stats } = useFetchNextStats();
         | 
| 50 | 
            +
             | 
| 51 | 
            +
              return Object.keys(stats).reduce((pre, cur) => {
         | 
| 52 | 
            +
                const item = stats[cur as keyof IStats];
         | 
| 53 | 
            +
                if (item.length > 0) {
         | 
| 54 | 
            +
                  pre[cur as keyof IStats] = item.map((x) => ({
         | 
| 55 | 
            +
                    xAxis: x[0] as string,
         | 
| 56 | 
            +
                    yAxis: x[1] as number,
         | 
| 57 | 
            +
                  }));
         | 
| 58 | 
            +
                }
         | 
| 59 | 
            +
                return pre;
         | 
| 60 | 
            +
              }, {} as ChartStatsType);
         | 
| 61 | 
            +
            };
         | 
| 62 | 
            +
             | 
| 63 | 
            +
            export const useShowTokenEmptyError = () => {
         | 
| 64 | 
            +
              const [messageApi, contextHolder] = message.useMessage();
         | 
| 65 | 
            +
              const { t } = useTranslate('chat');
         | 
| 66 | 
            +
             | 
| 67 | 
            +
              const showTokenEmptyError = useCallback(() => {
         | 
| 68 | 
            +
                messageApi.error(t('tokenError'));
         | 
| 69 | 
            +
              }, [messageApi, t]);
         | 
| 70 | 
            +
              return { showTokenEmptyError, contextHolder };
         | 
| 71 | 
            +
            };
         | 
| 72 | 
            +
             | 
| 73 | 
            +
            const getUrlWithToken = (token: string) => {
         | 
| 74 | 
            +
              const { protocol, host } = window.location;
         | 
| 75 | 
            +
              return `${protocol}//${host}/chat/share?shared_id=${token}`;
         | 
| 76 | 
            +
            };
         | 
| 77 | 
            +
             | 
| 78 | 
            +
            const useFetchTokenListBeforeOtherStep = (dialogId: string, idKey: string) => {
         | 
| 79 | 
            +
              const { showTokenEmptyError, contextHolder } = useShowTokenEmptyError();
         | 
| 80 | 
            +
             | 
| 81 | 
            +
              const { data: tokenList, refetch } = useFetchTokenList({ [idKey]: dialogId });
         | 
| 82 | 
            +
             | 
| 83 | 
            +
              const token =
         | 
| 84 | 
            +
                Array.isArray(tokenList) && tokenList.length > 0 ? tokenList[0].token : '';
         | 
| 85 | 
            +
             | 
| 86 | 
            +
              const handleOperate = useCallback(async () => {
         | 
| 87 | 
            +
                const ret = await refetch();
         | 
| 88 | 
            +
                const list = ret.data;
         | 
| 89 | 
            +
                if (Array.isArray(list) && list.length > 0) {
         | 
| 90 | 
            +
                  return list[0]?.token;
         | 
| 91 | 
            +
                } else {
         | 
| 92 | 
            +
                  showTokenEmptyError();
         | 
| 93 | 
            +
                  return false;
         | 
| 94 | 
            +
                }
         | 
| 95 | 
            +
              }, [showTokenEmptyError, refetch]);
         | 
| 96 | 
            +
             | 
| 97 | 
            +
              return {
         | 
| 98 | 
            +
                token,
         | 
| 99 | 
            +
                contextHolder,
         | 
| 100 | 
            +
                handleOperate,
         | 
| 101 | 
            +
              };
         | 
| 102 | 
            +
            };
         | 
| 103 | 
            +
             | 
| 104 | 
            +
            export const useShowEmbedModal = (dialogId: string, idKey: string) => {
         | 
| 105 | 
            +
              const {
         | 
| 106 | 
            +
                visible: embedVisible,
         | 
| 107 | 
            +
                hideModal: hideEmbedModal,
         | 
| 108 | 
            +
                showModal: showEmbedModal,
         | 
| 109 | 
            +
              } = useSetModalState();
         | 
| 110 | 
            +
             | 
| 111 | 
            +
              const { handleOperate, token, contextHolder } =
         | 
| 112 | 
            +
                useFetchTokenListBeforeOtherStep(dialogId, idKey);
         | 
| 113 | 
            +
             | 
| 114 | 
            +
              const handleShowEmbedModal = useCallback(async () => {
         | 
| 115 | 
            +
                const succeed = await handleOperate();
         | 
| 116 | 
            +
                if (succeed) {
         | 
| 117 | 
            +
                  showEmbedModal();
         | 
| 118 | 
            +
                }
         | 
| 119 | 
            +
              }, [handleOperate, showEmbedModal]);
         | 
| 120 | 
            +
             | 
| 121 | 
            +
              return {
         | 
| 122 | 
            +
                showEmbedModal: handleShowEmbedModal,
         | 
| 123 | 
            +
                hideEmbedModal,
         | 
| 124 | 
            +
                embedVisible,
         | 
| 125 | 
            +
                embedToken: token,
         | 
| 126 | 
            +
                errorContextHolder: contextHolder,
         | 
| 127 | 
            +
              };
         | 
| 128 | 
            +
            };
         | 
| 129 | 
            +
             | 
| 130 | 
            +
            export const usePreviewChat = (dialogId: string, idKey: string) => {
         | 
| 131 | 
            +
              const { handleOperate, contextHolder } = useFetchTokenListBeforeOtherStep(
         | 
| 132 | 
            +
                dialogId,
         | 
| 133 | 
            +
                idKey,
         | 
| 134 | 
            +
              );
         | 
| 135 | 
            +
             | 
| 136 | 
            +
              const open = useCallback((t: string) => {
         | 
| 137 | 
            +
                window.open(getUrlWithToken(t), '_blank');
         | 
| 138 | 
            +
              }, []);
         | 
| 139 | 
            +
             | 
| 140 | 
            +
              const handlePreview = useCallback(async () => {
         | 
| 141 | 
            +
                const token = await handleOperate();
         | 
| 142 | 
            +
                if (token) {
         | 
| 143 | 
            +
                  open(token);
         | 
| 144 | 
            +
                }
         | 
| 145 | 
            +
              }, [handleOperate, open]);
         | 
| 146 | 
            +
             | 
| 147 | 
            +
              return {
         | 
| 148 | 
            +
                handlePreview,
         | 
| 149 | 
            +
                contextHolder,
         | 
| 150 | 
            +
              };
         | 
| 151 | 
            +
            };
         | 
    	
        web/src/hooks/chat-hooks.ts
    CHANGED
    
    | @@ -4,7 +4,10 @@ import { | |
| 4 | 
             
              IStats,
         | 
| 5 | 
             
              IToken,
         | 
| 6 | 
             
            } from '@/interfaces/database/chat';
         | 
| 7 | 
            -
            import  | 
|  | |
|  | |
|  | |
| 8 | 
             
            import { useDispatch, useSelector } from 'umi';
         | 
| 9 |  | 
| 10 | 
             
            export const useFetchDialogList = () => {
         | 
| @@ -175,79 +178,108 @@ export const useCompleteConversation = () => { | |
| 175 |  | 
| 176 | 
             
            // #region API provided for external calls
         | 
| 177 |  | 
| 178 | 
            -
            export const useCreateToken = ( | 
| 179 | 
             
              const dispatch = useDispatch();
         | 
| 180 |  | 
| 181 | 
             
              const createToken = useCallback(() => {
         | 
| 182 | 
             
                return dispatch<any>({
         | 
| 183 | 
             
                  type: 'chatModel/createToken',
         | 
| 184 | 
            -
                  payload:  | 
| 185 | 
             
                });
         | 
| 186 | 
            -
              }, [dispatch,  | 
| 187 |  | 
| 188 | 
             
              return createToken;
         | 
| 189 | 
             
            };
         | 
| 190 |  | 
| 191 | 
            -
            export const  | 
| 192 | 
            -
              const  | 
| 193 | 
            -
             | 
| 194 | 
            -
             | 
| 195 | 
            -
                 | 
| 196 | 
            -
             | 
| 197 | 
            -
             | 
| 198 | 
            -
             | 
| 199 | 
            -
             | 
|  | |
|  | |
|  | |
|  | |
|  | |
| 200 | 
             
                },
         | 
| 201 | 
            -
             | 
| 202 | 
            -
              );
         | 
| 203 |  | 
| 204 | 
            -
              return  | 
| 205 | 
             
            };
         | 
| 206 |  | 
| 207 | 
            -
            export const  | 
| 208 | 
            -
              const  | 
| 209 | 
            -
                 | 
| 210 | 
            -
             | 
| 211 | 
            -
             | 
| 212 | 
            -
               | 
| 213 | 
            -
             | 
| 214 | 
            -
             | 
| 215 | 
            -
             | 
| 216 | 
            -
             | 
| 217 | 
            -
             | 
| 218 | 
            -
             | 
| 219 | 
            -
             | 
| 220 | 
            -
                  return dispatch<any>({
         | 
| 221 | 
            -
                    type: 'chatModel/removeToken',
         | 
| 222 | 
            -
                    payload: payload,
         | 
| 223 | 
            -
                  });
         | 
| 224 | 
             
                },
         | 
| 225 | 
            -
             | 
| 226 | 
            -
              );
         | 
| 227 |  | 
| 228 | 
            -
              return  | 
| 229 | 
             
            };
         | 
| 230 |  | 
| 231 | 
            -
            export const  | 
| 232 | 
            -
              const  | 
| 233 | 
            -
             | 
| 234 | 
            -
             | 
| 235 | 
            -
                 | 
| 236 | 
            -
             | 
| 237 | 
            -
             | 
| 238 | 
            -
             | 
| 239 | 
            -
             | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 240 | 
             
                },
         | 
| 241 | 
            -
             | 
| 242 | 
            -
              );
         | 
| 243 |  | 
| 244 | 
            -
              return  | 
| 245 | 
             
            };
         | 
| 246 |  | 
| 247 | 
            -
             | 
| 248 | 
            -
             | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 249 |  | 
| 250 | 
            -
              return  | 
| 251 | 
             
            };
         | 
| 252 |  | 
| 253 | 
             
            //#endregion
         | 
|  | |
| 4 | 
             
              IStats,
         | 
| 5 | 
             
              IToken,
         | 
| 6 | 
             
            } from '@/interfaces/database/chat';
         | 
| 7 | 
            +
            import chatService from '@/services/chat-service';
         | 
| 8 | 
            +
            import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
         | 
| 9 | 
            +
            import dayjs, { Dayjs } from 'dayjs';
         | 
| 10 | 
            +
            import { useCallback, useState } from 'react';
         | 
| 11 | 
             
            import { useDispatch, useSelector } from 'umi';
         | 
| 12 |  | 
| 13 | 
             
            export const useFetchDialogList = () => {
         | 
|  | |
| 178 |  | 
| 179 | 
             
            // #region API provided for external calls
         | 
| 180 |  | 
| 181 | 
            +
            export const useCreateToken = (params: Record<string, any>) => {
         | 
| 182 | 
             
              const dispatch = useDispatch();
         | 
| 183 |  | 
| 184 | 
             
              const createToken = useCallback(() => {
         | 
| 185 | 
             
                return dispatch<any>({
         | 
| 186 | 
             
                  type: 'chatModel/createToken',
         | 
| 187 | 
            +
                  payload: params,
         | 
| 188 | 
             
                });
         | 
| 189 | 
            +
              }, [dispatch, params]);
         | 
| 190 |  | 
| 191 | 
             
              return createToken;
         | 
| 192 | 
             
            };
         | 
| 193 |  | 
| 194 | 
            +
            export const useCreateNextToken = () => {
         | 
| 195 | 
            +
              const queryClient = useQueryClient();
         | 
| 196 | 
            +
              const {
         | 
| 197 | 
            +
                data,
         | 
| 198 | 
            +
                isPending: loading,
         | 
| 199 | 
            +
                mutateAsync,
         | 
| 200 | 
            +
              } = useMutation({
         | 
| 201 | 
            +
                mutationKey: ['createToken'],
         | 
| 202 | 
            +
                mutationFn: async (params: Record<string, any>) => {
         | 
| 203 | 
            +
                  const { data } = await chatService.createToken(params);
         | 
| 204 | 
            +
                  if (data.retcode === 0) {
         | 
| 205 | 
            +
                    queryClient.invalidateQueries({ queryKey: ['fetchTokenList'] });
         | 
| 206 | 
            +
                  }
         | 
| 207 | 
            +
                  return data?.data ?? [];
         | 
| 208 | 
             
                },
         | 
| 209 | 
            +
              });
         | 
|  | |
| 210 |  | 
| 211 | 
            +
              return { data, loading, createToken: mutateAsync };
         | 
| 212 | 
             
            };
         | 
| 213 |  | 
| 214 | 
            +
            export const useFetchTokenList = (params: Record<string, any>) => {
         | 
| 215 | 
            +
              const {
         | 
| 216 | 
            +
                data,
         | 
| 217 | 
            +
                isFetching: loading,
         | 
| 218 | 
            +
                refetch,
         | 
| 219 | 
            +
              } = useQuery<IToken[]>({
         | 
| 220 | 
            +
                queryKey: ['fetchTokenList', params],
         | 
| 221 | 
            +
                initialData: [],
         | 
| 222 | 
            +
                gcTime: 0,
         | 
| 223 | 
            +
                queryFn: async () => {
         | 
| 224 | 
            +
                  const { data } = await chatService.listToken(params);
         | 
| 225 | 
            +
             | 
| 226 | 
            +
                  return data?.data ?? [];
         | 
|  | |
|  | |
|  | |
|  | |
| 227 | 
             
                },
         | 
| 228 | 
            +
              });
         | 
|  | |
| 229 |  | 
| 230 | 
            +
              return { data, loading, refetch };
         | 
| 231 | 
             
            };
         | 
| 232 |  | 
| 233 | 
            +
            export const useRemoveNextToken = () => {
         | 
| 234 | 
            +
              const queryClient = useQueryClient();
         | 
| 235 | 
            +
              const {
         | 
| 236 | 
            +
                data,
         | 
| 237 | 
            +
                isPending: loading,
         | 
| 238 | 
            +
                mutateAsync,
         | 
| 239 | 
            +
              } = useMutation({
         | 
| 240 | 
            +
                mutationKey: ['removeToken'],
         | 
| 241 | 
            +
                mutationFn: async (params: {
         | 
| 242 | 
            +
                  tenantId: string;
         | 
| 243 | 
            +
                  dialogId: string;
         | 
| 244 | 
            +
                  tokens: string[];
         | 
| 245 | 
            +
                }) => {
         | 
| 246 | 
            +
                  const { data } = await chatService.removeToken(params);
         | 
| 247 | 
            +
                  if (data.retcode === 0) {
         | 
| 248 | 
            +
                    queryClient.invalidateQueries({ queryKey: ['fetchTokenList'] });
         | 
| 249 | 
            +
                  }
         | 
| 250 | 
            +
                  return data?.data ?? [];
         | 
| 251 | 
             
                },
         | 
| 252 | 
            +
              });
         | 
|  | |
| 253 |  | 
| 254 | 
            +
              return { data, loading, removeToken: mutateAsync };
         | 
| 255 | 
             
            };
         | 
| 256 |  | 
| 257 | 
            +
            type RangeValue = [Dayjs | null, Dayjs | null] | null;
         | 
| 258 | 
            +
             | 
| 259 | 
            +
            const getDay = (date?: Dayjs) => date?.format('YYYY-MM-DD');
         | 
| 260 | 
            +
             | 
| 261 | 
            +
            export const useFetchNextStats = () => {
         | 
| 262 | 
            +
              const [pickerValue, setPickerValue] = useState<RangeValue>([
         | 
| 263 | 
            +
                dayjs(),
         | 
| 264 | 
            +
                dayjs().subtract(7, 'day'),
         | 
| 265 | 
            +
              ]);
         | 
| 266 | 
            +
              const { data, isFetching: loading } = useQuery<IStats>({
         | 
| 267 | 
            +
                queryKey: ['fetchStats', pickerValue],
         | 
| 268 | 
            +
                initialData: {} as IStats,
         | 
| 269 | 
            +
                gcTime: 0,
         | 
| 270 | 
            +
                queryFn: async () => {
         | 
| 271 | 
            +
                  if (Array.isArray(pickerValue) && pickerValue[0]) {
         | 
| 272 | 
            +
                    const { data } = await chatService.getStats({
         | 
| 273 | 
            +
                      fromDate: getDay(pickerValue[0]),
         | 
| 274 | 
            +
                      toDate: getDay(pickerValue[1] ?? dayjs()),
         | 
| 275 | 
            +
                    });
         | 
| 276 | 
            +
                    return data?.data ?? {};
         | 
| 277 | 
            +
                  }
         | 
| 278 | 
            +
                  return {};
         | 
| 279 | 
            +
                },
         | 
| 280 | 
            +
              });
         | 
| 281 |  | 
| 282 | 
            +
              return { data, loading, pickerValue, setPickerValue };
         | 
| 283 | 
             
            };
         | 
| 284 |  | 
| 285 | 
             
            //#endregion
         | 
    	
        web/src/locales/en.ts
    CHANGED
    
    | @@ -783,6 +783,7 @@ The above is the content you need to summarize.`, | |
| 783 | 
             
                    '15d': '12 days',
         | 
| 784 | 
             
                    '30d': '30 days',
         | 
| 785 | 
             
                  },
         | 
|  | |
| 786 | 
             
                },
         | 
| 787 | 
             
                footer: {
         | 
| 788 | 
             
                  profile: 'All rights reserved @ React',
         | 
|  | |
| 783 | 
             
                    '15d': '12 days',
         | 
| 784 | 
             
                    '30d': '30 days',
         | 
| 785 | 
             
                  },
         | 
| 786 | 
            +
                  publish: 'Publish',
         | 
| 787 | 
             
                },
         | 
| 788 | 
             
                footer: {
         | 
| 789 | 
             
                  profile: 'All rights reserved @ React',
         | 
    	
        web/src/locales/zh-traditional.ts
    CHANGED
    
    | @@ -741,6 +741,7 @@ export default { | |
| 741 | 
             
                    '15d': '12倩',
         | 
| 742 | 
             
                    '30d': '30倩',
         | 
| 743 | 
             
                  },
         | 
|  | |
| 744 | 
             
                },
         | 
| 745 | 
             
                footer: {
         | 
| 746 | 
             
                  profile: 'βδΏηζζζ¬ε© @ reactβ',
         | 
|  | |
| 741 | 
             
                    '15d': '12倩',
         | 
| 742 | 
             
                    '30d': '30倩',
         | 
| 743 | 
             
                  },
         | 
| 744 | 
            +
                  publish: 'ηΌεΈ',
         | 
| 745 | 
             
                },
         | 
| 746 | 
             
                footer: {
         | 
| 747 | 
             
                  profile: 'βδΏηζζζ¬ε© @ reactβ',
         | 
    	
        web/src/locales/zh.ts
    CHANGED
    
    | @@ -759,6 +759,7 @@ export default { | |
| 759 | 
             
                    '15d': '12倩',
         | 
| 760 | 
             
                    '30d': '30倩',
         | 
| 761 | 
             
                  },
         | 
|  | |
| 762 | 
             
                },
         | 
| 763 | 
             
                footer: {
         | 
| 764 | 
             
                  profile: 'All rights reserved @ React',
         | 
|  | |
| 759 | 
             
                    '15d': '12倩',
         | 
| 760 | 
             
                    '30d': '30倩',
         | 
| 761 | 
             
                  },
         | 
| 762 | 
            +
                  publish: 'εεΈ',
         | 
| 763 | 
             
                },
         | 
| 764 | 
             
                footer: {
         | 
| 765 | 
             
                  profile: 'All rights reserved @ React',
         | 
    	
        web/src/pages/chat/hooks.ts
    CHANGED
    
    | @@ -1,20 +1,14 @@ | |
| 1 | 
             
            import { MessageType } from '@/constants/chat';
         | 
| 2 | 
             
            import { fileIconMap } from '@/constants/common';
         | 
| 3 | 
             
            import {
         | 
| 4 | 
            -
              useCreateToken,
         | 
| 5 | 
             
              useFetchConversation,
         | 
| 6 | 
             
              useFetchConversationList,
         | 
| 7 | 
             
              useFetchDialog,
         | 
| 8 | 
             
              useFetchDialogList,
         | 
| 9 | 
            -
              useFetchStats,
         | 
| 10 | 
            -
              useListToken,
         | 
| 11 | 
             
              useRemoveConversation,
         | 
| 12 | 
             
              useRemoveDialog,
         | 
| 13 | 
            -
              useRemoveToken,
         | 
| 14 | 
             
              useSelectConversationList,
         | 
| 15 | 
             
              useSelectDialogList,
         | 
| 16 | 
            -
              useSelectStats,
         | 
| 17 | 
            -
              useSelectTokenList,
         | 
| 18 | 
             
              useSetDialog,
         | 
| 19 | 
             
              useUpdateConversation,
         | 
| 20 | 
             
            } from '@/hooks/chat-hooks';
         | 
| @@ -25,16 +19,9 @@ import { | |
| 25 | 
             
            } from '@/hooks/common-hooks';
         | 
| 26 | 
             
            import { useSendMessageWithSse } from '@/hooks/logic-hooks';
         | 
| 27 | 
             
            import { useOneNamespaceEffectsLoading } from '@/hooks/store-hooks';
         | 
| 28 | 
            -
            import {
         | 
| 29 | 
            -
              IAnswer,
         | 
| 30 | 
            -
              IConversation,
         | 
| 31 | 
            -
              IDialog,
         | 
| 32 | 
            -
              IStats,
         | 
| 33 | 
            -
            } from '@/interfaces/database/chat';
         | 
| 34 | 
             
            import { IChunk } from '@/interfaces/database/knowledge';
         | 
| 35 | 
             
            import { getFileExtension } from '@/utils';
         | 
| 36 | 
            -
            import { message } from 'antd';
         | 
| 37 | 
            -
            import dayjs, { Dayjs } from 'dayjs';
         | 
| 38 | 
             
            import omit from 'lodash/omit';
         | 
| 39 | 
             
            import trim from 'lodash/trim';
         | 
| 40 | 
             
            import {
         | 
| @@ -773,202 +760,3 @@ export const useSendButtonDisabled = (value: string) => { | |
| 773 | 
             
              return trim(value) === '';
         | 
| 774 | 
             
            };
         | 
| 775 | 
             
            //#endregion
         | 
| 776 | 
            -
             | 
| 777 | 
            -
            //#region API provided for external calls
         | 
| 778 | 
            -
             | 
| 779 | 
            -
            type RangeValue = [Dayjs | null, Dayjs | null] | null;
         | 
| 780 | 
            -
             | 
| 781 | 
            -
            const getDay = (date: Dayjs) => date.format('YYYY-MM-DD');
         | 
| 782 | 
            -
             | 
| 783 | 
            -
            export const useFetchStatsOnMount = (visible: boolean) => {
         | 
| 784 | 
            -
              const fetchStats = useFetchStats();
         | 
| 785 | 
            -
              const [pickerValue, setPickerValue] = useState<RangeValue>([
         | 
| 786 | 
            -
                dayjs(),
         | 
| 787 | 
            -
                dayjs().subtract(7, 'day'),
         | 
| 788 | 
            -
              ]);
         | 
| 789 | 
            -
             | 
| 790 | 
            -
              useEffect(() => {
         | 
| 791 | 
            -
                if (visible && Array.isArray(pickerValue) && pickerValue[0]) {
         | 
| 792 | 
            -
                  fetchStats({
         | 
| 793 | 
            -
                    fromDate: getDay(pickerValue[0]),
         | 
| 794 | 
            -
                    toDate: getDay(pickerValue[1] ?? dayjs()),
         | 
| 795 | 
            -
                  });
         | 
| 796 | 
            -
                }
         | 
| 797 | 
            -
              }, [fetchStats, pickerValue, visible]);
         | 
| 798 | 
            -
             | 
| 799 | 
            -
              return {
         | 
| 800 | 
            -
                pickerValue,
         | 
| 801 | 
            -
                setPickerValue,
         | 
| 802 | 
            -
              };
         | 
| 803 | 
            -
            };
         | 
| 804 | 
            -
             | 
| 805 | 
            -
            export const useOperateApiKey = (visible: boolean, dialogId: string) => {
         | 
| 806 | 
            -
              const removeToken = useRemoveToken();
         | 
| 807 | 
            -
              const createToken = useCreateToken(dialogId);
         | 
| 808 | 
            -
              const listToken = useListToken();
         | 
| 809 | 
            -
              const tokenList = useSelectTokenList();
         | 
| 810 | 
            -
              const creatingLoading = useOneNamespaceEffectsLoading('chatModel', [
         | 
| 811 | 
            -
                'createToken',
         | 
| 812 | 
            -
              ]);
         | 
| 813 | 
            -
              const listLoading = useOneNamespaceEffectsLoading('chatModel', ['list']);
         | 
| 814 | 
            -
             | 
| 815 | 
            -
              const showDeleteConfirm = useShowDeleteConfirm();
         | 
| 816 | 
            -
             | 
| 817 | 
            -
              const onRemoveToken = (token: string, tenantId: string) => {
         | 
| 818 | 
            -
                showDeleteConfirm({
         | 
| 819 | 
            -
                  onOk: () => removeToken({ dialogId, tokens: [token], tenantId }),
         | 
| 820 | 
            -
                });
         | 
| 821 | 
            -
              };
         | 
| 822 | 
            -
             | 
| 823 | 
            -
              useEffect(() => {
         | 
| 824 | 
            -
                if (visible && dialogId) {
         | 
| 825 | 
            -
                  listToken(dialogId);
         | 
| 826 | 
            -
                }
         | 
| 827 | 
            -
              }, [listToken, dialogId, visible]);
         | 
| 828 | 
            -
             | 
| 829 | 
            -
              return {
         | 
| 830 | 
            -
                removeToken: onRemoveToken,
         | 
| 831 | 
            -
                createToken,
         | 
| 832 | 
            -
                tokenList,
         | 
| 833 | 
            -
                creatingLoading,
         | 
| 834 | 
            -
                listLoading,
         | 
| 835 | 
            -
              };
         | 
| 836 | 
            -
            };
         | 
| 837 | 
            -
             | 
| 838 | 
            -
            type ChartStatsType = {
         | 
| 839 | 
            -
              [k in keyof IStats]: Array<{ xAxis: string; yAxis: number }>;
         | 
| 840 | 
            -
            };
         | 
| 841 | 
            -
             | 
| 842 | 
            -
            export const useSelectChartStatsList = (): ChartStatsType => {
         | 
| 843 | 
            -
              const stats: IStats = useSelectStats();
         | 
| 844 | 
            -
              // const stats = {
         | 
| 845 | 
            -
              //   pv: [
         | 
| 846 | 
            -
              //     ['2024-06-01', 1],
         | 
| 847 | 
            -
              //     ['2024-07-24', 3],
         | 
| 848 | 
            -
              //     ['2024-09-01', 10],
         | 
| 849 | 
            -
              //   ],
         | 
| 850 | 
            -
              //   uv: [
         | 
| 851 | 
            -
              //     ['2024-02-01', 0],
         | 
| 852 | 
            -
              //     ['2024-03-01', 99],
         | 
| 853 | 
            -
              //     ['2024-05-01', 3],
         | 
| 854 | 
            -
              //   ],
         | 
| 855 | 
            -
              //   speed: [
         | 
| 856 | 
            -
              //     ['2024-09-01', 2],
         | 
| 857 | 
            -
              //     ['2024-09-01', 3],
         | 
| 858 | 
            -
              //   ],
         | 
| 859 | 
            -
              //   tokens: [
         | 
| 860 | 
            -
              //     ['2024-09-01', 1],
         | 
| 861 | 
            -
              //     ['2024-09-01', 3],
         | 
| 862 | 
            -
              //   ],
         | 
| 863 | 
            -
              //   round: [
         | 
| 864 | 
            -
              //     ['2024-09-01', 0],
         | 
| 865 | 
            -
              //     ['2024-09-01', 3],
         | 
| 866 | 
            -
              //   ],
         | 
| 867 | 
            -
              //   thumb_up: [
         | 
| 868 | 
            -
              //     ['2024-09-01', 3],
         | 
| 869 | 
            -
              //     ['2024-09-01', 9],
         | 
| 870 | 
            -
              //   ],
         | 
| 871 | 
            -
              // };
         | 
| 872 | 
            -
             | 
| 873 | 
            -
              return Object.keys(stats).reduce((pre, cur) => {
         | 
| 874 | 
            -
                const item = stats[cur as keyof IStats];
         | 
| 875 | 
            -
                if (item.length > 0) {
         | 
| 876 | 
            -
                  pre[cur as keyof IStats] = item.map((x) => ({
         | 
| 877 | 
            -
                    xAxis: x[0] as string,
         | 
| 878 | 
            -
                    yAxis: x[1] as number,
         | 
| 879 | 
            -
                  }));
         | 
| 880 | 
            -
                }
         | 
| 881 | 
            -
                return pre;
         | 
| 882 | 
            -
              }, {} as ChartStatsType);
         | 
| 883 | 
            -
            };
         | 
| 884 | 
            -
             | 
| 885 | 
            -
            export const useShowTokenEmptyError = () => {
         | 
| 886 | 
            -
              const [messageApi, contextHolder] = message.useMessage();
         | 
| 887 | 
            -
              const { t } = useTranslate('chat');
         | 
| 888 | 
            -
             | 
| 889 | 
            -
              const showTokenEmptyError = useCallback(() => {
         | 
| 890 | 
            -
                messageApi.error(t('tokenError'));
         | 
| 891 | 
            -
              }, [messageApi, t]);
         | 
| 892 | 
            -
              return { showTokenEmptyError, contextHolder };
         | 
| 893 | 
            -
            };
         | 
| 894 | 
            -
             | 
| 895 | 
            -
            const getUrlWithToken = (token: string) => {
         | 
| 896 | 
            -
              const { protocol, host } = window.location;
         | 
| 897 | 
            -
              return `${protocol}//${host}/chat/share?shared_id=${token}`;
         | 
| 898 | 
            -
            };
         | 
| 899 | 
            -
             | 
| 900 | 
            -
            const useFetchTokenListBeforeOtherStep = (dialogId: string) => {
         | 
| 901 | 
            -
              const { showTokenEmptyError, contextHolder } = useShowTokenEmptyError();
         | 
| 902 | 
            -
             | 
| 903 | 
            -
              const listToken = useListToken();
         | 
| 904 | 
            -
              const tokenList = useSelectTokenList();
         | 
| 905 | 
            -
             | 
| 906 | 
            -
              const token =
         | 
| 907 | 
            -
                Array.isArray(tokenList) && tokenList.length > 0 ? tokenList[0].token : '';
         | 
| 908 | 
            -
             | 
| 909 | 
            -
              const handleOperate = useCallback(async () => {
         | 
| 910 | 
            -
                const data = await listToken(dialogId);
         | 
| 911 | 
            -
                const list = data.data;
         | 
| 912 | 
            -
                if (data.retcode === 0 && Array.isArray(list) && list.length > 0) {
         | 
| 913 | 
            -
                  return list[0]?.token;
         | 
| 914 | 
            -
                } else {
         | 
| 915 | 
            -
                  showTokenEmptyError();
         | 
| 916 | 
            -
                  return false;
         | 
| 917 | 
            -
                }
         | 
| 918 | 
            -
              }, [dialogId, listToken, showTokenEmptyError]);
         | 
| 919 | 
            -
             | 
| 920 | 
            -
              return {
         | 
| 921 | 
            -
                token,
         | 
| 922 | 
            -
                contextHolder,
         | 
| 923 | 
            -
                handleOperate,
         | 
| 924 | 
            -
              };
         | 
| 925 | 
            -
            };
         | 
| 926 | 
            -
             | 
| 927 | 
            -
            export const useShowEmbedModal = (dialogId: string) => {
         | 
| 928 | 
            -
              const {
         | 
| 929 | 
            -
                visible: embedVisible,
         | 
| 930 | 
            -
                hideModal: hideEmbedModal,
         | 
| 931 | 
            -
                showModal: showEmbedModal,
         | 
| 932 | 
            -
              } = useSetModalState();
         | 
| 933 | 
            -
             | 
| 934 | 
            -
              const { handleOperate, token, contextHolder } =
         | 
| 935 | 
            -
                useFetchTokenListBeforeOtherStep(dialogId);
         | 
| 936 | 
            -
             | 
| 937 | 
            -
              const handleShowEmbedModal = useCallback(async () => {
         | 
| 938 | 
            -
                const succeed = await handleOperate();
         | 
| 939 | 
            -
                if (succeed) {
         | 
| 940 | 
            -
                  showEmbedModal();
         | 
| 941 | 
            -
                }
         | 
| 942 | 
            -
              }, [handleOperate, showEmbedModal]);
         | 
| 943 | 
            -
             | 
| 944 | 
            -
              return {
         | 
| 945 | 
            -
                showEmbedModal: handleShowEmbedModal,
         | 
| 946 | 
            -
                hideEmbedModal,
         | 
| 947 | 
            -
                embedVisible,
         | 
| 948 | 
            -
                embedToken: token,
         | 
| 949 | 
            -
                errorContextHolder: contextHolder,
         | 
| 950 | 
            -
              };
         | 
| 951 | 
            -
            };
         | 
| 952 | 
            -
             | 
| 953 | 
            -
            export const usePreviewChat = (dialogId: string) => {
         | 
| 954 | 
            -
              const { handleOperate, contextHolder } =
         | 
| 955 | 
            -
                useFetchTokenListBeforeOtherStep(dialogId);
         | 
| 956 | 
            -
             | 
| 957 | 
            -
              const open = useCallback((t: string) => {
         | 
| 958 | 
            -
                window.open(getUrlWithToken(t), '_blank');
         | 
| 959 | 
            -
              }, []);
         | 
| 960 | 
            -
             | 
| 961 | 
            -
              const handlePreview = useCallback(async () => {
         | 
| 962 | 
            -
                const token = await handleOperate();
         | 
| 963 | 
            -
                if (token) {
         | 
| 964 | 
            -
                  open(token);
         | 
| 965 | 
            -
                }
         | 
| 966 | 
            -
              }, [handleOperate, open]);
         | 
| 967 | 
            -
             | 
| 968 | 
            -
              return {
         | 
| 969 | 
            -
                handlePreview,
         | 
| 970 | 
            -
                contextHolder,
         | 
| 971 | 
            -
              };
         | 
| 972 | 
            -
            };
         | 
| 973 | 
            -
             | 
| 974 | 
            -
            //#endregion
         | 
|  | |
| 1 | 
             
            import { MessageType } from '@/constants/chat';
         | 
| 2 | 
             
            import { fileIconMap } from '@/constants/common';
         | 
| 3 | 
             
            import {
         | 
|  | |
| 4 | 
             
              useFetchConversation,
         | 
| 5 | 
             
              useFetchConversationList,
         | 
| 6 | 
             
              useFetchDialog,
         | 
| 7 | 
             
              useFetchDialogList,
         | 
|  | |
|  | |
| 8 | 
             
              useRemoveConversation,
         | 
| 9 | 
             
              useRemoveDialog,
         | 
|  | |
| 10 | 
             
              useSelectConversationList,
         | 
| 11 | 
             
              useSelectDialogList,
         | 
|  | |
|  | |
| 12 | 
             
              useSetDialog,
         | 
| 13 | 
             
              useUpdateConversation,
         | 
| 14 | 
             
            } from '@/hooks/chat-hooks';
         | 
|  | |
| 19 | 
             
            } from '@/hooks/common-hooks';
         | 
| 20 | 
             
            import { useSendMessageWithSse } from '@/hooks/logic-hooks';
         | 
| 21 | 
             
            import { useOneNamespaceEffectsLoading } from '@/hooks/store-hooks';
         | 
| 22 | 
            +
            import { IAnswer, IConversation, IDialog } from '@/interfaces/database/chat';
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
| 23 | 
             
            import { IChunk } from '@/interfaces/database/knowledge';
         | 
| 24 | 
             
            import { getFileExtension } from '@/utils';
         | 
|  | |
|  | |
| 25 | 
             
            import omit from 'lodash/omit';
         | 
| 26 | 
             
            import trim from 'lodash/trim';
         | 
| 27 | 
             
            import {
         | 
|  | |
| 760 | 
             
              return trim(value) === '';
         | 
| 761 | 
             
            };
         | 
| 762 | 
             
            //#endregion
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
    	
        web/src/pages/chat/index.tsx
    CHANGED
    
    | @@ -41,10 +41,10 @@ import { | |
| 41 | 
             
              useSelectFirstDialogOnMount,
         | 
| 42 | 
             
            } from './hooks';
         | 
| 43 |  | 
|  | |
| 44 | 
             
            import { useSetModalState, useTranslate } from '@/hooks/common-hooks';
         | 
| 45 | 
             
            import { useSetSelectedRecord } from '@/hooks/logic-hooks';
         | 
| 46 | 
             
            import { IDialog } from '@/interfaces/database/chat';
         | 
| 47 | 
            -
            import ChatOverviewModal from './chat-overview-modal';
         | 
| 48 | 
             
            import styles from './index.less';
         | 
| 49 |  | 
| 50 | 
             
            const { Text } = Typography;
         | 
| @@ -371,11 +371,15 @@ const Chat = () => { | |
| 371 | 
             
                    initialName={initialConversationName}
         | 
| 372 | 
             
                    loading={conversationRenameLoading}
         | 
| 373 | 
             
                  ></RenameModal>
         | 
| 374 | 
            -
                   | 
| 375 | 
            -
                     | 
| 376 | 
            -
             | 
| 377 | 
            -
             | 
| 378 | 
            -
             | 
|  | |
|  | |
|  | |
|  | |
| 379 | 
             
                </Flex>
         | 
| 380 | 
             
              );
         | 
| 381 | 
             
            };
         | 
|  | |
| 41 | 
             
              useSelectFirstDialogOnMount,
         | 
| 42 | 
             
            } from './hooks';
         | 
| 43 |  | 
| 44 | 
            +
            import ChatOverviewModal from '@/components/api-service/chat-overview-modal';
         | 
| 45 | 
             
            import { useSetModalState, useTranslate } from '@/hooks/common-hooks';
         | 
| 46 | 
             
            import { useSetSelectedRecord } from '@/hooks/logic-hooks';
         | 
| 47 | 
             
            import { IDialog } from '@/interfaces/database/chat';
         | 
|  | |
| 48 | 
             
            import styles from './index.less';
         | 
| 49 |  | 
| 50 | 
             
            const { Text } = Typography;
         | 
|  | |
| 371 | 
             
                    initialName={initialConversationName}
         | 
| 372 | 
             
                    loading={conversationRenameLoading}
         | 
| 373 | 
             
                  ></RenameModal>
         | 
| 374 | 
            +
                  {overviewVisible && (
         | 
| 375 | 
            +
                    <ChatOverviewModal
         | 
| 376 | 
            +
                      visible={overviewVisible}
         | 
| 377 | 
            +
                      hideModal={hideOverviewModal}
         | 
| 378 | 
            +
                      id={currentRecord.id}
         | 
| 379 | 
            +
                      name={currentRecord.name}
         | 
| 380 | 
            +
                      idKey="dialogId"
         | 
| 381 | 
            +
                    ></ChatOverviewModal>
         | 
| 382 | 
            +
                  )}
         | 
| 383 | 
             
                </Flex>
         | 
| 384 | 
             
              );
         | 
| 385 | 
             
            };
         | 
    	
        web/src/pages/chat/model.ts
    CHANGED
    
    | @@ -1,14 +1,7 @@ | |
| 1 | 
            -
            import {
         | 
| 2 | 
            -
              IConversation,
         | 
| 3 | 
            -
              IDialog,
         | 
| 4 | 
            -
              IStats,
         | 
| 5 | 
            -
              IToken,
         | 
| 6 | 
            -
              Message,
         | 
| 7 | 
            -
            } from '@/interfaces/database/chat';
         | 
| 8 | 
             
            import i18n from '@/locales/config';
         | 
| 9 | 
             
            import chatService from '@/services/chat-service';
         | 
| 10 | 
             
            import { message } from 'antd';
         | 
| 11 | 
            -
            import omit from 'lodash/omit';
         | 
| 12 | 
             
            import { DvaModel } from 'umi';
         | 
| 13 | 
             
            import { v4 as uuid } from 'uuid';
         | 
| 14 | 
             
            import { IClientConversation, IMessage } from './interface';
         | 
| @@ -20,8 +13,6 @@ export interface ChatModelState { | |
| 20 | 
             
              currentDialog: IDialog;
         | 
| 21 | 
             
              conversationList: IConversation[];
         | 
| 22 | 
             
              currentConversation: IClientConversation;
         | 
| 23 | 
            -
              tokenList: IToken[];
         | 
| 24 | 
            -
              stats: IStats;
         | 
| 25 | 
             
            }
         | 
| 26 |  | 
| 27 | 
             
            const model: DvaModel<ChatModelState> = {
         | 
| @@ -32,8 +23,6 @@ const model: DvaModel<ChatModelState> = { | |
| 32 | 
             
                currentDialog: <IDialog>{},
         | 
| 33 | 
             
                conversationList: [],
         | 
| 34 | 
             
                currentConversation: {} as IClientConversation,
         | 
| 35 | 
            -
                tokenList: [],
         | 
| 36 | 
            -
                stats: {} as IStats,
         | 
| 37 | 
             
              },
         | 
| 38 | 
             
              reducers: {
         | 
| 39 | 
             
                save(state, action) {
         | 
| @@ -71,18 +60,6 @@ const model: DvaModel<ChatModelState> = { | |
| 71 | 
             
                    currentConversation: { ...payload, message: messageList },
         | 
| 72 | 
             
                  };
         | 
| 73 | 
             
                },
         | 
| 74 | 
            -
                setTokenList(state, { payload }) {
         | 
| 75 | 
            -
                  return {
         | 
| 76 | 
            -
                    ...state,
         | 
| 77 | 
            -
                    tokenList: payload,
         | 
| 78 | 
            -
                  };
         | 
| 79 | 
            -
                },
         | 
| 80 | 
            -
                setStats(state, { payload }) {
         | 
| 81 | 
            -
                  return {
         | 
| 82 | 
            -
                    ...state,
         | 
| 83 | 
            -
                    stats: payload,
         | 
| 84 | 
            -
                  };
         | 
| 85 | 
            -
                },
         | 
| 86 | 
             
              },
         | 
| 87 |  | 
| 88 | 
             
              effects: {
         | 
| @@ -183,51 +160,6 @@ const model: DvaModel<ChatModelState> = { | |
| 183 | 
             
                  }
         | 
| 184 | 
             
                  return data.retcode;
         | 
| 185 | 
             
                },
         | 
| 186 | 
            -
                *createToken({ payload }, { call, put }) {
         | 
| 187 | 
            -
                  const { data } = yield call(chatService.createToken, payload);
         | 
| 188 | 
            -
                  if (data.retcode === 0) {
         | 
| 189 | 
            -
                    yield put({
         | 
| 190 | 
            -
                      type: 'listToken',
         | 
| 191 | 
            -
                      payload: payload,
         | 
| 192 | 
            -
                    });
         | 
| 193 | 
            -
                    message.success(i18n.t('message.created'));
         | 
| 194 | 
            -
                  }
         | 
| 195 | 
            -
                  return data;
         | 
| 196 | 
            -
                },
         | 
| 197 | 
            -
                *listToken({ payload }, { call, put }) {
         | 
| 198 | 
            -
                  const { data } = yield call(chatService.listToken, payload);
         | 
| 199 | 
            -
                  if (data.retcode === 0) {
         | 
| 200 | 
            -
                    yield put({
         | 
| 201 | 
            -
                      type: 'setTokenList',
         | 
| 202 | 
            -
                      payload: data.data,
         | 
| 203 | 
            -
                    });
         | 
| 204 | 
            -
                  }
         | 
| 205 | 
            -
                  return data;
         | 
| 206 | 
            -
                },
         | 
| 207 | 
            -
                *removeToken({ payload }, { call, put }) {
         | 
| 208 | 
            -
                  const { data } = yield call(
         | 
| 209 | 
            -
                    chatService.removeToken,
         | 
| 210 | 
            -
                    omit(payload, ['dialogId']),
         | 
| 211 | 
            -
                  );
         | 
| 212 | 
            -
                  if (data.retcode === 0) {
         | 
| 213 | 
            -
                    message.success(i18n.t('message.deleted'));
         | 
| 214 | 
            -
                    yield put({
         | 
| 215 | 
            -
                      type: 'listToken',
         | 
| 216 | 
            -
                      payload: { dialog_id: payload.dialogId },
         | 
| 217 | 
            -
                    });
         | 
| 218 | 
            -
                  }
         | 
| 219 | 
            -
                  return data.retcode;
         | 
| 220 | 
            -
                },
         | 
| 221 | 
            -
                *getStats({ payload }, { call, put }) {
         | 
| 222 | 
            -
                  const { data } = yield call(chatService.getStats, payload);
         | 
| 223 | 
            -
                  if (data.retcode === 0) {
         | 
| 224 | 
            -
                    yield put({
         | 
| 225 | 
            -
                      type: 'setStats',
         | 
| 226 | 
            -
                      payload: data.data,
         | 
| 227 | 
            -
                    });
         | 
| 228 | 
            -
                  }
         | 
| 229 | 
            -
                  return data.retcode;
         | 
| 230 | 
            -
                },
         | 
| 231 | 
             
                *createExternalConversation({ payload }, { call, put }) {
         | 
| 232 | 
             
                  const { data } = yield call(
         | 
| 233 | 
             
                    chatService.createExternalConversation,
         | 
|  | |
| 1 | 
            +
            import { IConversation, IDialog, Message } from '@/interfaces/database/chat';
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 2 | 
             
            import i18n from '@/locales/config';
         | 
| 3 | 
             
            import chatService from '@/services/chat-service';
         | 
| 4 | 
             
            import { message } from 'antd';
         | 
|  | |
| 5 | 
             
            import { DvaModel } from 'umi';
         | 
| 6 | 
             
            import { v4 as uuid } from 'uuid';
         | 
| 7 | 
             
            import { IClientConversation, IMessage } from './interface';
         | 
|  | |
| 13 | 
             
              currentDialog: IDialog;
         | 
| 14 | 
             
              conversationList: IConversation[];
         | 
| 15 | 
             
              currentConversation: IClientConversation;
         | 
|  | |
|  | |
| 16 | 
             
            }
         | 
| 17 |  | 
| 18 | 
             
            const model: DvaModel<ChatModelState> = {
         | 
|  | |
| 23 | 
             
                currentDialog: <IDialog>{},
         | 
| 24 | 
             
                conversationList: [],
         | 
| 25 | 
             
                currentConversation: {} as IClientConversation,
         | 
|  | |
|  | |
| 26 | 
             
              },
         | 
| 27 | 
             
              reducers: {
         | 
| 28 | 
             
                save(state, action) {
         | 
|  | |
| 60 | 
             
                    currentConversation: { ...payload, message: messageList },
         | 
| 61 | 
             
                  };
         | 
| 62 | 
             
                },
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 63 | 
             
              },
         | 
| 64 |  | 
| 65 | 
             
              effects: {
         | 
|  | |
| 160 | 
             
                  }
         | 
| 161 | 
             
                  return data.retcode;
         | 
| 162 | 
             
                },
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 163 | 
             
                *createExternalConversation({ payload }, { call, put }) {
         | 
| 164 | 
             
                  const { data } = yield call(
         | 
| 165 | 
             
                    chatService.createExternalConversation,
         | 
    	
        web/src/pages/flow/header/index.tsx
    CHANGED
    
    | @@ -1,8 +1,9 @@ | |
| 1 | 
            -
            import  | 
|  | |
| 2 | 
             
            import { useFetchFlow } from '@/hooks/flow-hooks';
         | 
| 3 | 
             
            import { ArrowLeftOutlined } from '@ant-design/icons';
         | 
| 4 | 
             
            import { Button, Flex, Space } from 'antd';
         | 
| 5 | 
            -
            import { Link } from 'umi';
         | 
| 6 | 
             
            import { useSaveGraph, useSaveGraphBeforeOpeningDebugDrawer } from '../hooks';
         | 
| 7 | 
             
            import styles from './index.less';
         | 
| 8 |  | 
| @@ -15,6 +16,12 @@ const FlowHeader = ({ showChatDrawer }: IProps) => { | |
| 15 | 
             
              const handleRun = useSaveGraphBeforeOpeningDebugDrawer(showChatDrawer);
         | 
| 16 | 
             
              const { data } = useFetchFlow();
         | 
| 17 | 
             
              const { t } = useTranslate('flow');
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 18 |  | 
| 19 | 
             
              return (
         | 
| 20 | 
             
                <>
         | 
| @@ -37,8 +44,19 @@ const FlowHeader = ({ showChatDrawer }: IProps) => { | |
| 37 | 
             
                      <Button type="primary" onClick={saveGraph}>
         | 
| 38 | 
             
                        <b>{t('save')}</b>
         | 
| 39 | 
             
                      </Button>
         | 
|  | |
|  | |
|  | |
| 40 | 
             
                    </Space>
         | 
| 41 | 
             
                  </Flex>
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 42 | 
             
                </>
         | 
| 43 | 
             
              );
         | 
| 44 | 
             
            };
         | 
|  | |
| 1 | 
            +
            import ChatOverviewModal from '@/components/api-service/chat-overview-modal';
         | 
| 2 | 
            +
            import { useSetModalState, useTranslate } from '@/hooks/common-hooks';
         | 
| 3 | 
             
            import { useFetchFlow } from '@/hooks/flow-hooks';
         | 
| 4 | 
             
            import { ArrowLeftOutlined } from '@ant-design/icons';
         | 
| 5 | 
             
            import { Button, Flex, Space } from 'antd';
         | 
| 6 | 
            +
            import { Link, useParams } from 'umi';
         | 
| 7 | 
             
            import { useSaveGraph, useSaveGraphBeforeOpeningDebugDrawer } from '../hooks';
         | 
| 8 | 
             
            import styles from './index.less';
         | 
| 9 |  | 
|  | |
| 16 | 
             
              const handleRun = useSaveGraphBeforeOpeningDebugDrawer(showChatDrawer);
         | 
| 17 | 
             
              const { data } = useFetchFlow();
         | 
| 18 | 
             
              const { t } = useTranslate('flow');
         | 
| 19 | 
            +
              const {
         | 
| 20 | 
            +
                visible: overviewVisible,
         | 
| 21 | 
            +
                hideModal: hideOverviewModal,
         | 
| 22 | 
            +
                showModal: showOverviewModal,
         | 
| 23 | 
            +
              } = useSetModalState();
         | 
| 24 | 
            +
              const { id } = useParams();
         | 
| 25 |  | 
| 26 | 
             
              return (
         | 
| 27 | 
             
                <>
         | 
|  | |
| 44 | 
             
                      <Button type="primary" onClick={saveGraph}>
         | 
| 45 | 
             
                        <b>{t('save')}</b>
         | 
| 46 | 
             
                      </Button>
         | 
| 47 | 
            +
                      <Button type="primary" onClick={showOverviewModal}>
         | 
| 48 | 
            +
                        <b>{t('publish')}</b>
         | 
| 49 | 
            +
                      </Button>
         | 
| 50 | 
             
                    </Space>
         | 
| 51 | 
             
                  </Flex>
         | 
| 52 | 
            +
                  {overviewVisible && (
         | 
| 53 | 
            +
                    <ChatOverviewModal
         | 
| 54 | 
            +
                      visible={overviewVisible}
         | 
| 55 | 
            +
                      hideModal={hideOverviewModal}
         | 
| 56 | 
            +
                      id={id!}
         | 
| 57 | 
            +
                      idKey="canvasId"
         | 
| 58 | 
            +
                    ></ChatOverviewModal>
         | 
| 59 | 
            +
                  )}
         | 
| 60 | 
             
                </>
         | 
| 61 | 
             
              );
         | 
| 62 | 
             
            };
         |