wwf
3 天以前 a430284aa21e3ae1f0d5654e55b2ad2852519cc2
app/components/base/chat/embedded-chatbot/hooks.tsx
@@ -11,12 +11,10 @@
import produce from 'immer'
import type {
  ChatConfig,
  ChatItem,
  Feedback,
} from '../types'
import { CONVERSATION_ID_INFO } from '../constants'
import { buildChatItemTree, getProcessedInputsFromUrlParams, getProcessedSystemVariablesFromUrlParams } from '../utils'
import { getProcessedFilesFromResponse } from '../../file-uploader/utils'
import { getPrevChatList, getProcessedInputsFromUrlParams } from '../utils'
import {
  fetchAppInfo,
  fetchAppMeta,
@@ -34,34 +32,6 @@
import { changeLanguage } from '@/i18n/i18next-config'
import { InputVarType } from '@/app/components/workflow/types'
import { TransferMethod } from '@/types/app'
import { addFileInfos, sortAgentSorts } from '@/app/components/tools/utils'
import { noop } from 'lodash-es'
function getFormattedChatList(messages: any[]) {
  const newChatList: ChatItem[] = []
  messages.forEach((item) => {
    const questionFiles = item.message_files?.filter((file: any) => file.belongs_to === 'user') || []
    newChatList.push({
      id: `question-${item.id}`,
      content: item.query,
      isAnswer: false,
      message_files: getProcessedFilesFromResponse(questionFiles.map((item: any) => ({ ...item, related_id: item.id }))),
      parentMessageId: item.parent_message_id || undefined,
    })
    const answerFiles = item.message_files?.filter((file: any) => file.belongs_to === 'assistant') || []
    newChatList.push({
      id: item.id,
      content: item.answer,
      agent_thoughts: addFileInfos(item.agent_thoughts ? sortAgentSorts(item.agent_thoughts) : item.agent_thoughts, item.message_files),
      feedback: item.feedback,
      isAnswer: true,
      citation: item.retriever_resources,
      message_files: getProcessedFilesFromResponse(answerFiles.map((item: any) => ({ ...item, related_id: item.id }))),
      parentMessageId: `question-${item.id}`,
    })
  })
  return newChatList
}
export const useEmbeddedChatbot = () => {
  const isInstalledApp = false
@@ -72,62 +42,24 @@
  }, [appInfo])
  const appId = useMemo(() => appData?.app_id, [appData])
  const [userId, setUserId] = useState<string>()
  const [conversationId, setConversationId] = useState<string>()
  useEffect(() => {
    getProcessedSystemVariablesFromUrlParams().then(({ user_id, conversation_id }) => {
      setUserId(user_id)
      setConversationId(conversation_id)
    })
  }, [])
  useEffect(() => {
    const setLanguageFromParams = async () => {
      // Check URL parameters for language override
      const urlParams = new URLSearchParams(window.location.search)
      const localeParam = urlParams.get('locale')
      // Check for encoded system variables
      const systemVariables = await getProcessedSystemVariablesFromUrlParams()
      const localeFromSysVar = systemVariables.locale
      if (localeParam) {
        // If locale parameter exists in URL, use it instead of default
        changeLanguage(localeParam)
      }
      else if (localeFromSysVar) {
        // If locale is set as a system variable, use that
        changeLanguage(localeFromSysVar)
      }
      else if (appInfo?.site.default_language) {
        // Otherwise use the default from app config
    if (appInfo?.site.default_language)
        changeLanguage(appInfo.site.default_language)
      }
    }
    setLanguageFromParams()
  }, [appInfo])
  const [conversationIdInfo, setConversationIdInfo] = useLocalStorageState<Record<string, Record<string, string>>>(CONVERSATION_ID_INFO, {
  const [conversationIdInfo, setConversationIdInfo] = useLocalStorageState<Record<string, string>>(CONVERSATION_ID_INFO, {
    defaultValue: {},
  })
  const allowResetChat = !conversationId
  const currentConversationId = useMemo(() => conversationIdInfo?.[appId || '']?.[userId || 'DEFAULT'] || conversationId || '',
    [appId, conversationIdInfo, userId, conversationId])
  const currentConversationId = useMemo(() => conversationIdInfo?.[appId || ''] || '', [appId, conversationIdInfo])
  const handleConversationIdInfoChange = useCallback((changeConversationId: string) => {
    if (appId) {
      let prevValue = conversationIdInfo?.[appId || '']
      if (typeof prevValue === 'string')
        prevValue = {}
      setConversationIdInfo({
        ...conversationIdInfo,
        [appId || '']: {
          ...prevValue,
          [userId || 'DEFAULT']: changeConversationId,
        },
        [appId || '']: changeConversationId,
      })
    }
  }, [appId, conversationIdInfo, setConversationIdInfo, userId])
  }, [appId, conversationIdInfo, setConversationIdInfo])
  const [showConfigPanelBeforeChat, setShowConfigPanelBeforeChat] = useState(true)
  const [newConversationId, setNewConversationId] = useState('')
  const chatShouldReloadKey = useMemo(() => {
@@ -143,11 +75,9 @@
  const { data: appConversationData, isLoading: appConversationDataLoading, mutate: mutateAppConversationData } = useSWR(['appConversationData', isInstalledApp, appId, false], () => fetchConversations(isInstalledApp, appId, undefined, false, 100))
  const { data: appChatListData, isLoading: appChatListDataLoading } = useSWR(chatShouldReloadKey ? ['appChatList', chatShouldReloadKey, isInstalledApp, appId] : null, () => fetchChatList(chatShouldReloadKey, isInstalledApp, appId))
  const [clearChatList, setClearChatList] = useState(false)
  const [isResponding, setIsResponding] = useState(false)
  const appPrevChatList = useMemo(
    () => (currentConversationId && appChatListData?.data.length)
      ? buildChatItemTree(getFormattedChatList(appChatListData.data))
      ? getPrevChatList(appChatListData.data)
      : [],
    [appChatListData, currentConversationId],
  )
@@ -223,10 +153,7 @@
  useEffect(() => {
    // init inputs from url params
    (async () => {
      const inputs = await getProcessedInputsFromUrlParams()
      setInitInputs(inputs)
    })()
    setInitInputs(getProcessedInputsFromUrlParams())
  }, [])
  useEffect(() => {
    const conversationInputs: Record<string, any> = {}
@@ -279,17 +206,6 @@
    return conversationItem
  }, [conversationList, currentConversationId, pinnedConversationList])
  const currentConversationLatestInputs = useMemo(() => {
    if (!currentConversationId || !appChatListData?.data.length)
      return newConversationInputsRef.current || {}
    return appChatListData.data.slice().pop().inputs || {}
  }, [appChatListData, currentConversationId])
  const [currentConversationInputs, setCurrentConversationInputs] = useState<Record<string, any>>(currentConversationLatestInputs || {})
  useEffect(() => {
    if (currentConversationItem)
      setCurrentConversationInputs(currentConversationLatestInputs || {})
  }, [currentConversationItem, currentConversationLatestInputs])
  const { notify } = useToastContext()
  const checkInputsRequired = useCallback((silent?: boolean) => {
    let hasEmptyInput = ''
@@ -328,27 +244,37 @@
    return true
  }, [inputsForms, notify, t])
  const handleStartChat = useCallback((callback?: any) => {
  const handleStartChat = useCallback(() => {
    if (checkInputsRequired()) {
      setShowConfigPanelBeforeChat(false)
      setShowNewConversationItemInList(true)
      callback?.()
    }
  }, [setShowNewConversationItemInList, checkInputsRequired])
  const currentChatInstanceRef = useRef<{ handleStop: () => void }>({ handleStop: noop })
  }, [setShowConfigPanelBeforeChat, setShowNewConversationItemInList, checkInputsRequired])
  const currentChatInstanceRef = useRef<{ handleStop: () => void }>({ handleStop: () => { } })
  const handleChangeConversation = useCallback((conversationId: string) => {
    currentChatInstanceRef.current.handleStop()
    setNewConversationId('')
    handleConversationIdInfoChange(conversationId)
    if (conversationId)
      setClearChatList(false)
  }, [handleConversationIdInfoChange, setClearChatList])
  const handleNewConversation = useCallback(async () => {
    if (conversationId === '' && !checkInputsRequired(true))
      setShowConfigPanelBeforeChat(true)
    else
      setShowConfigPanelBeforeChat(false)
  }, [handleConversationIdInfoChange, setShowConfigPanelBeforeChat, checkInputsRequired])
  const handleNewConversation = useCallback(() => {
    currentChatInstanceRef.current.handleStop()
    setShowNewConversationItemInList(true)
    setNewConversationId('')
    if (showNewConversationItemInList) {
    handleChangeConversation('')
    handleNewConversationInputsChange(await getProcessedInputsFromUrlParams())
    setClearChatList(true)
  }, [handleChangeConversation, setShowNewConversationItemInList, handleNewConversationInputsChange, setClearChatList])
    }
    else if (currentConversationId) {
      handleConversationIdInfoChange('')
      setShowConfigPanelBeforeChat(true)
      setShowNewConversationItemInList(true)
      handleNewConversationInputsChange({})
    }
  }, [handleChangeConversation, currentConversationId, handleConversationIdInfoChange, setShowConfigPanelBeforeChat, setShowNewConversationItemInList, showNewConversationItemInList, handleNewConversationInputsChange])
  const handleNewConversationCompleted = useCallback((newConversationId: string) => {
    setNewConversationId(newConversationId)
@@ -366,7 +292,6 @@
    appInfoError,
    appInfoLoading,
    isInstalledApp,
    allowResetChat,
    appId,
    currentConversationId,
    currentConversationItem,
@@ -382,6 +307,8 @@
    appPrevChatList,
    pinnedConversationList,
    conversationList,
    showConfigPanelBeforeChat,
    setShowConfigPanelBeforeChat,
    setShowNewConversationItemInList,
    newConversationInputs,
    newConversationInputsRef,
@@ -395,11 +322,5 @@
    chatShouldReloadKey,
    handleFeedback,
    currentChatInstanceRef,
    clearChatList,
    setClearChatList,
    isResponding,
    setIsResponding,
    currentConversationInputs,
    setCurrentConversationInputs,
  }
}