move status to AppContext
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useState } from "react";
|
||||
import { useContext, useState } from "react";
|
||||
import { ChatStore } from "@/types/chatstore";
|
||||
import { MessageDetail } from "@/chatgpt";
|
||||
import { Tr } from "@/translate";
|
||||
@@ -20,10 +20,9 @@ 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 {
|
||||
chatStore: ChatStore;
|
||||
setChatStore: (cs: ChatStore) => void;
|
||||
images: MessageDetail[];
|
||||
showAddImage: boolean;
|
||||
setShowAddImage: (se: boolean) => void;
|
||||
@@ -35,13 +34,14 @@ interface ImageResponse {
|
||||
revised_prompt: string;
|
||||
}
|
||||
export function AddImage({
|
||||
chatStore,
|
||||
setChatStore,
|
||||
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");
|
||||
@@ -134,7 +134,7 @@ export function AddImage({
|
||||
</div>
|
||||
</div>
|
||||
<Separator className="my-2" />
|
||||
{chatStore.image_gen_api && chatStore.image_gen_key && (
|
||||
{ctx.chatStore.image_gen_api && ctx.chatStore.image_gen_key && (
|
||||
<div className="flex flex-col">
|
||||
<h3>Generate Image</h3>
|
||||
<span className="flex flex-col justify-between m-1 p-1">
|
||||
@@ -240,11 +240,11 @@ export function AddImage({
|
||||
body.style = imageGenStyle;
|
||||
}
|
||||
const resp: ImageResponse[] = (
|
||||
await fetch(chatStore.image_gen_api, {
|
||||
await fetch(ctx.chatStore.image_gen_api, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${chatStore.image_gen_key}`,
|
||||
Authorization: `Bearer ${ctx.chatStore.image_gen_key}`,
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
}).then((resp) => resp.json())
|
||||
@@ -258,7 +258,7 @@ export function AddImage({
|
||||
url = "data:image/png;base64," + image.b64_json;
|
||||
if (!url) continue;
|
||||
|
||||
chatStore.history.push({
|
||||
ctx.chatStore.history.push({
|
||||
role: "assistant",
|
||||
content: [
|
||||
{
|
||||
@@ -281,7 +281,7 @@ export function AddImage({
|
||||
response_model_name: imageGenModel,
|
||||
});
|
||||
|
||||
setChatStore({ ...chatStore });
|
||||
ctx.setChatStore({ ...ctx.chatStore });
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
||||
@@ -77,6 +77,7 @@ import {
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { Slider } from "@/components/ui/slider";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
import { AppContext } from "@/pages/App";
|
||||
|
||||
const TTS_VOICES: string[] = [
|
||||
"alloy",
|
||||
@@ -96,14 +97,13 @@ const Help = (props: { children: any; help: string; field: string }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const SelectModel = (props: {
|
||||
chatStore: ChatStore;
|
||||
setChatStore: (cs: ChatStore) => void;
|
||||
help: string;
|
||||
}) => {
|
||||
const SelectModel = (props: { help: string }) => {
|
||||
const ctx = useContext(AppContext);
|
||||
if (ctx === null) return <></>;
|
||||
|
||||
let shouldIUseCustomModel: boolean = true;
|
||||
for (const model in models) {
|
||||
if (props.chatStore.model === model) {
|
||||
if (ctx.chatStore.model === model) {
|
||||
shouldIUseCustomModel = false;
|
||||
}
|
||||
}
|
||||
@@ -143,22 +143,22 @@ const SelectModel = (props: {
|
||||
|
||||
{useCustomModel ? (
|
||||
<Input
|
||||
value={props.chatStore.model}
|
||||
value={ctx.chatStore.model}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
props.chatStore.model = e.target.value;
|
||||
props.setChatStore({ ...props.chatStore });
|
||||
ctx.chatStore.model = e.target.value;
|
||||
ctx.setChatStore({ ...ctx.chatStore });
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<Select
|
||||
value={props.chatStore.model}
|
||||
value={ctx.chatStore.model}
|
||||
onValueChange={(model: string) => {
|
||||
props.chatStore.model = model;
|
||||
props.chatStore.maxTokens = getDefaultParams(
|
||||
ctx.chatStore.model = model;
|
||||
ctx.chatStore.maxTokens = getDefaultParams(
|
||||
"max",
|
||||
models[model].maxToken
|
||||
);
|
||||
props.setChatStore({ ...props.chatStore });
|
||||
ctx.setChatStore({ ...ctx.chatStore });
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="w-full">
|
||||
@@ -181,12 +181,12 @@ const SelectModel = (props: {
|
||||
};
|
||||
|
||||
const LongInput = (props: {
|
||||
chatStore: ChatStore;
|
||||
setChatStore: (cs: ChatStore) => void;
|
||||
field: "systemMessageContent" | "toolsString";
|
||||
label: string;
|
||||
help: string;
|
||||
}) => {
|
||||
const ctx = useContext(AppContext);
|
||||
if (ctx === null) return <></>;
|
||||
return (
|
||||
<div>
|
||||
<Label htmlFor="name" className="text-right">
|
||||
@@ -208,10 +208,10 @@ const LongInput = (props: {
|
||||
|
||||
<Textarea
|
||||
className="h-24 w-full"
|
||||
value={props.chatStore[props.field]}
|
||||
value={ctx.chatStore[props.field]}
|
||||
onChange={(event: any) => {
|
||||
props.chatStore[props.field] = event.target.value;
|
||||
props.setChatStore({ ...props.chatStore });
|
||||
ctx.chatStore[props.field] = event.target.value;
|
||||
ctx.setChatStore({ ...ctx.chatStore });
|
||||
autoHeight(event.target);
|
||||
}}
|
||||
onKeyPress={(event: any) => {
|
||||
@@ -223,8 +223,6 @@ const LongInput = (props: {
|
||||
};
|
||||
|
||||
const InputField = (props: {
|
||||
chatStore: ChatStore;
|
||||
setChatStore: (cs: ChatStore) => void;
|
||||
field:
|
||||
| "apiKey"
|
||||
| "apiEndpoint"
|
||||
@@ -236,6 +234,8 @@ const InputField = (props: {
|
||||
| "image_gen_key";
|
||||
help: string;
|
||||
}) => {
|
||||
const ctx = useContext(AppContext);
|
||||
if (ctx === null) return <></>;
|
||||
const [hideInput, setHideInput] = useState(true);
|
||||
return (
|
||||
<>
|
||||
@@ -261,10 +261,10 @@ const InputField = (props: {
|
||||
<div className="flex w-full items-center space-x-2">
|
||||
<Input
|
||||
type={hideInput ? "password" : "text"}
|
||||
value={props.chatStore[props.field]}
|
||||
value={ctx.chatStore[props.field]}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
props.chatStore[props.field] = event.target.value;
|
||||
props.setChatStore({ ...props.chatStore });
|
||||
ctx.chatStore[props.field] = event.target.value;
|
||||
ctx.setChatStore({ ...ctx.chatStore });
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
@@ -285,30 +285,30 @@ const InputField = (props: {
|
||||
};
|
||||
|
||||
const Slicer = (props: {
|
||||
chatStore: ChatStore;
|
||||
setChatStore: (cs: ChatStore) => void;
|
||||
field: "temperature" | "top_p" | "tts_speed";
|
||||
help: string;
|
||||
min: number;
|
||||
max: number;
|
||||
}) => {
|
||||
const ctx = useContext(AppContext);
|
||||
if (ctx === null) return <></>;
|
||||
const enable_filed_name: "temperature_enabled" | "top_p_enabled" =
|
||||
`${props.field}_enabled` as any;
|
||||
|
||||
const enabled = props.chatStore[enable_filed_name];
|
||||
const enabled = ctx.chatStore[enable_filed_name];
|
||||
|
||||
if (enabled === null || enabled === undefined) {
|
||||
if (props.field === "temperature") {
|
||||
props.chatStore[enable_filed_name] = true;
|
||||
ctx.chatStore[enable_filed_name] = true;
|
||||
}
|
||||
if (props.field === "top_p") {
|
||||
props.chatStore[enable_filed_name] = false;
|
||||
ctx.chatStore[enable_filed_name] = false;
|
||||
}
|
||||
}
|
||||
|
||||
const setEnabled = (state: boolean) => {
|
||||
props.chatStore[enable_filed_name] = state;
|
||||
props.setChatStore({ ...props.chatStore });
|
||||
ctx.chatStore[enable_filed_name] = state;
|
||||
ctx.setChatStore({ ...ctx.chatStore });
|
||||
};
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
@@ -329,10 +329,10 @@ const Slicer = (props: {
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
<Checkbox
|
||||
checked={props.chatStore[enable_filed_name]}
|
||||
checked={ctx.chatStore[enable_filed_name]}
|
||||
onCheckedChange={(checked: boolean) => setEnabled(!!checked)}
|
||||
/>
|
||||
{!props.chatStore[enable_filed_name] && (
|
||||
{!ctx.chatStore[enable_filed_name] && (
|
||||
<span className="text-xs text-muted-foreground">disabled</span>
|
||||
)}
|
||||
</Label>
|
||||
@@ -345,10 +345,10 @@ const Slicer = (props: {
|
||||
min={props.min}
|
||||
max={props.max}
|
||||
step={0.01}
|
||||
value={[props.chatStore[props.field]]}
|
||||
value={[ctx.chatStore[props.field]]}
|
||||
onValueChange={(value) => {
|
||||
props.chatStore[props.field] = value[0];
|
||||
props.setChatStore({ ...props.chatStore });
|
||||
ctx.chatStore[props.field] = value[0];
|
||||
ctx.setChatStore({ ...ctx.chatStore });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@@ -356,11 +356,11 @@ const Slicer = (props: {
|
||||
type="number"
|
||||
disabled={!enabled}
|
||||
className="w-24"
|
||||
value={props.chatStore[props.field]}
|
||||
value={ctx.chatStore[props.field]}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = parseFloat(e.target.value);
|
||||
props.chatStore[props.field] = value;
|
||||
props.setChatStore({ ...props.chatStore });
|
||||
ctx.chatStore[props.field] = value;
|
||||
ctx.setChatStore({ ...ctx.chatStore });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@@ -370,8 +370,6 @@ const Slicer = (props: {
|
||||
};
|
||||
|
||||
const Number = (props: {
|
||||
chatStore: ChatStore;
|
||||
setChatStore: (cs: ChatStore) => void;
|
||||
field:
|
||||
| "totalTokens"
|
||||
| "maxTokens"
|
||||
@@ -383,6 +381,8 @@ const Number = (props: {
|
||||
readOnly: boolean;
|
||||
help: string;
|
||||
}) => {
|
||||
const ctx = useContext(AppContext);
|
||||
if (ctx === null) return <></>;
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<Label className="flex items-center gap-2">
|
||||
@@ -404,12 +404,12 @@ const Number = (props: {
|
||||
|
||||
{props.field === "maxGenTokens" && (
|
||||
<Checkbox
|
||||
checked={props.chatStore.maxGenTokens_enabled}
|
||||
checked={ctx.chatStore.maxGenTokens_enabled}
|
||||
onCheckedChange={() => {
|
||||
const newChatStore = { ...props.chatStore };
|
||||
const newChatStore = { ...ctx.chatStore };
|
||||
newChatStore.maxGenTokens_enabled =
|
||||
!newChatStore.maxGenTokens_enabled;
|
||||
props.setChatStore({ ...newChatStore });
|
||||
ctx.setChatStore({ ...newChatStore });
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -419,15 +419,14 @@ const Number = (props: {
|
||||
type="number"
|
||||
readOnly={props.readOnly}
|
||||
disabled={
|
||||
props.field === "maxGenTokens" &&
|
||||
!props.chatStore.maxGenTokens_enabled
|
||||
props.field === "maxGenTokens" && !ctx.chatStore.maxGenTokens_enabled
|
||||
}
|
||||
value={props.chatStore[props.field]}
|
||||
value={ctx.chatStore[props.field]}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
let newNumber = parseFloat(event.target.value);
|
||||
if (newNumber < 0) newNumber = 0;
|
||||
props.chatStore[props.field] = newNumber;
|
||||
props.setChatStore({ ...props.chatStore });
|
||||
ctx.chatStore[props.field] = newNumber;
|
||||
ctx.setChatStore({ ...ctx.chatStore });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@@ -435,20 +434,21 @@ const Number = (props: {
|
||||
};
|
||||
|
||||
const Choice = (props: {
|
||||
chatStore: ChatStore;
|
||||
setChatStore: (cs: ChatStore) => void;
|
||||
field: "streamMode" | "develop_mode" | "json_mode" | "logprobs";
|
||||
help: string;
|
||||
}) => {
|
||||
const ctx = useContext(AppContext);
|
||||
if (ctx === null) return <></>;
|
||||
|
||||
return (
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="flex items-center">
|
||||
<Checkbox
|
||||
id={`${props.field}-checkbox`}
|
||||
checked={props.chatStore[props.field]}
|
||||
checked={ctx.chatStore[props.field]}
|
||||
onCheckedChange={(checked: boolean) => {
|
||||
props.chatStore[props.field] = checked;
|
||||
props.setChatStore({ ...props.chatStore });
|
||||
ctx.chatStore[props.field] = checked;
|
||||
ctx.setChatStore({ ...ctx.chatStore });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@@ -475,37 +475,21 @@ const Choice = (props: {
|
||||
);
|
||||
};
|
||||
|
||||
export default (props: {
|
||||
chatStore: ChatStore;
|
||||
setChatStore: (cs: ChatStore) => void;
|
||||
setShow: Dispatch<boolean>;
|
||||
selectedChatStoreIndex: number;
|
||||
templates: TemplateChatStore[];
|
||||
setTemplates: (templates: TemplateChatStore[]) => void;
|
||||
templateAPIs: TemplateAPI[];
|
||||
setTemplateAPIs: (templateAPIs: TemplateAPI[]) => void;
|
||||
templateAPIsWhisper: TemplateAPI[];
|
||||
setTemplateAPIsWhisper: (templateAPIs: TemplateAPI[]) => void;
|
||||
templateAPIsTTS: TemplateAPI[];
|
||||
setTemplateAPIsTTS: (templateAPIs: TemplateAPI[]) => void;
|
||||
templateAPIsImageGen: TemplateAPI[];
|
||||
setTemplateAPIsImageGen: (templateAPIs: TemplateAPI[]) => void;
|
||||
templateTools: TemplateTools[];
|
||||
setTemplateTools: (templateTools: TemplateTools[]) => void;
|
||||
}) => {
|
||||
export default (props: { setShow: Dispatch<boolean> }) => {
|
||||
const ctx = useContext(AppContext);
|
||||
if (ctx === null) return <></>;
|
||||
|
||||
let link =
|
||||
location.protocol +
|
||||
"//" +
|
||||
location.host +
|
||||
location.pathname +
|
||||
`?key=${encodeURIComponent(
|
||||
props.chatStore.apiKey
|
||||
)}&api=${encodeURIComponent(props.chatStore.apiEndpoint)}&mode=${
|
||||
props.chatStore.streamMode ? "stream" : "fetch"
|
||||
}&model=${props.chatStore.model}&sys=${encodeURIComponent(
|
||||
props.chatStore.systemMessageContent
|
||||
)}`;
|
||||
if (props.chatStore.develop_mode) {
|
||||
`?key=${encodeURIComponent(ctx.chatStore.apiKey)}&api=${encodeURIComponent(
|
||||
ctx.chatStore.apiEndpoint
|
||||
)}&mode=${ctx.chatStore.streamMode ? "stream" : "fetch"}&model=${
|
||||
ctx.chatStore.model
|
||||
}&sys=${encodeURIComponent(ctx.chatStore.systemMessageContent)}`;
|
||||
if (ctx.chatStore.develop_mode) {
|
||||
link = link + `&dev=true`;
|
||||
}
|
||||
|
||||
@@ -562,7 +546,7 @@ export default (props: {
|
||||
$ USD
|
||||
</span>
|
||||
<span className="text-lg font-bold leading-none sm:text-3xl">
|
||||
{props.chatStore.cost?.toFixed(4)}
|
||||
{ctx.chatStore.cost?.toFixed(4)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -583,7 +567,7 @@ export default (props: {
|
||||
/>
|
||||
<span className="pt-1">
|
||||
JSON Check:{" "}
|
||||
{isVailedJSON(props.chatStore.toolsString) ? (
|
||||
{isVailedJSON(ctx.chatStore.toolsString) ? (
|
||||
<CheckIcon className="inline w-3 h-3" />
|
||||
) : (
|
||||
<BanIcon className="inline w-3 h-3" />
|
||||
@@ -591,7 +575,7 @@ export default (props: {
|
||||
</span>
|
||||
<div className="box">
|
||||
<div className="flex justify-evenly flex-wrap">
|
||||
{props.chatStore.toolsString.trim() && (
|
||||
{ctx.chatStore.toolsString.trim() && (
|
||||
<Button
|
||||
onClick={() => {
|
||||
const name = prompt(
|
||||
@@ -603,10 +587,10 @@ export default (props: {
|
||||
}
|
||||
const newToolsTmp: TemplateTools = {
|
||||
name,
|
||||
toolsString: props.chatStore.toolsString,
|
||||
toolsString: ctx.chatStore.toolsString,
|
||||
};
|
||||
props.templateTools.push(newToolsTmp);
|
||||
props.setTemplateTools([...props.templateTools]);
|
||||
ctx.templateTools.push(newToolsTmp);
|
||||
ctx.setTemplateTools([...ctx.templateTools]);
|
||||
}}
|
||||
>
|
||||
{Tr(`Save Tools`)}
|
||||
@@ -710,12 +694,12 @@ export default (props: {
|
||||
<Button
|
||||
variant="destructive"
|
||||
onClick={() => {
|
||||
props.chatStore.history =
|
||||
props.chatStore.history.filter(
|
||||
ctx.chatStore.history =
|
||||
ctx.chatStore.history.filter(
|
||||
(msg) => msg.example && !msg.hide
|
||||
);
|
||||
props.chatStore.postBeginIndex = 0;
|
||||
props.setChatStore({ ...props.chatStore });
|
||||
ctx.chatStore.postBeginIndex = 0;
|
||||
ctx.setChatStore({ ...ctx.chatStore });
|
||||
}}
|
||||
>
|
||||
Yes, clear all history
|
||||
@@ -731,14 +715,14 @@ export default (props: {
|
||||
let dataStr =
|
||||
"data:text/json;charset=utf-8," +
|
||||
encodeURIComponent(
|
||||
JSON.stringify(props.chatStore, null, "\t")
|
||||
JSON.stringify(ctx.chatStore, null, "\t")
|
||||
);
|
||||
let downloadAnchorNode =
|
||||
document.createElement("a");
|
||||
downloadAnchorNode.setAttribute("href", dataStr);
|
||||
downloadAnchorNode.setAttribute(
|
||||
"download",
|
||||
`chatgpt-api-web-${props.selectedChatStoreIndex}.json`
|
||||
`chatgpt-api-web-${ctx.selectedChatIndex}.json`
|
||||
);
|
||||
document.body.appendChild(downloadAnchorNode);
|
||||
downloadAnchorNode.click();
|
||||
@@ -760,7 +744,7 @@ export default (props: {
|
||||
return;
|
||||
}
|
||||
const tmp: ChatStore = structuredClone(
|
||||
props.chatStore
|
||||
ctx.chatStore
|
||||
);
|
||||
tmp.history = tmp.history.filter((h) => h.example);
|
||||
tmp.apiEndpoint = "";
|
||||
@@ -773,8 +757,8 @@ export default (props: {
|
||||
tmp.image_gen_key = "";
|
||||
// @ts-ignore
|
||||
tmp.name = name;
|
||||
props.templates.push(tmp as TemplateChatStore);
|
||||
props.setTemplates([...props.templates]);
|
||||
ctx.templates.push(tmp as TemplateChatStore);
|
||||
ctx.setTemplates([...ctx.templates]);
|
||||
}}
|
||||
>
|
||||
{Tr("As template")}
|
||||
@@ -826,7 +810,7 @@ export default (props: {
|
||||
langCode
|
||||
);
|
||||
}
|
||||
props.setChatStore({ ...newChatStore });
|
||||
ctx.setChatStore({ ...newChatStore });
|
||||
} catch (e) {
|
||||
alert(
|
||||
tr(
|
||||
@@ -868,10 +852,10 @@ export default (props: {
|
||||
/>
|
||||
<SetAPIsTemplate
|
||||
label="Chat API"
|
||||
endpoint={props.chatStore.apiEndpoint}
|
||||
APIkey={props.chatStore.apiKey}
|
||||
tmps={props.templateAPIs}
|
||||
setTmps={props.setTemplateAPIs}
|
||||
endpoint={ctx.chatStore.apiEndpoint}
|
||||
APIkey={ctx.chatStore.apiKey}
|
||||
tmps={ctx.templateAPIs}
|
||||
setTmps={ctx.setTemplateAPIs}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -973,10 +957,10 @@ export default (props: {
|
||||
/>
|
||||
<SetAPIsTemplate
|
||||
label="Whisper API"
|
||||
endpoint={props.chatStore.whisper_api}
|
||||
APIkey={props.chatStore.whisper_key}
|
||||
tmps={props.templateAPIsWhisper}
|
||||
setTmps={props.setTemplateAPIsWhisper}
|
||||
endpoint={ctx.chatStore.whisper_api}
|
||||
APIkey={ctx.chatStore.whisper_key}
|
||||
tmps={ctx.templateAPIsWhisper}
|
||||
setTmps={ctx.setTemplateAPIsWhisper}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -1006,10 +990,10 @@ export default (props: {
|
||||
/>
|
||||
<SetAPIsTemplate
|
||||
label="TTS API"
|
||||
endpoint={props.chatStore.tts_api}
|
||||
APIkey={props.chatStore.tts_key}
|
||||
tmps={props.templateAPIsTTS}
|
||||
setTmps={props.setTemplateAPIsTTS}
|
||||
endpoint={ctx.chatStore.tts_api}
|
||||
APIkey={ctx.chatStore.tts_key}
|
||||
tmps={ctx.templateAPIsTTS}
|
||||
setTmps={ctx.setTemplateAPIsTTS}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -1034,10 +1018,10 @@ export default (props: {
|
||||
</Dialog>
|
||||
</Label>
|
||||
<Select
|
||||
value={props.chatStore.tts_voice}
|
||||
value={ctx.chatStore.tts_voice}
|
||||
onValueChange={(value) => {
|
||||
props.chatStore.tts_voice = value;
|
||||
props.setChatStore({ ...props.chatStore });
|
||||
ctx.chatStore.tts_voice = value;
|
||||
ctx.setChatStore({ ...ctx.chatStore });
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="w-full">
|
||||
@@ -1084,10 +1068,10 @@ export default (props: {
|
||||
</Dialog>
|
||||
</Label>
|
||||
<Select
|
||||
value={props.chatStore.tts_format}
|
||||
value={ctx.chatStore.tts_format}
|
||||
onValueChange={(value) => {
|
||||
props.chatStore.tts_format = value;
|
||||
props.setChatStore({ ...props.chatStore });
|
||||
ctx.chatStore.tts_format = value;
|
||||
ctx.setChatStore({ ...ctx.chatStore });
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="w-full">
|
||||
@@ -1131,10 +1115,10 @@ export default (props: {
|
||||
/>
|
||||
<SetAPIsTemplate
|
||||
label="Image Gen API"
|
||||
endpoint={props.chatStore.image_gen_api}
|
||||
APIkey={props.chatStore.image_gen_key}
|
||||
tmps={props.templateAPIsImageGen}
|
||||
setTmps={props.setTemplateAPIsImageGen}
|
||||
endpoint={ctx.chatStore.image_gen_api}
|
||||
APIkey={ctx.chatStore.image_gen_key}
|
||||
tmps={ctx.templateAPIsImageGen}
|
||||
setTmps={ctx.setTemplateAPIsImageGen}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -1144,7 +1128,7 @@ export default (props: {
|
||||
<div className="pt-4 space-y-2">
|
||||
<p className="text-sm text-muted-foreground text-center">
|
||||
chatgpt-api-web ChatStore {Tr("Version")}{" "}
|
||||
{props.chatStore.chatgpt_api_web_version}
|
||||
{ctx.chatStore.chatgpt_api_web_version}
|
||||
</p>
|
||||
<p className="text-sm text-muted-foreground text-center">
|
||||
{Tr("Documents and source code are avaliable here")}:{" "}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { AppContext } from "@/pages/App";
|
||||
import { TemplateChatStore } from "@/types/chatstore";
|
||||
import { ChatStore } from "@/types/chatstore";
|
||||
import { getDefaultParams } from "@/utils/getDefaultParam";
|
||||
import { useContext } from "react";
|
||||
|
||||
const Templates = () => {
|
||||
const ctx = useContext(AppContext);
|
||||
if (ctx === null) return <></>;
|
||||
const { templates, chatStore, setChatStore, setTemplates } = ctx;
|
||||
|
||||
const Templates = (props: {
|
||||
templates: TemplateChatStore[];
|
||||
chatStore: ChatStore;
|
||||
setChatStore: (cs: ChatStore) => void;
|
||||
setTemplates: (templates: TemplateChatStore[]) => void;
|
||||
}) => {
|
||||
const { templates, chatStore, setChatStore, setTemplates } = props;
|
||||
return (
|
||||
<>
|
||||
{templates.map((t, index) => (
|
||||
|
||||
@@ -13,61 +13,54 @@ import {
|
||||
} 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 {
|
||||
chatStore: ChatStore;
|
||||
setChatStore: (cs: ChatStore) => void;
|
||||
tmps: TemplateAPI[];
|
||||
setTmps: (tmps: TemplateAPI[]) => void;
|
||||
label: string;
|
||||
apiField: string;
|
||||
keyField: string;
|
||||
}
|
||||
export function ListAPIs({
|
||||
tmps,
|
||||
setTmps,
|
||||
chatStore,
|
||||
setChatStore,
|
||||
label,
|
||||
apiField,
|
||||
keyField,
|
||||
}: Props) {
|
||||
export function ListAPIs({ label, apiField, keyField }: Props) {
|
||||
const ctx = useContext(AppContext);
|
||||
if (ctx === null) return <></>;
|
||||
|
||||
return (
|
||||
<NavigationMenuItem>
|
||||
<NavigationMenuTrigger>
|
||||
{label}{" "}
|
||||
<span className="hidden lg:inline">
|
||||
{tmps.find(
|
||||
{ctx.templateAPIs.find(
|
||||
(t) =>
|
||||
chatStore[apiField as keyof ChatStore] === t.endpoint &&
|
||||
chatStore[keyField as keyof ChatStore] === t.key
|
||||
ctx.chatStore[apiField as keyof ChatStore] === t.endpoint &&
|
||||
ctx.chatStore[keyField as keyof ChatStore] === t.key
|
||||
)?.name &&
|
||||
`: ${
|
||||
tmps.find(
|
||||
ctx.templateAPIs.find(
|
||||
(t) =>
|
||||
chatStore[apiField as keyof ChatStore] === t.endpoint &&
|
||||
chatStore[keyField as keyof ChatStore] === t.key
|
||||
ctx.chatStore[apiField as keyof ChatStore] === t.endpoint &&
|
||||
ctx.chatStore[keyField as keyof ChatStore] === t.key
|
||||
)?.name
|
||||
}`}
|
||||
</span>
|
||||
</NavigationMenuTrigger>
|
||||
<NavigationMenuContent>
|
||||
<ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px] ">
|
||||
{tmps.map((t, index) => (
|
||||
{ctx.templateAPIs.map((t, index) => (
|
||||
<li>
|
||||
<NavigationMenuLink asChild>
|
||||
<a
|
||||
onClick={() => {
|
||||
// @ts-ignore
|
||||
chatStore[apiField] = t.endpoint;
|
||||
ctx.chatStore[apiField as keyof ChatStore] = t.endpoint;
|
||||
// @ts-ignore
|
||||
chatStore[keyField] = t.key;
|
||||
setChatStore({ ...chatStore });
|
||||
ctx.chatStore[keyField] = t.key;
|
||||
ctx.setChatStore({ ...ctx.chatStore });
|
||||
}}
|
||||
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",
|
||||
chatStore[apiField as keyof ChatStore] === t.endpoint &&
|
||||
chatStore[keyField as keyof ChatStore] === t.key
|
||||
ctx.chatStore[apiField as keyof ChatStore] === t.endpoint &&
|
||||
ctx.chatStore[keyField as keyof ChatStore] === t.key
|
||||
? "bg-accent text-accent-foreground"
|
||||
: ""
|
||||
)}
|
||||
@@ -88,7 +81,7 @@ export function ListAPIs({
|
||||
const name = prompt(`Give **${label}** template a name`);
|
||||
if (!name) return;
|
||||
t.name = name;
|
||||
setTmps(structuredClone(tmps));
|
||||
ctx.setTemplateAPIs(structuredClone(ctx.templateAPIs));
|
||||
}}
|
||||
>
|
||||
Edit
|
||||
@@ -104,8 +97,8 @@ export function ListAPIs({
|
||||
) {
|
||||
return;
|
||||
}
|
||||
tmps.splice(index, 1);
|
||||
setTmps(structuredClone(tmps));
|
||||
ctx.templateAPIs.splice(index, 1);
|
||||
ctx.setTemplateAPIs(structuredClone(ctx.templateAPIs));
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { XMarkIcon } from "@heroicons/react/24/outline";
|
||||
import Markdown from "react-markdown";
|
||||
import { useState } from "react";
|
||||
import { useContext, useState } from "react";
|
||||
|
||||
import { Tr, langCodeContext, LANG_OPTIONS } from "@/translate";
|
||||
import { ChatStore, ChatStoreMessage } from "@/types/chatstore";
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
MessageSquareOffIcon,
|
||||
MessageSquarePlusIcon,
|
||||
} from "lucide-react";
|
||||
import { AppContext } from "./pages/App";
|
||||
|
||||
export const isVailedJSON = (str: string): boolean => {
|
||||
try {
|
||||
@@ -36,14 +37,12 @@ export const isVailedJSON = (str: string): boolean => {
|
||||
return true;
|
||||
};
|
||||
|
||||
interface Props {
|
||||
messageIndex: number;
|
||||
chatStore: ChatStore;
|
||||
setChatStore: (cs: ChatStore) => void;
|
||||
}
|
||||
export default function Message(props: { messageIndex: number }) {
|
||||
const ctx = useContext(AppContext);
|
||||
if (ctx === null) return <></>;
|
||||
const { messageIndex } = props;
|
||||
const { chatStore, setChatStore } = ctx;
|
||||
|
||||
export default function Message(props: Props) {
|
||||
const { chatStore, messageIndex, setChatStore } = props;
|
||||
const chat = chatStore.history[messageIndex];
|
||||
const [showEdit, setShowEdit] = useState(false);
|
||||
const [showCopiedHint, setShowCopiedHint] = useState(false);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { openDB } from "idb";
|
||||
import { useEffect, useState } from "react";
|
||||
import { IDBPDatabase, openDB } from "idb";
|
||||
import { createContext, useEffect, useState } from "react";
|
||||
import "@/global.css";
|
||||
|
||||
import { calculate_token_length } from "@/chatgpt";
|
||||
@@ -14,6 +14,43 @@ import { STORAGE_NAME, STORAGE_NAME_SELECTED } from "@/const";
|
||||
import { upgrade } from "@/indexedDB/upgrade";
|
||||
import { getTotalCost } from "@/utils/totalCost";
|
||||
|
||||
import {
|
||||
STORAGE_NAME_TEMPLATE,
|
||||
STORAGE_NAME_TEMPLATE_API,
|
||||
STORAGE_NAME_TEMPLATE_API_IMAGE_GEN,
|
||||
STORAGE_NAME_TEMPLATE_API_TTS,
|
||||
STORAGE_NAME_TEMPLATE_API_WHISPER,
|
||||
STORAGE_NAME_TEMPLATE_TOOLS,
|
||||
} from "@/const";
|
||||
import {
|
||||
ChatStoreMessage,
|
||||
TemplateChatStore,
|
||||
TemplateAPI,
|
||||
TemplateTools,
|
||||
} from "../types/chatstore";
|
||||
|
||||
interface AppContextType {
|
||||
db: Promise<IDBPDatabase<ChatStore>>;
|
||||
chatStore: ChatStore;
|
||||
setChatStore: (cs: ChatStore) => void;
|
||||
selectedChatIndex: number;
|
||||
setSelectedChatIndex: (i: number) => void;
|
||||
templates: TemplateChatStore[];
|
||||
setTemplates: (t: TemplateChatStore[]) => void;
|
||||
templateAPIs: TemplateAPI[];
|
||||
setTemplateAPIs: (t: TemplateAPI[]) => void;
|
||||
templateAPIsWhisper: TemplateAPI[];
|
||||
setTemplateAPIsWhisper: (t: TemplateAPI[]) => void;
|
||||
templateAPIsTTS: TemplateAPI[];
|
||||
setTemplateAPIsTTS: (t: TemplateAPI[]) => void;
|
||||
templateAPIsImageGen: TemplateAPI[];
|
||||
setTemplateAPIsImageGen: (t: TemplateAPI[]) => void;
|
||||
templateTools: TemplateTools[];
|
||||
setTemplateTools: (t: TemplateTools[]) => void;
|
||||
}
|
||||
|
||||
export const AppContext = createContext<AppContextType | null>(null);
|
||||
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
@@ -247,6 +284,77 @@ export function App() {
|
||||
run();
|
||||
}, []);
|
||||
|
||||
const [templates, _setTemplates] = useState(
|
||||
JSON.parse(
|
||||
localStorage.getItem(STORAGE_NAME_TEMPLATE) || "[]"
|
||||
) as TemplateChatStore[]
|
||||
);
|
||||
const [templateAPIs, _setTemplateAPIs] = useState(
|
||||
JSON.parse(
|
||||
localStorage.getItem(STORAGE_NAME_TEMPLATE_API) || "[]"
|
||||
) as TemplateAPI[]
|
||||
);
|
||||
const [templateAPIsWhisper, _setTemplateAPIsWhisper] = useState(
|
||||
JSON.parse(
|
||||
localStorage.getItem(STORAGE_NAME_TEMPLATE_API_WHISPER) || "[]"
|
||||
) as TemplateAPI[]
|
||||
);
|
||||
const [templateAPIsTTS, _setTemplateAPIsTTS] = useState(
|
||||
JSON.parse(
|
||||
localStorage.getItem(STORAGE_NAME_TEMPLATE_API_TTS) || "[]"
|
||||
) as TemplateAPI[]
|
||||
);
|
||||
const [templateAPIsImageGen, _setTemplateAPIsImageGen] = useState(
|
||||
JSON.parse(
|
||||
localStorage.getItem(STORAGE_NAME_TEMPLATE_API_IMAGE_GEN) || "[]"
|
||||
) as TemplateAPI[]
|
||||
);
|
||||
const [templateTools, _setTemplateTools] = useState(
|
||||
JSON.parse(
|
||||
localStorage.getItem(STORAGE_NAME_TEMPLATE_TOOLS) || "[]"
|
||||
) as TemplateTools[]
|
||||
);
|
||||
const setTemplates = (templates: TemplateChatStore[]) => {
|
||||
localStorage.setItem(STORAGE_NAME_TEMPLATE, JSON.stringify(templates));
|
||||
_setTemplates(templates);
|
||||
};
|
||||
const setTemplateAPIs = (templateAPIs: TemplateAPI[]) => {
|
||||
localStorage.setItem(
|
||||
STORAGE_NAME_TEMPLATE_API,
|
||||
JSON.stringify(templateAPIs)
|
||||
);
|
||||
_setTemplateAPIs(templateAPIs);
|
||||
};
|
||||
const setTemplateAPIsWhisper = (templateAPIWhisper: TemplateAPI[]) => {
|
||||
localStorage.setItem(
|
||||
STORAGE_NAME_TEMPLATE_API_WHISPER,
|
||||
JSON.stringify(templateAPIWhisper)
|
||||
);
|
||||
_setTemplateAPIsWhisper(templateAPIWhisper);
|
||||
};
|
||||
const setTemplateAPIsTTS = (templateAPITTS: TemplateAPI[]) => {
|
||||
localStorage.setItem(
|
||||
STORAGE_NAME_TEMPLATE_API_TTS,
|
||||
JSON.stringify(templateAPITTS)
|
||||
);
|
||||
_setTemplateAPIsTTS(templateAPITTS);
|
||||
};
|
||||
const setTemplateAPIsImageGen = (templateAPIImageGen: TemplateAPI[]) => {
|
||||
localStorage.setItem(
|
||||
STORAGE_NAME_TEMPLATE_API_IMAGE_GEN,
|
||||
JSON.stringify(templateAPIImageGen)
|
||||
);
|
||||
_setTemplateAPIsImageGen(templateAPIImageGen);
|
||||
};
|
||||
const setTemplateTools = (templateTools: TemplateTools[]) => {
|
||||
localStorage.setItem(
|
||||
STORAGE_NAME_TEMPLATE_TOOLS,
|
||||
JSON.stringify(templateTools)
|
||||
);
|
||||
_setTemplateTools(templateTools);
|
||||
};
|
||||
console.log("[PERFORMANCE!] reading localStorage");
|
||||
|
||||
return (
|
||||
<>
|
||||
<Sidebar>
|
||||
@@ -410,13 +518,29 @@ export function App() {
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<ChatBOX
|
||||
db={db}
|
||||
chatStore={chatStore}
|
||||
setChatStore={setChatStore}
|
||||
selectedChatIndex={selectedChatIndex}
|
||||
setSelectedChatIndex={setSelectedChatIndex}
|
||||
/>
|
||||
<AppContext.Provider
|
||||
value={{
|
||||
db,
|
||||
chatStore,
|
||||
setChatStore,
|
||||
selectedChatIndex,
|
||||
setSelectedChatIndex,
|
||||
templates,
|
||||
setTemplates,
|
||||
templateAPIs,
|
||||
setTemplateAPIs,
|
||||
templateAPIsWhisper,
|
||||
setTemplateAPIsWhisper,
|
||||
templateAPIsTTS,
|
||||
setTemplateAPIsTTS,
|
||||
templateAPIsImageGen,
|
||||
setTemplateAPIsImageGen,
|
||||
templateTools,
|
||||
setTemplateTools,
|
||||
}}
|
||||
>
|
||||
<ChatBOX />
|
||||
</AppContext.Provider>
|
||||
</SidebarInset>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
import { IDBPDatabase } from "idb";
|
||||
import { useRef } from "react";
|
||||
import { useContext, useRef } from "react";
|
||||
import { useEffect, useState, Dispatch } from "react";
|
||||
import { Tr, langCodeContext, LANG_OPTIONS } from "@/translate";
|
||||
import {
|
||||
STORAGE_NAME_TEMPLATE,
|
||||
STORAGE_NAME_TEMPLATE_API,
|
||||
STORAGE_NAME_TEMPLATE_API_IMAGE_GEN,
|
||||
STORAGE_NAME_TEMPLATE_API_TTS,
|
||||
STORAGE_NAME_TEMPLATE_API_WHISPER,
|
||||
STORAGE_NAME_TEMPLATE_TOOLS,
|
||||
} from "@/const";
|
||||
import { addTotalCost, getTotalCost } from "@/utils/totalCost";
|
||||
import ChatGPT, {
|
||||
calculate_token_length,
|
||||
@@ -79,14 +71,18 @@ import {
|
||||
navigationMenuTriggerStyle,
|
||||
} from "@/components/ui/navigation-menu";
|
||||
|
||||
export default function ChatBOX(props: {
|
||||
db: Promise<IDBPDatabase<ChatStore>>;
|
||||
chatStore: ChatStore;
|
||||
setChatStore: (cs: ChatStore) => void;
|
||||
selectedChatIndex: number;
|
||||
setSelectedChatIndex: Dispatch<number>;
|
||||
}) {
|
||||
const { chatStore, setChatStore } = props;
|
||||
import { AppContext } from "./App";
|
||||
|
||||
export default function ChatBOX() {
|
||||
const ctx = useContext(AppContext);
|
||||
if (ctx === null) return <></>;
|
||||
const {
|
||||
db,
|
||||
chatStore,
|
||||
setChatStore,
|
||||
selectedChatIndex,
|
||||
setSelectedChatIndex,
|
||||
} = ctx;
|
||||
// prevent error
|
||||
if (chatStore === undefined) return <div></div>;
|
||||
const [inputMsg, setInputMsg] = useState("");
|
||||
@@ -357,7 +353,7 @@ export default function ChatBOX(props: {
|
||||
alert(error);
|
||||
} finally {
|
||||
setShowGenerating(false);
|
||||
props.setSelectedChatIndex(props.selectedChatIndex);
|
||||
setSelectedChatIndex(selectedChatIndex);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -401,102 +397,13 @@ export default function ChatBOX(props: {
|
||||
};
|
||||
|
||||
const [showSettings, setShowSettings] = useState(false);
|
||||
|
||||
const [templates, _setTemplates] = useState(
|
||||
JSON.parse(
|
||||
localStorage.getItem(STORAGE_NAME_TEMPLATE) || "[]"
|
||||
) as TemplateChatStore[]
|
||||
);
|
||||
const [templateAPIs, _setTemplateAPIs] = useState(
|
||||
JSON.parse(
|
||||
localStorage.getItem(STORAGE_NAME_TEMPLATE_API) || "[]"
|
||||
) as TemplateAPI[]
|
||||
);
|
||||
const [templateAPIsWhisper, _setTemplateAPIsWhisper] = useState(
|
||||
JSON.parse(
|
||||
localStorage.getItem(STORAGE_NAME_TEMPLATE_API_WHISPER) || "[]"
|
||||
) as TemplateAPI[]
|
||||
);
|
||||
const [templateAPIsTTS, _setTemplateAPIsTTS] = useState(
|
||||
JSON.parse(
|
||||
localStorage.getItem(STORAGE_NAME_TEMPLATE_API_TTS) || "[]"
|
||||
) as TemplateAPI[]
|
||||
);
|
||||
const [templateAPIsImageGen, _setTemplateAPIsImageGen] = useState(
|
||||
JSON.parse(
|
||||
localStorage.getItem(STORAGE_NAME_TEMPLATE_API_IMAGE_GEN) || "[]"
|
||||
) as TemplateAPI[]
|
||||
);
|
||||
const [toolsTemplates, _setToolsTemplates] = useState(
|
||||
JSON.parse(
|
||||
localStorage.getItem(STORAGE_NAME_TEMPLATE_TOOLS) || "[]"
|
||||
) as TemplateTools[]
|
||||
);
|
||||
const setTemplates = (templates: TemplateChatStore[]) => {
|
||||
localStorage.setItem(STORAGE_NAME_TEMPLATE, JSON.stringify(templates));
|
||||
_setTemplates(templates);
|
||||
};
|
||||
const setTemplateAPIs = (templateAPIs: TemplateAPI[]) => {
|
||||
localStorage.setItem(
|
||||
STORAGE_NAME_TEMPLATE_API,
|
||||
JSON.stringify(templateAPIs)
|
||||
);
|
||||
_setTemplateAPIs(templateAPIs);
|
||||
};
|
||||
const setTemplateAPIsWhisper = (templateAPIWhisper: TemplateAPI[]) => {
|
||||
localStorage.setItem(
|
||||
STORAGE_NAME_TEMPLATE_API_WHISPER,
|
||||
JSON.stringify(templateAPIWhisper)
|
||||
);
|
||||
_setTemplateAPIsWhisper(templateAPIWhisper);
|
||||
};
|
||||
const setTemplateAPIsTTS = (templateAPITTS: TemplateAPI[]) => {
|
||||
localStorage.setItem(
|
||||
STORAGE_NAME_TEMPLATE_API_TTS,
|
||||
JSON.stringify(templateAPITTS)
|
||||
);
|
||||
_setTemplateAPIsTTS(templateAPITTS);
|
||||
};
|
||||
const setTemplateAPIsImageGen = (templateAPIImageGen: TemplateAPI[]) => {
|
||||
localStorage.setItem(
|
||||
STORAGE_NAME_TEMPLATE_API_IMAGE_GEN,
|
||||
JSON.stringify(templateAPIImageGen)
|
||||
);
|
||||
_setTemplateAPIsImageGen(templateAPIImageGen);
|
||||
};
|
||||
const setTemplateTools = (templateTools: TemplateTools[]) => {
|
||||
localStorage.setItem(
|
||||
STORAGE_NAME_TEMPLATE_TOOLS,
|
||||
JSON.stringify(templateTools)
|
||||
);
|
||||
_setToolsTemplates(templateTools);
|
||||
};
|
||||
const userInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col p-2 gap-2 w-full">
|
||||
<div className="flex items-center gap-2 justify-between">
|
||||
{true && (
|
||||
<Settings
|
||||
chatStore={chatStore}
|
||||
setChatStore={setChatStore}
|
||||
setShow={setShowSettings}
|
||||
selectedChatStoreIndex={props.selectedChatIndex}
|
||||
templates={templates}
|
||||
setTemplates={setTemplates}
|
||||
templateAPIs={templateAPIs}
|
||||
setTemplateAPIs={setTemplateAPIs}
|
||||
templateAPIsWhisper={templateAPIsWhisper}
|
||||
setTemplateAPIsWhisper={setTemplateAPIsWhisper}
|
||||
templateAPIsTTS={templateAPIsTTS}
|
||||
setTemplateAPIsTTS={setTemplateAPIsTTS}
|
||||
templateAPIsImageGen={templateAPIsImageGen}
|
||||
setTemplateAPIsImageGen={setTemplateAPIsImageGen}
|
||||
templateTools={toolsTemplates}
|
||||
setTemplateTools={setTemplateTools}
|
||||
/>
|
||||
)}
|
||||
{true && <Settings setShow={setShowSettings} />}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
@@ -505,15 +412,7 @@ export default function ChatBOX(props: {
|
||||
<SearchIcon />
|
||||
</Button>
|
||||
</div>
|
||||
{showSearch && (
|
||||
<Search
|
||||
setSelectedChatIndex={props.setSelectedChatIndex}
|
||||
db={props.db}
|
||||
chatStore={chatStore}
|
||||
show={showSearch}
|
||||
setShow={setShowSearch}
|
||||
/>
|
||||
)}
|
||||
{showSearch && <Search show={showSearch} setShow={setShowSearch} />}
|
||||
|
||||
{!chatStore.apiKey && (
|
||||
<Alert>
|
||||
@@ -535,54 +434,30 @@ export default function ChatBOX(props: {
|
||||
)}
|
||||
<NavigationMenu>
|
||||
<NavigationMenuList>
|
||||
{templateAPIs.length > 0 && (
|
||||
<ListAPIs
|
||||
label="API"
|
||||
tmps={templateAPIs}
|
||||
setTmps={setTemplateAPIs}
|
||||
chatStore={chatStore}
|
||||
setChatStore={setChatStore}
|
||||
apiField="apiEndpoint"
|
||||
keyField="apiKey"
|
||||
/>
|
||||
{ctx.templateAPIs.length > 0 && (
|
||||
<ListAPIs label="API" apiField="apiEndpoint" keyField="apiKey" />
|
||||
)}
|
||||
{templateAPIsWhisper.length > 0 && (
|
||||
{ctx.templateAPIsWhisper.length > 0 && (
|
||||
<ListAPIs
|
||||
label="Whisper API"
|
||||
tmps={templateAPIsWhisper}
|
||||
setTmps={setTemplateAPIsWhisper}
|
||||
chatStore={chatStore}
|
||||
setChatStore={setChatStore}
|
||||
apiField="whisper_api"
|
||||
keyField="whisper_key"
|
||||
/>
|
||||
)}
|
||||
{templateAPIsTTS.length > 0 && (
|
||||
<ListAPIs
|
||||
label="TTS API"
|
||||
tmps={templateAPIsTTS}
|
||||
setTmps={setTemplateAPIsTTS}
|
||||
chatStore={chatStore}
|
||||
setChatStore={setChatStore}
|
||||
apiField="tts_api"
|
||||
keyField="tts_key"
|
||||
/>
|
||||
{ctx.templateAPIsTTS.length > 0 && (
|
||||
<ListAPIs label="TTS API" apiField="tts_api" keyField="tts_key" />
|
||||
)}
|
||||
{templateAPIsImageGen.length > 0 && (
|
||||
{ctx.templateAPIsImageGen.length > 0 && (
|
||||
<ListAPIs
|
||||
label="Image Gen API"
|
||||
tmps={templateAPIsImageGen}
|
||||
setTmps={setTemplateAPIsImageGen}
|
||||
chatStore={chatStore}
|
||||
setChatStore={setChatStore}
|
||||
apiField="image_gen_api"
|
||||
keyField="image_gen_key"
|
||||
/>
|
||||
)}
|
||||
{toolsTemplates.length > 0 && (
|
||||
{ctx.templateTools.length > 0 && (
|
||||
<ListToolsTempaltes
|
||||
templateTools={toolsTemplates}
|
||||
setTemplateTools={setTemplateTools}
|
||||
templateTools={ctx.templateTools}
|
||||
setTemplateTools={ctx.setTemplateTools}
|
||||
chatStore={chatStore}
|
||||
setChatStore={setChatStore}
|
||||
/>
|
||||
@@ -611,12 +486,7 @@ export default function ChatBOX(props: {
|
||||
</h2>
|
||||
<div className="divider"></div>
|
||||
<div className="flex flex-wrap">
|
||||
<Templates
|
||||
templates={templates}
|
||||
setTemplates={setTemplates}
|
||||
chatStore={chatStore}
|
||||
setChatStore={setChatStore}
|
||||
/>
|
||||
<Templates />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -675,11 +545,7 @@ export default function ChatBOX(props: {
|
||||
</ChatBubble>
|
||||
)}
|
||||
{chatStore.history.map((_, messageIndex) => (
|
||||
<Message
|
||||
chatStore={chatStore}
|
||||
setChatStore={setChatStore}
|
||||
messageIndex={messageIndex}
|
||||
/>
|
||||
<Message messageIndex={messageIndex} />
|
||||
))}
|
||||
{showGenerating && (
|
||||
<ChatBubble variant="received">
|
||||
@@ -841,8 +707,6 @@ export default function ChatBOX(props: {
|
||||
</form>
|
||||
|
||||
<AddImage
|
||||
chatStore={chatStore}
|
||||
setChatStore={setChatStore}
|
||||
setShowAddImage={setShowAddImage}
|
||||
images={images}
|
||||
showAddImage={showAddImage}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { IDBPDatabase } from "idb";
|
||||
import { useRef, useState, Dispatch } from "react";
|
||||
import { useRef, useState, Dispatch, useContext } from "react";
|
||||
|
||||
import { ChatStore } from "@/types/chatstore";
|
||||
import { MessageDetail } from "./chatgpt";
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
} from "@/components/ui/pagination";
|
||||
|
||||
import { Input } from "./components/ui/input";
|
||||
import { AppContext } from "./pages/App";
|
||||
|
||||
interface ChatStoreSearchResult {
|
||||
key: IDBValidKey;
|
||||
@@ -33,12 +34,13 @@ interface ChatStoreSearchResult {
|
||||
}
|
||||
|
||||
export default function Search(props: {
|
||||
db: Promise<IDBPDatabase<ChatStore>>;
|
||||
setSelectedChatIndex: Dispatch<number>;
|
||||
chatStore: ChatStore;
|
||||
show: boolean;
|
||||
setShow: (show: boolean) => void;
|
||||
}) {
|
||||
const ctx = useContext(AppContext);
|
||||
if (ctx === null) return <></>;
|
||||
const { setSelectedChatIndex, db } = ctx;
|
||||
|
||||
const [searchResult, setSearchResult] = useState<ChatStoreSearchResult[]>([]);
|
||||
const [searching, setSearching] = useState<boolean>(false);
|
||||
const [searchingNow, setSearchingNow] = useState<number>(0);
|
||||
@@ -76,8 +78,8 @@ export default function Search(props: {
|
||||
|
||||
setSearching(true);
|
||||
|
||||
const db = await props.db;
|
||||
const resultKeys = await db.getAllKeys("chatgpt-api-web");
|
||||
const idb = await db;
|
||||
const resultKeys = await idb.getAllKeys("chatgpt-api-web");
|
||||
|
||||
const result: ChatStoreSearchResult[] = [];
|
||||
for (const key of resultKeys) {
|
||||
@@ -91,7 +93,7 @@ export default function Search(props: {
|
||||
);
|
||||
if (now !== searchingNow) setSearchingNow(now);
|
||||
|
||||
const value: ChatStore = await db.get("chatgpt-api-web", key);
|
||||
const value: ChatStore = await idb.get("chatgpt-api-web", key);
|
||||
|
||||
let preview: string = "";
|
||||
for (const msg of value.history) {
|
||||
@@ -157,7 +159,7 @@ export default function Search(props: {
|
||||
className="flex justify-start p-1 m-1 rounded border bg-base-200 cursor-pointer"
|
||||
key={result.key as number}
|
||||
onClick={() => {
|
||||
props.setSelectedChatIndex(parseInt(result.key.toString()));
|
||||
setSelectedChatIndex(parseInt(result.key.toString()));
|
||||
props.setShow(false);
|
||||
}}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user