mirror of
https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
synced 2025-10-08 19:16:37 +08:00
feat:修复apikey使用额度接口缓存问题和修复setting页面针对该接口频繁调用的问题
1.为了解决缓存问题,更新了调用apikey使用额度接口的方法。由于nextjs的fetch默认会缓存同样参数的请求,需要针对fetch加入cache: 'no-store' 的参数修复以避免这一现象。(https://beta.nextjs.org/docs/data-fetching/fetching#dynamic-data-fetching) 2.为了提升用户体验,引入了usageStore,该存储库能够在有数据的情况下,优先使用缓存数据来加载apikey使用额度的信息。只有当重新检查的按钮被点击时,才会再次调用apikey使用额度接口更新usageStore数据,并且在页面上显示最新的更新数据。通过实现这种操作,我们能够避免在进入setting页面时频繁地调用apikey使用额度接口,从而进一步提升响应速度和用户体验。
This commit is contained in:
parent
9146b98285
commit
6ac26b7d4a
@ -8,6 +8,8 @@ const BASE_URL = process.env.BASE_URL ?? OPENAI_URL;
|
||||
export async function requestOpenai(req: NextRequest) {
|
||||
const apiKey = req.headers.get("token");
|
||||
const openaiPath = req.headers.get("path");
|
||||
const fetchCache =
|
||||
req.headers.get("fetch-cache") == "enable" ? "default" : "no-store";
|
||||
|
||||
console.log("[Proxy] ", openaiPath);
|
||||
|
||||
@ -16,6 +18,7 @@ export async function requestOpenai(req: NextRequest) {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
},
|
||||
cache: fetchCache,
|
||||
method: req.method,
|
||||
body: req.body,
|
||||
});
|
||||
|
@ -21,6 +21,7 @@ import {
|
||||
ALL_MODELS,
|
||||
useUpdateStore,
|
||||
useAccessStore,
|
||||
useUsageStore,
|
||||
ModalConfigValidator,
|
||||
} from "../store";
|
||||
import { Avatar } from "./chat";
|
||||
@ -92,25 +93,33 @@ export function Settings(props: { closeSettings: () => void }) {
|
||||
const remoteId = updateStore.remoteVersion;
|
||||
const hasNewVersion = currentVersion !== remoteId;
|
||||
|
||||
function checkUpdate(force = false) {
|
||||
function checkUpdate(force: boolean = false) {
|
||||
setCheckingUpdate(true);
|
||||
updateStore.getLatestVersion(force).then(() => {
|
||||
setCheckingUpdate(false);
|
||||
});
|
||||
}
|
||||
|
||||
const [usage, setUsage] = useState<{
|
||||
used?: number;
|
||||
subscription?: number;
|
||||
}>();
|
||||
// const [usage, setUsage] = useState<{
|
||||
// used?: number;
|
||||
// subscription?: number;
|
||||
// }>();
|
||||
const { used, subscription, updateUsage, hasUsageData } = useUsageStore();
|
||||
const [loadingUsage, setLoadingUsage] = useState(false);
|
||||
function checkUsage() {
|
||||
setLoadingUsage(true);
|
||||
requestUsage()
|
||||
.then((res) => setUsage(res))
|
||||
.finally(() => {
|
||||
setLoadingUsage(false);
|
||||
});
|
||||
function checkUsage(forceUpdate: boolean = false) {
|
||||
if (!hasUsageData() || forceUpdate) {
|
||||
setLoadingUsage(true);
|
||||
requestUsage()
|
||||
.then((res) => {
|
||||
if (res) {
|
||||
const { used, subscription } = res;
|
||||
updateUsage(used?.toString(), subscription?.toString());
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
setLoadingUsage(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const accessStore = useAccessStore();
|
||||
@ -385,10 +394,7 @@ export function Settings(props: { closeSettings: () => void }) {
|
||||
showUsage
|
||||
? loadingUsage
|
||||
? Locale.Settings.Usage.IsChecking
|
||||
: Locale.Settings.Usage.SubTitle(
|
||||
usage?.used ?? "[?]",
|
||||
usage?.subscription ?? "[?]",
|
||||
)
|
||||
: Locale.Settings.Usage.SubTitle(used, subscription)
|
||||
: Locale.Settings.Usage.NoAccess
|
||||
}
|
||||
>
|
||||
@ -398,7 +404,9 @@ export function Settings(props: { closeSettings: () => void }) {
|
||||
<IconButton
|
||||
icon={<ResetIcon></ResetIcon>}
|
||||
text={Locale.Settings.Usage.Check}
|
||||
onClick={checkUsage}
|
||||
onClick={() => {
|
||||
checkUsage(true);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</SettingItem>
|
||||
|
@ -49,15 +49,17 @@ function getHeaders() {
|
||||
}
|
||||
|
||||
export function requestOpenaiClient(path: string) {
|
||||
return (body: any, method = "POST") =>
|
||||
return (body: any, method: string = "POST", fetchCache: boolean = true) =>
|
||||
fetch("/api/openai?_vercel_no_cache=1", {
|
||||
method,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
path,
|
||||
...getHeaders(),
|
||||
"fetch-cache": fetchCache ? "enable" : "disable",
|
||||
},
|
||||
body: body && JSON.stringify(body),
|
||||
cache: fetchCache ? "default" : "no-store", //https://beta.nextjs.org/docs/data-fetching/fetching#dynamic-data-fetching
|
||||
});
|
||||
}
|
||||
|
||||
@ -75,6 +77,7 @@ export async function requestChat(messages: Message[]) {
|
||||
}
|
||||
|
||||
export async function requestUsage() {
|
||||
const useFetchCache = false;
|
||||
const formatDate = (d: Date) =>
|
||||
`${d.getFullYear()}-${(d.getMonth() + 1).toString().padStart(2, "0")}-${d
|
||||
.getDate()
|
||||
@ -89,8 +92,12 @@ export async function requestUsage() {
|
||||
const [used, subs] = await Promise.all([
|
||||
requestOpenaiClient(
|
||||
`dashboard/billing/usage?start_date=${startDate}&end_date=${endDate}`,
|
||||
)(null, "GET"),
|
||||
requestOpenaiClient("dashboard/billing/subscription")(null, "GET"),
|
||||
)(null, "GET", useFetchCache),
|
||||
requestOpenaiClient("dashboard/billing/subscription")(
|
||||
null,
|
||||
"GET",
|
||||
useFetchCache,
|
||||
),
|
||||
]);
|
||||
|
||||
const response = (await used.json()) as {
|
||||
@ -171,11 +178,11 @@ export async function requestChatStream(
|
||||
const resTimeoutId = setTimeout(() => finish(), TIME_OUT_MS);
|
||||
const content = await reader?.read();
|
||||
clearTimeout(resTimeoutId);
|
||||
|
||||
|
||||
if (!content || !content.value) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
const text = decoder.decode(content.value, { stream: true });
|
||||
responseText += text;
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
export * from "./app";
|
||||
export * from "./update";
|
||||
export * from "./access";
|
||||
export * from "./usage";
|
||||
|
41
app/store/usage.ts
Normal file
41
app/store/usage.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { create } from "zustand";
|
||||
import { persist } from "zustand/middleware";
|
||||
|
||||
export interface UsageStore {
|
||||
used: string;
|
||||
subscription: string;
|
||||
|
||||
updateUsage: (used?: string, subscription?: string) => void;
|
||||
hasUsageData: () => boolean;
|
||||
}
|
||||
|
||||
const USAGE_KEY = "api-usage";
|
||||
|
||||
let fetchState = 0; // 0 not fetch, 1 fetching, 2 done
|
||||
|
||||
export const useUsageStore = create<UsageStore>()(
|
||||
persist(
|
||||
(set, get) => ({
|
||||
used: "",
|
||||
subscription: "",
|
||||
|
||||
updateUsage(used?: string, subscription?: string) {
|
||||
set((state) => ({
|
||||
used: used ?? "[?]",
|
||||
subscription: subscription ?? "[?]",
|
||||
}));
|
||||
},
|
||||
hasUsageData() {
|
||||
const used = get().used;
|
||||
const sub = get().subscription;
|
||||
const hasUsed = used != "" && used != "[?]";
|
||||
const hasSubscription = sub != "" && sub != "[?]";
|
||||
return hasUsed && hasSubscription;
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: USAGE_KEY,
|
||||
version: 1,
|
||||
},
|
||||
),
|
||||
);
|
Loading…
Reference in New Issue
Block a user