diff --git a/web/src/components/indented-tree/indented-tree.tsx b/web/src/components/indented-tree/indented-tree.tsx index 547439459e..770f132fd2 100644 --- a/web/src/components/indented-tree/indented-tree.tsx +++ b/web/src/components/indented-tree/indented-tree.tsx @@ -16,7 +16,7 @@ import { } from '@antv/g6'; import { TreeData } from '@antv/g6/lib/types'; import isEmpty from 'lodash/isEmpty'; -import { useCallback, useEffect, useRef } from 'react'; +import React, { useCallback, useEffect, useRef } from 'react'; const rootId = 'root'; @@ -294,9 +294,10 @@ register( interface IProps { data: TreeData; show: boolean; + style?: React.CSSProperties; } -const IndentedTree = ({ data, show }: IProps) => { +const IndentedTree = ({ data, show, style = {} }: IProps) => { const containerRef = useRef(null); const graphRef = useRef(null); @@ -388,6 +389,7 @@ const IndentedTree = ({ data, show }: IProps) => { width: '90vw', height: '80vh', display: show ? 'block' : 'none', + ...style, }} /> ); diff --git a/web/src/hooks/chat-hooks.ts b/web/src/hooks/chat-hooks.ts index 6a152c62cb..1d4205c373 100644 --- a/web/src/hooks/chat-hooks.ts +++ b/web/src/hooks/chat-hooks.ts @@ -490,13 +490,32 @@ export const useFetchMindMap = () => { mutateAsync, } = useMutation({ mutationKey: ['fetchMindMap'], + gcTime: 0, mutationFn: async (params: IAskRequestBody) => { const { data } = await chatService.getMindMap(params); - return data; + return data?.data ?? []; }, }); return { data, loading, fetchMindMap: mutateAsync }; }; + +export const useFetchRelatedQuestions = () => { + const { + data, + isPending: loading, + mutateAsync, + } = useMutation({ + mutationKey: ['fetchRelatedQuestions'], + gcTime: 0, + mutationFn: async (question: string): Promise => { + const { data } = await chatService.getRelatedQuestions({ question }); + + return data?.data ?? []; + }, + }); + + return { data, loading, fetchRelatedQuestions: mutateAsync }; +}; //#endregion diff --git a/web/src/hooks/flow-hooks.ts b/web/src/hooks/flow-hooks.ts index a2bc992983..bde39217fd 100644 --- a/web/src/hooks/flow-hooks.ts +++ b/web/src/hooks/flow-hooks.ts @@ -57,7 +57,7 @@ export const useFetchFlowTemplates = (): ResponseType => { data.data.unshift({ id: uuid(), title: 'Blank', - description: 'Create from nothing', + description: 'Create your agent from scratch', dsl: EmptyDsl, }); } diff --git a/web/src/interfaces/request/chat.ts b/web/src/interfaces/request/chat.ts index 1cc0657e51..a61af9fb6a 100644 --- a/web/src/interfaces/request/chat.ts +++ b/web/src/interfaces/request/chat.ts @@ -5,6 +5,6 @@ export interface IFeedbackRequestBody { } export interface IAskRequestBody { - questionkb_ids: string; + question: string; kb_ids: string[]; } diff --git a/web/src/layouts/components/header/index.tsx b/web/src/layouts/components/header/index.tsx index 694840547b..357fca80f1 100644 --- a/web/src/layouts/components/header/index.tsx +++ b/web/src/layouts/components/header/index.tsx @@ -9,7 +9,7 @@ import { useLocation } from 'umi'; import Toolbar from '../right-toolbar'; import { useFetchAppConf } from '@/hooks/logic-hooks'; -import { MessageOutlined } from '@ant-design/icons'; +import { SearchOutlined } from '@ant-design/icons'; import styles from './index.less'; const { Header } = Layout; @@ -26,8 +26,8 @@ const RagHeader = () => { const tagsData = useMemo( () => [ { path: '/knowledge', name: t('knowledgeBase'), icon: KnowledgeBaseIcon }, - { path: '/chat', name: t('chat'), icon: MessageOutlined }, - // { path: '/search', name: t('search'), icon: SearchOutlined }, + // { path: '/chat', name: t('chat'), icon: MessageOutlined }, + { path: '/search', name: t('search'), icon: SearchOutlined }, { path: '/flow', name: t('flow'), icon: GraphIcon }, { path: '/file', name: t('fileManager'), icon: FileIcon }, ], diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index c51dc7d286..d405ad5c73 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -634,6 +634,7 @@ The above is the content you need to summarize.`, messagePlaceholder: 'message', messageMsg: 'Please input message or delete this field.', addField: 'Add field', + addMessage: 'Add message', loop: 'Loop', loopTip: 'Loop is the upper limit of the number of loops of the current component, when the number of loops exceeds the value of loop, it means that the component can not complete the current task, please re-optimize agent', @@ -672,7 +673,7 @@ The above is the content you need to summarize.`, begin: 'Begin', message: 'Message', blank: 'Blank', - createFromNothing: 'Create from nothing', + createFromNothing: 'Create your agent from scratch', addItem: 'Add Item', addSubItem: 'Add Sub Item', nameRequiredMsg: 'Name is required', diff --git a/web/src/locales/zh-traditional.ts b/web/src/locales/zh-traditional.ts index 3f489f86e0..ec500121bc 100644 --- a/web/src/locales/zh-traditional.ts +++ b/web/src/locales/zh-traditional.ts @@ -590,6 +590,7 @@ export default { messagePlaceholder: '訊息', messageMsg: '請輸入訊息或刪除此欄位。', addField: '新增字段', + addMessage: '新增訊息', loop: '循環上限', loopTip: 'loop為目前元件循環次數上限,當循環次數超過loop的值時,表示元件無法完成目前任務,請重新最佳化agent', diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts index 9adf1da571..2ab7dfeb24 100644 --- a/web/src/locales/zh.ts +++ b/web/src/locales/zh.ts @@ -609,6 +609,7 @@ export default { messagePlaceholder: '消息', messageMsg: '请输入消息或删除此字段。', addField: '新增字段', + addMessage: '新增消息', loop: '循环上限', loopTip: 'loop为当前组件循环次数上限,当循环次数超过loop的值时,说明组件不能完成当前任务,请重新优化agent', diff --git a/web/src/pages/chat/chat-configuration-modal/assistant-setting.tsx b/web/src/pages/chat/chat-configuration-modal/assistant-setting.tsx index e31d43a1ce..dddc81a325 100644 --- a/web/src/pages/chat/chat-configuration-modal/assistant-setting.tsx +++ b/web/src/pages/chat/chat-configuration-modal/assistant-setting.tsx @@ -90,7 +90,7 @@ const AssistantSetting = ({ show }: ISegmentedContentProps) => { > - { initialValue={false} > - + */} {/* { style={{ width: '80%' }} icon={} > - {t('addField')} + {t('addMessage')} diff --git a/web/src/pages/force-graph/index.tsx b/web/src/pages/force-graph/index.tsx index 4c95d39f28..215e4a7d9b 100644 --- a/web/src/pages/force-graph/index.tsx +++ b/web/src/pages/force-graph/index.tsx @@ -1,112 +1,3 @@ -import { Graph } from '@antv/g6'; -import { useSize } from 'ahooks'; -import { useEffect, useRef } from 'react'; -import { graphData } from './constant'; import InputWithUpload from './input-upload'; -import styles from './index.less'; -import { Converter } from './util'; - -const converter = new Converter(); - -const nextData = converter.buildNodesAndCombos( - graphData.nodes, - graphData.edges, -); -console.log('🚀 ~ nextData:', nextData); - -const finalData = { ...graphData, ...nextData }; - -const ForceGraph = () => { - const containerRef = useRef(null); - const size = useSize(containerRef); - let graph: Graph; - - const render = () => { - graph = new Graph({ - container: containerRef.current!, - autoFit: 'view', - behaviors: [ - 'drag-element', - 'drag-canvas', - 'zoom-canvas', - 'collapse-expand', - { - type: 'hover-activate', - degree: 1, // 👈🏻 Activate relations. - }, - ], - plugins: [ - { - type: 'tooltip', - getContent: (e, items) => { - if (items.every((x) => x?.description)) { - let result = ``; - items.forEach((item) => { - if (item?.description) { - result += `

