move status to AppContext

This commit is contained in:
2024-12-27 17:39:03 +08:00
parent 0aacbeccb2
commit 092ac46c15
8 changed files with 317 additions and 351 deletions

View File

@@ -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")}:{" "}

View File

@@ -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) => (