353 lines
10 KiB
TypeScript
353 lines
10 KiB
TypeScript
// TODO: Separate into multiple contexts, keeping simple for now
|
|
|
|
"use client"
|
|
|
|
import { ChatbotUIContext } from "@/context/context"
|
|
import { usePathname } from "next/navigation"
|
|
|
|
import { getProfileByUserId } from "@/db/profile"
|
|
import { getWorkspaceImageFromStorage } from "@/db/storage/workspace-images"
|
|
import { getWorkspacesByUserId } from "@/db/workspaces"
|
|
import { convertBlobToBase64 } from "@/lib/blob-to-b64"
|
|
import {
|
|
fetchHostedModels,
|
|
fetchOllamaModels,
|
|
fetchOpenRouterModels
|
|
} from "@/lib/models/fetch-models"
|
|
import { supabase } from "@/lib/supabase/browser-client"
|
|
import { Tables } from "@/supabase/types"
|
|
import {
|
|
ChatFile,
|
|
ChatMessage,
|
|
ChatSettings,
|
|
LLM,
|
|
MessageImage,
|
|
OpenRouterLLM,
|
|
WorkspaceImage
|
|
} from "@/types"
|
|
import { AssistantImage } from "@/types/images/assistant-image"
|
|
import { VALID_ENV_KEYS } from "@/types/valid-keys"
|
|
import { useRouter } from "next/navigation"
|
|
import { FC, useEffect, useState } from "react"
|
|
|
|
import i18nConfig from "@/i18nConfig"
|
|
|
|
interface GlobalStateProps {
|
|
children: React.ReactNode
|
|
}
|
|
|
|
export const GlobalState: FC<GlobalStateProps> = ({ children }) => {
|
|
const router = useRouter()
|
|
|
|
|
|
const pathname = usePathname() // 获取当前路径
|
|
const pathSegments = pathname.split("/").filter(Boolean)
|
|
const locales = i18nConfig.locales
|
|
const defaultLocale = i18nConfig.defaultLocale
|
|
|
|
let locale: (typeof locales)[number] = defaultLocale
|
|
|
|
const segment = pathSegments[0] as (typeof locales)[number]
|
|
|
|
if (locales.includes(segment)) {
|
|
locale = segment
|
|
}
|
|
const homePath = locale === defaultLocale ? "/" : `/${locale}`
|
|
|
|
// PROFILE STORE
|
|
const [profile, setProfile] = useState<Tables<"profiles"> | null>(null)
|
|
|
|
// ITEMS STORE
|
|
const [assistants, setAssistants] = useState<Tables<"assistants">[]>([])
|
|
const [collections, setCollections] = useState<Tables<"collections">[]>([])
|
|
const [chats, setChats] = useState<Tables<"chats">[]>([])
|
|
const [files, setFiles] = useState<Tables<"files">[]>([])
|
|
const [folders, setFolders] = useState<Tables<"folders">[]>([])
|
|
const [models, setModels] = useState<Tables<"models">[]>([])
|
|
const [presets, setPresets] = useState<Tables<"presets">[]>([])
|
|
const [prompts, setPrompts] = useState<Tables<"prompts">[]>([])
|
|
const [tools, setTools] = useState<Tables<"tools">[]>([])
|
|
const [workspaces, setWorkspaces] = useState<Tables<"workspaces">[]>([])
|
|
|
|
// MODELS STORE
|
|
const [envKeyMap, setEnvKeyMap] = useState<Record<string, VALID_ENV_KEYS>>({})
|
|
const [availableHostedModels, setAvailableHostedModels] = useState<LLM[]>([])
|
|
const [availableLocalModels, setAvailableLocalModels] = useState<LLM[]>([])
|
|
const [availableOpenRouterModels, setAvailableOpenRouterModels] = useState<
|
|
OpenRouterLLM[]
|
|
>([])
|
|
|
|
// WORKSPACE STORE
|
|
const [selectedWorkspace, setSelectedWorkspace] =
|
|
useState<Tables<"workspaces"> | null>(null)
|
|
const [workspaceImages, setWorkspaceImages] = useState<WorkspaceImage[]>([])
|
|
|
|
// PRESET STORE
|
|
const [selectedPreset, setSelectedPreset] =
|
|
useState<Tables<"presets"> | null>(null)
|
|
|
|
// ASSISTANT STORE
|
|
const [selectedAssistant, setSelectedAssistant] =
|
|
useState<Tables<"assistants"> | null>(null)
|
|
const [assistantImages, setAssistantImages] = useState<AssistantImage[]>([])
|
|
const [openaiAssistants, setOpenaiAssistants] = useState<any[]>([])
|
|
|
|
// PASSIVE CHAT STORE
|
|
const [userInput, setUserInput] = useState<string>("")
|
|
const [chatMessages, setChatMessages] = useState<ChatMessage[]>([])
|
|
const [chatSettings, setChatSettings] = useState<ChatSettings>({
|
|
model: "GPT",
|
|
prompt: "You are a helpful AI assistant.",
|
|
temperature: 0.5,
|
|
contextLength: 4000,
|
|
includeProfileContext: true,
|
|
includeWorkspaceInstructions: true,
|
|
embeddingsProvider: "bge-m3"
|
|
})
|
|
const [selectedChat, setSelectedChat] = useState<Tables<"chats"> | null>(null)
|
|
const [chatFileItems, setChatFileItems] = useState<Tables<"file_items">[]>([])
|
|
|
|
// ACTIVE CHAT STORE
|
|
const [isGenerating, setIsGenerating] = useState<boolean>(false)
|
|
const [firstTokenReceived, setFirstTokenReceived] = useState<boolean>(false)
|
|
const [abortController, setAbortController] =
|
|
useState<AbortController | null>(null)
|
|
|
|
// CHAT INPUT COMMAND STORE
|
|
const [isPromptPickerOpen, setIsPromptPickerOpen] = useState(false)
|
|
const [slashCommand, setSlashCommand] = useState("")
|
|
const [isFilePickerOpen, setIsFilePickerOpen] = useState(false)
|
|
const [hashtagCommand, setHashtagCommand] = useState("")
|
|
const [isToolPickerOpen, setIsToolPickerOpen] = useState(false)
|
|
const [toolCommand, setToolCommand] = useState("")
|
|
const [focusPrompt, setFocusPrompt] = useState(false)
|
|
const [focusFile, setFocusFile] = useState(false)
|
|
const [focusTool, setFocusTool] = useState(false)
|
|
const [focusAssistant, setFocusAssistant] = useState(false)
|
|
const [atCommand, setAtCommand] = useState("")
|
|
const [isAssistantPickerOpen, setIsAssistantPickerOpen] = useState(false)
|
|
|
|
// ATTACHMENTS STORE
|
|
const [chatFiles, setChatFiles] = useState<ChatFile[]>([])
|
|
const [chatImages, setChatImages] = useState<MessageImage[]>([])
|
|
const [newMessageFiles, setNewMessageFiles] = useState<ChatFile[]>([])
|
|
const [newMessageImages, setNewMessageImages] = useState<MessageImage[]>([])
|
|
const [showFilesDisplay, setShowFilesDisplay] = useState<boolean>(false)
|
|
|
|
// RETIEVAL STORE
|
|
const [useRetrieval, setUseRetrieval] = useState<boolean>(true)
|
|
const [sourceCount, setSourceCount] = useState<number>(4)
|
|
|
|
// TOOL STORE
|
|
const [selectedTools, setSelectedTools] = useState<Tables<"tools">[]>([])
|
|
const [toolInUse, setToolInUse] = useState<string>("none")
|
|
|
|
useEffect(() => {
|
|
;(async () => {
|
|
const profile = await fetchStartingData()
|
|
|
|
if (profile) {
|
|
const hostedModelRes = await fetchHostedModels(profile)
|
|
if (!hostedModelRes) return
|
|
|
|
setEnvKeyMap(hostedModelRes.envKeyMap)
|
|
setAvailableHostedModels(hostedModelRes.hostedModels)
|
|
|
|
if (
|
|
profile["openrouter_api_key"] ||
|
|
hostedModelRes.envKeyMap["openrouter"]
|
|
) {
|
|
const openRouterModels = await fetchOpenRouterModels()
|
|
if (!openRouterModels) return
|
|
setAvailableOpenRouterModels(openRouterModels)
|
|
}
|
|
}
|
|
|
|
if (process.env.NEXT_PUBLIC_OLLAMA_URL) {
|
|
const localModels = await fetchOllamaModels()
|
|
if (!localModels) return
|
|
setAvailableLocalModels(localModels)
|
|
}
|
|
})()
|
|
}, [])
|
|
|
|
const fetchStartingData = async () => {
|
|
const session = (await supabase.auth.getSession()).data.session
|
|
|
|
if (session) {
|
|
const user = session.user
|
|
|
|
const profile = await getProfileByUserId(user.id)
|
|
setProfile(profile)
|
|
|
|
if (profile !== null && profile !== undefined && !profile.has_onboarded) {
|
|
const homePath = locale === defaultLocale ? "" : `/${locale}`
|
|
const targetPath = `${homePath}/setup`.replace(/\/\//g, '/')
|
|
router.push(targetPath)
|
|
}
|
|
|
|
const workspaces = await getWorkspacesByUserId(user.id)
|
|
setWorkspaces(workspaces)
|
|
|
|
for (const workspace of workspaces) {
|
|
let workspaceImageUrl = ""
|
|
|
|
if (workspace.image_path) {
|
|
workspaceImageUrl =
|
|
(await getWorkspaceImageFromStorage(workspace.image_path)) || ""
|
|
}
|
|
|
|
if (workspaceImageUrl) {
|
|
const response = await fetch(workspaceImageUrl)
|
|
const blob = await response.blob()
|
|
const base64 = await convertBlobToBase64(blob)
|
|
|
|
setWorkspaceImages(prev => [
|
|
...prev,
|
|
{
|
|
workspaceId: workspace.id,
|
|
path: workspace.image_path,
|
|
base64: base64,
|
|
url: workspaceImageUrl
|
|
}
|
|
])
|
|
}
|
|
}
|
|
|
|
return profile
|
|
}
|
|
}
|
|
|
|
return (
|
|
<ChatbotUIContext.Provider
|
|
value={{
|
|
// PROFILE STORE
|
|
profile,
|
|
setProfile,
|
|
|
|
// ITEMS STORE
|
|
assistants,
|
|
setAssistants,
|
|
collections,
|
|
setCollections,
|
|
chats,
|
|
setChats,
|
|
files,
|
|
setFiles,
|
|
folders,
|
|
setFolders,
|
|
models,
|
|
setModels,
|
|
presets,
|
|
setPresets,
|
|
prompts,
|
|
setPrompts,
|
|
tools,
|
|
setTools,
|
|
workspaces,
|
|
setWorkspaces,
|
|
|
|
// MODELS STORE
|
|
envKeyMap,
|
|
setEnvKeyMap,
|
|
availableHostedModels,
|
|
setAvailableHostedModels,
|
|
availableLocalModels,
|
|
setAvailableLocalModels,
|
|
availableOpenRouterModels,
|
|
setAvailableOpenRouterModels,
|
|
|
|
// WORKSPACE STORE
|
|
selectedWorkspace,
|
|
setSelectedWorkspace,
|
|
workspaceImages,
|
|
setWorkspaceImages,
|
|
|
|
// PRESET STORE
|
|
selectedPreset,
|
|
setSelectedPreset,
|
|
|
|
// ASSISTANT STORE
|
|
selectedAssistant,
|
|
setSelectedAssistant,
|
|
assistantImages,
|
|
setAssistantImages,
|
|
openaiAssistants,
|
|
setOpenaiAssistants,
|
|
|
|
// PASSIVE CHAT STORE
|
|
userInput,
|
|
setUserInput,
|
|
chatMessages,
|
|
setChatMessages,
|
|
chatSettings,
|
|
setChatSettings,
|
|
selectedChat,
|
|
setSelectedChat,
|
|
chatFileItems,
|
|
setChatFileItems,
|
|
|
|
// ACTIVE CHAT STORE
|
|
isGenerating,
|
|
setIsGenerating,
|
|
firstTokenReceived,
|
|
setFirstTokenReceived,
|
|
abortController,
|
|
setAbortController,
|
|
|
|
// CHAT INPUT COMMAND STORE
|
|
isPromptPickerOpen,
|
|
setIsPromptPickerOpen,
|
|
slashCommand,
|
|
setSlashCommand,
|
|
isFilePickerOpen,
|
|
setIsFilePickerOpen,
|
|
hashtagCommand,
|
|
setHashtagCommand,
|
|
isToolPickerOpen,
|
|
setIsToolPickerOpen,
|
|
toolCommand,
|
|
setToolCommand,
|
|
focusPrompt,
|
|
setFocusPrompt,
|
|
focusFile,
|
|
setFocusFile,
|
|
focusTool,
|
|
setFocusTool,
|
|
focusAssistant,
|
|
setFocusAssistant,
|
|
atCommand,
|
|
setAtCommand,
|
|
isAssistantPickerOpen,
|
|
setIsAssistantPickerOpen,
|
|
|
|
// ATTACHMENT STORE
|
|
chatFiles,
|
|
setChatFiles,
|
|
chatImages,
|
|
setChatImages,
|
|
newMessageFiles,
|
|
setNewMessageFiles,
|
|
newMessageImages,
|
|
setNewMessageImages,
|
|
showFilesDisplay,
|
|
setShowFilesDisplay,
|
|
|
|
// RETRIEVAL STORE
|
|
useRetrieval,
|
|
setUseRetrieval,
|
|
sourceCount,
|
|
setSourceCount,
|
|
|
|
// TOOL STORE
|
|
selectedTools,
|
|
setSelectedTools,
|
|
toolInUse,
|
|
setToolInUse
|
|
}}
|
|
>
|
|
{children}
|
|
</ChatbotUIContext.Provider>
|
|
)
|
|
}
|