diff --git a/web/app/(shareLayout)/chat/[token]/page.tsx b/web/app/(shareLayout)/chat/[token]/page.tsx index fbb9d5ade..6c3fe2b4a 100644 --- a/web/app/(shareLayout)/chat/[token]/page.tsx +++ b/web/app/(shareLayout)/chat/[token]/page.tsx @@ -1,12 +1,14 @@ +'use client' + import type { FC } from 'react' import React from 'react' import type { IMainProps } from '@/app/components/share/chat' -import Main from '@/app/components/share/chat' +import ChatWithHistoryWrap from '@/app/components/base/chat/chat-with-history' const Chat: FC = () => { return ( -
+ ) } diff --git a/web/app/components/base/chat/chat-with-history/chat-wrapper.tsx b/web/app/components/base/chat/chat-with-history/chat-wrapper.tsx new file mode 100644 index 000000000..1e58e37b6 --- /dev/null +++ b/web/app/components/base/chat/chat-with-history/chat-wrapper.tsx @@ -0,0 +1,141 @@ +import { useCallback, useEffect, useMemo } from 'react' +import Chat from '../chat' +import type { + ChatConfig, + OnSend, +} from '../types' +import { useChat } from '../chat/hooks' +import { useChatWithHistoryContext } from './context' +import Header from './header' +import ConfigPanel from './config-panel' +import { + fetchSuggestedQuestions, + getUrl, +} from '@/service/share' + +const ChatWrapper = () => { + const { + appParams, + appPrevChatList, + currentConversationId, + currentConversationItem, + inputsForms, + newConversationInputs, + handleNewConversationCompleted, + isMobile, + isInstalledApp, + appId, + appMeta, + handleFeedback, + currentChatInstanceRef, + } = useChatWithHistoryContext() + const appConfig = useMemo(() => { + const config = appParams || {} + + return { + ...config, + supportFeedback: true, + } as ChatConfig + }, [appParams]) + const { + chatList, + handleSend, + handleStop, + isResponsing, + suggestedQuestions, + } = useChat( + appConfig, + undefined, + appPrevChatList, + ) + + useEffect(() => { + if (currentChatInstanceRef.current) + currentChatInstanceRef.current.handleStop = handleStop + }, []) + + const doSend: OnSend = useCallback((message, files) => { + const data: any = { + query: message, + inputs: currentConversationId ? currentConversationItem?.inputs : newConversationInputs, + conversation_id: currentConversationId, + } + + if (appConfig?.file_upload?.image.enabled && files?.length) + data.files = files + + handleSend( + getUrl('chat-messages', isInstalledApp, appId || ''), + data, + { + onGetSuggestedQuestions: responseItemId => fetchSuggestedQuestions(responseItemId, isInstalledApp, appId), + onConversationComplete: currentConversationId ? undefined : handleNewConversationCompleted, + isPublicAPI: !isInstalledApp, + }, + ) + }, [ + appConfig, + currentConversationId, + currentConversationItem, + handleSend, + newConversationInputs, + handleNewConversationCompleted, + isInstalledApp, + appId, + ]) + const chatNode = useMemo(() => { + if (inputsForms.length) { + return ( + <> +
+ { + !currentConversationId && ( +
+
+ +
+
+ ) + } + + ) + } + + return ( +
+ ) + }, [ + currentConversationId, + inputsForms, + currentConversationItem, + isMobile, + ]) + + return ( + + ) +} + +export default ChatWrapper diff --git a/web/app/components/base/chat/chat-with-history/config-panel/form.tsx b/web/app/components/base/chat/chat-with-history/config-panel/form.tsx new file mode 100644 index 000000000..3940568e4 --- /dev/null +++ b/web/app/components/base/chat/chat-with-history/config-panel/form.tsx @@ -0,0 +1,82 @@ +import { useTranslation } from 'react-i18next' +import { useChatWithHistoryContext } from '../context' +import { PortalSelect } from '@/app/components/base/select' + +const Form = () => { + const { t } = useTranslation() + const { + inputsForms, + newConversationInputs, + handleNewConversationInputsChange, + isMobile, + } = useChatWithHistoryContext() + + const handleFormChange = (variable: string, value: string) => { + handleNewConversationInputsChange({ + ...newConversationInputs, + [variable]: value, + }) + } + + const renderField = (form: any) => { + const { + label, + required, + max_length, + variable, + options, + } = form + + if (form.type === 'text-input') { + return ( + handleFormChange(variable, e.target.value)} + placeholder={`${label}${!required ? `(${t('appDebug.variableTable.optional')})` : ''}`} + /> + ) + } + if (form.type === 'paragraph') { + return ( +