@@ -29,10 +29,22 @@ import {
|
|||||||
PopoverContent,
|
PopoverContent,
|
||||||
PopoverTrigger,
|
PopoverTrigger,
|
||||||
} from "@/components/ui/popover";
|
} from "@/components/ui/popover";
|
||||||
import { BrushIcon } from "lucide-react";
|
import { BrushIcon, DeleteIcon, EditIcon } from "lucide-react";
|
||||||
|
|
||||||
import { useToast } from "@/hooks/use-toast";
|
import { useToast } from "@/hooks/use-toast";
|
||||||
import { newChatStore } from "@/types/newChatstore";
|
import { newChatStore } from "@/types/newChatstore";
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTrigger,
|
||||||
|
} from "./ui/dialog";
|
||||||
|
import { DialogTitle } from "@radix-ui/react-dialog";
|
||||||
|
import { Textarea } from "./ui/textarea";
|
||||||
|
import { Label } from "./ui/label";
|
||||||
|
import { Input } from "./ui/input";
|
||||||
|
import { SetAPIsTemplate } from "./setAPIsTemplate";
|
||||||
|
import { isVailedJSON } from "@/utils/isVailedJSON";
|
||||||
|
|
||||||
interface APITemplateDropdownProps {
|
interface APITemplateDropdownProps {
|
||||||
label: string;
|
label: string;
|
||||||
@@ -46,17 +58,29 @@ function APIsDropdownList({
|
|||||||
apiField,
|
apiField,
|
||||||
keyField,
|
keyField,
|
||||||
}: APITemplateDropdownProps) {
|
}: APITemplateDropdownProps) {
|
||||||
const ctxAppChatStore = useContext(AppChatStoreContext);
|
const { chatStore, setChatStore } = useContext(AppChatStoreContext);
|
||||||
const ctxApp = useContext(AppContext);
|
const {
|
||||||
let API = ctxApp.templateAPIs;
|
templates,
|
||||||
|
templateAPIs,
|
||||||
|
templateAPIsImageGen,
|
||||||
|
templateAPIsTTS,
|
||||||
|
templateAPIsWhisper,
|
||||||
|
setTemplates,
|
||||||
|
setTemplateAPIs,
|
||||||
|
setTemplateAPIsImageGen,
|
||||||
|
setTemplateAPIsTTS,
|
||||||
|
setTemplateAPIsWhisper,
|
||||||
|
setTemplateTools,
|
||||||
|
} = useContext(AppContext);
|
||||||
|
let API = templateAPIs;
|
||||||
if (label === "Chat API") {
|
if (label === "Chat API") {
|
||||||
API = ctxApp.templateAPIs;
|
API = templateAPIs;
|
||||||
} else if (label === "Whisper API") {
|
} else if (label === "Whisper API") {
|
||||||
API = ctxApp.templateAPIsWhisper;
|
API = templateAPIsWhisper;
|
||||||
} else if (label === "TTS API") {
|
} else if (label === "TTS API") {
|
||||||
API = ctxApp.templateAPIsTTS;
|
API = templateAPIsTTS;
|
||||||
} else if (label === "Image Gen API") {
|
} else if (label === "Image Gen API") {
|
||||||
API = ctxApp.templateAPIsImageGen;
|
API = templateAPIsImageGen;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -67,17 +91,14 @@ function APIsDropdownList({
|
|||||||
{label}{" "}
|
{label}{" "}
|
||||||
{API.find(
|
{API.find(
|
||||||
(t: TemplateAPI) =>
|
(t: TemplateAPI) =>
|
||||||
ctxAppChatStore.chatStore[apiField as keyof ChatStore] ===
|
chatStore[apiField as keyof ChatStore] === t.endpoint &&
|
||||||
t.endpoint &&
|
chatStore[keyField as keyof ChatStore] === t.key
|
||||||
ctxAppChatStore.chatStore[keyField as keyof ChatStore] === t.key
|
|
||||||
)?.name &&
|
)?.name &&
|
||||||
`: ${
|
`: ${
|
||||||
API.find(
|
API.find(
|
||||||
(t: TemplateAPI) =>
|
(t: TemplateAPI) =>
|
||||||
ctxAppChatStore.chatStore[apiField as keyof ChatStore] ===
|
chatStore[apiField as keyof ChatStore] === t.endpoint &&
|
||||||
t.endpoint &&
|
chatStore[keyField as keyof ChatStore] === t.key
|
||||||
ctxAppChatStore.chatStore[keyField as keyof ChatStore] ===
|
|
||||||
t.key
|
|
||||||
)?.name
|
)?.name
|
||||||
}`}
|
}`}
|
||||||
</span>
|
</span>
|
||||||
@@ -90,20 +111,17 @@ function APIsDropdownList({
|
|||||||
<a
|
<a
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
ctxAppChatStore.chatStore[apiField as keyof ChatStore] =
|
chatStore[apiField as keyof ChatStore] = t.endpoint;
|
||||||
t.endpoint;
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
ctxAppChatStore.chatStore[keyField] = t.key;
|
chatStore[keyField] = t.key;
|
||||||
ctxAppChatStore.setChatStore({
|
setChatStore({
|
||||||
...ctxAppChatStore.chatStore,
|
...chatStore,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
"block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground",
|
"block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground",
|
||||||
ctxAppChatStore.chatStore[apiField as keyof ChatStore] ===
|
chatStore[apiField as keyof ChatStore] === t.endpoint &&
|
||||||
t.endpoint &&
|
chatStore[keyField as keyof ChatStore] === t.key
|
||||||
ctxAppChatStore.chatStore[keyField as keyof ChatStore] ===
|
|
||||||
t.key
|
|
||||||
? "bg-accent text-accent-foreground"
|
? "bg-accent text-accent-foreground"
|
||||||
: ""
|
: ""
|
||||||
)}
|
)}
|
||||||
@@ -198,7 +216,7 @@ function ChatTemplateDropdownList() {
|
|||||||
const ctx = useContext(AppContext);
|
const ctx = useContext(AppContext);
|
||||||
|
|
||||||
const { chatStore, setChatStore } = useContext(AppChatStoreContext);
|
const { chatStore, setChatStore } = useContext(AppChatStoreContext);
|
||||||
const { templates } = useContext(AppContext);
|
const { templates, setTemplates } = useContext(AppContext);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavigationMenuItem>
|
<NavigationMenuItem>
|
||||||
@@ -209,32 +227,7 @@ function ChatTemplateDropdownList() {
|
|||||||
<NavigationMenuContent>
|
<NavigationMenuContent>
|
||||||
<ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px]">
|
<ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px]">
|
||||||
{templates.map((t: TemplateChatStore, index: number) => (
|
{templates.map((t: TemplateChatStore, index: number) => (
|
||||||
<li key={index}>
|
<ChatTemplateItem key={index} t={t} index={index} />
|
||||||
<NavigationMenuLink asChild>
|
|
||||||
<a
|
|
||||||
onClick={() => {
|
|
||||||
// Update chatStore with the selected template
|
|
||||||
if (
|
|
||||||
chatStore.history.length > 0 ||
|
|
||||||
chatStore.systemMessageContent
|
|
||||||
) {
|
|
||||||
const confirm = window.confirm(
|
|
||||||
"This will replace the current chat history. Are you sure?"
|
|
||||||
);
|
|
||||||
if (!confirm) return;
|
|
||||||
}
|
|
||||||
setChatStore({ ...t });
|
|
||||||
}}
|
|
||||||
className={cn(
|
|
||||||
"block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div className="text-sm font-medium leading-none">
|
|
||||||
{t.name}
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</NavigationMenuLink>
|
|
||||||
</li>
|
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</NavigationMenuContent>
|
</NavigationMenuContent>
|
||||||
@@ -242,6 +235,107 @@ function ChatTemplateDropdownList() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ChatTemplateItem = ({
|
||||||
|
t,
|
||||||
|
index,
|
||||||
|
}: {
|
||||||
|
t: TemplateChatStore;
|
||||||
|
index: number;
|
||||||
|
}) => {
|
||||||
|
const [dialogOpen, setDialogOpen] = React.useState(false);
|
||||||
|
const { chatStore, setChatStore } = useContext(AppChatStoreContext);
|
||||||
|
const { templates, setTemplates } = useContext(AppContext);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li>
|
||||||
|
<NavigationMenuLink asChild>
|
||||||
|
<a
|
||||||
|
onClick={() => {
|
||||||
|
// Update chatStore with the selected template
|
||||||
|
if (
|
||||||
|
chatStore.history.length > 0 ||
|
||||||
|
chatStore.systemMessageContent
|
||||||
|
) {
|
||||||
|
console.log("you clicked", t.name);
|
||||||
|
const confirm = window.confirm(
|
||||||
|
"This will replace the current chat history. Are you sure?"
|
||||||
|
);
|
||||||
|
if (!confirm) return;
|
||||||
|
}
|
||||||
|
setChatStore({ ...newChatStore({ ...chatStore, ...t }) });
|
||||||
|
}}
|
||||||
|
className={cn(
|
||||||
|
"flex flex-row justify-between items-center select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className="text-sm font-medium leading-non">{t.name}</div>
|
||||||
|
<div onClick={(e) => e.stopPropagation()}>
|
||||||
|
<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
|
||||||
|
<DialogTrigger asChild>
|
||||||
|
<EditIcon />
|
||||||
|
</DialogTrigger>
|
||||||
|
<DialogContent>
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Edit Template</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
|
<Label>Template Name</Label>
|
||||||
|
<Input
|
||||||
|
value={t.name}
|
||||||
|
onBlur={(e) => {
|
||||||
|
t.name = e.target.value;
|
||||||
|
templates[index] = t;
|
||||||
|
setTemplates([...templates]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<p>
|
||||||
|
Raw JSON allows you to modify any content within the template.
|
||||||
|
You can remove unnecessary fields, and non-existent fields
|
||||||
|
will be inherited from the current session.
|
||||||
|
</p>
|
||||||
|
<Textarea
|
||||||
|
className="h-64"
|
||||||
|
value={JSON.stringify(t, null, 2)}
|
||||||
|
onBlur={(e) => {
|
||||||
|
try {
|
||||||
|
const json = JSON.parse(
|
||||||
|
e.target.value
|
||||||
|
) as TemplateChatStore;
|
||||||
|
json.name = t.name;
|
||||||
|
templates[index] = json;
|
||||||
|
setTemplates([...templates]);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
alert("Invalid JSON");
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
variant={"destructive"}
|
||||||
|
onClick={() => {
|
||||||
|
let confirm = window.confirm(
|
||||||
|
"Are you sure you want to delete this template?"
|
||||||
|
);
|
||||||
|
if (!confirm) return;
|
||||||
|
templates.splice(index, 1);
|
||||||
|
setTemplates([...templates]);
|
||||||
|
setDialogOpen(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</Button>
|
||||||
|
<Button type="submit" onClick={() => setDialogOpen(false)}>
|
||||||
|
Close
|
||||||
|
</Button>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</NavigationMenuLink>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const APIListMenu: React.FC = () => {
|
const APIListMenu: React.FC = () => {
|
||||||
const ctx = useContext(AppContext);
|
const ctx = useContext(AppContext);
|
||||||
return (
|
return (
|
||||||
|
|||||||
Reference in New Issue
Block a user