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 { showToast } from "@/app/components/ui-lib"; import Locale from "@/app/locales"; import { Path } from "@/app/constant"; import BottomIcon from "@/app/icons/bottom.svg"; import StopIcon from "@/app/icons/pause.svg"; import LoadingButtonIcon from "@/app/icons/loading.svg"; import PromptIcon from "@/app/icons/comandIcon.svg"; import MaskIcon from "@/app/icons/maskIcon.svg"; import BreakIcon from "@/app/icons/eraserIcon.svg"; import SettingsIcon from "@/app/icons/configIcon.svg"; import ImageIcon from "@/app/icons/uploadImgIcon.svg"; import AddCircleIcon from "@/app/icons/addCircle.svg"; import Popover from "@/app/components/Popover"; import ModelSelect from "./ModelSelect"; export interface Action { onClick?: () => void; text: string; isShow: boolean; render?: (key: string) => JSX.Element; icon?: JSX.Element; placement: "left" | "right"; } export function ChatActions(props: { uploadImage: () => void; setAttachImages: (images: string[]) => void; setUploading: (uploading: boolean) => void; showChatSetting: () => void; scrollToBottom: () => void; showPromptHints: () => void; hitBottom: boolean; uploading: boolean; isMobileScreen: boolean; className?: string; }) { 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 [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]); const actions: Action[] = [ { onClick: stopAll, text: Locale.Chat.InputActions.Stop, isShow: couldStop, icon: , placement: "left", }, { text: currentModel, isShow: !props.isMobileScreen, render: (key: string) => , placement: "left", }, { onClick: props.scrollToBottom, text: Locale.Chat.InputActions.ToBottom, isShow: !props.hitBottom, icon: , placement: "left", }, { onClick: props.uploadImage, text: Locale.Chat.InputActions.UploadImage, isShow: showUploadImage, icon: props.uploading ? : , placement: "left", }, // { // onClick: nextTheme, // text: Locale.Chat.InputActions.Theme[theme], // isShow: true, // icon: ( // <> // {theme === Theme.Auto ? ( // // ) : theme === Theme.Light ? ( // // ) : theme === Theme.Dark ? ( // // ) : null} // // ), // placement: "left", // }, { onClick: props.showPromptHints, text: Locale.Chat.InputActions.Prompt, isShow: true, icon: , placement: "left", }, { onClick: () => { navigate(Path.Masks); }, text: Locale.Chat.InputActions.Masks, isShow: true, icon: , placement: "left", }, { onClick: () => { chatStore.updateCurrentSession((session) => { if (session.clearContextIndex === session.messages.length) { session.clearContextIndex = undefined; } else { session.clearContextIndex = session.messages.length; session.memoryPrompt = ""; // will clear memory } }); }, text: Locale.Chat.InputActions.Clear, isShow: true, icon: , placement: "right", }, { onClick: props.showChatSetting, text: Locale.Chat.InputActions.Settings, isShow: true, icon: , placement: "right", }, ]; if (props.isMobileScreen) { const content = (
{actions .filter((v) => v.isShow && v.icon) .map((act) => { return (
{act.icon}
{act.text}
); })}
); return ( ); } const popoverClassName = `bg-chat-actions-btn-popover px-3 py-2.5 text-text-chat-actions-btn-popover text-sm-title rounded-md`; return (
{actions .filter((v) => v.placement === "left" && v.isShow) .map((act, ind) => { if (act.render) { return act.render(act.text); } return (
{act.icon}
); })}
{actions .filter((v) => v.placement === "right" && v.isShow) .map((act, ind, arr) => { return (
{act.icon}
); })}
); }