import { themeChange } from "theme-change";
import {
InformationCircleIcon,
CheckIcon,
NoSymbolIcon,
CogIcon,
KeyIcon,
EyeIcon,
EllipsisHorizontalCircleIcon,
HandRaisedIcon,
AdjustmentsHorizontalIcon,
Cog6ToothIcon,
ListBulletIcon,
} from "@heroicons/react/24/outline";
import { createRef } from "preact";
import {
StateUpdater,
useContext,
useEffect,
useState,
Dispatch,
} from "preact/hooks";
import { clearTotalCost, getTotalCost } from "@/utils/totalCost";
import {
ChatStore,
TemplateChatStore,
TemplateAPI,
TemplateTools,
} from "@/types/chatstore";
import { models } from "@/types/models";
import { tr, Tr, langCodeContext, LANG_OPTIONS } from "@/translate";
import { isVailedJSON } from "@/message";
import { SetAPIsTemplate } from "@/setAPIsTemplate";
import { autoHeight } from "@/textarea";
import { getDefaultParams } from "@/utils/getDefaultParam";
const TTS_VOICES: string[] = [
"alloy",
"echo",
"fable",
"onyx",
"nova",
"shimmer",
];
const TTS_FORMAT: string[] = ["mp3", "opus", "aac", "flac"];
const Help = (props: { children: any; help: string; field: string }) => {
return (
);
};
const SelectModel = (props: {
chatStore: ChatStore;
setChatStore: (cs: ChatStore) => void;
help: string;
}) => {
let shouldIUseCustomModel: boolean = true;
for (const model in models) {
if (props.chatStore.model === model) {
shouldIUseCustomModel = false;
}
}
const [useCustomModel, setUseCustomModel] = useState(shouldIUseCustomModel);
return (
Model
{" "}
{Tr("Custom")}
{
setUseCustomModel(!useCustomModel);
}}
/>
{/*
Top Right label */}
);
};
const LongInput = (props: {
chatStore: ChatStore;
setChatStore: (cs: ChatStore) => void;
field: "systemMessageContent" | "toolsString";
label: string;
help: string;
}) => {
return (
);
};
const Input = (props: {
chatStore: ChatStore;
setChatStore: (cs: ChatStore) => void;
field:
| "apiKey"
| "apiEndpoint"
| "whisper_api"
| "whisper_key"
| "tts_api"
| "tts_key"
| "image_gen_api"
| "image_gen_key";
help: string;
}) => {
const [hideInput, setHideInput] = useState(true);
return (
{props.field}
);
};
const Slicer = (props: {
chatStore: ChatStore;
setChatStore: (cs: ChatStore) => void;
field: "temperature" | "top_p" | "tts_speed";
help: string;
min: number;
max: number;
}) => {
const enable_filed_name: "temperature_enabled" | "top_p_enabled" =
`${props.field}_enabled` as any;
const enabled = props.chatStore[enable_filed_name];
if (enabled === null || enabled === undefined) {
if (props.field === "temperature") {
props.chatStore[enable_filed_name] = true;
}
if (props.field === "top_p") {
props.chatStore[enable_filed_name] = false;
}
}
const setEnabled = (state: boolean) => {
props.chatStore[enable_filed_name] = state;
props.setChatStore({ ...props.chatStore });
};
return (
{enabled ? (
{
const value = parseFloat(event.target.value);
props.chatStore[props.field] = value;
props.setChatStore({ ...props.chatStore });
}}
/>
{
const value = parseFloat(event.target.value);
props.chatStore[props.field] = value;
props.setChatStore({ ...props.chatStore });
}}
/>
) : (
""
)}
);
};
const Number = (props: {
chatStore: ChatStore;
setChatStore: (cs: ChatStore) => void;
field:
| "totalTokens"
| "maxTokens"
| "maxGenTokens"
| "tokenMargin"
| "postBeginIndex"
| "presence_penalty"
| "frequency_penalty";
readOnly: boolean;
help: string;
}) => {
return (
{
console.log("type", typeof event.target.value);
let newNumber = parseFloat(event.target.value);
if (newNumber < 0) newNumber = 0;
props.chatStore[props.field] = newNumber;
props.setChatStore({ ...props.chatStore });
}}
>
);
};
const Choice = (props: {
chatStore: ChatStore;
setChatStore: (cs: ChatStore) => void;
field: "streamMode" | "develop_mode" | "json_mode" | "logprobs";
help: string;
}) => {
return (
{props.field}
{
props.chatStore[props.field] = event.target.checked;
props.setChatStore({ ...props.chatStore });
}}
/>
);
};
export default (props: {
chatStore: ChatStore;
setChatStore: (cs: ChatStore) => void;
setShow: Dispatch>;
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;
}) => {
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) {
link = link + `&dev=true`;
}
const importFileRef = createRef();
const [totalCost, setTotalCost] = useState(getTotalCost());
// @ts-ignore
const { langCode, setLangCode } = useContext(langCodeContext);
useEffect(() => {
themeChange(false);
const handleKeyPress = (event: any) => {
if (event.keyCode === 27) {
// keyCode for ESC key is 27
props.setShow(false);
}
};
document.addEventListener("keydown", handleKeyPress);
return () => {
document.removeEventListener("keydown", handleKeyPress);
};
}, []); // The empty dependency array ensures that the effect runs only once
return (
props.setShow(false)}
className="left-0 top-0 overflow-scroll flex justify-center absolute w-full h-full z-10"
>
{
event.stopPropagation();
}}
className="modal-box"
>
{Tr("Settings")}
Session
Session cost
{props.chatStore.cost.toFixed(4)} $
JSON Check:{" "}
{isVailedJSON(props.chatStore.toolsString) ? (
) : (
)}
{props.chatStore.toolsString.trim() && (
)}
System
Accumulated cost
{totalCost.toFixed(4)} $
Theme Switch
Language
Quick Actions
{
const file = importFileRef.current.files[0];
console.log("file to import", file);
if (!file || file.type !== "application/json") {
alert(tr("Please select a json file", langCode));
return;
}
const reader = new FileReader();
reader.onload = () => {
console.log("import content", reader.result);
if (!reader) {
alert(tr("Empty file", langCode));
return;
}
try {
const newChatStore: ChatStore = JSON.parse(
reader.result as string,
);
if (!newChatStore.chatgpt_api_web_version) {
throw tr(
"This is not an exported chatgpt-api-web chatstore file. The key 'chatgpt_api_web_version' is missing!",
langCode,
);
}
props.setChatStore({ ...newChatStore });
} catch (e) {
alert(
tr(`Import error on parsing json:`, langCode) +
`${e}`,
);
}
};
reader.readAsText(file);
}}
/>
);
};