feat: add URL parameter configuration import dialog and related functionality
This commit is contained in:
129
src/components/ImportDialog.tsx
Normal file
129
src/components/ImportDialog.tsx
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
import { Tr } from "@/translate";
|
||||||
|
import {
|
||||||
|
AlertDialog,
|
||||||
|
AlertDialogAction,
|
||||||
|
AlertDialogCancel,
|
||||||
|
AlertDialogContent,
|
||||||
|
AlertDialogDescription,
|
||||||
|
AlertDialogFooter,
|
||||||
|
AlertDialogHeader,
|
||||||
|
AlertDialogTitle,
|
||||||
|
} from "./ui/alert-dialog";
|
||||||
|
import { useContext } from "react";
|
||||||
|
import { AppChatStoreContext, AppContext } from "@/pages/App";
|
||||||
|
import { STORAGE_NAME } from "@/const";
|
||||||
|
|
||||||
|
const Item = ({ children }: { children: React.ReactNode }) => (
|
||||||
|
<div className="mt-2">{children}</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const ImportDialog = ({
|
||||||
|
open,
|
||||||
|
setOpen,
|
||||||
|
}: {
|
||||||
|
open: boolean;
|
||||||
|
setOpen: (open: boolean) => void;
|
||||||
|
}) => {
|
||||||
|
const { handleNewChatStoreWithOldOne } = useContext(AppContext);
|
||||||
|
const { chatStore } = useContext(AppChatStoreContext);
|
||||||
|
|
||||||
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
const api = params.get("api");
|
||||||
|
const key = params.get("key");
|
||||||
|
const sys = params.get("sys");
|
||||||
|
const mode = params.get("mode");
|
||||||
|
const model = params.get("model");
|
||||||
|
const max = params.get("max");
|
||||||
|
const temp = params.get("temp");
|
||||||
|
const dev = params.get("dev");
|
||||||
|
const whisper_api = params.get("whisper-api");
|
||||||
|
const whisper_key = params.get("whisper-key");
|
||||||
|
const tts_api = params.get("tts-api");
|
||||||
|
const tts_key = params.get("tts-key");
|
||||||
|
return (
|
||||||
|
<AlertDialog open={open}>
|
||||||
|
<AlertDialogContent>
|
||||||
|
<AlertDialogHeader>
|
||||||
|
<AlertDialogTitle>
|
||||||
|
<Tr>Import Configuration</Tr>
|
||||||
|
</AlertDialogTitle>
|
||||||
|
<AlertDialogDescription className="message-content">
|
||||||
|
<Tr>There are some configurations in the URL, import them?</Tr>
|
||||||
|
{key && <Item>Key: {key}</Item>}
|
||||||
|
{api && <Item>API: {api}</Item>}
|
||||||
|
{sys && <Item>Sys: {sys}</Item>}
|
||||||
|
{mode && <Item>Mode: {mode}</Item>}
|
||||||
|
{model && <Item>Model: {model}</Item>}
|
||||||
|
{max && <Item>Max: {max}</Item>}
|
||||||
|
{temp && <Item>Temp: {temp}</Item>}
|
||||||
|
{dev && <Item>Dev: {dev}</Item>}
|
||||||
|
{whisper_api && <Item>Whisper API: {whisper_api}</Item>}
|
||||||
|
{whisper_key && <Item>Whisper Key: {whisper_key}</Item>}
|
||||||
|
{tts_api && <div className="mt-2">TTS API: {tts_api}</div>}
|
||||||
|
{tts_key && <div className="mt-2">TTS Key: {tts_key}</div>}
|
||||||
|
</AlertDialogDescription>
|
||||||
|
</AlertDialogHeader>
|
||||||
|
<AlertDialogFooter>
|
||||||
|
<AlertDialogCancel onClick={() => setOpen(false)}>
|
||||||
|
<Tr>Cancel</Tr>
|
||||||
|
</AlertDialogCancel>
|
||||||
|
<AlertDialogAction
|
||||||
|
onClick={async () => {
|
||||||
|
params.delete("key");
|
||||||
|
params.delete("api");
|
||||||
|
params.delete("sys");
|
||||||
|
params.delete("mode");
|
||||||
|
params.delete("model");
|
||||||
|
params.delete("max");
|
||||||
|
params.delete("temp");
|
||||||
|
params.delete("dev");
|
||||||
|
params.delete("whisper-api");
|
||||||
|
params.delete("whisper-key");
|
||||||
|
params.delete("tts-api");
|
||||||
|
params.delete("tts-key");
|
||||||
|
|
||||||
|
const newChatStore = structuredClone(chatStore);
|
||||||
|
if (key) newChatStore.apiKey = key;
|
||||||
|
if (api) newChatStore.apiEndpoint = api;
|
||||||
|
if (sys) newChatStore.systemMessageContent = sys;
|
||||||
|
if (mode) newChatStore.streamMode = mode === "stream";
|
||||||
|
if (model) newChatStore.model = model;
|
||||||
|
if (max) {
|
||||||
|
try {
|
||||||
|
newChatStore.maxTokens = parseInt(max);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (temp) {
|
||||||
|
try {
|
||||||
|
newChatStore.temperature = parseFloat(temp);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dev) newChatStore.develop_mode = dev === "true";
|
||||||
|
if (whisper_api) newChatStore.whisper_api = whisper_api;
|
||||||
|
if (whisper_key) newChatStore.whisper_key = whisper_key;
|
||||||
|
if (tts_api) newChatStore.tts_api = tts_api;
|
||||||
|
if (tts_key) newChatStore.tts_key = tts_key;
|
||||||
|
|
||||||
|
await handleNewChatStoreWithOldOne(newChatStore);
|
||||||
|
|
||||||
|
const newUrl =
|
||||||
|
window.location.pathname +
|
||||||
|
(params.toString() ? `?${params}` : "");
|
||||||
|
window.history.replaceState(null, "", newUrl); // 替换URL不刷新页面
|
||||||
|
|
||||||
|
setOpen(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Tr>Import</Tr>
|
||||||
|
</AlertDialogAction>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ImportDialog;
|
||||||
@@ -10,7 +10,6 @@ import { tr, Tr, langCodeContext, LANG_OPTIONS } from "@/translate";
|
|||||||
import { isVailedJSON } from "@/utils/isVailedJSON";
|
import { isVailedJSON } from "@/utils/isVailedJSON";
|
||||||
import { SetAPIsTemplate } from "@/components/setAPIsTemplate";
|
import { SetAPIsTemplate } from "@/components/setAPIsTemplate";
|
||||||
import { autoHeight } from "@/utils/textAreaHelp";
|
import { autoHeight } from "@/utils/textAreaHelp";
|
||||||
import { getDefaultParams } from "@/utils/getDefaultParam";
|
|
||||||
|
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
@@ -153,10 +152,7 @@ const SelectModel = (props: { help: string }) => {
|
|||||||
value={chatStore.model}
|
value={chatStore.model}
|
||||||
onValueChange={(model: string) => {
|
onValueChange={(model: string) => {
|
||||||
chatStore.model = model;
|
chatStore.model = model;
|
||||||
chatStore.maxTokens = getDefaultParams(
|
chatStore.maxTokens = models[model].maxToken;
|
||||||
"max",
|
|
||||||
models[model].maxToken
|
|
||||||
);
|
|
||||||
setChatStore({ ...chatStore });
|
setChatStore({ ...chatStore });
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { AppChatStoreContext, AppContext } from "@/pages/App";
|
import { AppChatStoreContext, AppContext } from "@/pages/App";
|
||||||
import { TemplateChatStore } from "@/types/chatstore";
|
import { TemplateChatStore } from "@/types/chatstore";
|
||||||
import { ChatStore } from "@/types/chatstore";
|
import { ChatStore } from "@/types/chatstore";
|
||||||
import { getDefaultParams } from "@/utils/getDefaultParam";
|
|
||||||
import { useContext } from "react";
|
import { useContext } from "react";
|
||||||
|
|
||||||
const Templates = () => {
|
const Templates = () => {
|
||||||
@@ -18,51 +17,6 @@ const Templates = () => {
|
|||||||
const newChatStore: ChatStore = structuredClone(t);
|
const newChatStore: ChatStore = structuredClone(t);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
delete newChatStore.name;
|
delete newChatStore.name;
|
||||||
if (!newChatStore.apiEndpoint) {
|
|
||||||
newChatStore.apiEndpoint = getDefaultParams(
|
|
||||||
"api",
|
|
||||||
chatStore.apiEndpoint
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (!newChatStore.apiKey) {
|
|
||||||
newChatStore.apiKey = getDefaultParams("key", chatStore.apiKey);
|
|
||||||
}
|
|
||||||
if (!newChatStore.whisper_api) {
|
|
||||||
newChatStore.whisper_api = getDefaultParams(
|
|
||||||
"whisper-api",
|
|
||||||
chatStore.whisper_api
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (!newChatStore.whisper_key) {
|
|
||||||
newChatStore.whisper_key = getDefaultParams(
|
|
||||||
"whisper-key",
|
|
||||||
chatStore.whisper_key
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (!newChatStore.tts_api) {
|
|
||||||
newChatStore.tts_api = getDefaultParams(
|
|
||||||
"tts-api",
|
|
||||||
chatStore.tts_api
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (!newChatStore.tts_key) {
|
|
||||||
newChatStore.tts_key = getDefaultParams(
|
|
||||||
"tts-key",
|
|
||||||
chatStore.tts_key
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (!newChatStore.image_gen_api) {
|
|
||||||
newChatStore.image_gen_api = getDefaultParams(
|
|
||||||
"image-gen-api",
|
|
||||||
chatStore.image_gen_api
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (!newChatStore.image_gen_key) {
|
|
||||||
newChatStore.image_gen_key = getDefaultParams(
|
|
||||||
"image-gen-key",
|
|
||||||
chatStore.image_gen_key
|
|
||||||
);
|
|
||||||
}
|
|
||||||
newChatStore.cost = 0;
|
newChatStore.cost = 0;
|
||||||
|
|
||||||
// manage undefined value because of version update
|
// manage undefined value because of version update
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
@import 'highlight.js/styles/monokai.css';
|
@import "highlight.js/styles/monokai.css";
|
||||||
|
|
||||||
@tailwind base;
|
@tailwind base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ interface AppContextType {
|
|||||||
defaultRenderMD: boolean;
|
defaultRenderMD: boolean;
|
||||||
setDefaultRenderMD: (b: boolean) => void;
|
setDefaultRenderMD: (b: boolean) => void;
|
||||||
handleNewChatStore: () => Promise<void>;
|
handleNewChatStore: () => Promise<void>;
|
||||||
|
handleNewChatStoreWithOldOne: (chatStore: ChatStore) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AppChatStoreContextType {
|
interface AppChatStoreContextType {
|
||||||
@@ -96,6 +97,7 @@ import Search from "@/components/Search";
|
|||||||
|
|
||||||
import Navbar from "@/components/navbar";
|
import Navbar from "@/components/navbar";
|
||||||
import ConversationTitle from "@/components/ConversationTitle.";
|
import ConversationTitle from "@/components/ConversationTitle.";
|
||||||
|
import ImportDialog from "@/components/ImportDialog";
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
// init selected index
|
// init selected index
|
||||||
@@ -194,9 +196,28 @@ export function App() {
|
|||||||
window.location.reload();
|
window.location.reload();
|
||||||
};
|
};
|
||||||
|
|
||||||
// if there are any params in URL, create a new chatStore
|
const [showImportDialog, setShowImportDialog] = useState(false);
|
||||||
|
// if there are any params in URL, show the alert dialog to import configure
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const run = async () => {
|
const run = async () => {
|
||||||
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
if (
|
||||||
|
params.get("api") ||
|
||||||
|
params.get("key") ||
|
||||||
|
params.get("sys") ||
|
||||||
|
params.get("mode") ||
|
||||||
|
params.get("model") ||
|
||||||
|
params.get("max") ||
|
||||||
|
params.get("temp") ||
|
||||||
|
params.get("dev") ||
|
||||||
|
params.get("whisper-api") ||
|
||||||
|
params.get("whisper-key") ||
|
||||||
|
params.get("tts-api") ||
|
||||||
|
params.get("tts-key")
|
||||||
|
) {
|
||||||
|
setShowImportDialog(true);
|
||||||
|
}
|
||||||
|
/*
|
||||||
const chatStore = await getChatStoreByIndex(selectedChatIndex);
|
const chatStore = await getChatStoreByIndex(selectedChatIndex);
|
||||||
const api = getDefaultParams("api", "");
|
const api = getDefaultParams("api", "");
|
||||||
const key = getDefaultParams("key", "");
|
const key = getDefaultParams("key", "");
|
||||||
@@ -224,6 +245,7 @@ export function App() {
|
|||||||
handleNewChatStore();
|
handleNewChatStore();
|
||||||
}
|
}
|
||||||
setAllChatStoreIndexes(await (await db).getAllKeys(STORAGE_NAME));
|
setAllChatStoreIndexes(await (await db).getAllKeys(STORAGE_NAME));
|
||||||
|
*/
|
||||||
};
|
};
|
||||||
run();
|
run();
|
||||||
}, []);
|
}, []);
|
||||||
@@ -328,6 +350,7 @@ export function App() {
|
|||||||
defaultRenderMD,
|
defaultRenderMD,
|
||||||
setDefaultRenderMD,
|
setDefaultRenderMD,
|
||||||
handleNewChatStore,
|
handleNewChatStore,
|
||||||
|
handleNewChatStoreWithOldOne,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Sidebar>
|
<Sidebar>
|
||||||
@@ -406,6 +429,7 @@ export function App() {
|
|||||||
selectedChatIndex={selectedChatIndex}
|
selectedChatIndex={selectedChatIndex}
|
||||||
getChatStoreByIndex={getChatStoreByIndex}
|
getChatStoreByIndex={getChatStoreByIndex}
|
||||||
>
|
>
|
||||||
|
<ImportDialog open={showImportDialog} setOpen={setShowImportDialog} />
|
||||||
<Navbar />
|
<Navbar />
|
||||||
<ChatBOX />
|
<ChatBOX />
|
||||||
</AppChatStoreProvider>
|
</AppChatStoreProvider>
|
||||||
|
|||||||
@@ -300,7 +300,7 @@ export default function ChatBOX() {
|
|||||||
token: data.usage?.completion_tokens_details
|
token: data.usage?.completion_tokens_details
|
||||||
? data.usage.completion_tokens -
|
? data.usage.completion_tokens -
|
||||||
data.usage.completion_tokens_details.reasoning_tokens
|
data.usage.completion_tokens_details.reasoning_tokens
|
||||||
: data.usage.completion_tokens ?? calculate_token_length(msg.content),
|
: (data.usage.completion_tokens ?? calculate_token_length(msg.content)),
|
||||||
example: false,
|
example: false,
|
||||||
audio: null,
|
audio: null,
|
||||||
logprobs: data.choices[0]?.logprobs,
|
logprobs: data.choices[0]?.logprobs,
|
||||||
|
|||||||
@@ -144,6 +144,10 @@ const LANG_MAP: Record<string, string> = {
|
|||||||
"removed from context": "已从上下文中移除",
|
"removed from context": "已从上下文中移除",
|
||||||
follow: "跟随",
|
follow: "跟随",
|
||||||
"stop generating": "停止生成",
|
"stop generating": "停止生成",
|
||||||
|
"there are some configurations in the URL, import them?":
|
||||||
|
"URL 中有一些配置,是否导入?",
|
||||||
|
"Import Configuration": "导入配置",
|
||||||
|
cancel: "取消",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LANG_MAP;
|
export default LANG_MAP;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import {
|
|||||||
DefaultModel,
|
DefaultModel,
|
||||||
CHATGPT_API_WEB_VERSION,
|
CHATGPT_API_WEB_VERSION,
|
||||||
} from "@/const";
|
} from "@/const";
|
||||||
import { getDefaultParams } from "@/utils/getDefaultParam";
|
|
||||||
import { ChatStore, ChatStoreMessage } from "@/types/chatstore";
|
import { ChatStore, ChatStoreMessage } from "@/types/chatstore";
|
||||||
import { models } from "@/types/models";
|
import { models } from "@/types/models";
|
||||||
|
|
||||||
@@ -42,33 +41,24 @@ interface NewChatStoreOptions {
|
|||||||
export const newChatStore = (options: NewChatStoreOptions): ChatStore => {
|
export const newChatStore = (options: NewChatStoreOptions): ChatStore => {
|
||||||
return {
|
return {
|
||||||
chatgpt_api_web_version: CHATGPT_API_WEB_VERSION,
|
chatgpt_api_web_version: CHATGPT_API_WEB_VERSION,
|
||||||
systemMessageContent: getDefaultParams(
|
systemMessageContent: options.systemMessageContent ?? "",
|
||||||
"sys",
|
|
||||||
options.systemMessageContent ?? ""
|
|
||||||
),
|
|
||||||
toolsString: options.toolsString ?? "",
|
toolsString: options.toolsString ?? "",
|
||||||
history: options.use_this_history ?? [],
|
history: options.use_this_history ?? [],
|
||||||
postBeginIndex: 0,
|
postBeginIndex: 0,
|
||||||
tokenMargin: 1024,
|
tokenMargin: 1024,
|
||||||
totalTokens: 0,
|
totalTokens: 0,
|
||||||
maxTokens: getDefaultParams(
|
maxTokens:
|
||||||
"max",
|
models[options.model ?? DefaultModel]?.maxToken ??
|
||||||
models[getDefaultParams("model", options.model ?? DefaultModel)]
|
options.maxTokens ??
|
||||||
?.maxToken ??
|
2048,
|
||||||
options.maxTokens ??
|
|
||||||
2048
|
|
||||||
),
|
|
||||||
maxGenTokens: 2048,
|
maxGenTokens: 2048,
|
||||||
maxGenTokens_enabled: false,
|
maxGenTokens_enabled: false,
|
||||||
apiKey: getDefaultParams("key", options.apiKey ?? ""),
|
apiKey: options.apiKey ?? "",
|
||||||
apiEndpoint: getDefaultParams(
|
apiEndpoint: options.apiEndpoint ?? DefaultAPIEndpoint,
|
||||||
"api",
|
streamMode: options.streamMode ?? true,
|
||||||
options.apiEndpoint ?? DefaultAPIEndpoint
|
model: options.model ?? DefaultModel,
|
||||||
),
|
|
||||||
streamMode: getDefaultParams("mode", options.streamMode ?? true),
|
|
||||||
model: getDefaultParams("model", options.model ?? DefaultModel),
|
|
||||||
cost: 0,
|
cost: 0,
|
||||||
temperature: getDefaultParams("temp", options.temperature ?? 1),
|
temperature: options.temperature ?? 1,
|
||||||
temperature_enabled: options.temperature_enabled ?? true,
|
temperature_enabled: options.temperature_enabled ?? true,
|
||||||
top_p: options.top_p ?? 1,
|
top_p: options.top_p ?? 1,
|
||||||
top_p_enabled: options.top_p_enabled ?? false,
|
top_p_enabled: options.top_p_enabled ?? false,
|
||||||
@@ -76,17 +66,12 @@ export const newChatStore = (options: NewChatStoreOptions): ChatStore => {
|
|||||||
presence_penalty_enabled: options.presence_penalty_enabled ?? false,
|
presence_penalty_enabled: options.presence_penalty_enabled ?? false,
|
||||||
frequency_penalty: options.frequency_penalty ?? 0,
|
frequency_penalty: options.frequency_penalty ?? 0,
|
||||||
frequency_penalty_enabled: options.frequency_penalty_enabled ?? false,
|
frequency_penalty_enabled: options.frequency_penalty_enabled ?? false,
|
||||||
develop_mode: getDefaultParams("dev", options.dev ?? false),
|
develop_mode: options.dev ?? false,
|
||||||
whisper_api: getDefaultParams(
|
whisper_api:
|
||||||
"whisper-api",
|
options.whisper_api ?? "https://api.openai.com/v1/audio/transcriptions",
|
||||||
options.whisper_api ?? "https://api.openai.com/v1/audio/transcriptions"
|
whisper_key: options.whisper_key ?? "",
|
||||||
),
|
tts_api: options.tts_api ?? "https://api.openai.com/v1/audio/speech",
|
||||||
whisper_key: getDefaultParams("whisper-key", options.whisper_key ?? ""),
|
tts_key: options.tts_key ?? "",
|
||||||
tts_api: getDefaultParams(
|
|
||||||
"tts-api",
|
|
||||||
options.tts_api ?? "https://api.openai.com/v1/audio/speech"
|
|
||||||
),
|
|
||||||
tts_key: getDefaultParams("tts-key", options.tts_key ?? ""),
|
|
||||||
tts_voice: options.tts_voice ?? "alloy",
|
tts_voice: options.tts_voice ?? "alloy",
|
||||||
tts_speed: options.tts_speed ?? 1.0,
|
tts_speed: options.tts_speed ?? 1.0,
|
||||||
tts_speed_enabled: options.tts_speed_enabled ?? false,
|
tts_speed_enabled: options.tts_speed_enabled ?? false,
|
||||||
|
|||||||
Reference in New Issue
Block a user