chatbot-ui/components/chat/chat-hooks/use-select-file-handler.tsx

205 lines
5.5 KiB
TypeScript

import { ChatbotUIContext } from "@/context/context"
import { createDocXFile, createFile } from "@/db/files"
import { LLM_LIST } from "@/lib/models/llm/llm-list"
import mammoth from "mammoth"
import { useContext, useEffect, useState } from "react"
import { toast } from "sonner"
export const ACCEPTED_FILE_TYPES = [
"text/csv",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"application/json",
"text/markdown",
"application/pdf",
"text/plain"
].join(",")
export const useSelectFileHandler = () => {
const {
selectedWorkspace,
profile,
chatSettings,
setNewMessageImages,
setNewMessageFiles,
setShowFilesDisplay,
setFiles,
setUseRetrieval
} = useContext(ChatbotUIContext)
const [filesToAccept, setFilesToAccept] = useState(ACCEPTED_FILE_TYPES)
useEffect(() => {
handleFilesToAccept()
}, [chatSettings?.model])
const handleFilesToAccept = () => {
const model = chatSettings?.model
const FULL_MODEL = LLM_LIST.find(llm => llm.modelId === model)
if (!FULL_MODEL) return
setFilesToAccept(
FULL_MODEL.imageInput
? `${ACCEPTED_FILE_TYPES},image/*`
: ACCEPTED_FILE_TYPES
)
}
const handleSelectDeviceFile = async (file: File) => {
if (!profile || !selectedWorkspace || !chatSettings) return
setShowFilesDisplay(true)
setUseRetrieval(true)
if (file) {
let simplifiedFileType = file.type.split("/")[1]
let reader = new FileReader()
if (file.type.includes("image")) {
reader.readAsDataURL(file)
} else if (ACCEPTED_FILE_TYPES.split(",").includes(file.type)) {
if (simplifiedFileType.includes("vnd.adobe.pdf")) {
simplifiedFileType = "pdf"
} else if (
simplifiedFileType.includes(
"vnd.openxmlformats-officedocument.wordprocessingml.document" ||
"docx"
)
) {
simplifiedFileType = "docx"
}
setNewMessageFiles(prev => [
...prev,
{
id: "loading",
name: file.name,
type: simplifiedFileType,
file: file
}
])
// Handle docx files
if (
file.type.includes(
"vnd.openxmlformats-officedocument.wordprocessingml.document" ||
"docx"
)
) {
const arrayBuffer = await file.arrayBuffer()
const result = await mammoth.extractRawText({
arrayBuffer
})
const createdFile = await createDocXFile(
result.value,
file,
{
user_id: profile.user_id,
description: "",
file_path: "",
name: file.name,
size: file.size,
tokens: 0,
type: simplifiedFileType
},
selectedWorkspace.id,
chatSettings.embeddingsProvider
)
setFiles(prev => [...prev, createdFile])
setNewMessageFiles(prev =>
prev.map(item =>
item.id === "loading"
? {
id: createdFile.id,
name: createdFile.name,
type: createdFile.type,
file: file
}
: item
)
)
reader.onloadend = null
return
} else {
// Use readAsArrayBuffer for PDFs and readAsText for other types
file.type.includes("pdf")
? reader.readAsArrayBuffer(file)
: reader.readAsText(file)
}
} else {
throw new Error("Unsupported file type")
}
reader.onloadend = async function () {
try {
if (file.type.includes("image")) {
// Create a temp url for the image file
const imageUrl = URL.createObjectURL(file)
// This is a temporary image for display purposes in the chat input
setNewMessageImages(prev => [
...prev,
{
messageId: "temp",
path: "",
base64: reader.result, // base64 image
url: imageUrl,
file
}
])
} else {
const createdFile = await createFile(
file,
{
user_id: profile.user_id,
description: "",
file_path: "",
name: file.name,
size: file.size,
tokens: 0,
type: simplifiedFileType
},
selectedWorkspace.id,
chatSettings.embeddingsProvider
)
setFiles(prev => [...prev, createdFile])
setNewMessageFiles(prev =>
prev.map(item =>
item.id === "loading"
? {
id: createdFile.id,
name: createdFile.name,
type: createdFile.type,
file: file
}
: item
)
)
}
} catch (error: any) {
toast.error("Failed to upload. " + error?.message, {
duration: 10000
})
setNewMessageImages(prev =>
prev.filter(img => img.messageId !== "temp")
)
setNewMessageFiles(prev => prev.filter(file => file.id !== "loading"))
}
}
}
}
return {
handleSelectDeviceFile,
filesToAccept
}
}