From a63502ae2bf316dd238fff25ad86dd8a3fbe8bd7 Mon Sep 17 00:00:00 2001 From: ecwu Date: Tue, 31 Dec 2024 14:40:33 +0800 Subject: [PATCH 01/30] remove typo text from scroll area components --- src/components/ui/scroll-area.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/ui/scroll-area.tsx b/src/components/ui/scroll-area.tsx index b241efe..37836af 100644 --- a/src/components/ui/scroll-area.tsx +++ b/src/components/ui/scroll-area.tsx @@ -12,7 +12,6 @@ const NonOverflowScrollArea = React.forwardRef< className={cn("relative", className)} {...props} > - aaa {children} @@ -30,7 +29,6 @@ const ScrollArea = React.forwardRef< className={cn("relative overflow-hidden", className)} {...props} > - aaa {children} From 6fe10122707cdbb789f45b75bace7caec71ccb85 Mon Sep 17 00:00:00 2001 From: ecwu Date: Fri, 3 Jan 2025 00:33:02 +0800 Subject: [PATCH 02/30] add Navbar component and integrate into App layout --- src/components/navbar.tsx | 133 ++++++++++++++++++++++++++++++++++ src/pages/App.tsx | 147 +++++++------------------------------- 2 files changed, 159 insertions(+), 121 deletions(-) create mode 100644 src/components/navbar.tsx diff --git a/src/components/navbar.tsx b/src/components/navbar.tsx new file mode 100644 index 0000000..1229a1c --- /dev/null +++ b/src/components/navbar.tsx @@ -0,0 +1,133 @@ +import React from "react"; +import { Badge } from "./ui/badge"; +import { + Menubar, + MenubarContent, + MenubarItem, + MenubarMenu, + MenubarSeparator, + MenubarTrigger, + MenubarCheckboxItem, +} from "@/components/ui/menubar"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; +import { ModeToggle } from "@/components/mode-toggle"; +import { SidebarTrigger } from "@/components/ui/sidebar"; +import { Separator } from "@/components/ui/separator"; +import { + EllipsisIcon, + WholeWordIcon, + CircleDollarSignIcon, + RulerIcon, + ReceiptIcon, + WalletIcon, + ArrowUpDownIcon, + ScissorsIcon, +} from "lucide-react"; +import { AppContext } from "@/pages/App"; +import { models } from "@/types/models"; +import { getTotalCost } from "@/utils/totalCost"; +import { Tr } from "@/translate"; + +import { useContext } from "react"; + +const Navbar: React.FC = () => { + const ctx = useContext(AppContext); + if (!ctx) return
error
; + const { chatStore, setChatStore } = ctx; + + return ( +
+
+ + +

{chatStore.model}

+
+
+
+ + {chatStore.totalTokens.toString()} + + + + + + +

+ Tokens: {chatStore.totalTokens}/{chatStore.maxTokens} +

+

+ Cut(s): {chatStore.postBeginIndex}/ + {chatStore.history.filter(({ hide }) => !hide).length} +

+

+ Cost: ${chatStore.cost?.toFixed(4)} / $ + {getTotalCost().toFixed(2)} +

+
+
+
+
+ + + + {" "} + {chatStore.totalTokens} + + {chatStore.cost?.toFixed(4)} + + + + + Max Length: {chatStore.maxTokens} + + + + Price:{" "} + {models[chatStore.model]?.price?.prompt * 1000 * 1000}$ / + 1M input tokens + + + + Total: {getTotalCost().toFixed(2)}$ + + + + {chatStore.streamMode ? ( + <> + {Tr("STREAM")}· + {Tr("FETCH")} + + ) : ( + <> + {Tr("STREAM")}· + {Tr("FETCH")} + + )} + + + + {chatStore.postBeginIndex} / {chatStore.history.length} + + + Switch to Model (TODO): + gpt-4o + gpt-o1 + gpt-o1-mini + gpt-o3 + + + +
+
+ +
+
+
+ ); +}; + +export default Navbar; diff --git a/src/pages/App.tsx b/src/pages/App.tsx index dc0f33f..c1a0c90 100644 --- a/src/pages/App.tsx +++ b/src/pages/App.tsx @@ -115,6 +115,8 @@ import { import { Badge } from "@/components/ui/badge"; import { ModeToggle } from "@/components/mode-toggle"; +import Navbar from "@/components/navbar"; + export function App() { // init selected index const [selectedChatIndex, setSelectedChatIndex] = useState( @@ -356,7 +358,27 @@ export function App() { console.log("[PERFORMANCE!] reading localStorage"); return ( - <> + - - {showSearch && } - {!chatStore.apiKey && ( diff --git a/src/search.tsx b/src/search.tsx index 9759b71..891fe0e 100644 --- a/src/search.tsx +++ b/src/search.tsx @@ -25,6 +25,8 @@ import { import { Input } from "./components/ui/input"; import { AppContext } from "./pages/App"; +import { Button } from "./components/ui/button"; +import { SearchIcon } from "lucide-react"; interface ChatStoreSearchResult { key: IDBValidKey; @@ -33,10 +35,7 @@ interface ChatStoreSearchResult { preview: string; } -export default function Search(props: { - show: boolean; - setShow: (show: boolean) => void; -}) { +export default function Search() { const ctx = useContext(AppContext); if (ctx === null) return <>; const { setSelectedChatIndex, db } = ctx; @@ -46,9 +45,15 @@ export default function Search(props: { const [searchingNow, setSearchingNow] = useState(0); const [pageIndex, setPageIndex] = useState(0); const searchAbortRef = useRef(null); + const [open, setOpen] = useState(false); return ( - + + + + Search @@ -160,7 +165,7 @@ export default function Search(props: { key={result.key as number} onClick={() => { setSelectedChatIndex(parseInt(result.key.toString())); - props.setShow(false); + setOpen(false); }} >
From 45d405adf3992325ce18eb2942f6539f88decde0 Mon Sep 17 00:00:00 2001 From: ecwu Date: Fri, 3 Jan 2025 01:19:50 +0800 Subject: [PATCH 04/30] refactor: remove settings visibility logic and add TODO for future implementation --- src/pages/Chatbox.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/Chatbox.tsx b/src/pages/Chatbox.tsx index e7b5353..07a3c91 100644 --- a/src/pages/Chatbox.tsx +++ b/src/pages/Chatbox.tsx @@ -423,7 +423,6 @@ export default function ChatBOX() { } }; - const [showSettings, setShowSettings] = useState(false); const userInputRef = useRef(null); return ( @@ -537,7 +536,8 @@ export default function ChatBOX() {
System Prompt
setShowSettings(true)} + // onClick={() => setShowSettings(true)} + // TODO: add a button to show settings > {chatStore.systemMessageContent}
@@ -547,7 +547,7 @@ export default function ChatBOX() { } - onClick={() => setShowSettings(true)} + // TODO: add a button to show settings /> From c421792b9f25f82b474eef184118244c878e9b16 Mon Sep 17 00:00:00 2001 From: ecwu Date: Fri, 3 Jan 2025 01:35:45 +0800 Subject: [PATCH 05/30] feat: add alert icon in Settings button for missing API key or endpoint --- src/components/Settings.tsx | 4 ++++ src/pages/Chatbox.tsx | 18 ------------------ 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/src/components/Settings.tsx b/src/components/Settings.tsx index 531f0fa..d1c7bd8 100644 --- a/src/components/Settings.tsx +++ b/src/components/Settings.tsx @@ -73,6 +73,7 @@ import { KeyIcon, ListIcon, MoveHorizontalIcon, + TriangleAlertIcon, } from "lucide-react"; import { Separator } from "@/components/ui/separator"; import { Slider } from "@/components/ui/slider"; @@ -519,6 +520,9 @@ export default (props: {}) => { diff --git a/src/pages/Chatbox.tsx b/src/pages/Chatbox.tsx index 07a3c91..dad1ea9 100644 --- a/src/pages/Chatbox.tsx +++ b/src/pages/Chatbox.tsx @@ -428,24 +428,6 @@ export default function ChatBOX() { return ( <>
- {!chatStore.apiKey && ( - - - Heads up! - - {Tr("Please click above to set")} (OpenAI) API KEY - - - )} - {!chatStore.apiEndpoint && ( - - - Heads up! - - {Tr("Please click above to set")} API Endpoint - - - )} {ctx.templateAPIs.length > 0 && ( From 3060543ee7a7a3456c3d6db00c97b02516fda89a Mon Sep 17 00:00:00 2001 From: ecwu Date: Fri, 3 Jan 2025 01:43:40 +0800 Subject: [PATCH 06/30] refactor: rename and reorganize Search component imports for better structure --- src/{search.tsx => components/Search.tsx} | 11 ++++------- src/components/navbar.tsx | 7 ++----- src/pages/Chatbox.tsx | 2 -- 3 files changed, 6 insertions(+), 14 deletions(-) rename src/{search.tsx => components/Search.tsx} (96%) diff --git a/src/search.tsx b/src/components/Search.tsx similarity index 96% rename from src/search.tsx rename to src/components/Search.tsx index 891fe0e..0469040 100644 --- a/src/search.tsx +++ b/src/components/Search.tsx @@ -1,8 +1,7 @@ -import { IDBPDatabase } from "idb"; import { useRef, useState, Dispatch, useContext } from "react"; import { ChatStore } from "@/types/chatstore"; -import { MessageDetail } from "./chatgpt"; +import { MessageDetail } from "../chatgpt"; import { Dialog, @@ -16,16 +15,14 @@ import { import { Pagination, PaginationContent, - PaginationEllipsis, PaginationItem, - PaginationLink, PaginationNext, PaginationPrevious, } from "@/components/ui/pagination"; -import { Input } from "./components/ui/input"; -import { AppContext } from "./pages/App"; -import { Button } from "./components/ui/button"; +import { Input } from "./ui/input"; +import { AppContext } from "../pages/App"; +import { Button } from "./ui/button"; import { SearchIcon } from "lucide-react"; interface ChatStoreSearchResult { diff --git a/src/components/navbar.tsx b/src/components/navbar.tsx index 93fc4af..e12857f 100644 --- a/src/components/navbar.tsx +++ b/src/components/navbar.tsx @@ -26,8 +26,6 @@ import { WalletIcon, ArrowUpDownIcon, ScissorsIcon, - SearchIcon, - CogIcon, } from "lucide-react"; import { AppContext } from "@/pages/App"; import { models } from "@/types/models"; @@ -35,9 +33,8 @@ import { getTotalCost } from "@/utils/totalCost"; import { Tr } from "@/translate"; import { useContext } from "react"; -import { Button } from "./ui/button"; -import Search from "@/search"; -import Settings from "./Settings"; +import Search from "@/components/Search"; +import Settings from "@/components/Settings"; const Navbar: React.FC = () => { const ctx = useContext(AppContext); diff --git a/src/pages/Chatbox.tsx b/src/pages/Chatbox.tsx index dad1ea9..c7c0b8b 100644 --- a/src/pages/Chatbox.tsx +++ b/src/pages/Chatbox.tsx @@ -21,12 +21,10 @@ import { } from "../types/chatstore"; import Message from "@/message"; import { models } from "@/types/models"; -import Settings from "@/components/Settings"; import { AddImage } from "@/addImage"; import { ListAPIs } from "@/listAPIs"; import { ListToolsTempaltes } from "@/listToolsTemplates"; import { autoHeight } from "@/textarea"; -import Search from "@/search"; import Templates from "@/components/Templates"; import VersionHint from "@/components/VersionHint"; import StatusBar from "@/components/StatusBar"; From 3728766d7f3f5527b8a42fe54f8da9870f367bec Mon Sep 17 00:00:00 2001 From: ecwu Date: Fri, 3 Jan 2025 11:30:12 +0800 Subject: [PATCH 07/30] refactor: rename components and update import paths for consistency --- .../{mode-toggle.tsx => ModeToggle.tsx} | 2 +- src/components/Search.tsx | 2 +- src/components/Settings.tsx | 2 +- src/components/StatusBar.tsx | 204 ------------------ .../{theme-provider.tsx => ThemeProvider.tsx} | 0 src/components/WhisperButton.tsx | 8 +- src/components/navbar.tsx | 2 +- src/main.tsx | 2 +- src/message.tsx | 1 - src/pages/App.tsx | 2 +- src/pages/Chatbox.tsx | 3 +- src/{textarea.tsx => utils/textAreaHelp.tsx} | 0 12 files changed, 8 insertions(+), 220 deletions(-) rename src/components/{mode-toggle.tsx => ModeToggle.tsx} (95%) delete mode 100644 src/components/StatusBar.tsx rename src/components/{theme-provider.tsx => ThemeProvider.tsx} (100%) rename src/{textarea.tsx => utils/textAreaHelp.tsx} (100%) diff --git a/src/components/mode-toggle.tsx b/src/components/ModeToggle.tsx similarity index 95% rename from src/components/mode-toggle.tsx rename to src/components/ModeToggle.tsx index 6490f27..8a925d1 100644 --- a/src/components/mode-toggle.tsx +++ b/src/components/ModeToggle.tsx @@ -7,7 +7,7 @@ import { DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; -import { useTheme } from "@/components/theme-provider"; +import { useTheme } from "@/components/ThemeProvider"; export function ModeToggle() { const { setTheme } = useTheme(); diff --git a/src/components/Search.tsx b/src/components/Search.tsx index 0469040..bbe0b3e 100644 --- a/src/components/Search.tsx +++ b/src/components/Search.tsx @@ -46,7 +46,7 @@ export default function Search() { return ( - + diff --git a/src/components/Settings.tsx b/src/components/Settings.tsx index d1c7bd8..a4387b0 100644 --- a/src/components/Settings.tsx +++ b/src/components/Settings.tsx @@ -13,7 +13,7 @@ import { models } from "@/types/models"; import { tr, Tr, langCodeContext, LANG_OPTIONS } from "@/translate"; import { isVailedJSON } from "@/message"; import { SetAPIsTemplate } from "@/setAPIsTemplate"; -import { autoHeight } from "@/textarea"; +import { autoHeight } from "@/utils/textAreaHelp"; import { getDefaultParams } from "@/utils/getDefaultParam"; import { Button } from "@/components/ui/button"; diff --git a/src/components/StatusBar.tsx b/src/components/StatusBar.tsx deleted file mode 100644 index f7ab2b1..0000000 --- a/src/components/StatusBar.tsx +++ /dev/null @@ -1,204 +0,0 @@ -import { - CubeIcon, - BanknotesIcon, - ChatBubbleLeftEllipsisIcon, - ScissorsIcon, - SwatchIcon, - SparklesIcon, -} from "@heroicons/react/24/outline"; - -import { ChatStore } from "@/types/chatstore"; -import { models } from "@/types/models"; -import { Tr } from "@/translate"; -import { getTotalCost } from "@/utils/totalCost"; - -const StatusBar = (props: { - chatStore: ChatStore; - setShowSettings: (show: boolean) => void; - setShowSearch: (show: boolean) => void; -}) => { - const { chatStore, setShowSettings, setShowSearch } = props; - return ( -
-
-
-
- - - -
-
    -
  • -

    - - Tokens: {chatStore.totalTokens}/{chatStore.maxTokens} -

    -
  • -
  • -

    - - Cut: - {chatStore.postBeginIndex}/ - {chatStore.history.filter(({ hide }) => !hide).length} -

    -
  • -
  • -

    - - Cost: ${chatStore.cost?.toFixed(4)} -

    -
  • -
-
-
-
{ - setShowSettings(true); - }} - > - {/* the long staus bar */} -
-
-
- -
-
Model
-
{chatStore.model}
-
- {models[chatStore.model]?.price?.prompt * 1000 * 1000} $/M tokens -
-
-
-
- -
-
Mode
-
- {chatStore.streamMode ? Tr("STREAM") : Tr("FETCH")} -
-
STREAM/FETCH
-
- -
-
- -
-
Tokens
-
{chatStore.totalTokens}
-
Max: {chatStore.maxTokens}
-
- -
-
- -
-
Cut
-
- {chatStore.postBeginIndex} -
-
- Max: {chatStore.history.filter(({ hide }) => !hide).length} -
-
- -
-
- -
-
Cost
-
- ${chatStore.cost?.toFixed(4)} -
-
- Accumulated: ${getTotalCost().toFixed(2)} -
-
-
- - {/* the short status bar */} -
- {chatStore.totalTokens !== 0 && ( - - Tokens: {chatStore.totalTokens} - - )} - - - {chatStore.model} - -
-
-
- - -
-
- ); -}; - -export default StatusBar; diff --git a/src/components/theme-provider.tsx b/src/components/ThemeProvider.tsx similarity index 100% rename from src/components/theme-provider.tsx rename to src/components/ThemeProvider.tsx diff --git a/src/components/WhisperButton.tsx b/src/components/WhisperButton.tsx index 9029907..4791be2 100644 --- a/src/components/WhisperButton.tsx +++ b/src/components/WhisperButton.tsx @@ -3,13 +3,7 @@ import { createRef, useContext } from "react"; import { ChatStore } from "@/types/chatstore"; import { useEffect, useState, Dispatch } from "react"; import { Button } from "@/components/ui/button"; -import { - AudioWaveform, - AudioWaveformIcon, - CircleStopIcon, - MicIcon, - VoicemailIcon, -} from "lucide-react"; +import { AudioWaveformIcon, CircleStopIcon, MicIcon } from "lucide-react"; import { AppContext } from "@/pages/App"; const WhisperButton = (props: { diff --git a/src/components/navbar.tsx b/src/components/navbar.tsx index e12857f..2d6bbd8 100644 --- a/src/components/navbar.tsx +++ b/src/components/navbar.tsx @@ -14,7 +14,7 @@ import { PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; -import { ModeToggle } from "@/components/mode-toggle"; +import { ModeToggle } from "@/components/ModeToggle"; import { SidebarTrigger } from "@/components/ui/sidebar"; import { Separator } from "@/components/ui/separator"; import { diff --git a/src/main.tsx b/src/main.tsx index 9b2301f..704b294 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -5,7 +5,7 @@ import { App } from "@/pages/App"; import { Tr, langCodeContext, LANG_OPTIONS } from "@/translate"; import { SidebarProvider } from "@/components/ui/sidebar"; import { Toaster } from "@/components/ui/toaster"; -import { ThemeProvider } from "@/components/theme-provider"; +import { ThemeProvider } from "@/components/ThemeProvider"; function Base() { const [langCode, _setLangCode] = useState("en-US"); diff --git a/src/message.tsx b/src/message.tsx index cf337e4..8a4e523 100644 --- a/src/message.tsx +++ b/src/message.tsx @@ -14,7 +14,6 @@ import { EditMessage } from "@/editMessage"; import logprobToColor from "@/logprob"; import { ChatBubble, - ChatBubbleAvatar, ChatBubbleMessage, ChatBubbleAction, ChatBubbleActionWrapper, diff --git a/src/pages/App.tsx b/src/pages/App.tsx index c1a0c90..bcbee45 100644 --- a/src/pages/App.tsx +++ b/src/pages/App.tsx @@ -113,7 +113,7 @@ import { RulerIcon, } from "lucide-react"; import { Badge } from "@/components/ui/badge"; -import { ModeToggle } from "@/components/mode-toggle"; +import { ModeToggle } from "@/components/ModeToggle"; import Navbar from "@/components/navbar"; diff --git a/src/pages/Chatbox.tsx b/src/pages/Chatbox.tsx index c7c0b8b..e73aa34 100644 --- a/src/pages/Chatbox.tsx +++ b/src/pages/Chatbox.tsx @@ -24,10 +24,9 @@ import { models } from "@/types/models"; import { AddImage } from "@/addImage"; import { ListAPIs } from "@/listAPIs"; import { ListToolsTempaltes } from "@/listToolsTemplates"; -import { autoHeight } from "@/textarea"; +import { autoHeight } from "@/utils/textAreaHelp"; import Templates from "@/components/Templates"; import VersionHint from "@/components/VersionHint"; -import StatusBar from "@/components/StatusBar"; import WhisperButton from "@/components/WhisperButton"; import AddToolMsg from "./AddToolMsg"; import { Textarea } from "@/components/ui/textarea"; diff --git a/src/textarea.tsx b/src/utils/textAreaHelp.tsx similarity index 100% rename from src/textarea.tsx rename to src/utils/textAreaHelp.tsx From 34360e53700a532b3a597c26d462bf1ff94fc7ff Mon Sep 17 00:00:00 2001 From: ecwu Date: Fri, 3 Jan 2025 11:34:46 +0800 Subject: [PATCH 08/30] refactor: clean up imports and move logprobToColor function to utils --- src/listAPIs.tsx | 4 ---- src/listToolsTemplates.tsx | 7 +------ src/message.tsx | 2 +- src/pages/Chatbox.tsx | 2 +- src/{ => utils}/logprob.tsx | 0 5 files changed, 3 insertions(+), 12 deletions(-) rename src/{ => utils}/logprob.tsx (100%) diff --git a/src/listAPIs.tsx b/src/listAPIs.tsx index de8ed72..62c9e38 100644 --- a/src/listAPIs.tsx +++ b/src/listAPIs.tsx @@ -2,14 +2,10 @@ import { ChatStore, TemplateAPI } from "@/types/chatstore"; import { Tr } from "@/translate"; import { - NavigationMenu, NavigationMenuContent, - NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, - NavigationMenuList, NavigationMenuTrigger, - NavigationMenuViewport, } from "@/components/ui/navigation-menu"; import { Button } from "./components/ui/button"; import { cn } from "@/lib/utils"; diff --git a/src/listToolsTemplates.tsx b/src/listToolsTemplates.tsx index 682be1e..6b1909f 100644 --- a/src/listToolsTemplates.tsx +++ b/src/listToolsTemplates.tsx @@ -1,21 +1,16 @@ -import { ChatStore, TemplateTools } from "@/types/chatstore"; import { Tr } from "@/translate"; import { - NavigationMenu, NavigationMenuContent, - NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, - NavigationMenuList, NavigationMenuTrigger, - NavigationMenuViewport, } from "@/components/ui/navigation-menu"; import { cn } from "@/lib/utils"; import { Button } from "./components/ui/button"; import { useContext } from "react"; import { AppContext } from "./pages/App"; -export function ListToolsTempaltes() { +export function ListToolsTemplates() { const ctx = useContext(AppContext); if (!ctx) return
error
; diff --git a/src/message.tsx b/src/message.tsx index 8a4e523..2784854 100644 --- a/src/message.tsx +++ b/src/message.tsx @@ -11,7 +11,7 @@ import { MessageDetail } from "@/messageDetail"; import { MessageToolCall } from "@/messageToolCall"; import { MessageToolResp } from "@/messageToolResp"; import { EditMessage } from "@/editMessage"; -import logprobToColor from "@/logprob"; +import logprobToColor from "@/utils/logprob"; import { ChatBubble, ChatBubbleMessage, diff --git a/src/pages/Chatbox.tsx b/src/pages/Chatbox.tsx index e73aa34..79e5a77 100644 --- a/src/pages/Chatbox.tsx +++ b/src/pages/Chatbox.tsx @@ -23,7 +23,7 @@ import Message from "@/message"; import { models } from "@/types/models"; import { AddImage } from "@/addImage"; import { ListAPIs } from "@/listAPIs"; -import { ListToolsTempaltes } from "@/listToolsTemplates"; +import { ListToolsTemplates } from "@/listToolsTemplates"; import { autoHeight } from "@/utils/textAreaHelp"; import Templates from "@/components/Templates"; import VersionHint from "@/components/VersionHint"; diff --git a/src/logprob.tsx b/src/utils/logprob.tsx similarity index 100% rename from src/logprob.tsx rename to src/utils/logprob.tsx From 1f9c75b91e6d776523963fbb24c5781f46488acf Mon Sep 17 00:00:00 2001 From: ecwu Date: Sat, 4 Jan 2025 22:49:45 +0800 Subject: [PATCH 09/30] refactor: rename tmps to temps in Settings and setAPIsTemplate components for consistency --- src/components/Settings.tsx | 16 +++--- src/pages/Chatbox.tsx | 2 +- src/setAPIsTemplate.tsx | 99 +++++++++++++++++++++++++++---------- 3 files changed, 83 insertions(+), 34 deletions(-) diff --git a/src/components/Settings.tsx b/src/components/Settings.tsx index a4387b0..e9d0653 100644 --- a/src/components/Settings.tsx +++ b/src/components/Settings.tsx @@ -859,8 +859,8 @@ export default (props: {}) => { label="Chat API" endpoint={ctx.chatStore.apiEndpoint} APIkey={ctx.chatStore.apiKey} - tmps={ctx.templateAPIs} - setTmps={ctx.setTemplateAPIs} + temps={ctx.templateAPIs} + setTemps={ctx.setTemplateAPIs} /> @@ -964,8 +964,8 @@ export default (props: {}) => { label="Whisper API" endpoint={ctx.chatStore.whisper_api} APIkey={ctx.chatStore.whisper_key} - tmps={ctx.templateAPIsWhisper} - setTmps={ctx.setTemplateAPIsWhisper} + temps={ctx.templateAPIsWhisper} + setTemps={ctx.setTemplateAPIsWhisper} /> @@ -997,8 +997,8 @@ export default (props: {}) => { label="TTS API" endpoint={ctx.chatStore.tts_api} APIkey={ctx.chatStore.tts_key} - tmps={ctx.templateAPIsTTS} - setTmps={ctx.setTemplateAPIsTTS} + temps={ctx.templateAPIsTTS} + setTemps={ctx.setTemplateAPIsTTS} /> @@ -1122,8 +1122,8 @@ export default (props: {}) => { label="Image Gen API" endpoint={ctx.chatStore.image_gen_api} APIkey={ctx.chatStore.image_gen_key} - tmps={ctx.templateAPIsImageGen} - setTmps={ctx.setTemplateAPIsImageGen} + temps={ctx.templateAPIsImageGen} + setTemps={ctx.setTemplateAPIsImageGen} /> diff --git a/src/pages/Chatbox.tsx b/src/pages/Chatbox.tsx index 79e5a77..1e45148 100644 --- a/src/pages/Chatbox.tsx +++ b/src/pages/Chatbox.tsx @@ -447,7 +447,7 @@ export default function ChatBOX() { keyField="image_gen_key" /> )} - {ctx.templateTools.length > 0 && } + {ctx.templateTools.length > 0 && }
diff --git a/src/setAPIsTemplate.tsx b/src/setAPIsTemplate.tsx index 0bb2936..e120eb2 100644 --- a/src/setAPIsTemplate.tsx +++ b/src/setAPIsTemplate.tsx @@ -1,10 +1,24 @@ import { TemplateAPI } from "@/types/chatstore"; import { Tr } from "@/translate"; + +import { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; import { Button } from "./components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { SaveIcon } from "lucide-react"; interface Props { - tmps: TemplateAPI[]; - setTmps: (tmps: TemplateAPI[]) => void; + temps: TemplateAPI[]; + setTemps: (temps: TemplateAPI[]) => void; label: string; endpoint: string; APIkey: string; @@ -12,31 +26,66 @@ interface Props { export function SetAPIsTemplate({ endpoint, APIkey, - tmps, - setTmps, + temps: temps, + setTemps: setTemps, label, }: Props) { return ( - + + + + + + + Save {label} as Template + + Once saved, you can easily access your templates from the dropdown + menu. + + +
+
+ + + +
+
+ + + + + +
+
); } From 236d48e72d06225a6aecb80b5ba7d2850d663dda Mon Sep 17 00:00:00 2001 From: ecwu Date: Sat, 4 Jan 2025 23:13:58 +0800 Subject: [PATCH 10/30] feat: enhance ListAPIs component with shortLabel prop for improved display and update translations for new chat session prompts --- src/listAPIs.tsx | 6 ++- src/pages/Chatbox.tsx | 109 ++++++++++++++++------------------------- src/translate/zh_CN.ts | 6 +++ 3 files changed, 51 insertions(+), 70 deletions(-) diff --git a/src/listAPIs.tsx b/src/listAPIs.tsx index 62c9e38..a48f4fe 100644 --- a/src/listAPIs.tsx +++ b/src/listAPIs.tsx @@ -14,18 +14,20 @@ import { AppContext } from "./pages/App"; interface Props { label: string; + shortLabel: string; apiField: string; keyField: string; } -export function ListAPIs({ label, apiField, keyField }: Props) { +export function ListAPIs({ label, shortLabel, apiField, keyField }: Props) { const ctx = useContext(AppContext); if (ctx === null) return <>; return ( - {label}{" "} + {shortLabel} + {label}{" "} {ctx.templateAPIs.find( (t) => ctx.chatStore[apiField as keyof ChatStore] === t.endpoint && diff --git a/src/pages/Chatbox.tsx b/src/pages/Chatbox.tsx index 1e45148..f8d2b5f 100644 --- a/src/pages/Chatbox.tsx +++ b/src/pages/Chatbox.tsx @@ -1,8 +1,7 @@ -import { IDBPDatabase } from "idb"; import { useContext, useRef } from "react"; -import { useEffect, useState, Dispatch } from "react"; -import { Tr, langCodeContext, LANG_OPTIONS } from "@/translate"; -import { addTotalCost, getTotalCost } from "@/utils/totalCost"; +import { useEffect, useState } from "react"; +import { Tr } from "@/translate"; +import { addTotalCost } from "@/utils/totalCost"; import ChatGPT, { calculate_token_length, FetchResponse, @@ -12,30 +11,19 @@ import ChatGPT, { Logprobs, Usage, } from "@/chatgpt"; -import { - ChatStore, - ChatStoreMessage, - TemplateChatStore, - TemplateAPI, - TemplateTools, -} from "../types/chatstore"; +import { ChatStoreMessage } from "../types/chatstore"; import Message from "@/message"; import { models } from "@/types/models"; import { AddImage } from "@/addImage"; import { ListAPIs } from "@/listAPIs"; import { ListToolsTemplates } from "@/listToolsTemplates"; import { autoHeight } from "@/utils/textAreaHelp"; -import Templates from "@/components/Templates"; import VersionHint from "@/components/VersionHint"; import WhisperButton from "@/components/WhisperButton"; -import AddToolMsg from "./AddToolMsg"; -import { Textarea } from "@/components/ui/textarea"; import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; import { ChatInput } from "@/components/ui/chat/chat-input"; import { ChatBubble, - ChatBubbleAvatar, ChatBubbleMessage, ChatBubbleAction, ChatBubbleActionWrapper, @@ -43,33 +31,22 @@ import { import { ChatMessageList } from "@/components/ui/chat/chat-message-list"; import { - AlertTriangleIcon, - ArrowUpIcon, + ArrowDownToDotIcon, CornerDownLeftIcon, CornerLeftUpIcon, - CornerUpLeftIcon, - GlobeIcon, + CornerRightUpIcon, ImageIcon, InfoIcon, - KeyIcon, - SearchIcon, - Settings2, - Settings2Icon, + ScissorsIcon, } from "lucide-react"; import { Switch } from "@/components/ui/switch"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { NavigationMenu, - NavigationMenuContent, - NavigationMenuItem, - NavigationMenuLink, NavigationMenuList, - NavigationMenuTrigger, - navigationMenuTriggerStyle, } from "@/components/ui/navigation-menu"; import { AppContext } from "./App"; -import { addToRange } from "react-day-picker"; export default function ChatBOX() { const ctx = useContext(AppContext); @@ -428,21 +405,33 @@ export default function ChatBOX() { {ctx.templateAPIs.length > 0 && ( - + )} {ctx.templateAPIsWhisper.length > 0 && ( )} {ctx.templateAPIsTTS.length > 0 && ( - + )} {ctx.templateAPIsImageGen.length > 0 && ( @@ -453,52 +442,31 @@ export default function ChatBOX() {
- {chatStore.history.filter((msg) => !msg.example).length == 0 && ( -
-

- {Tr("Saved prompt templates")} - -

-
-
- -
-
- )} {chatStore.history.length === 0 && ( - {Tr("No chat history here")} + + {Tr("This is a new chat session, start by typing a message")} +
- + - {Tr("Model")}: {chatStore.model} - -
-
- - - {Tr("Click above to change the settings of this chat")} + {Tr( + "Settings button located at the top right corner can be used to change the settings of this chat" + )}
- {Tr("Click the corner to create a new chat")} + + {Tr( + "'New' button located at the top left corner can be used to create a new chat" + )} +
- + {Tr( "All chat history and settings are stored in the local browser" @@ -525,8 +493,13 @@ export default function ChatBOX() { } - // TODO: add a button to show settings + icon={} + onClick={() => { + chatStore.systemMessageContent = ""; + chatStore.toolsString = ""; + chatStore.history = []; + setChatStore({ ...chatStore }); + }} /> diff --git a/src/translate/zh_CN.ts b/src/translate/zh_CN.ts index 11a8863..a4eeb3a 100644 --- a/src/translate/zh_CN.ts +++ b/src/translate/zh_CN.ts @@ -14,6 +14,12 @@ const LANG_MAP: Record = { "saved api templates": "已保存的 API 模板", "saved prompt templates": "已保存的提示模板", "no chat history here": "暂无历史对话记录", + "This is a new chat session, start by typing a message": + "这是一个新对话,开始输入消息", + "Settings button located at the top right corner can be used to change the settings of this chat": + "右上角的设置按钮可用于更改此对话的设置", + "'New' button located at the top left corner can be used to create a new chat": + "左上角的 '新' 按钮可用于创建新对话", "click above to change the settings of this chat": "点击上方更改此对话的参数(请勿泄漏)", "click the NEW to create a new chat": "点击左上角 NEW 新建对话", From 503bf6a9bb49da4f8e1c35f3033d017a1f9f58fb Mon Sep 17 00:00:00 2001 From: ecwu Date: Sat, 4 Jan 2025 23:29:20 +0800 Subject: [PATCH 11/30] feat: replace DropdownMenu with Select component in ModeToggle for improved theme selection --- src/components/ModeToggle.tsx | 44 +++++++++++++++++--------------- src/components/ThemeProvider.tsx | 2 +- src/components/navbar.tsx | 2 -- src/pages/App.tsx | 1 + 4 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/components/ModeToggle.tsx b/src/components/ModeToggle.tsx index 8a925d1..70cc101 100644 --- a/src/components/ModeToggle.tsx +++ b/src/components/ModeToggle.tsx @@ -7,31 +7,33 @@ import { DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; -import { useTheme } from "@/components/ThemeProvider"; +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectLabel, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { useTheme, Theme } from "@/components/ThemeProvider"; export function ModeToggle() { const { setTheme } = useTheme(); return ( - - - - - - setTheme("light")}> - Light - - setTheme("dark")}> - Dark - - setTheme("system")}> - System - - - + ); } diff --git a/src/components/ThemeProvider.tsx b/src/components/ThemeProvider.tsx index 7b9eeb2..d35ebbf 100644 --- a/src/components/ThemeProvider.tsx +++ b/src/components/ThemeProvider.tsx @@ -1,6 +1,6 @@ import { createContext, useContext, useEffect, useState } from "react"; -type Theme = "dark" | "light" | "system"; +export type Theme = "dark" | "light" | "system"; type ThemeProviderProps = { children: React.ReactNode; diff --git a/src/components/navbar.tsx b/src/components/navbar.tsx index 2d6bbd8..68923c8 100644 --- a/src/components/navbar.tsx +++ b/src/components/navbar.tsx @@ -14,7 +14,6 @@ import { PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; -import { ModeToggle } from "@/components/ModeToggle"; import { SidebarTrigger } from "@/components/ui/sidebar"; import { Separator } from "@/components/ui/separator"; import { @@ -130,7 +129,6 @@ const Navbar: React.FC = () => {
-
diff --git a/src/pages/App.tsx b/src/pages/App.tsx index bcbee45..6a7cf7a 100644 --- a/src/pages/App.tsx +++ b/src/pages/App.tsx @@ -414,6 +414,7 @@ export function App() { + From f3d08afcdd4bbb66acf68af9f2633b206c0942bb Mon Sep 17 00:00:00 2001 From: ecwu Date: Sat, 4 Jan 2025 23:53:28 +0800 Subject: [PATCH 12/30] feat: add isVailedJSON utility function for JSON validation --- src/utils/isVailedJSON.ts | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/utils/isVailedJSON.ts diff --git a/src/utils/isVailedJSON.ts b/src/utils/isVailedJSON.ts new file mode 100644 index 0000000..b35a8a3 --- /dev/null +++ b/src/utils/isVailedJSON.ts @@ -0,0 +1,8 @@ +export const isVailedJSON = (str: string): boolean => { + try { + JSON.parse(str); + } catch (e) { + return false; + } + return true; +}; From 3663193f509e30fee542a0005e587b1a4d60f589 Mon Sep 17 00:00:00 2001 From: ecwu Date: Sat, 4 Jan 2025 23:53:38 +0800 Subject: [PATCH 13/30] refactor: move isVailedJSON import to utils for better organization --- src/components/Settings.tsx | 2 +- src/editMessageString.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Settings.tsx b/src/components/Settings.tsx index e9d0653..ab84823 100644 --- a/src/components/Settings.tsx +++ b/src/components/Settings.tsx @@ -11,7 +11,7 @@ import { } from "@/types/chatstore"; import { models } from "@/types/models"; import { tr, Tr, langCodeContext, LANG_OPTIONS } from "@/translate"; -import { isVailedJSON } from "@/message"; +import { isVailedJSON } from "@/utils/isVailedJSON"; import { SetAPIsTemplate } from "@/setAPIsTemplate"; import { autoHeight } from "@/utils/textAreaHelp"; import { getDefaultParams } from "@/utils/getDefaultParam"; diff --git a/src/editMessageString.tsx b/src/editMessageString.tsx index f04a794..a0ebe58 100644 --- a/src/editMessageString.tsx +++ b/src/editMessageString.tsx @@ -1,5 +1,5 @@ import { ChatStore, ChatStoreMessage } from "@/types/chatstore"; -import { isVailedJSON } from "@/message"; +import { isVailedJSON } from "@/utils/isVailedJSON"; import { calculate_token_length } from "@/chatgpt"; import { Tr } from "@/translate"; From 47f63364b1b1671c87a5f5f09ba4ccbe61f27854 Mon Sep 17 00:00:00 2001 From: ecwu Date: Sat, 4 Jan 2025 23:53:45 +0800 Subject: [PATCH 14/30] refactor: rename message.tsx to MessageBubble.tsx and consolidate message-related components for better organization --- .../MessageBubble.tsx} | 138 ++++++++++++++++-- src/messageDetail.tsx | 35 ----- src/messageHide.tsx | 20 --- src/messageToolCall.tsx | 46 ------ src/messageToolResp.tsx | 25 ---- src/pages/App.tsx | 4 + src/pages/Chatbox.tsx | 2 +- 7 files changed, 127 insertions(+), 143 deletions(-) rename src/{message.tsx => components/MessageBubble.tsx} (72%) delete mode 100644 src/messageDetail.tsx delete mode 100644 src/messageHide.tsx delete mode 100644 src/messageToolCall.tsx delete mode 100644 src/messageToolResp.tsx diff --git a/src/message.tsx b/src/components/MessageBubble.tsx similarity index 72% rename from src/message.tsx rename to src/components/MessageBubble.tsx index 2784854..d99bd38 100644 --- a/src/message.tsx +++ b/src/components/MessageBubble.tsx @@ -1,15 +1,11 @@ import { XMarkIcon } from "@heroicons/react/24/outline"; import Markdown from "react-markdown"; import { useContext, useState } from "react"; +import { ChatStoreMessage } from "@/types/chatstore"; -import { Tr, langCodeContext, LANG_OPTIONS } from "@/translate"; -import { ChatStore, ChatStoreMessage } from "@/types/chatstore"; -import { calculate_token_length, getMessageText } from "@/chatgpt"; +import { Tr } from "@/translate"; +import { getMessageText } from "@/chatgpt"; import TTSButton, { TTSPlay } from "@/tts"; -import { MessageHide } from "@/messageHide"; -import { MessageDetail } from "@/messageDetail"; -import { MessageToolCall } from "@/messageToolCall"; -import { MessageToolResp } from "@/messageToolResp"; import { EditMessage } from "@/editMessage"; import logprobToColor from "@/utils/logprob"; import { @@ -18,6 +14,7 @@ import { ChatBubbleAction, ChatBubbleActionWrapper, } from "@/components/ui/chat/chat-bubble"; +import { Badge } from "@/components/ui/badge"; import { useToast } from "@/hooks/use-toast"; import { ClipboardIcon, @@ -25,16 +22,126 @@ import { MessageSquareOffIcon, MessageSquarePlusIcon, } from "lucide-react"; -import { AppContext } from "./pages/App"; +import { AppContext } from "@/pages/App"; -export const isVailedJSON = (str: string): boolean => { - try { - JSON.parse(str); - } catch (e) { - return false; +interface HideMessageProps { + chat: ChatStoreMessage; +} + +function MessageHide({ chat }: HideMessageProps) { + return ( + <> +
+ {getMessageText(chat).split("\n")[0].slice(0, 28)} ... +
+
+ Removed from context +
+ + ); +} + +interface MessageDetailProps { + chat: ChatStoreMessage; + renderMarkdown: boolean; +} +function MessageDetail({ chat, renderMarkdown }: MessageDetailProps) { + if (typeof chat.content === "string") { + return
; } - return true; -}; + return ( +
+ {chat.content.map((mdt) => + mdt.type === "text" ? ( + chat.hide ? ( + mdt.text?.split("\n")[0].slice(0, 16) + " ..." + ) : renderMarkdown ? ( + {mdt.text} + ) : ( + mdt.text + ) + ) : ( + { + window.open(mdt.image_url?.url, "_blank"); + }} + /> + ) + )} +
+ ); +} + +interface ToolCallMessageProps { + chat: ChatStoreMessage; + copyToClipboard: (text: string) => void; +} +function MessageToolCall({ chat, copyToClipboard }: ToolCallMessageProps) { + return ( +
+ {chat.tool_calls?.map((tool_call) => ( +
+ + Tool Call ID:{" "} + copyToClipboard(String(tool_call.id))} + > + {tool_call?.id} + + +

Type: {tool_call?.type}

+

+ Function: + copyToClipboard(tool_call.function.name)} + > + {tool_call.function.name} + +

+

+ Arguments: + copyToClipboard(tool_call.function.arguments)} + > + {tool_call.function.arguments} + +

+
+ ))} + {/* [TODO] */} + {chat.content as string} +
+ ); +} + +interface ToolRespondMessageProps { + chat: ChatStoreMessage; + copyToClipboard: (text: string) => void; +} +function MessageToolResp({ chat, copyToClipboard }: ToolRespondMessageProps) { + return ( +
+
+ + Tool Response ID:{" "} + copyToClipboard(String(chat.tool_call_id))} + > + {chat.tool_call_id} + + + {/* [TODO] */} +

{chat.content as string}

+
+
+ ); +} export default function Message(props: { messageIndex: number }) { const ctx = useContext(AppContext); @@ -44,7 +151,6 @@ export default function Message(props: { messageIndex: number }) { const chat = chatStore.history[messageIndex]; const [showEdit, setShowEdit] = useState(false); - const [showCopiedHint, setShowCopiedHint] = useState(false); const [renderMarkdown, setRenderWorkdown] = useState(false); const [renderColor, setRenderColor] = useState(false); const DeleteIcon = () => ( diff --git a/src/messageDetail.tsx b/src/messageDetail.tsx deleted file mode 100644 index 63d7cd9..0000000 --- a/src/messageDetail.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { ChatStoreMessage } from "@/types/chatstore"; -import Markdown from "react-markdown"; - -interface Props { - chat: ChatStoreMessage; - renderMarkdown: boolean; -} -export function MessageDetail({ chat, renderMarkdown }: Props) { - if (typeof chat.content === "string") { - return
; - } - return ( -
- {chat.content.map((mdt) => - mdt.type === "text" ? ( - chat.hide ? ( - mdt.text?.split("\n")[0].slice(0, 16) + " ..." - ) : renderMarkdown ? ( - {mdt.text} - ) : ( - mdt.text - ) - ) : ( - { - window.open(mdt.image_url?.url, "_blank"); - }} - /> - ) - )} -
- ); -} diff --git a/src/messageHide.tsx b/src/messageHide.tsx deleted file mode 100644 index 82b2ac4..0000000 --- a/src/messageHide.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { ChatStoreMessage } from "@/types/chatstore"; -import { getMessageText } from "@/chatgpt"; -import { Badge } from "./components/ui/badge"; - -interface Props { - chat: ChatStoreMessage; -} - -export function MessageHide({ chat }: Props) { - return ( - <> -
- {getMessageText(chat).split("\n")[0].slice(0, 28)} ... -
-
- Removed from context -
- - ); -} diff --git a/src/messageToolCall.tsx b/src/messageToolCall.tsx deleted file mode 100644 index 7957f21..0000000 --- a/src/messageToolCall.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { ChatStoreMessage } from "@/types/chatstore"; - -interface Props { - chat: ChatStoreMessage; - copyToClipboard: (text: string) => void; -} -export function MessageToolCall({ chat, copyToClipboard }: Props) { - return ( -
- {chat.tool_calls?.map((tool_call) => ( -
- - Tool Call ID:{" "} - copyToClipboard(String(tool_call.id))} - > - {tool_call?.id} - - -

Type: {tool_call?.type}

-

- Function: - copyToClipboard(tool_call.function.name)} - > - {tool_call.function.name} - -

-

- Arguments: - copyToClipboard(tool_call.function.arguments)} - > - {tool_call.function.arguments} - -

-
- ))} - {/* [TODO] */} - {chat.content as string} -
- ); -} diff --git a/src/messageToolResp.tsx b/src/messageToolResp.tsx deleted file mode 100644 index 2968d03..0000000 --- a/src/messageToolResp.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { ChatStoreMessage } from "@/types/chatstore"; - -interface Props { - chat: ChatStoreMessage; - copyToClipboard: (text: string) => void; -} -export function MessageToolResp({ chat, copyToClipboard }: Props) { - return ( -
-
- - Tool Response ID:{" "} - copyToClipboard(String(chat.tool_call_id))} - > - {chat.tool_call_id} - - - {/* [TODO] */} -

{chat.content as string}

-
-
- ); -} diff --git a/src/pages/App.tsx b/src/pages/App.tsx index 6a7cf7a..b4e7d20 100644 --- a/src/pages/App.tsx +++ b/src/pages/App.tsx @@ -215,6 +215,10 @@ export function App() { const newKey = await (await db).add(STORAGE_NAME, newChatStore(chatStore)); setSelectedChatIndex(newKey as number); setAllChatStoreIndexes(await (await db).getAllKeys(STORAGE_NAME)); + toast({ + title: "New chat session created", + description: `A new chat session (ID. ${newKey}) has been created.`, + }); }; const handleNewChatStore = async () => { return handleNewChatStoreWithOldOne(chatStore); diff --git a/src/pages/Chatbox.tsx b/src/pages/Chatbox.tsx index f8d2b5f..a06175f 100644 --- a/src/pages/Chatbox.tsx +++ b/src/pages/Chatbox.tsx @@ -12,7 +12,7 @@ import ChatGPT, { Usage, } from "@/chatgpt"; import { ChatStoreMessage } from "../types/chatstore"; -import Message from "@/message"; +import Message from "@/components/MessageBubble"; import { models } from "@/types/models"; import { AddImage } from "@/addImage"; import { ListAPIs } from "@/listAPIs"; From 9383cf045aac5a0d6bca14088bc3d24d28f1362b Mon Sep 17 00:00:00 2001 From: ecwu Date: Sun, 5 Jan 2025 00:00:11 +0800 Subject: [PATCH 15/30] refactor: replace ListAPIs component with ListAPI for improved structure and organization --- src/components/ListAPI.tsx | 254 +++++++++++++++++++++++++++++++++++++ src/listAPIs.tsx | 109 ---------------- src/pages/Chatbox.tsx | 47 +------ 3 files changed, 256 insertions(+), 154 deletions(-) create mode 100644 src/components/ListAPI.tsx diff --git a/src/components/ListAPI.tsx b/src/components/ListAPI.tsx new file mode 100644 index 0000000..e7e2b9e --- /dev/null +++ b/src/components/ListAPI.tsx @@ -0,0 +1,254 @@ +import React from "react"; +import { ChatStore, TemplateAPI } from "@/types/chatstore"; +import { Tr } from "@/translate"; + +import { + NavigationMenuContent, + NavigationMenuItem, + NavigationMenuLink, + NavigationMenuTrigger, +} from "@/components/ui/navigation-menu"; +import { Button } from "@/components/ui/button"; +import { cn } from "@/lib/utils"; +import { useContext } from "react"; +import { AppContext } from "@/pages/App"; +import { + NavigationMenu, + NavigationMenuList, +} from "@/components/ui/navigation-menu"; + +interface APITemplateItemProps { + label: string; + shortLabel: string; + apiField: string; + keyField: string; +} +function ListAPIs({ + label, + shortLabel, + apiField, + keyField, +}: APITemplateItemProps) { + const ctx = useContext(AppContext); + if (ctx === null) return <>; + + return ( + + + {shortLabel} + + {label}{" "} + {ctx.templateAPIs.find( + (t) => + ctx.chatStore[apiField as keyof ChatStore] === t.endpoint && + ctx.chatStore[keyField as keyof ChatStore] === t.key + )?.name && + `: ${ + ctx.templateAPIs.find( + (t) => + ctx.chatStore[apiField as keyof ChatStore] === t.endpoint && + ctx.chatStore[keyField as keyof ChatStore] === t.key + )?.name + }`} + + + + + + + ); +} + +function ListToolsTemplates() { + const ctx = useContext(AppContext); + if (!ctx) return
error
; + + const { chatStore, setChatStore } = ctx; + + return ( + + + {Tr(`Saved tools templates`)} + + + + + + + ); +} + +const ListAPI: React.FC = () => { + const ctx = useContext(AppContext); + if (!ctx) return
error
; + return ( +
+ + + {ctx.templateAPIs.length > 0 && ( + + )} + {ctx.templateAPIsWhisper.length > 0 && ( + + )} + {ctx.templateAPIsTTS.length > 0 && ( + + )} + {ctx.templateAPIsImageGen.length > 0 && ( + + )} + {ctx.templateTools.length > 0 && } + + +
+ ); +}; + +export default ListAPI; diff --git a/src/listAPIs.tsx b/src/listAPIs.tsx index a48f4fe..139597f 100644 --- a/src/listAPIs.tsx +++ b/src/listAPIs.tsx @@ -1,111 +1,2 @@ -import { ChatStore, TemplateAPI } from "@/types/chatstore"; -import { Tr } from "@/translate"; -import { - NavigationMenuContent, - NavigationMenuItem, - NavigationMenuLink, - NavigationMenuTrigger, -} from "@/components/ui/navigation-menu"; -import { Button } from "./components/ui/button"; -import { cn } from "@/lib/utils"; -import { useContext } from "react"; -import { AppContext } from "./pages/App"; -interface Props { - label: string; - shortLabel: string; - apiField: string; - keyField: string; -} -export function ListAPIs({ label, shortLabel, apiField, keyField }: Props) { - const ctx = useContext(AppContext); - if (ctx === null) return <>; - - return ( - - - {shortLabel} - - {label}{" "} - {ctx.templateAPIs.find( - (t) => - ctx.chatStore[apiField as keyof ChatStore] === t.endpoint && - ctx.chatStore[keyField as keyof ChatStore] === t.key - )?.name && - `: ${ - ctx.templateAPIs.find( - (t) => - ctx.chatStore[apiField as keyof ChatStore] === t.endpoint && - ctx.chatStore[keyField as keyof ChatStore] === t.key - )?.name - }`} - - - - - - - ); -} diff --git a/src/pages/Chatbox.tsx b/src/pages/Chatbox.tsx index a06175f..e4a4d75 100644 --- a/src/pages/Chatbox.tsx +++ b/src/pages/Chatbox.tsx @@ -15,8 +15,6 @@ import { ChatStoreMessage } from "../types/chatstore"; import Message from "@/components/MessageBubble"; import { models } from "@/types/models"; import { AddImage } from "@/addImage"; -import { ListAPIs } from "@/listAPIs"; -import { ListToolsTemplates } from "@/listToolsTemplates"; import { autoHeight } from "@/utils/textAreaHelp"; import VersionHint from "@/components/VersionHint"; import WhisperButton from "@/components/WhisperButton"; @@ -41,12 +39,9 @@ import { } from "lucide-react"; import { Switch } from "@/components/ui/switch"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; -import { - NavigationMenu, - NavigationMenuList, -} from "@/components/ui/navigation-menu"; import { AppContext } from "./App"; +import ListAPI from "@/components/ListAPI"; export default function ChatBOX() { const ctx = useContext(AppContext); @@ -401,45 +396,7 @@ export default function ChatBOX() { return ( <> -
- - - {ctx.templateAPIs.length > 0 && ( - - )} - {ctx.templateAPIsWhisper.length > 0 && ( - - )} - {ctx.templateAPIsTTS.length > 0 && ( - - )} - {ctx.templateAPIsImageGen.length > 0 && ( - - )} - {ctx.templateTools.length > 0 && } - - -
+
{chatStore.history.length === 0 && ( From 76d50317e9ef3632610164a628f94eaff774c561 Mon Sep 17 00:00:00 2001 From: ecwu Date: Sun, 5 Jan 2025 00:01:13 +0800 Subject: [PATCH 16/30] refactor: remove unused ListAPIs and ListToolsTemplates components for cleaner codebase --- src/listAPIs.tsx | 2 - src/listToolsTemplates.tsx | 96 -------------------------------------- 2 files changed, 98 deletions(-) delete mode 100644 src/listAPIs.tsx delete mode 100644 src/listToolsTemplates.tsx diff --git a/src/listAPIs.tsx b/src/listAPIs.tsx deleted file mode 100644 index 139597f..0000000 --- a/src/listAPIs.tsx +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/src/listToolsTemplates.tsx b/src/listToolsTemplates.tsx deleted file mode 100644 index 6b1909f..0000000 --- a/src/listToolsTemplates.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import { Tr } from "@/translate"; -import { - NavigationMenuContent, - NavigationMenuItem, - NavigationMenuLink, - NavigationMenuTrigger, -} from "@/components/ui/navigation-menu"; -import { cn } from "@/lib/utils"; -import { Button } from "./components/ui/button"; -import { useContext } from "react"; -import { AppContext } from "./pages/App"; - -export function ListToolsTemplates() { - const ctx = useContext(AppContext); - if (!ctx) return
error
; - - const { chatStore, setChatStore } = ctx; - - return ( - - - {Tr(`Saved tools templates`)} - - - - - - - ); -} From 75a431360beec4c5158836afe96fe924ad2dc49f Mon Sep 17 00:00:00 2001 From: ecwu Date: Sun, 5 Jan 2025 00:11:31 +0800 Subject: [PATCH 17/30] refactor: reorganize SetAPIsTemplate component and update imports for improved structure --- src/components/ListAPI.tsx | 21 +---- src/components/MessageBubble.tsx | 95 ++++++++++++++++++++++- src/components/Settings.tsx | 2 +- src/{ => components}/setAPIsTemplate.tsx | 6 +- src/tts.tsx | 97 ------------------------ 5 files changed, 100 insertions(+), 121 deletions(-) rename src/{ => components}/setAPIsTemplate.tsx (95%) delete mode 100644 src/tts.tsx diff --git a/src/components/ListAPI.tsx b/src/components/ListAPI.tsx index e7e2b9e..4f06e0c 100644 --- a/src/components/ListAPI.tsx +++ b/src/components/ListAPI.tsx @@ -19,25 +19,18 @@ import { interface APITemplateItemProps { label: string; - shortLabel: string; apiField: string; keyField: string; } -function ListAPIs({ - label, - shortLabel, - apiField, - keyField, -}: APITemplateItemProps) { +function ListAPIs({ label, apiField, keyField }: APITemplateItemProps) { const ctx = useContext(AppContext); if (ctx === null) return <>; return ( - {shortLabel} + {label}{" "} - {label}{" "} {ctx.templateAPIs.find( (t) => ctx.chatStore[apiField as keyof ChatStore] === t.endpoint && @@ -215,7 +208,6 @@ const ListAPI: React.FC = () => { {ctx.templateAPIs.length > 0 && ( @@ -223,23 +215,16 @@ const ListAPI: React.FC = () => { {ctx.templateAPIsWhisper.length > 0 && ( )} {ctx.templateAPIsTTS.length > 0 && ( - + )} {ctx.templateAPIsImageGen.length > 0 && ( diff --git a/src/components/MessageBubble.tsx b/src/components/MessageBubble.tsx index d99bd38..a6c5984 100644 --- a/src/components/MessageBubble.tsx +++ b/src/components/MessageBubble.tsx @@ -1,11 +1,11 @@ import { XMarkIcon } from "@heroicons/react/24/outline"; import Markdown from "react-markdown"; -import { useContext, useState } from "react"; +import { useContext, useState, useMemo } from "react"; import { ChatStoreMessage } from "@/types/chatstore"; +import { addTotalCost } from "@/utils/totalCost"; import { Tr } from "@/translate"; import { getMessageText } from "@/chatgpt"; -import TTSButton, { TTSPlay } from "@/tts"; import { EditMessage } from "@/editMessage"; import logprobToColor from "@/utils/logprob"; import { @@ -15,12 +15,15 @@ import { ChatBubbleActionWrapper, } from "@/components/ui/chat/chat-bubble"; import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; import { useToast } from "@/hooks/use-toast"; import { ClipboardIcon, PencilIcon, MessageSquareOffIcon, MessageSquarePlusIcon, + AudioLinesIcon, + LoaderCircleIcon, } from "lucide-react"; import { AppContext } from "@/pages/App"; @@ -143,6 +146,94 @@ function MessageToolResp({ chat, copyToClipboard }: ToolRespondMessageProps) { ); } +interface TTSProps { + chat: ChatStoreMessage; +} +interface TTSPlayProps { + chat: ChatStoreMessage; +} +export function TTSPlay(props: TTSPlayProps) { + const src = useMemo(() => { + if (props.chat.audio instanceof Blob) { + return URL.createObjectURL(props.chat.audio); + } + return ""; + }, [props.chat.audio]); + + if (props.chat.hide) { + return <>; + } + if (props.chat.audio instanceof Blob) { + return
; @@ -198,7 +215,7 @@ function ListToolsTemplates() { ); } -const ListAPI: React.FC = () => { +const APIListMenu: React.FC = () => { const ctx = useContext(AppContext); if (!ctx) return
error
; return ( @@ -206,34 +223,46 @@ const ListAPI: React.FC = () => { {ctx.templateAPIs.length > 0 && ( - )} {ctx.templateAPIsWhisper.length > 0 && ( - )} {ctx.templateAPIsTTS.length > 0 && ( - + )} {ctx.templateAPIsImageGen.length > 0 && ( - )} - {ctx.templateTools.length > 0 && } + {ctx.templateTools.length > 0 && }
); }; -export default ListAPI; +export default APIListMenu; diff --git a/src/pages/Chatbox.tsx b/src/pages/Chatbox.tsx index e4a4d75..f76928b 100644 --- a/src/pages/Chatbox.tsx +++ b/src/pages/Chatbox.tsx @@ -41,7 +41,7 @@ import { Switch } from "@/components/ui/switch"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { AppContext } from "./App"; -import ListAPI from "@/components/ListAPI"; +import APIListMenu from "@/components/ListAPI"; export default function ChatBOX() { const ctx = useContext(AppContext); @@ -61,8 +61,6 @@ export default function ChatBOX() { const [showGenerating, setShowGenerating] = useState(false); const [generatingMessage, setGeneratingMessage] = useState(""); const [showRetry, setShowRetry] = useState(false); - const [showAddToolMsg, setShowAddToolMsg] = useState(false); - const [showSearch, setShowSearch] = useState(false); let default_follow = localStorage.getItem("follow"); if (default_follow === null) { default_follow = "true"; @@ -396,7 +394,7 @@ export default function ChatBOX() { return ( <> - +
{chatStore.history.length === 0 && ( From 40f61dd6f9c6eed1e43444bf640671f80eb58566 Mon Sep 17 00:00:00 2001 From: ecwu Date: Sun, 5 Jan 2025 19:43:57 +0800 Subject: [PATCH 19/30] refactor: update button labels and improve dialog for saving tools templates --- src/components/ListAPI.tsx | 2 +- src/components/MessageBubble.tsx | 52 -------------------- src/components/Settings.tsx | 83 ++++++++++++++++++++++++-------- src/pages/App.tsx | 2 +- src/translate/zh_CN.ts | 2 + 5 files changed, 68 insertions(+), 73 deletions(-) diff --git a/src/components/ListAPI.tsx b/src/components/ListAPI.tsx index c854089..ee61de4 100644 --- a/src/components/ListAPI.tsx +++ b/src/components/ListAPI.tsx @@ -139,7 +139,7 @@ function ToolsDropdownList() { return ( - {Tr(`Saved tools templates`)} + {Tr(`Tools`)} - ); - const CopiedHint = () => ( -
- - - - {Tr("Message copied to clipboard!")} -
- ); const { toast } = useToast(); const copyToClipboard = async (text: string) => { @@ -309,20 +271,6 @@ export default function Message(props: { messageIndex: number }) { } }; - const CopyIcon = ({ textToCopy }: { textToCopy: string }) => { - return ( - <> - - - ); - }; - return ( <> {chatStore.postBeginIndex !== 0 && diff --git a/src/components/Settings.tsx b/src/components/Settings.tsx index 70a904a..cd9b34f 100644 --- a/src/components/Settings.tsx +++ b/src/components/Settings.tsx @@ -53,6 +53,7 @@ import { } from "@/components/ui/select"; import { Dialog, + DialogClose, DialogContent, DialogDescription, DialogFooter, @@ -73,6 +74,7 @@ import { KeyIcon, ListIcon, MoveHorizontalIcon, + SaveIcon, TriangleAlertIcon, } from "lucide-react"; import { Separator } from "@/components/ui/separator"; @@ -581,25 +583,68 @@ export default (props: {}) => {
{ctx.chatStore.toolsString.trim() && ( - + + + + + + + Save the tool as Template + + Once saved, you can easily access your tools from + the dropdown menu. + + +
+
+ + + +
+
+ + + + + +
+
)}
diff --git a/src/pages/App.tsx b/src/pages/App.tsx index b4e7d20..15e9a32 100644 --- a/src/pages/App.tsx +++ b/src/pages/App.tsx @@ -115,7 +115,7 @@ import { import { Badge } from "@/components/ui/badge"; import { ModeToggle } from "@/components/ModeToggle"; -import Navbar from "@/components/navbar"; +import Navbar from "@/components/Navbar"; export function App() { // init selected index diff --git a/src/translate/zh_CN.ts b/src/translate/zh_CN.ts index a4eeb3a..edf60cd 100644 --- a/src/translate/zh_CN.ts +++ b/src/translate/zh_CN.ts @@ -11,6 +11,8 @@ const LANG_MAP: Record = { cost: "消费", stream: "流式返回", fetch: "一次获取", + Tools: "工具", + Clear: "清空", "saved api templates": "已保存的 API 模板", "saved prompt templates": "已保存的提示模板", "no chat history here": "暂无历史对话记录", From c4dc89784d62e8e70e2fccb79d3aaa4941930da9 Mon Sep 17 00:00:00 2001 From: ecwu Date: Sun, 5 Jan 2025 20:00:17 +0800 Subject: [PATCH 20/30] refactor: replace AddImage component with ImageUploadDrawer and add ImageGenDrawer for enhanced image handling --- src/addImage.tsx | 369 --------------------------- src/components/ImageGenDrawer.tsx | 213 ++++++++++++++++ src/components/ImageUploadDrawer.tsx | 187 ++++++++++++++ src/pages/Chatbox.tsx | 21 +- 4 files changed, 419 insertions(+), 371 deletions(-) create mode 100644 src/components/ImageGenDrawer.tsx create mode 100644 src/components/ImageUploadDrawer.tsx diff --git a/src/addImage.tsx b/src/addImage.tsx index 14f6e99..e69de29 100644 --- a/src/addImage.tsx +++ b/src/addImage.tsx @@ -1,369 +0,0 @@ -import { useContext, useState } from "react"; -import { ChatStore } from "@/types/chatstore"; -import { MessageDetail } from "@/chatgpt"; -import { Tr } from "@/translate"; - -import { - Drawer, - DrawerClose, - DrawerContent, - DrawerDescription, - DrawerFooter, - DrawerHeader, - DrawerTitle, - DrawerTrigger, -} from "@/components/ui/drawer"; - -import { Button } from "./components/ui/button"; -import { PenIcon, XIcon } from "lucide-react"; -import { Checkbox } from "./components/ui/checkbox"; -import { Label } from "./components/ui/label"; -import { Textarea } from "./components/ui/textarea"; -import { Separator } from "./components/ui/separator"; -import { AppContext } from "./pages/App"; - -interface Props { - images: MessageDetail[]; - showAddImage: boolean; - setShowAddImage: (se: boolean) => void; - setImages: (images: MessageDetail[]) => void; -} -interface ImageResponse { - url?: string; - b64_json?: string; - revised_prompt: string; -} -export function AddImage({ - showAddImage, - setShowAddImage, - setImages, - images, -}: Props) { - const ctx = useContext(AppContext); - if (ctx === null) return <>; - - const [enableHighResolution, setEnableHighResolution] = useState(true); - const [imageGenPrompt, setImageGenPrompt] = useState(""); - const [imageGenModel, setImageGenModel] = useState("dall-e-3"); - const [imageGenN, setImageGenN] = useState(1); - const [imageGenQuality, setImageGEnQuality] = useState("standard"); - const [imageGenResponseFormat, setImageGenResponseFormat] = - useState("b64_json"); - const [imageGenSize, setImageGenSize] = useState("1024x1024"); - const [imageGenStyle, setImageGenStyle] = useState("vivid"); - const [imageGenGenerating, setImageGenGenerating] = useState(false); - useState("b64_json"); - return ( - - -
- - Add Images - -
- - -
- - setEnableHighResolution(checked === true) - } - /> - -
-
- - {ctx.chatStore.image_gen_api && ctx.chatStore.image_gen_key && ( -
-

Generate Image

- - -