feat: add URL parameter configuration import dialog and related functionality

This commit is contained in:
2025-03-25 10:49:10 +08:00
parent 9b32948cfa
commit 667b334dfc
8 changed files with 177 additions and 85 deletions

View 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;

View File

@@ -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 });
}} }}
> >

View File

@@ -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

View File

@@ -1,4 +1,4 @@
@import 'highlight.js/styles/monokai.css'; @import "highlight.js/styles/monokai.css";
@tailwind base; @tailwind base;
@tailwind components; @tailwind components;

View File

@@ -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>

View File

@@ -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,

View File

@@ -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;

View File

@@ -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)]
?.maxToken ??
options.maxTokens ?? options.maxTokens ??
2048 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,