import { useNavigate } from "react-router-dom"; import { ModelType, Theme, useAppConfig } from "@/app/store/config"; import { useChatStore } from "@/app/store/chat"; import { ChatControllerPool } from "@/app/client/controller"; import { useAllModels } from "@/app/utils/hooks"; import { useEffect, useMemo, useState } from "react"; import { isVisionModel } from "@/app/utils"; import { Selector, showToast } from "@/app/components/ui-lib"; import Locale from "@/app/locales"; import { Path } from "@/app/constant"; import LightIcon from "@/app/icons/light.svg"; import DarkIcon from "@/app/icons/dark.svg"; import AutoIcon from "@/app/icons/auto.svg"; import BottomIcon from "@/app/icons/bottom.svg"; import StopIcon from "@/app/icons/pause.svg"; import RobotIcon from "@/app/icons/robot.svg"; import LoadingButtonIcon from "@/app/icons/loading.svg"; import PromptIcon from "@/app/icons/prompt.svg"; import MaskIcon from "@/app/icons/mask.svg"; import BreakIcon from "@/app/icons/break.svg"; import SettingsIcon from "@/app/icons/chat-settings.svg"; import ImageIcon from "@/app/icons/image.svg"; import ChatAction from "./ChatAction"; import styles from "./index.module.scss"; export function ChatActions(props: { uploadImage: () => void; setAttachImages: (images: string[]) => void; setUploading: (uploading: boolean) => void; showPromptModal: () => void; scrollToBottom: () => void; showPromptHints: () => void; hitBottom: boolean; uploading: boolean; }) { const config = useAppConfig(); const navigate = useNavigate(); const chatStore = useChatStore(); // switch themes const theme = config.theme; function nextTheme() { const themes = [Theme.Auto, Theme.Light, Theme.Dark]; const themeIndex = themes.indexOf(theme); const nextIndex = (themeIndex + 1) % themes.length; const nextTheme = themes[nextIndex]; config.update((config) => (config.theme = nextTheme)); } // stop all responses const couldStop = ChatControllerPool.hasPending(); const stopAll = () => ChatControllerPool.stopAll(); // switch model const currentModel = chatStore.currentSession().mask.modelConfig.model; const allModels = useAllModels(); const models = useMemo( () => allModels.filter((m) => m.available), [allModels], ); const [showModelSelector, setShowModelSelector] = useState(false); const [showUploadImage, setShowUploadImage] = useState(false); useEffect(() => { const show = isVisionModel(currentModel); setShowUploadImage(show); if (!show) { props.setAttachImages([]); props.setUploading(false); } // if current model is not available // switch to first available model const isUnavaliableModel = !models.some((m) => m.name === currentModel); if (isUnavaliableModel && models.length > 0) { const nextModel = models[0].name as ModelType; chatStore.updateCurrentSession( (session) => (session.mask.modelConfig.model = nextModel), ); showToast(nextModel); } }, [chatStore, currentModel, models]); return (
{couldStop && ( } /> )} {!props.hitBottom && ( } /> )} {props.hitBottom && ( } /> )} {showUploadImage && ( : } /> )} {theme === Theme.Auto ? ( ) : theme === Theme.Light ? ( ) : theme === Theme.Dark ? ( ) : null} } /> } /> { navigate(Path.Masks); }} text={Locale.Chat.InputActions.Masks} icon={} /> } onClick={() => { chatStore.updateCurrentSession((session) => { if (session.clearContextIndex === session.messages.length) { session.clearContextIndex = undefined; } else { session.clearContextIndex = session.messages.length; session.memoryPrompt = ""; // will clear memory } }); }} /> setShowModelSelector(true)} text={currentModel} icon={} /> {showModelSelector && ( ({ title: m.displayName, value: m.name, }))} onClose={() => setShowModelSelector(false)} onSelection={(s) => { if (s.length === 0) return; chatStore.updateCurrentSession((session) => { session.mask.modelConfig.model = s[0] as ModelType; session.mask.syncGlobalConfig = false; }); showToast(s[0]); }} /> )}
); }