diff --git a/web/app/components/app/configuration/debug/index.tsx b/web/app/components/app/configuration/debug/index.tsx index a4d19be265..363cb4c3e3 100644 --- a/web/app/components/app/configuration/debug/index.tsx +++ b/web/app/components/app/configuration/debug/index.tsx @@ -1,36 +1,36 @@ 'use client' import type { FC } from 'react' import { useTranslation } from 'react-i18next' -import React, { useEffect, useState, useRef } from 'react' +import React, { useEffect, useRef, useState } from 'react' import cn from 'classnames' import produce from 'immer' import { useBoolean, useGetState } from 'ahooks' import { useContext } from 'use-context-selector' +import dayjs from 'dayjs' +import HasNotSetAPIKEY from '../base/warning-mask/has-not-set-api' +import FormattingChanged from '../base/warning-mask/formatting-changed' +import GroupName from '../base/group-name' import { AppType } from '@/types/app' import PromptValuePanel, { replaceStringWithValues } from '@/app/components/app/configuration/prompt-value-panel' import type { IChatItem } from '@/app/components/app/chat' import Chat from '@/app/components/app/chat' import ConfigContext from '@/context/debug-configuration' import { ToastContext } from '@/app/components/base/toast' -import { sendChatMessage, sendCompletionMessage, fetchSuggestedQuestions, fetchConvesationMessages } from '@/service/debug' +import { fetchConvesationMessages, fetchSuggestedQuestions, sendChatMessage, sendCompletionMessage } from '@/service/debug' import Button from '@/app/components/base/button' import type { ModelConfig as BackendModelConfig } from '@/types/app' import { promptVariablesToUserInputsForm } from '@/utils/model-config' -import HasNotSetAPIKEY from '../base/warning-mask/has-not-set-api' -import FormattingChanged from '../base/warning-mask/formatting-changed' import TextGeneration from '@/app/components/app/text-generate/item' -import GroupName from '../base/group-name' -import dayjs from 'dayjs' import { IS_CE_EDITION } from '@/config' -interface IDebug { +type IDebug = { hasSetAPIKEY: boolean onSetting: () => void } const Debug: FC = ({ hasSetAPIKEY = true, - onSetting + onSetting, }) => { const { t } = useTranslation() const { @@ -51,14 +51,12 @@ const Debug: FC = ({ completionParams, } = useContext(ConfigContext) - const [chatList, setChatList, getChatList] = useGetState([]) const chatListDomRef = useRef(null) useEffect(() => { // scroll to bottom - if (chatListDomRef.current) { + if (chatListDomRef.current) chatListDomRef.current.scrollTop = chatListDomRef.current.scrollHeight - } }, [chatList]) const getIntroduction = () => replaceStringWithValues(introduction, modelConfig.configs.prompt_variables, inputs) @@ -68,7 +66,7 @@ const Debug: FC = ({ id: `${Date.now()}`, content: getIntroduction(), isAnswer: true, - isOpeningStatement: true + isOpeningStatement: true, }]) } }, [introduction, modelConfig.configs.prompt_variables, inputs]) @@ -76,11 +74,12 @@ const Debug: FC = ({ const [isResponsing, { setTrue: setResponsingTrue, setFalse: setResponsingFalse }] = useBoolean(false) const [abortController, setAbortController] = useState(null) const [isShowFormattingChangeConfirm, setIsShowFormattingChangeConfirm] = useState(false) + const [isShowSuggestion, setIsShowSuggestion] = useState(false) useEffect(() => { - if (formattingChanged && chatList.some(item => !item.isAnswer)) { + if (formattingChanged && chatList.some(item => !item.isAnswer)) setIsShowFormattingChangeConfirm(true) - } + setFormattingChanged(false) }, [formattingChanged]) @@ -88,12 +87,14 @@ const Debug: FC = ({ setConversationId(null) abortController?.abort() setResponsingFalse() - setChatList(introduction ? [{ - id: `${Date.now()}`, - content: getIntroduction(), - isAnswer: true, - isOpeningStatement: true - }] : []) + setChatList(introduction + ? [{ + id: `${Date.now()}`, + content: getIntroduction(), + isAnswer: true, + isOpeningStatement: true, + }] + : []) setIsShowSuggestion(false) } @@ -119,12 +120,11 @@ const Debug: FC = ({ }) // compatible with old version // debugger requiredVars.forEach(({ key }) => { - if (hasEmptyInput) { + if (hasEmptyInput) return - } - if (!inputs[key]) { + + if (!inputs[key]) hasEmptyInput = true - } }) if (hasEmptyInput) { @@ -134,7 +134,6 @@ const Debug: FC = ({ return !hasEmptyInput } - const [isShowSuggestion, setIsShowSuggestion] = useState(false) const doShowSuggestion = isShowSuggestion && !isResponsing const [suggestQuestions, setSuggestQuestions] = useState([]) const onSend = async (message: string) => { @@ -147,7 +146,7 @@ const Debug: FC = ({ dataset: { enabled: true, id, - } + }, })) const postModelConfig: BackendModelConfig = { @@ -155,17 +154,17 @@ const Debug: FC = ({ user_input_form: promptVariablesToUserInputsForm(modelConfig.configs.prompt_variables), opening_statement: introduction, more_like_this: { - enabled: false + enabled: false, }, suggested_questions_after_answer: suggestedQuestionsAfterAnswerConfig, agent_mode: { enabled: true, - tools: [...postDatasets] + tools: [...postDatasets], }, model: { provider: modelConfig.provider, name: modelConfig.model_id, - completion_params: completionParams as any + completion_params: completionParams as any, }, } @@ -215,32 +214,32 @@ const Debug: FC = ({ setConversationId(newConversationId) _newConversationId = newConversationId } - if (messageId) { + if (messageId) responseItem.id = messageId - } + // closesure new list is outdated. const newListWithAnswer = produce( getChatList().filter(item => item.id !== responseItem.id && item.id !== placeholderAnswerId), (draft) => { - if (!draft.find(item => item.id === questionId)) { + if (!draft.find(item => item.id === questionId)) draft.push({ ...questionItem }) - } + draft.push({ ...responseItem }) }) setChatList(newListWithAnswer) }, async onCompleted(hasError?: boolean) { setResponsingFalse() - if (hasError) { + if (hasError) return - } + if (_newConversationId) { const { data }: any = await fetchConvesationMessages(appId, _newConversationId as string) const newResponseItem = data.find((item: any) => item.id === responseItem.id) - if (!newResponseItem) { + if (!newResponseItem) return - } - setChatList(produce(getChatList(), draft => { + + setChatList(produce(getChatList(), (draft) => { const index = draft.findIndex(item => item.id === responseItem.id) if (index !== -1) { draft[index] = { @@ -249,7 +248,7 @@ const Debug: FC = ({ time: dayjs.unix(newResponseItem.created_at).format('hh:mm A'), tokens: newResponseItem.answer_tokens + newResponseItem.message_tokens, latency: newResponseItem.provider_response_latency.toFixed(2), - } + }, } } })) @@ -263,10 +262,10 @@ const Debug: FC = ({ onError() { setResponsingFalse() // role back placeholder answer - setChatList(produce(getChatList(), draft => { + setChatList(produce(getChatList(), (draft) => { draft.splice(draft.findIndex(item => item.id === placeholderAnswerId), 1) })) - } + }, }) return true } @@ -277,7 +276,7 @@ const Debug: FC = ({ }, [controlClearChatMessage]) const [completionQuery, setCompletionQuery] = useState('') - const [completionRes, setCompletionRes] = useState(``) + const [completionRes, setCompletionRes] = useState('') const sendTextCompletion = async () => { if (isResponsing) { @@ -297,7 +296,7 @@ const Debug: FC = ({ dataset: { enabled: true, id, - } + }, })) const postModelConfig: BackendModelConfig = { @@ -308,16 +307,15 @@ const Debug: FC = ({ more_like_this: moreLikeThisConifg, agent_mode: { enabled: true, - tools: [...postDatasets] + tools: [...postDatasets], }, model: { provider: modelConfig.provider, name: modelConfig.model_id, - completion_params: completionParams as any + completion_params: completionParams as any, }, } - const data = { inputs, query: completionQuery, @@ -338,11 +336,10 @@ const Debug: FC = ({ }, onError() { setResponsingFalse() - } + }, }) } - return ( <>
@@ -368,7 +365,7 @@ const Debug: FC = ({ {/* Chat */} {mode === AppType.chat && (
-
+
{/* {JSON.stringify(chatList)} */} = ({ isInstalledApp = false, - installedAppInfo + installedAppInfo, }) => { const { t } = useTranslation() const media = useBreakpoints() @@ -53,7 +52,7 @@ const Main: FC = ({ const [plan, setPlan] = useState('basic') // basic/plus/pro // in mobile, show sidebar by click button const [isShowSidebar, { setTrue: showSidebar, setFalse: hideSidebar }] = useBoolean(false) - // Can Use metadata(https://beta.nextjs.org/docs/api-reference/metadata) to set title. But it only works in server side client. + // Can Use metadata(https://beta.nextjs.org/docs/api-reference/metadata) to set title. But it only works in server side client. useEffect(() => { if (siteInfo?.title) { if (plan !== 'basic') @@ -61,7 +60,6 @@ const Main: FC = ({ else document.title = `${siteInfo.title} - Powered by Dify` } - }, [siteInfo?.title, plan]) /* @@ -81,7 +79,7 @@ const Main: FC = ({ resetNewConversationInputs, setCurrInputs, setNewConversationInfo, - setExistConversationInfo + setExistConversationInfo, } = useConversation() const [hasMore, setHasMore] = useState(false) const onMoreLoaded = ({ data: conversations, has_more }: any) => { @@ -101,9 +99,9 @@ const Main: FC = ({ setChatList(generateNewChatListWithOpenstatement('', inputs)) } const hasSetInputs = (() => { - if (!isNewConversation) { + if (!isNewConversation) return true - } + return isChatStarted })() @@ -111,7 +109,8 @@ const Main: FC = ({ const conversationIntroduction = currConversationInfo?.introduction || '' const handleConversationSwitch = () => { - if (!inited) return + if (!inited) + return if (!appId) { // wait for appId setTimeout(handleConversationSwitch, 100) @@ -130,12 +129,13 @@ const Main: FC = ({ name: item?.name || '', introduction: notSyncToStateIntroduction, }) - } else { + } + else { notSyncToStateInputs = newConversationInputs setCurrInputs(notSyncToStateInputs) } - // update chat list of current conversation + // update chat list of current conversation if (!isNewConversation && !conversationIdChangeBecauseOfNew && !isResponsing) { fetchChatList(currConversationId, isInstalledApp, installedAppInfo?.id).then((res: any) => { const { data } = res @@ -158,9 +158,8 @@ const Main: FC = ({ }) } - if (isNewConversation && isChatStarted) { + if (isNewConversation && isChatStarted) setChatList(generateNewChatListWithOpenstatement()) - } setControlFocus(Date.now()) } @@ -170,7 +169,8 @@ const Main: FC = ({ if (id === '-1') { createNewChat() setConversationIdChangeBecauseOfNew(true) - } else { + } + else { setConversationIdChangeBecauseOfNew(false) } // trigger handleConversationSwitch @@ -186,9 +186,8 @@ const Main: FC = ({ const chatListDomRef = useRef(null) useEffect(() => { // scroll to bottom - if (chatListDomRef.current) { + if (chatListDomRef.current) chatListDomRef.current.scrollTop = chatListDomRef.current.scrollHeight - } }, [chatList, currConversationId]) // user can not edit inputs if user had send message const canEditInpus = !chatList.some(item => item.isAnswer === false) && isNewConversation @@ -196,15 +195,15 @@ const Main: FC = ({ // if new chat is already exist, do not create new chat abortController?.abort() setResponsingFalse() - if (conversationList.some(item => item.id === '-1')) { + if (conversationList.some(item => item.id === '-1')) return - } - setConversationList(produce(conversationList, draft => { + + setConversationList(produce(conversationList, (draft) => { draft.unshift({ id: '-1', name: t('share.chat.newChatDefaultName'), inputs: newConversationInputs, - introduction: conversationIntroduction + introduction: conversationIntroduction, }) })) } @@ -213,36 +212,37 @@ const Main: FC = ({ const generateNewChatListWithOpenstatement = (introduction?: string, inputs?: Record | null) => { let caculatedIntroduction = introduction || conversationIntroduction || '' const caculatedPromptVariables = inputs || currInputs || null - if (caculatedIntroduction && caculatedPromptVariables) { + if (caculatedIntroduction && caculatedPromptVariables) caculatedIntroduction = replaceStringWithValues(caculatedIntroduction, promptConfig?.prompt_variables || [], caculatedPromptVariables) - } + // console.log(isPublicVersion) const openstatement = { id: `${Date.now()}`, content: caculatedIntroduction, isAnswer: true, feedbackDisabled: true, - isOpeningStatement: isPublicVersion + isOpeningStatement: isPublicVersion, } - if (caculatedIntroduction) { + if (caculatedIntroduction) return [openstatement] - } + return [] } const fetchInitData = () => { - return Promise.all([isInstalledApp ? { - app_id: installedAppInfo?.id, - site: { - title: installedAppInfo?.app.name, - prompt_public: false, - copyright: '' - }, - plan: 'basic', - }: fetchAppInfo(), fetchConversations(isInstalledApp, installedAppInfo?.id), fetchAppParams(isInstalledApp, installedAppInfo?.id)]) + return Promise.all([isInstalledApp + ? { + app_id: installedAppInfo?.id, + site: { + title: installedAppInfo?.app.name, + prompt_public: false, + copyright: '', + }, + plan: 'basic', + } + : fetchAppInfo(), fetchConversations(isInstalledApp, installedAppInfo?.id), fetchAppParams(isInstalledApp, installedAppInfo?.id)]) } - // init useEffect(() => { (async () => { @@ -255,16 +255,16 @@ const Main: FC = ({ setIsPublicVersion(tempIsPublicVersion) const prompt_template = '' // handle current conversation id - const { data: conversations, has_more } = conversationData as { data: ConversationItem[], has_more: boolean } + const { data: conversations, has_more } = conversationData as { data: ConversationItem[]; has_more: boolean } const _conversationId = getConversationIdFromStorage(appId) const isNotNewConversation = conversations.some(item => item.id === _conversationId) setHasMore(has_more) // fetch new conversation info const { user_input_form, opening_statement: introduction, suggested_questions_after_answer }: any = appParams const prompt_variables = userInputsFormToPromptVariables(user_input_form) - if(siteInfo.default_language) { + if (siteInfo.default_language) changeLanguage(siteInfo.default_language) - } + setNewConversationInfo({ name: t('share.chat.newChatDefaultName'), introduction, @@ -272,20 +272,22 @@ const Main: FC = ({ setSiteInfo(siteInfo as SiteInfo) setPromptConfig({ prompt_template, - prompt_variables: prompt_variables, + prompt_variables, } as PromptConfig) setSuggestedQuestionsAfterAnswerConfig(suggested_questions_after_answer) setConversationList(conversations as ConversationItem[]) - if (isNotNewConversation) { + if (isNotNewConversation) setCurrConversationId(_conversationId, appId, false) - } + setInited(true) - } catch (e: any) { + } + catch (e: any) { if (e.status === 404) { setAppUnavailable(true) - } else { + } + else { setIsUnknwonReason(true) setAppUnavailable(true) } @@ -303,21 +305,20 @@ const Main: FC = ({ const checkCanSend = () => { const prompt_variables = promptConfig?.prompt_variables const inputs = currInputs - if (!inputs || !prompt_variables || prompt_variables?.length === 0) { + if (!inputs || !prompt_variables || prompt_variables?.length === 0) return true - } + let hasEmptyInput = false const requiredVars = prompt_variables?.filter(({ key, name, required }) => { const res = (!key || !key.trim()) || (!name || !name.trim()) || (required || required === undefined || required === null) return res }) || [] // compatible with old version requiredVars.forEach(({ key }) => { - if (hasEmptyInput) { + if (hasEmptyInput) return - } - if (!inputs?.[key]) { + + if (!inputs?.[key]) hasEmptyInput = true - } }) if (hasEmptyInput) { @@ -378,9 +379,8 @@ const Main: FC = ({ onData: (message: string, isFirstMessage: boolean, { conversationId: newConversationId, messageId }: any) => { responseItem.content = responseItem.content + message responseItem.id = messageId - if (isFirstMessage && newConversationId) { + if (isFirstMessage && newConversationId) tempNewConversationId = newConversationId - } // closesure new list is outdated. const newListWithAnswer = produce( @@ -395,9 +395,9 @@ const Main: FC = ({ }, async onCompleted(hasError?: boolean) { setResponsingFalse() - if (hasError) { + if (hasError) return - } + let currChatList = conversationList if (getConversationIdChangeBecauseOfNew()) { const { data: conversations, has_more }: any = await fetchConversations(isInstalledApp, installedAppInfo?.id) @@ -418,7 +418,7 @@ const Main: FC = ({ onError() { setResponsingFalse() // role back placeholder answer - setChatList(produce(getChatList(), draft => { + setChatList(produce(getChatList(), (draft) => { draft.splice(draft.findIndex(item => item.id === placeholderAnswerId), 1) })) }, @@ -476,18 +476,20 @@ const Main: FC = ({ onCreateNewChat={() => handleConversationIdChange('-1')} /> )} - + {/* {isNewConversation ? 'new' : 'exist'} {JSON.stringify(newConversationInputs ? newConversationInputs : {})} {JSON.stringify(existConversationInputs ? existConversationInputs : {})} */} -
{/* sidebar */} {!isMobile && renderSidebar()} @@ -504,8 +506,8 @@ const Main: FC = ({ {/* main */}
= ({ { hasSetInputs && ( -
+