${item?.description}

`; - } - }); - return result; - } - return undefined; - }, - }, - ], - layout: { - type: 'combo-combined', - preventOverlap: true, - comboPadding: 1, - spacing: 20, - }, - node: { - style: { - size: 20, - labelText: (d) => d.id, - labelPadding: 30, - // labelOffsetX: 20, - // labelOffsetY: 5, - labelPlacement: 'center', - labelWordWrap: true, - }, - palette: { - type: 'group', - field: (d) => d.combo, - }, - // state: { - // highlight: { - // fill: '#D580FF', - // halo: true, - // lineWidth: 0, - // }, - // dim: { - // fill: '#99ADD1', - // }, - // }, - }, - edge: { - style: (model) => { - const { size, color } = model.data; - return { - stroke: color || '#99ADD1', - lineWidth: size || 1, - }; - }, - }, - // data: graphData, - }); - - graph.setData(finalData); - - graph.render(); - }; - - useEffect(() => { - console.info('rendered'); - render(); - }, []); - - return
; -}; - export default InputWithUpload; diff --git a/web/src/pages/search/hooks.ts b/web/src/pages/search/hooks.ts index 2b0d6a64cc..7025355363 100644 --- a/web/src/pages/search/hooks.ts +++ b/web/src/pages/search/hooks.ts @@ -1,3 +1,4 @@ +import { useFetchMindMap, useFetchRelatedQuestions } from '@/hooks/chat-hooks'; import { useTestChunkRetrieval } from '@/hooks/knowledge-hooks'; import { useSendMessageWithSse } from '@/hooks/logic-hooks'; import { IAnswer } from '@/interfaces/database/chat'; @@ -10,6 +11,13 @@ export const useSendQuestion = (kbIds: string[]) => { const { testChunk, loading } = useTestChunkRetrieval(); const [sendingLoading, setSendingLoading] = useState(false); const [currentAnswer, setCurrentAnswer] = useState({} as IAnswer); + const { fetchRelatedQuestions, data: relatedQuestions } = + useFetchRelatedQuestions(); + const { + fetchMindMap, + data: mindMap, + loading: mindMapLoading, + } = useFetchMindMap(); const sendQuestion = useCallback( (question: string) => { @@ -17,8 +25,13 @@ export const useSendQuestion = (kbIds: string[]) => { setSendingLoading(true); send({ kb_ids: kbIds, question }); testChunk({ kb_id: kbIds, highlight: true, question }); + fetchMindMap({ + question, + kb_ids: kbIds, + }); + fetchRelatedQuestions(question); }, - [send, testChunk, kbIds], + [send, testChunk, kbIds, fetchRelatedQuestions, fetchMindMap], ); useEffect(() => { @@ -33,5 +46,13 @@ export const useSendQuestion = (kbIds: string[]) => { } }, [done]); - return { sendQuestion, loading, sendingLoading, answer: currentAnswer }; + return { + sendQuestion, + loading, + sendingLoading, + answer: currentAnswer, + relatedQuestions: relatedQuestions?.slice(0, 5) ?? [], + mindMap, + mindMapLoading, + }; }; diff --git a/web/src/pages/search/index.less b/web/src/pages/search/index.less index d20b2bfc76..dc1610c286 100644 --- a/web/src/pages/search/index.less +++ b/web/src/pages/search/index.less @@ -2,6 +2,10 @@ .card { width: 100%; } + .tag { + padding: 4px 8px; + font-size: 14px; + } } .searchSide { @@ -49,6 +53,6 @@ .graph { width: 40%; - background-color: bisque; + padding-right: 10px; } } diff --git a/web/src/pages/search/index.tsx b/web/src/pages/search/index.tsx index ce567360b7..48b3dd9804 100644 --- a/web/src/pages/search/index.tsx +++ b/web/src/pages/search/index.tsx @@ -2,12 +2,13 @@ import HightLightMarkdown from '@/components/highlight-markdown'; import { ImageWithPopover } from '@/components/image'; import { useSelectTestingResult } from '@/hooks/knowledge-hooks'; import { IReference } from '@/interfaces/database/chat'; -import { Card, Flex, Input, Layout, List, Space } from 'antd'; +import { Card, Flex, Input, Layout, List, Skeleton, Space, Tag } from 'antd'; import { useState } from 'react'; import MarkdownContent from '../chat/markdown-content'; import { useSendQuestion } from './hooks'; import SearchSidebar from './sidebar'; +import IndentedTree from '@/components/indented-tree/indented-tree'; import styles from './index.less'; const { Content } = Layout; @@ -16,7 +17,14 @@ const { Search } = Input; const SearchPage = () => { const [checkedList, setCheckedList] = useState([]); const list = useSelectTestingResult(); - const { sendQuestion, answer, sendingLoading } = useSendQuestion(checkedList); + const { + sendQuestion, + answer, + sendingLoading, + relatedQuestions, + mindMap, + mindMapLoading, + } = useSendQuestion(checkedList); return ( @@ -56,8 +64,29 @@ const SearchPage = () => { )} /> + {relatedQuestions?.length > 0 && ( + + + {relatedQuestions?.map((x, idx) => ( + + {x} + + ))} + + + )} + +
+ {mindMapLoading ? ( + + ) : ( + + )}
-
diff --git a/web/src/pages/search/sidebar.tsx b/web/src/pages/search/sidebar.tsx index 68f5b6385f..aa99d65713 100644 --- a/web/src/pages/search/sidebar.tsx +++ b/web/src/pages/search/sidebar.tsx @@ -30,20 +30,23 @@ const SearchSidebar = ({ checkedList, setCheckedList }: IProps) => { const indeterminate = checkedList.length > 0 && checkedList.length < list.length; - const onChange = useCallback((list: CheckboxValueType[]) => { - setCheckedList(list as string[]); - }, []); + const onChange = useCallback( + (list: CheckboxValueType[]) => { + setCheckedList(list as string[]); + }, + [setCheckedList], + ); const onCheckAllChange: CheckboxProps['onChange'] = useCallback( (e: CheckboxChangeEvent) => { setCheckedList(e.target.checked ? ids : []); }, - [ids], + [ids, setCheckedList], ); useEffect(() => { setCheckedList(ids); - }, [ids]); + }, [ids, setCheckedList]); return ( @@ -53,7 +56,7 @@ const SearchSidebar = ({ checkedList, setCheckedList }: IProps) => { onChange={onCheckAllChange} checked={checkAll} > - Check all + All (methods, request); diff --git a/web/src/utils/api.ts b/web/src/utils/api.ts index 635fbe322f..df1cc42d2d 100644 --- a/web/src/utils/api.ts +++ b/web/src/utils/api.ts @@ -68,6 +68,7 @@ export default { tts: `${api_host}/conversation/tts`, ask: `${api_host}/conversation/ask`, mindmap: `${api_host}/conversation/mindmap`, + getRelatedQuestions: `${api_host}/conversation/related_questions`, // chat for external createToken: `${api_host}/api/new_token`, listToken: `${api_host}/api/token_list`,