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 */}
-
-
-
-
-
-
-
- );
-};
-
-export default StatusBar;
diff --git a/src/components/theme-provider.tsx b/src/components/ThemeProvider.tsx
similarity index 96%
rename from src/components/theme-provider.tsx
rename to src/components/ThemeProvider.tsx
index 7b9eeb2..d35ebbf 100644
--- a/src/components/theme-provider.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/WhisperButton.tsx b/src/components/WhisperButton.tsx
index 9029907..b0165ab 100644
--- a/src/components/WhisperButton.tsx
+++ b/src/components/WhisperButton.tsx
@@ -1,15 +1,8 @@
import { createRef, useContext } from "react";
-import { ChatStore } from "@/types/chatstore";
-import { useEffect, useState, Dispatch } from "react";
+import { 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: {
@@ -24,128 +17,137 @@ const WhisperButton = (props: {
const mediaRef = createRef();
const [isRecording, setIsRecording] = useState("Mic");
return (
-
+
Use Microphone
+ >
);
};
diff --git a/src/editMessage.tsx b/src/components/editMessage.tsx
similarity index 90%
rename from src/editMessage.tsx
rename to src/components/editMessage.tsx
index a06fda9..632a513 100644
--- a/src/editMessage.tsx
+++ b/src/components/editMessage.tsx
@@ -1,8 +1,8 @@
import { useState, useEffect, Dispatch, useContext } from "react";
import { Tr, langCodeContext, LANG_OPTIONS, tr } from "@/translate";
import { ChatStore, ChatStoreMessage } from "@/types/chatstore";
-import { EditMessageString } from "@/editMessageString";
-import { EditMessageDetail } from "@/editMessageDetail";
+import { EditMessageString } from "@/components/editMessageString";
+import { EditMessageDetail } from "@/components/editMessageDetail";
import {
Dialog,
@@ -12,8 +12,8 @@ import {
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
-import { Button } from "./components/ui/button";
-import { AppContext } from "./pages/App";
+import { Button } from "./ui/button";
+import { AppContext } from "../pages/App";
interface EditMessageProps {
chat: ChatStoreMessage;
diff --git a/src/editMessageDetail.tsx b/src/components/editMessageDetail.tsx
similarity index 98%
rename from src/editMessageDetail.tsx
rename to src/components/editMessageDetail.tsx
index 4d3549d..9dddb33 100644
--- a/src/editMessageDetail.tsx
+++ b/src/components/editMessageDetail.tsx
@@ -13,9 +13,9 @@ import {
DrawerTrigger,
} from "@/components/ui/drawer";
-import { Button } from "./components/ui/button";
+import { Button } from "./ui/button";
import { useContext } from "react";
-import { AppContext } from "./pages/App";
+import { AppContext } from "../pages/App";
interface Props {
chat: ChatStoreMessage;
diff --git a/src/editMessageString.tsx b/src/components/editMessageString.tsx
similarity index 97%
rename from src/editMessageString.tsx
rename to src/components/editMessageString.tsx
index f04a794..6487ebc 100644
--- a/src/editMessageString.tsx
+++ b/src/components/editMessageString.tsx
@@ -1,11 +1,11 @@
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";
import { Textarea } from "@/components/ui/textarea";
import { useContext } from "react";
-import { AppContext } from "./pages/App";
+import { AppContext } from "../pages/App";
interface Props {
chat: ChatStoreMessage;
diff --git a/src/components/mode-toggle.tsx b/src/components/mode-toggle.tsx
deleted file mode 100644
index 6490f27..0000000
--- a/src/components/mode-toggle.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import { Moon, Sun } from "lucide-react";
-
-import { Button } from "@/components/ui/button";
-import {
- DropdownMenu,
- DropdownMenuContent,
- DropdownMenuItem,
- DropdownMenuTrigger,
-} from "@/components/ui/dropdown-menu";
-import { useTheme } from "@/components/theme-provider";
-
-export function ModeToggle() {
- const { setTheme } = useTheme();
-
- return (
-
-
-
-
-
- Toggle theme
-
-
-
- setTheme("light")}>
- Light
-
- setTheme("dark")}>
- Dark
-
- setTheme("system")}>
- System
-
-
-
- );
-}
diff --git a/src/components/navbar.tsx b/src/components/navbar.tsx
new file mode 100644
index 0000000..68923c8
--- /dev/null
+++ b/src/components/navbar.tsx
@@ -0,0 +1,143 @@
+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 { 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";
+import Search from "@/components/Search";
+import Settings from "@/components/Settings";
+
+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/components/setAPIsTemplate.tsx b/src/components/setAPIsTemplate.tsx
new file mode 100644
index 0000000..4f1b8e4
--- /dev/null
+++ b/src/components/setAPIsTemplate.tsx
@@ -0,0 +1,91 @@
+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 "./ui/button";
+import { Input } from "@/components/ui/input";
+import { Label } from "@/components/ui/label";
+import { SaveIcon } from "lucide-react";
+
+interface Props {
+ temps: TemplateAPI[];
+ setTemps: (temps: TemplateAPI[]) => void;
+ label: string;
+ endpoint: string;
+ APIkey: string;
+}
+export function SetAPIsTemplate({
+ endpoint,
+ APIkey,
+ temps: temps,
+ setTemps: setTemps,
+ label,
+}: Props) {
+ return (
+
+ );
+}
diff --git a/src/listAPIs.tsx b/src/listAPIs.tsx
deleted file mode 100644
index de8ed72..0000000
--- a/src/listAPIs.tsx
+++ /dev/null
@@ -1,113 +0,0 @@
-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";
-import { useContext } from "react";
-import { AppContext } from "./pages/App";
-
-interface Props {
- label: string;
- apiField: string;
- keyField: string;
-}
-export function ListAPIs({ label, apiField, keyField }: Props) {
- const ctx = useContext(AppContext);
- if (ctx === null) return <>>;
-
- return (
-
-
- {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/listToolsTemplates.tsx b/src/listToolsTemplates.tsx
deleted file mode 100644
index 682be1e..0000000
--- a/src/listToolsTemplates.tsx
+++ /dev/null
@@ -1,101 +0,0 @@
-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() {
- const ctx = useContext(AppContext);
- if (!ctx) return
error
;
-
- const { chatStore, setChatStore } = ctx;
-
- return (
-
-
- {Tr(`Saved tools templates`)}
- {
- chatStore.toolsString = "";
- setChatStore({ ...chatStore });
- }}
- >
- {Tr(`Clear`)}
-
-
-
-
-
-
- );
-}
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/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 dc0f33f..b4e7d20 100644
--- a/src/pages/App.tsx
+++ b/src/pages/App.tsx
@@ -113,7 +113,9 @@ 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";
export function App() {
// init selected index
@@ -213,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);
@@ -356,7 +362,27 @@ export function App() {
console.log("[PERFORMANCE!] reading localStorage");
return (
- <>
+
@@ -392,6 +418,7 @@ export function App() {
+
{Tr("DEL")}
@@ -422,126 +449,9 @@ export function App() {
-
-
-
-
-
{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
-
-
-
-
-
-
-
-
-
-
-
-
+
+
- >
+
);
}
diff --git a/src/pages/Chatbox.tsx b/src/pages/Chatbox.tsx
index 3199a57..3315057 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,33 +11,17 @@ import ChatGPT, {
Logprobs,
Usage,
} from "@/chatgpt";
-import {
- ChatStore,
- ChatStoreMessage,
- TemplateChatStore,
- TemplateAPI,
- TemplateTools,
-} from "../types/chatstore";
-import Message from "@/message";
+import { ChatStoreMessage } from "../types/chatstore";
+import Message from "@/components/MessageBubble";
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 { ImageUploadDrawer } from "@/components/ImageUploadDrawer";
+import { autoHeight } from "@/utils/textAreaHelp";
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";
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,
@@ -46,33 +29,19 @@ import {
import { ChatMessageList } from "@/components/ui/chat/chat-message-list";
import {
- AlertTriangleIcon,
- ArrowUpIcon,
+ ArrowDownToDotIcon,
CornerDownLeftIcon,
CornerLeftUpIcon,
- CornerUpLeftIcon,
- GlobeIcon,
- ImageIcon,
+ CornerRightUpIcon,
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";
+import APIListMenu from "@/components/ListAPI";
+import { ImageGenDrawer } from "@/components/ImageGenDrawer";
export default function ChatBOX() {
const ctx = useContext(AppContext);
@@ -89,11 +58,10 @@ export default function ChatBOX() {
const [inputMsg, setInputMsg] = useState("");
const [images, setImages] = useState
([]);
const [showAddImage, setShowAddImage] = useState(false);
+ const [showGenImage, setShowGenImage] = useState(false);
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";
@@ -423,116 +391,38 @@ export default function ChatBOX() {
}
};
- const [showSettings, setShowSettings] = useState(false);
const userInputRef = useRef(null);
return (
<>
-
-
- {true && }
- setShowSearch(true)}
- >
-
-
-
- {showSearch &&
}
-
- {!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 && (
-
- )}
- {ctx.templateAPIsWhisper.length > 0 && (
-
- )}
- {ctx.templateAPIsTTS.length > 0 && (
-
- )}
- {ctx.templateAPIsImageGen.length > 0 && (
-
- )}
- {ctx.templateTools.length > 0 && }
-
-
-
+
- {chatStore.history.filter((msg) => !msg.example).length == 0 && (
-
-
- {Tr("Saved prompt templates")}
- {
- chatStore.systemMessageContent = "";
- chatStore.toolsString = "";
- chatStore.history = [];
- setChatStore({ ...chatStore });
- }}
- >
- {Tr("Reset Current")}
-
-
-
-
-
-
-
- )}
{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"
@@ -549,7 +439,8 @@ export default function ChatBOX() {
System Prompt
setShowSettings(true)}
+ // onClick={() => setShowSettings(true)}
+ // TODO: add a button to show settings
>
{chatStore.systemMessageContent}
@@ -558,14 +449,19 @@ export default function ChatBOX() {
}
- onClick={() => setShowSettings(true)}
+ icon={}
+ onClick={() => {
+ chatStore.systemMessageContent = "";
+ chatStore.toolsString = "";
+ chatStore.history = [];
+ setChatStore({ ...chatStore });
+ }}
/>
)}
{chatStore.history.map((_, messageIndex) => (
-
+
))}
{showGenerating && (
@@ -686,23 +582,14 @@ export default function ChatBOX() {
className="min-h-12 resize-none rounded-lg bg-background border-0 p-3 shadow-none focus-visible:ring-0"
/>
- setShowAddImage(true)}
- disabled={showGenerating}
- >
-
- Add Image
-
+
+
- {chatStore.whisper_api && chatStore.whisper_key && (
- <>
-
- Use Microphone
- >
- )}
+
-
-
>
);
diff --git a/src/setAPIsTemplate.tsx b/src/setAPIsTemplate.tsx
deleted file mode 100644
index 0bb2936..0000000
--- a/src/setAPIsTemplate.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import { TemplateAPI } from "@/types/chatstore";
-import { Tr } from "@/translate";
-import { Button } from "./components/ui/button";
-
-interface Props {
- tmps: TemplateAPI[];
- setTmps: (tmps: TemplateAPI[]) => void;
- label: string;
- endpoint: string;
- APIkey: string;
-}
-export function SetAPIsTemplate({
- endpoint,
- APIkey,
- tmps,
- setTmps,
- label,
-}: Props) {
- return (
- {
- const name = prompt(`Give this **${label}** template a name:`);
- if (!name) {
- alert("No template name specified");
- return;
- }
- const tmp: TemplateAPI = {
- name,
- endpoint,
- key: APIkey,
- };
- tmps.push(tmp);
- setTmps([...tmps]);
- }}
- >
- {Tr(`Save ${label}`)}
-
- );
-}
diff --git a/src/translate/zh_CN.ts b/src/translate/zh_CN.ts
index 11a8863..edf60cd 100644
--- a/src/translate/zh_CN.ts
+++ b/src/translate/zh_CN.ts
@@ -11,9 +11,17 @@ const LANG_MAP: Record = {
cost: "消费",
stream: "流式返回",
fetch: "一次获取",
+ Tools: "工具",
+ Clear: "清空",
"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 新建对话",
diff --git a/src/tts.tsx b/src/tts.tsx
deleted file mode 100644
index 26f3b90..0000000
--- a/src/tts.tsx
+++ /dev/null
@@ -1,97 +0,0 @@
-import { SpeakerWaveIcon } from "@heroicons/react/24/outline";
-import { useContext, useMemo, useState } from "react";
-
-import { addTotalCost } from "@/utils/totalCost";
-import { ChatStore, ChatStoreMessage } from "@/types/chatstore";
-import { Message, getMessageText } from "@/chatgpt";
-import { AudioLinesIcon, LoaderCircleIcon } from "lucide-react";
-import { Button } from "./components/ui/button";
-import { AppContext } from "./pages/App";
-
-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 ;
- }
- return <>>;
-}
-export default function TTSButton(props: TTSProps) {
- const [generating, setGenerating] = useState(false);
- const ctx = useContext(AppContext);
- if (!ctx) return error
;
-
- return (
- {
- const api = ctx.chatStore.tts_api;
- const api_key = ctx.chatStore.tts_key;
- const model = "tts-1";
- const input = getMessageText(props.chat);
- const voice = ctx.chatStore.tts_voice;
-
- const body: Record = {
- model,
- input,
- voice,
- response_format: ctx.chatStore.tts_format || "mp3",
- };
- if (ctx.chatStore.tts_speed_enabled) {
- body["speed"] = ctx.chatStore.tts_speed;
- }
-
- setGenerating(true);
-
- fetch(api, {
- method: "POST",
- headers: {
- Authorization: `Bearer ${api_key}`,
- "Content-Type": "application/json",
- },
- body: JSON.stringify(body),
- })
- .then((response) => response.blob())
- .then((blob) => {
- // update price
- const cost = (input.length * 0.015) / 1000;
- ctx.chatStore.cost += cost;
- addTotalCost(cost);
- ctx.setChatStore({ ...ctx.chatStore });
-
- // save blob
- props.chat.audio = blob;
- ctx.setChatStore({ ...ctx.chatStore });
-
- const url = URL.createObjectURL(blob);
- const audio = new Audio(url);
- audio.play();
- })
- .finally(() => {
- setGenerating(false);
- });
- }}
- >
- {generating ? (
-
- ) : (
-
- )}
-
- );
-}
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;
+};
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
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