diff --git a/src/components/Settings.tsx b/src/components/Settings.tsx new file mode 100644 index 0000000..5dd8a92 --- /dev/null +++ b/src/components/Settings.tsx @@ -0,0 +1,13 @@ +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { + Sheet, + SheetClose, + SheetContent, + SheetDescription, + SheetFooter, + SheetHeader, + SheetTitle, + SheetTrigger, +} from "@/components/ui/sheet"; diff --git a/src/main.tsx b/src/main.tsx index 7c3522c..1cd9d59 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -4,6 +4,7 @@ import { useState, useEffect } from "preact/hooks"; import { App } from "@/pages/App"; import { Tr, langCodeContext, LANG_OPTIONS } from "@/translate"; import { SidebarProvider } from "@/components/ui/sidebar"; +import { Toaster } from "@/components/ui/toaster"; function Base() { const [langCode, _setLangCode] = useState("en-US"); @@ -49,6 +50,7 @@ function Base() { + ); diff --git a/src/pages/App.tsx b/src/pages/App.tsx index 4356ebc..7ce3b37 100644 --- a/src/pages/App.tsx +++ b/src/pages/App.tsx @@ -12,10 +12,42 @@ import { newChatStore } from "@/types/newChatstore"; import { STORAGE_NAME, STORAGE_NAME_SELECTED } from "@/const"; import { upgrade } from "@/indexedDB/upgrade"; +import { + Sidebar, + SidebarContent, + SidebarFooter, + SidebarGroup, + SidebarGroupContent, + SidebarGroupLabel, + SidebarHeader, + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + SidebarRail, + SidebarInset, + SidebarTrigger, +} from "@/components/ui/sidebar"; +import { Button } from "@/components/ui/button"; + +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from "@/components/ui/alert-dialog"; + +import { useToast } from "@/hooks/use-toast"; +import { Separator } from "@/components/ui/separator"; + export function App() { // init selected index const [selectedChatIndex, setSelectedChatIndex] = useState( - parseInt(localStorage.getItem(STORAGE_NAME_SELECTED) ?? "1"), + parseInt(localStorage.getItem(STORAGE_NAME_SELECTED) ?? "1") ); console.log("selectedChatIndex", selectedChatIndex); useEffect(() => { @@ -27,6 +59,8 @@ export function App() { upgrade, }); + const { toast } = useToast(); + const getChatStoreByIndex = async (index: number): Promise => { const ret: ChatStore = await (await db).get(STORAGE_NAME, index); if (ret === null || ret === undefined) return newChatStore({}); @@ -54,7 +88,7 @@ export function App() { const max = chatStore.maxTokens - chatStore.tokenMargin; let sum = 0; chatStore.postBeginIndex = chatStore.history.filter( - ({ hide }) => !hide, + ({ hide }) => !hide ).length; for (const msg of chatStore.history .filter(({ hide }) => !hide) @@ -69,7 +103,7 @@ export function App() { // manually estimate token chatStore.totalTokens = calculate_token_length( - chatStore.systemMessageContent, + chatStore.systemMessageContent ); for (const msg of chatStore.history .filter(({ hide }) => !hide) @@ -82,7 +116,7 @@ export function App() { // update total tokens chatStore.totalTokens = calculate_token_length( - chatStore.systemMessageContent, + chatStore.systemMessageContent ); for (const msg of chatStore.history .filter(({ hide }) => !hide) @@ -101,7 +135,7 @@ export function App() { // all chat store indexes const [allChatStoreIndexes, setAllChatStoreIndexes] = useState( - [], + [] ); const handleNewChatStoreWithOldOne = async (chatStore: ChatStore) => { @@ -114,7 +148,6 @@ export function App() { }; const handleDEL = async () => { - if (!confirm("Are you sure you want to delete this chat history?")) return; console.log("remove item", `${STORAGE_NAME}-${selectedChatIndex}`); (await db).delete(STORAGE_NAME, selectedChatIndex); const newAllChatStoreIndexes = await (await db).getAllKeys(STORAGE_NAME); @@ -129,6 +162,11 @@ export function App() { console.log("next is", next); setSelectedChatIndex(next as number); setAllChatStoreIndexes(newAllChatStoreIndexes); + + toast({ + title: "Chat history deleted", + description: `Chat history ${selectedChatIndex} has been deleted.`, + }); }; const handleCLS = async () => { @@ -176,60 +214,87 @@ export function App() { }, []); return ( -
-
-
- -
    - {(allChatStoreIndexes as number[]) - .slice() - .reverse() - .map((i) => { - // reverse - return ( -
  • - -
  • - ); - })} -
-
-
- + <> + + + + + + + Conversation + + + {(allChatStoreIndexes as number[]) + .slice() + .reverse() + .map((i) => { + // reverse + return ( + setSelectedChatIndex(i)} + > + + {i} + + + ); + })} + + + + + + + + + + + + Are you absolutely sure? + + This action cannot be undone. This will permanently delete the + chat history. + + + + Cancel + + Delete + + + + + {chatStore.develop_mode && ( - + )} -
-
- -
+ + + + +
+
+ + +

MikuChat

+
+
+ +
+ ); } diff --git a/src/pages/Chatbox.tsx b/src/pages/Chatbox.tsx index fe34fa7..1bb3390 100644 --- a/src/pages/Chatbox.tsx +++ b/src/pages/Chatbox.tsx @@ -131,7 +131,7 @@ export default function ChatBOX(props: { // update tool call arguments const tool = allChunkTool.find( - (tool) => tool.index === tool_call.index, + (tool) => tool.index === tool_call.index ); if (!tool) { @@ -146,7 +146,7 @@ export default function ChatBOX(props: { allChunkMessage.join("") + allChunkTool.map((tool) => { return `Tool Call ID: ${tool.id}\nType: ${tool.type}\nFunction: ${tool.function.name}\nArguments: ${tool.function.arguments}`; - }), + }) ); } setShowGenerating(false); @@ -295,7 +295,7 @@ export default function ChatBOX(props: { setShowGenerating(true); const response = await client._fetch( chatStore.streamMode, - chatStore.logprobs, + chatStore.logprobs ); const contentType = response.headers.get("content-type"); if (contentType?.startsWith("text/event-stream")) { @@ -365,33 +365,33 @@ export default function ChatBOX(props: { const [templates, _setTemplates] = useState( JSON.parse( - localStorage.getItem(STORAGE_NAME_TEMPLATE) || "[]", - ) as TemplateChatStore[], + localStorage.getItem(STORAGE_NAME_TEMPLATE) || "[]" + ) as TemplateChatStore[] ); const [templateAPIs, _setTemplateAPIs] = useState( JSON.parse( - localStorage.getItem(STORAGE_NAME_TEMPLATE_API) || "[]", - ) as TemplateAPI[], + localStorage.getItem(STORAGE_NAME_TEMPLATE_API) || "[]" + ) as TemplateAPI[] ); const [templateAPIsWhisper, _setTemplateAPIsWhisper] = useState( JSON.parse( - localStorage.getItem(STORAGE_NAME_TEMPLATE_API_WHISPER) || "[]", - ) as TemplateAPI[], + localStorage.getItem(STORAGE_NAME_TEMPLATE_API_WHISPER) || "[]" + ) as TemplateAPI[] ); const [templateAPIsTTS, _setTemplateAPIsTTS] = useState( JSON.parse( - localStorage.getItem(STORAGE_NAME_TEMPLATE_API_TTS) || "[]", - ) as TemplateAPI[], + localStorage.getItem(STORAGE_NAME_TEMPLATE_API_TTS) || "[]" + ) as TemplateAPI[] ); const [templateAPIsImageGen, _setTemplateAPIsImageGen] = useState( JSON.parse( - localStorage.getItem(STORAGE_NAME_TEMPLATE_API_IMAGE_GEN) || "[]", - ) as TemplateAPI[], + localStorage.getItem(STORAGE_NAME_TEMPLATE_API_IMAGE_GEN) || "[]" + ) as TemplateAPI[] ); const [toolsTemplates, _setToolsTemplates] = useState( JSON.parse( - localStorage.getItem(STORAGE_NAME_TEMPLATE_TOOLS) || "[]", - ) as TemplateTools[], + localStorage.getItem(STORAGE_NAME_TEMPLATE_TOOLS) || "[]" + ) as TemplateTools[] ); const setTemplates = (templates: TemplateChatStore[]) => { localStorage.setItem(STORAGE_NAME_TEMPLATE, JSON.stringify(templates)); @@ -400,35 +400,35 @@ export default function ChatBOX(props: { const setTemplateAPIs = (templateAPIs: TemplateAPI[]) => { localStorage.setItem( STORAGE_NAME_TEMPLATE_API, - JSON.stringify(templateAPIs), + JSON.stringify(templateAPIs) ); _setTemplateAPIs(templateAPIs); }; const setTemplateAPIsWhisper = (templateAPIWhisper: TemplateAPI[]) => { localStorage.setItem( STORAGE_NAME_TEMPLATE_API_WHISPER, - JSON.stringify(templateAPIWhisper), + JSON.stringify(templateAPIWhisper) ); _setTemplateAPIsWhisper(templateAPIWhisper); }; const setTemplateAPIsTTS = (templateAPITTS: TemplateAPI[]) => { localStorage.setItem( STORAGE_NAME_TEMPLATE_API_TTS, - JSON.stringify(templateAPITTS), + JSON.stringify(templateAPITTS) ); _setTemplateAPIsTTS(templateAPITTS); }; const setTemplateAPIsImageGen = (templateAPIImageGen: TemplateAPI[]) => { localStorage.setItem( STORAGE_NAME_TEMPLATE_API_IMAGE_GEN, - JSON.stringify(templateAPIImageGen), + JSON.stringify(templateAPIImageGen) ); _setTemplateAPIsImageGen(templateAPIImageGen); }; const setTemplateTools = (templateTools: TemplateTools[]) => { localStorage.setItem( STORAGE_NAME_TEMPLATE_TOOLS, - JSON.stringify(templateTools), + JSON.stringify(templateTools) ); _setToolsTemplates(templateTools); }; @@ -574,7 +574,7 @@ export default function ChatBOX(props: {
↖{Tr("Click the conor to create a new chat")}
⚠ {Tr( - "All chat history and settings are stored in the local browser", + "All chat history and settings are stored in the local browser" )}

diff --git a/src/setAPIsTemplate.tsx b/src/setAPIsTemplate.tsx index c3a3319..0bb2936 100644 --- a/src/setAPIsTemplate.tsx +++ b/src/setAPIsTemplate.tsx @@ -1,5 +1,6 @@ import { TemplateAPI } from "@/types/chatstore"; import { Tr } from "@/translate"; +import { Button } from "./components/ui/button"; interface Props { tmps: TemplateAPI[]; @@ -16,8 +17,10 @@ export function SetAPIsTemplate({ label, }: Props) { return ( - + ); } diff --git a/src/settings.tsx b/src/settings.tsx index 9b92712..8b0a1d6 100644 --- a/src/settings.tsx +++ b/src/settings.tsx @@ -1,17 +1,4 @@ import { themeChange } from "theme-change"; -import { - InformationCircleIcon, - CheckIcon, - NoSymbolIcon, - CogIcon, - KeyIcon, - EyeIcon, - EllipsisHorizontalCircleIcon, - HandRaisedIcon, - AdjustmentsHorizontalIcon, - Cog6ToothIcon, - ListBulletIcon, -} from "@heroicons/react/24/outline"; import { createRef } from "preact"; import { @@ -35,6 +22,64 @@ import { SetAPIsTemplate } from "@/setAPIsTemplate"; import { autoHeight } from "@/textarea"; import { getDefaultParams } from "@/utils/getDefaultParam"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { + Sheet, + SheetClose, + SheetContent, + SheetDescription, + SheetFooter, + SheetHeader, + SheetTitle, + SheetTrigger, +} from "@/components/ui/sheet"; +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from "@/components/ui/accordion"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import { Checkbox } from "@/components/ui/checkbox"; +import { Textarea } from "@/components/ui/textarea"; +import { + BanIcon, + CheckIcon, + CircleEllipsisIcon, + CogIcon, + Ellipsis, + EyeIcon, + InfoIcon, + KeyIcon, + ListIcon, + MoveHorizontalIcon, +} from "lucide-react"; +import { Separator } from "./components/ui/separator"; +import { Slider } from "./components/ui/slider"; + const TTS_VOICES: string[] = [ "alloy", "echo", @@ -66,65 +111,68 @@ const SelectModel = (props: { } const [useCustomModel, setUseCustomModel] = useState(shouldIUseCustomModel); return ( - -
- - +
+
+
- + +
+ + setUseCustomModel(!useCustomModel)} /> - ) : ( - - )} - -
- +
+
+ + {useCustomModel ? ( + ) => { + props.chatStore.model = e.target.value; + props.setChatStore({ ...props.chatStore }); + }} + /> + ) : ( + + )} +
); }; @@ -136,21 +184,26 @@ const LongInput = (props: { help: string; }) => { return ( - + /> + ); }; -const Input = (props: { +const InputField = (props: { chatStore: ChatStore; setChatStore: (cs: ChatStore) => void; field: @@ -181,49 +234,49 @@ const Input = (props: { }) => { const [hideInput, setHideInput] = useState(true); return ( - -
- {props.field} - - - -
-