| @@ -16,7 +16,7 @@ import type { | |||
| Feedback, | |||
| } from '../types' | |||
| import { CONVERSATION_ID_INFO } from '../constants' | |||
| import { buildChatItemTree } from '../utils' | |||
| import { buildChatItemTree, getProcessedSystemVariablesFromUrlParams } from '../utils' | |||
| import { addFileInfos, sortAgentSorts } from '../../../tools/utils' | |||
| import { getProcessedFilesFromResponse } from '@/app/components/base/file-uploader/utils' | |||
| import { | |||
| @@ -106,6 +106,13 @@ export const useChatWithHistory = (installedAppInfo?: InstalledApp) => { | |||
| }, [isInstalledApp, installedAppInfo, appInfo]) | |||
| const appId = useMemo(() => appData?.app_id, [appData]) | |||
| const [userId, setUserId] = useState<string>() | |||
| useEffect(() => { | |||
| getProcessedSystemVariablesFromUrlParams().then(({ user_id }) => { | |||
| setUserId(user_id) | |||
| }) | |||
| }, []) | |||
| useEffect(() => { | |||
| if (appData?.site.default_language) | |||
| changeLanguage(appData.site.default_language) | |||
| @@ -124,18 +131,24 @@ export const useChatWithHistory = (installedAppInfo?: InstalledApp) => { | |||
| setSidebarCollapseState(localState === 'collapsed') | |||
| } | |||
| }, [appId]) | |||
| const [conversationIdInfo, setConversationIdInfo] = useLocalStorageState<Record<string, string>>(CONVERSATION_ID_INFO, { | |||
| const [conversationIdInfo, setConversationIdInfo] = useLocalStorageState<Record<string, Record<string, string>>>(CONVERSATION_ID_INFO, { | |||
| defaultValue: {}, | |||
| }) | |||
| const currentConversationId = useMemo(() => conversationIdInfo?.[appId || ''] || '', [appId, conversationIdInfo]) | |||
| const currentConversationId = useMemo(() => conversationIdInfo?.[appId || '']?.[userId || 'DEFAULT'] || '', [appId, conversationIdInfo, userId]) | |||
| const handleConversationIdInfoChange = useCallback((changeConversationId: string) => { | |||
| if (appId) { | |||
| let prevValue = conversationIdInfo?.[appId || ''] | |||
| if (typeof prevValue === 'string') | |||
| prevValue = {} | |||
| setConversationIdInfo({ | |||
| ...conversationIdInfo, | |||
| [appId || '']: changeConversationId, | |||
| [appId || '']: { | |||
| ...prevValue, | |||
| [userId || 'DEFAULT']: changeConversationId, | |||
| }, | |||
| }) | |||
| } | |||
| }, [appId, conversationIdInfo, setConversationIdInfo]) | |||
| }, [appId, conversationIdInfo, setConversationIdInfo, userId]) | |||
| const [newConversationId, setNewConversationId] = useState('') | |||
| const chatShouldReloadKey = useMemo(() => { | |||
| @@ -15,7 +15,7 @@ import type { | |||
| Feedback, | |||
| } from '../types' | |||
| import { CONVERSATION_ID_INFO } from '../constants' | |||
| import { buildChatItemTree, getProcessedInputsFromUrlParams } from '../utils' | |||
| import { buildChatItemTree, getProcessedInputsFromUrlParams, getProcessedSystemVariablesFromUrlParams } from '../utils' | |||
| import { getProcessedFilesFromResponse } from '../../file-uploader/utils' | |||
| import { | |||
| fetchAppInfo, | |||
| @@ -72,23 +72,36 @@ export const useEmbeddedChatbot = () => { | |||
| }, [appInfo]) | |||
| const appId = useMemo(() => appData?.app_id, [appData]) | |||
| const [userId, setUserId] = useState<string>() | |||
| useEffect(() => { | |||
| getProcessedSystemVariablesFromUrlParams().then(({ user_id }) => { | |||
| setUserId(user_id) | |||
| }) | |||
| }, []) | |||
| useEffect(() => { | |||
| if (appInfo?.site.default_language) | |||
| changeLanguage(appInfo.site.default_language) | |||
| }, [appInfo]) | |||
| const [conversationIdInfo, setConversationIdInfo] = useLocalStorageState<Record<string, string>>(CONVERSATION_ID_INFO, { | |||
| const [conversationIdInfo, setConversationIdInfo] = useLocalStorageState<Record<string, Record<string, string>>>(CONVERSATION_ID_INFO, { | |||
| defaultValue: {}, | |||
| }) | |||
| const currentConversationId = useMemo(() => conversationIdInfo?.[appId || ''] || '', [appId, conversationIdInfo]) | |||
| const currentConversationId = useMemo(() => conversationIdInfo?.[appId || '']?.[userId || 'DEFAULT'] || '', [appId, conversationIdInfo, userId]) | |||
| const handleConversationIdInfoChange = useCallback((changeConversationId: string) => { | |||
| if (appId) { | |||
| let prevValue = conversationIdInfo?.[appId || ''] | |||
| if (typeof prevValue === 'string') | |||
| prevValue = {} | |||
| setConversationIdInfo({ | |||
| ...conversationIdInfo, | |||
| [appId || '']: changeConversationId, | |||
| [appId || '']: { | |||
| ...prevValue, | |||
| [userId || 'DEFAULT']: changeConversationId, | |||
| }, | |||
| }) | |||
| } | |||
| }, [appId, conversationIdInfo, setConversationIdInfo]) | |||
| }, [appId, conversationIdInfo, setConversationIdInfo, userId]) | |||
| const [newConversationId, setNewConversationId] = useState('') | |||
| const chatShouldReloadKey = useMemo(() => { | |||
| @@ -2,29 +2,44 @@ import { CONVERSATION_ID_INFO } from '../base/chat/constants' | |||
| import { fetchAccessToken } from '@/service/share' | |||
| import { getProcessedSystemVariablesFromUrlParams } from '../base/chat/utils' | |||
| export const isTokenV1 = (token: Record<string, any>) => { | |||
| return !token.version | |||
| } | |||
| export const getInitialTokenV2 = (): Record<string, any> => ({ | |||
| version: 2, | |||
| }) | |||
| export const checkOrSetAccessToken = async () => { | |||
| const sharedToken = globalThis.location.pathname.split('/').slice(-1)[0] | |||
| const accessToken = localStorage.getItem('token') || JSON.stringify({ [sharedToken]: '' }) | |||
| let accessTokenJson = { [sharedToken]: '' } | |||
| const userId = (await getProcessedSystemVariablesFromUrlParams()).user_id | |||
| const accessToken = localStorage.getItem('token') || JSON.stringify(getInitialTokenV2()) | |||
| let accessTokenJson = getInitialTokenV2() | |||
| try { | |||
| accessTokenJson = JSON.parse(accessToken) | |||
| if (isTokenV1(accessTokenJson)) | |||
| accessTokenJson = getInitialTokenV2() | |||
| } | |||
| catch { | |||
| } | |||
| if (!accessTokenJson[sharedToken]) { | |||
| const sysUserId = (await getProcessedSystemVariablesFromUrlParams()).user_id | |||
| const res = await fetchAccessToken(sharedToken, sysUserId) | |||
| accessTokenJson[sharedToken] = res.access_token | |||
| if (!accessTokenJson[sharedToken]?.[userId || 'DEFAULT']) { | |||
| const res = await fetchAccessToken(sharedToken, userId) | |||
| accessTokenJson[sharedToken] = { | |||
| ...accessTokenJson[sharedToken], | |||
| [userId || 'DEFAULT']: res.access_token, | |||
| } | |||
| localStorage.setItem('token', JSON.stringify(accessTokenJson)) | |||
| } | |||
| } | |||
| export const setAccessToken = async (sharedToken: string, token: string) => { | |||
| const accessToken = localStorage.getItem('token') || JSON.stringify({ [sharedToken]: '' }) | |||
| let accessTokenJson = { [sharedToken]: '' } | |||
| export const setAccessToken = async (sharedToken: string, token: string, user_id?: string) => { | |||
| const accessToken = localStorage.getItem('token') || JSON.stringify(getInitialTokenV2()) | |||
| let accessTokenJson = getInitialTokenV2() | |||
| try { | |||
| accessTokenJson = JSON.parse(accessToken) | |||
| if (isTokenV1(accessTokenJson)) | |||
| accessTokenJson = getInitialTokenV2() | |||
| } | |||
| catch { | |||
| @@ -32,17 +47,22 @@ export const setAccessToken = async (sharedToken: string, token: string) => { | |||
| localStorage.removeItem(CONVERSATION_ID_INFO) | |||
| accessTokenJson[sharedToken] = token | |||
| accessTokenJson[sharedToken] = { | |||
| ...accessTokenJson[sharedToken], | |||
| [user_id || 'DEFAULT']: token, | |||
| } | |||
| localStorage.setItem('token', JSON.stringify(accessTokenJson)) | |||
| } | |||
| export const removeAccessToken = () => { | |||
| const sharedToken = globalThis.location.pathname.split('/').slice(-1)[0] | |||
| const accessToken = localStorage.getItem('token') || JSON.stringify({ [sharedToken]: '' }) | |||
| let accessTokenJson = { [sharedToken]: '' } | |||
| const accessToken = localStorage.getItem('token') || JSON.stringify(getInitialTokenV2()) | |||
| let accessTokenJson = getInitialTokenV2() | |||
| try { | |||
| accessTokenJson = JSON.parse(accessToken) | |||
| if (isTokenV1(accessTokenJson)) | |||
| accessTokenJson = getInitialTokenV2() | |||
| } | |||
| catch { | |||
| @@ -287,9 +287,9 @@ const handleStream = ( | |||
| const baseFetch = base | |||
| export const upload = (options: any, isPublicAPI?: boolean, url?: string, searchParams?: string): Promise<any> => { | |||
| export const upload = async (options: any, isPublicAPI?: boolean, url?: string, searchParams?: string): Promise<any> => { | |||
| const urlPrefix = isPublicAPI ? PUBLIC_API_PREFIX : API_PREFIX | |||
| const token = getAccessToken(isPublicAPI) | |||
| const token = await getAccessToken(isPublicAPI) | |||
| const defaultOptions = { | |||
| method: 'POST', | |||
| url: (url ? `${urlPrefix}${url}` : `${urlPrefix}/files/upload`) + (searchParams || ''), | |||
| @@ -324,7 +324,7 @@ export const upload = (options: any, isPublicAPI?: boolean, url?: string, search | |||
| }) | |||
| } | |||
| export const ssePost = ( | |||
| export const ssePost = async ( | |||
| url: string, | |||
| fetchOptions: FetchOptionType, | |||
| otherOptions: IOtherOptions, | |||
| @@ -385,7 +385,7 @@ export const ssePost = ( | |||
| if (body) | |||
| options.body = JSON.stringify(body) | |||
| const accessToken = getAccessToken(isPublicAPI) | |||
| const accessToken = await getAccessToken(isPublicAPI) | |||
| ; (options.headers as Headers).set('Authorization', `Bearer ${accessToken}`) | |||
| globalThis.fetch(urlWithPrefix, options as RequestInit) | |||
| @@ -3,6 +3,8 @@ import ky from 'ky' | |||
| import type { IOtherOptions } from './base' | |||
| import Toast from '@/app/components/base/toast' | |||
| import { API_PREFIX, MARKETPLACE_API_PREFIX, PUBLIC_API_PREFIX } from '@/config' | |||
| import { getInitialTokenV2, isTokenV1 } from '@/app/components/share/utils' | |||
| import { getProcessedSystemVariablesFromUrlParams } from '@/app/components/base/chat/utils' | |||
| const TIME_OUT = 100000 | |||
| @@ -67,44 +69,34 @@ const beforeErrorToast = (otherOptions: IOtherOptions): BeforeErrorHook => { | |||
| } | |||
| } | |||
| export const getPublicToken = () => { | |||
| let token = '' | |||
| const sharedToken = globalThis.location.pathname.split('/').slice(-1)[0] | |||
| const accessToken = localStorage.getItem('token') || JSON.stringify({ [sharedToken]: '' }) | |||
| let accessTokenJson = { [sharedToken]: '' } | |||
| try { | |||
| accessTokenJson = JSON.parse(accessToken) | |||
| } | |||
| catch { } | |||
| token = accessTokenJson[sharedToken] | |||
| return token || '' | |||
| } | |||
| export function getAccessToken(isPublicAPI?: boolean) { | |||
| export async function getAccessToken(isPublicAPI?: boolean) { | |||
| if (isPublicAPI) { | |||
| const sharedToken = globalThis.location.pathname.split('/').slice(-1)[0] | |||
| const accessToken = localStorage.getItem('token') || JSON.stringify({ [sharedToken]: '' }) | |||
| let accessTokenJson = { [sharedToken]: '' } | |||
| const userId = (await getProcessedSystemVariablesFromUrlParams()).user_id | |||
| const accessToken = localStorage.getItem('token') || JSON.stringify({ version: 2 }) | |||
| let accessTokenJson: Record<string, any> = { version: 2 } | |||
| try { | |||
| accessTokenJson = JSON.parse(accessToken) | |||
| if (isTokenV1(accessTokenJson)) | |||
| accessTokenJson = getInitialTokenV2() | |||
| } | |||
| catch { | |||
| } | |||
| return accessTokenJson[sharedToken] | |||
| return accessTokenJson[sharedToken]?.[userId || 'DEFAULT'] | |||
| } | |||
| else { | |||
| return localStorage.getItem('console_token') || '' | |||
| } | |||
| } | |||
| const beforeRequestPublicAuthorization: BeforeRequestHook = (request) => { | |||
| const token = getAccessToken(true) | |||
| const beforeRequestPublicAuthorization: BeforeRequestHook = async (request) => { | |||
| const token = await getAccessToken(true) | |||
| request.headers.set('Authorization', `Bearer ${token}`) | |||
| } | |||
| const beforeRequestAuthorization: BeforeRequestHook = (request) => { | |||
| const accessToken = getAccessToken() | |||
| const beforeRequestAuthorization: BeforeRequestHook = async (request) => { | |||
| const accessToken = await getAccessToken() | |||
| request.headers.set('Authorization', `Bearer ${accessToken}`) | |||
| } | |||