| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 | 'use client'import type { FC } from 'react'import React, { useEffect, useState } from 'react'import { useBoolean, useGetState } from 'ahooks'import { t } from 'i18next'import cn from 'classnames'import TextGenerationRes from '@/app/components/app/text-generate/item'import NoData from '@/app/components/share/text-generation/no-data'import Toast from '@/app/components/base/toast'import { sendCompletionMessage, updateFeedback } from '@/service/share'import type { Feedbacktype } from '@/app/components/app/chat/type'import Loading from '@/app/components/base/loading'import type { PromptConfig } from '@/models/debug'import type { InstalledApp } from '@/models/explore'export type IResultProps = {  isCallBatchAPI: boolean  isPC: boolean  isMobile: boolean  isInstalledApp: boolean  installedAppInfo?: InstalledApp  promptConfig: PromptConfig | null  moreLikeThisEnabled: boolean  inputs: Record<string, any>  query: string  controlSend?: number  controlStopResponding?: number  onShowRes: () => void  handleSaveMessage: (messageId: string) => void  taskId?: number  onCompleted: (completionRes: string, taskId?: number, success?: boolean) => void}const Result: FC<IResultProps> = ({  isCallBatchAPI,  isPC,  isMobile,  isInstalledApp,  installedAppInfo,  promptConfig,  moreLikeThisEnabled,  inputs,  query,  controlSend,  controlStopResponding,  onShowRes,  handleSaveMessage,  taskId,  onCompleted,}) => {  const [isResponsing, { setTrue: setResponsingTrue, setFalse: setResponsingFalse }] = useBoolean(false)  useEffect(() => {    if (controlStopResponding)      setResponsingFalse()  }, [controlStopResponding])  const [completionRes, setCompletionRes, getCompletionRes] = useGetState('')  const { notify } = Toast  const isNoData = !completionRes  const [messageId, setMessageId] = useState<string | null>(null)  const [feedback, setFeedback] = useState<Feedbacktype>({    rating: null,  })  const handleFeedback = async (feedback: Feedbacktype) => {    await updateFeedback({ url: `/messages/${messageId}/feedbacks`, body: { rating: feedback.rating } }, isInstalledApp, installedAppInfo?.id)    setFeedback(feedback)  }  const logError = (message: string) => {    notify({ type: 'error', message })  }  const checkCanSend = () => {    // batch will check outer    if (isCallBatchAPI)      return true    const prompt_variables = promptConfig?.prompt_variables    if (!prompt_variables || prompt_variables?.length === 0)      return true    let hasEmptyInput = ''    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, name }) => {      if (hasEmptyInput)        return      if (!inputs[key])        hasEmptyInput = name    })    if (hasEmptyInput) {      logError(t('appDebug.errorMessage.valueOfVarRequired', { key: hasEmptyInput }))      return false    }    return !hasEmptyInput  }  const handleSend = async () => {    if (isResponsing) {      notify({ type: 'info', message: t('appDebug.errorMessage.waitForResponse') })      return false    }    if (!checkCanSend())      return    if (!query) {      logError(t('appDebug.errorMessage.queryRequired'))      return false    }    const data = {      inputs,      query,    }    setMessageId(null)    setFeedback({      rating: null,    })    setCompletionRes('')    const res: string[] = []    let tempMessageId = ''    if (!isPC)      onShowRes()    setResponsingTrue()    sendCompletionMessage(data, {      onData: (data: string, _isFirstMessage: boolean, { messageId }) => {        tempMessageId = messageId        res.push(data)        setCompletionRes(res.join(''))      },      onCompleted: () => {        setResponsingFalse()        setMessageId(tempMessageId)        onCompleted(getCompletionRes(), taskId, true)      },      onError() {        setResponsingFalse()        onCompleted(getCompletionRes(), taskId, false)      },    }, isInstalledApp, installedAppInfo?.id)  }  const [controlClearMoreLikeThis, setControlClearMoreLikeThis] = useState(0)  useEffect(() => {    if (controlSend) {      handleSend()      setControlClearMoreLikeThis(Date.now())    }  }, [controlSend])  const renderTextGenerationRes = () => (    <TextGenerationRes      className='mt-3'      content={completionRes}      messageId={messageId}      isInWebApp      moreLikeThis={moreLikeThisEnabled}      onFeedback={handleFeedback}      feedback={feedback}      onSave={handleSaveMessage}      isMobile={isMobile}      isInstalledApp={isInstalledApp}      installedAppId={installedAppInfo?.id}      isLoading={isCallBatchAPI ? (!completionRes && isResponsing) : false}      taskId={isCallBatchAPI ? ((taskId as number) < 10 ? `0${taskId}` : `${taskId}`) : undefined}      controlClearMoreLikeThis={controlClearMoreLikeThis}    />  )  return (    <div className={cn(isNoData && !isCallBatchAPI && 'h-full')}>      {!isCallBatchAPI && (        (isResponsing && !completionRes)          ? (            <div className='flex h-full w-full justify-center items-center'>              <Loading type='area' />            </div>)          : (            <>              {isNoData                ? <NoData />                : renderTextGenerationRes()              }            </>          )      )}      {isCallBatchAPI && (        <div className='mt-2'>          {renderTextGenerationRes()}        </div>      )}    </div>  )}export default React.memo(Result)
 |