/* eslint-disable @typescript-eslint/no-explicit-any */ import { useContext, useEffect, useRef, useState } from 'react' import { InferenceEvent, MessageStatus, events } from '@janhq/core' import { Textarea, Button, Tooltip, TooltipArrow, TooltipContent, TooltipPortal, TooltipTrigger, } from '@janhq/uikit' import { useAtom, useAtomValue } from 'jotai' import { FileTextIcon, ImageIcon, StopCircle, PaperclipIcon, } from 'lucide-react' import { twMerge } from 'tailwind-merge' import { currentPromptAtom, fileUploadAtom } from '@/containers/Providers/Jotai' import { FeatureToggleContext } from '@/context/FeatureToggle' import { useActiveModel } from '@/hooks/useActiveModel' import { useClickOutside } from '@/hooks/useClickOutside' import useSendChatMessage from '@/hooks/useSendChatMessage' import FileUploadPreview from '../FileUploadPreview' import ImageUploadPreview from '../ImageUploadPreview' import { getCurrentChatMessagesAtom } from '@/helpers/atoms/ChatMessage.atom' import { activeThreadAtom, getActiveThreadIdAtom, waitingToSendMessage, } from '@/helpers/atoms/Thread.atom' const ChatInput: React.FC = () => { const activeThread = useAtomValue(activeThreadAtom) const { stateModel } = useActiveModel() const messages = useAtomValue(getCurrentChatMessagesAtom) const [currentPrompt, setCurrentPrompt] = useAtom(currentPromptAtom) const { sendChatMessage } = useSendChatMessage() const activeThreadId = useAtomValue(getActiveThreadIdAtom) const [isWaitingToSend, setIsWaitingToSend] = useAtom(waitingToSendMessage) const [fileUpload, setFileUpload] = useAtom(fileUploadAtom) const textareaRef = useRef(null) const fileInputRef = useRef(null) const imageInputRef = useRef(null) const [showAttacmentMenus, setShowAttacmentMenus] = useState(false) const { experimentalFeature } = useContext(FeatureToggleContext) const onPromptChange = (e: React.ChangeEvent) => { setCurrentPrompt(e.target.value) } const refAttachmentMenus = useClickOutside(() => setShowAttacmentMenus(false)) useEffect(() => { if (isWaitingToSend && activeThreadId) { setIsWaitingToSend(false) sendChatMessage(currentPrompt) } }, [ activeThreadId, isWaitingToSend, currentPrompt, setIsWaitingToSend, sendChatMessage, ]) useEffect(() => { if (textareaRef.current) { textareaRef.current.focus() } }, [activeThreadId]) useEffect(() => { if (textareaRef.current) { textareaRef.current.style.height = '40px' textareaRef.current.style.height = textareaRef.current.scrollHeight + 'px' } }, [currentPrompt]) const onKeyDown = async (e: React.KeyboardEvent) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault() if (messages[messages.length - 1]?.status !== MessageStatus.Pending) sendChatMessage(currentPrompt) else onStopInferenceClick() } } const onStopInferenceClick = async () => { events.emit(InferenceEvent.OnInferenceStopped, {}) } /** * Handles the change event of the extension file input element by setting the file name state. * Its to be used to display the extension file name of the selected file. * @param event - The change event object. */ const handleFileChange = (event: React.ChangeEvent) => { const file = event.target.files?.[0] if (!file) return setFileUpload([{ file: file, type: 'pdf' }]) } const handleImageChange = (event: React.ChangeEvent) => { const file = event.target.files?.[0] if (!file) return setFileUpload([{ file: file, type: 'image' }]) } const renderPreview = (fileUpload: any) => { if (fileUpload.length > 0) { if (fileUpload[0].type === 'image') { return } else { return } } } return (
{renderPreview(fileUpload)}