mirror of
https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
synced 2025-10-02 16:16:39 +08:00
commit
70ff0ccb9c
@ -13,6 +13,7 @@ const DANGER_CONFIG = {
|
|||||||
hideBalanceQuery: serverConfig.hideBalanceQuery,
|
hideBalanceQuery: serverConfig.hideBalanceQuery,
|
||||||
disableFastLink: serverConfig.disableFastLink,
|
disableFastLink: serverConfig.disableFastLink,
|
||||||
customModels: serverConfig.customModels,
|
customModels: serverConfig.customModels,
|
||||||
|
defaultModel: serverConfig.defaultModel,
|
||||||
};
|
};
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -92,9 +92,12 @@ function EchartsComponent({ currentDate, setCurrentDate }: ComponentProps) {
|
|||||||
if (searchDate != currentDateString) {
|
if (searchDate != currentDateString) {
|
||||||
async function fetchData() {
|
async function fetchData() {
|
||||||
// console.log("异步", searchDate, currentDateString);
|
// console.log("异步", searchDate, currentDateString);
|
||||||
const response = await fetch("/api/charts?date=" + currentDateString, {
|
const response = await fetch(
|
||||||
method: "GET",
|
"/api/admin/charts?date=" + currentDateString,
|
||||||
});
|
{
|
||||||
|
method: "GET",
|
||||||
|
},
|
||||||
|
);
|
||||||
// console.log('====', searchDate, currentDateString),
|
// console.log('====', searchDate, currentDateString),
|
||||||
const option: EChartsOption = await response.json();
|
const option: EChartsOption = await response.json();
|
||||||
option["tooltip"] = {
|
option["tooltip"] = {
|
||||||
|
@ -21,11 +21,10 @@ export class GeminiProApi implements LLMApi {
|
|||||||
}
|
}
|
||||||
async chat(options: ChatOptions): Promise<void> {
|
async chat(options: ChatOptions): Promise<void> {
|
||||||
// const apiClient = this;
|
// const apiClient = this;
|
||||||
const visionModel = isVisionModel(options.config.model);
|
|
||||||
let multimodal = false;
|
let multimodal = false;
|
||||||
const messages = options.messages.map((v) => {
|
const messages = options.messages.map((v) => {
|
||||||
let parts: any[] = [{ text: getMessageTextContent(v) }];
|
let parts: any[] = [{ text: getMessageTextContent(v) }];
|
||||||
if (visionModel) {
|
if (isVisionModel(options.config.model)) {
|
||||||
const images = getMessageImages(v);
|
const images = getMessageImages(v);
|
||||||
if (images.length > 0) {
|
if (images.length > 0) {
|
||||||
multimodal = true;
|
multimodal = true;
|
||||||
@ -117,17 +116,14 @@ export class GeminiProApi implements LLMApi {
|
|||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
options.onController?.(controller);
|
options.onController?.(controller);
|
||||||
try {
|
try {
|
||||||
let googleChatPath = visionModel
|
|
||||||
? Google.VisionChatPath(modelConfig.model)
|
|
||||||
: Google.ChatPath(modelConfig.model);
|
|
||||||
let chatPath = this.path(googleChatPath);
|
|
||||||
|
|
||||||
// let baseUrl = accessStore.googleUrl;
|
// let baseUrl = accessStore.googleUrl;
|
||||||
|
|
||||||
if (!baseUrl) {
|
if (!baseUrl) {
|
||||||
baseUrl = isApp
|
baseUrl = isApp
|
||||||
? DEFAULT_API_HOST + "/api/proxy/google/" + googleChatPath
|
? DEFAULT_API_HOST +
|
||||||
: chatPath;
|
"/api/proxy/google/" +
|
||||||
|
Google.ChatPath(modelConfig.model)
|
||||||
|
: this.path(Google.ChatPath(modelConfig.model));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isApp) {
|
if (isApp) {
|
||||||
@ -145,6 +141,7 @@ export class GeminiProApi implements LLMApi {
|
|||||||
() => controller.abort(),
|
() => controller.abort(),
|
||||||
REQUEST_TIMEOUT_MS,
|
REQUEST_TIMEOUT_MS,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (shouldStream) {
|
if (shouldStream) {
|
||||||
let responseText = "";
|
let responseText = "";
|
||||||
let remainText = "";
|
let remainText = "";
|
||||||
|
@ -135,7 +135,7 @@ export class ChatGPTApi implements LLMApi {
|
|||||||
|
|
||||||
// console.log("[Request] openai payload: ", requestPayload);
|
// console.log("[Request] openai payload: ", requestPayload);
|
||||||
// add max_tokens to vision model
|
// add max_tokens to vision model
|
||||||
if (visionModel) {
|
if (visionModel && modelConfig.model.includes("preview")) {
|
||||||
requestPayload["max_tokens"] = Math.max(modelConfig.max_tokens, 4000);
|
requestPayload["max_tokens"] = Math.max(modelConfig.max_tokens, 4000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -468,10 +468,20 @@ export function ChatActions(props: {
|
|||||||
// switch model
|
// switch model
|
||||||
const currentModel = chatStore.currentSession().mask.modelConfig.model;
|
const currentModel = chatStore.currentSession().mask.modelConfig.model;
|
||||||
const allModels = useAllModels();
|
const allModels = useAllModels();
|
||||||
const models = useMemo(
|
const models = useMemo(() => {
|
||||||
() => allModels.filter((m) => m.available),
|
const filteredModels = allModels.filter((m) => m.available);
|
||||||
[allModels],
|
const defaultModel = filteredModels.find((m) => m.isDefault);
|
||||||
);
|
|
||||||
|
if (defaultModel) {
|
||||||
|
const arr = [
|
||||||
|
defaultModel,
|
||||||
|
...filteredModels.filter((m) => m !== defaultModel),
|
||||||
|
];
|
||||||
|
return arr;
|
||||||
|
} else {
|
||||||
|
return filteredModels;
|
||||||
|
}
|
||||||
|
}, [allModels]);
|
||||||
const [showModelSelector, setShowModelSelector] = useState(false);
|
const [showModelSelector, setShowModelSelector] = useState(false);
|
||||||
const [showUploadImage, setShowUploadImage] = useState(false);
|
const [showUploadImage, setShowUploadImage] = useState(false);
|
||||||
const current_day_token = localStorage.getItem("current_day_token") ?? "";
|
const current_day_token = localStorage.getItem("current_day_token") ?? "";
|
||||||
@ -486,9 +496,12 @@ export function ChatActions(props: {
|
|||||||
|
|
||||||
// if current model is not available
|
// if current model is not available
|
||||||
// switch to first available model
|
// switch to first available model
|
||||||
const isUnavailableModel = !models.some((m) => m.name === currentModel);
|
const isUnavaliableModel = !models.some((m) => m.name === currentModel);
|
||||||
if (isUnavailableModel && models.length > 0) {
|
if (isUnavaliableModel && models.length > 0) {
|
||||||
const nextModel = models[0].name as ModelType;
|
// show next model to default model if exist
|
||||||
|
let nextModel: ModelType = (
|
||||||
|
models.find((model) => model.isDefault) || models[0]
|
||||||
|
).name as ModelType;
|
||||||
chatStore.updateCurrentSession(
|
chatStore.updateCurrentSession(
|
||||||
(session) => (session.mask.modelConfig.model = nextModel),
|
(session) => (session.mask.modelConfig.model = nextModel),
|
||||||
);
|
);
|
||||||
|
@ -192,6 +192,7 @@ export function useLoadData() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function Home() {
|
export function Home() {
|
||||||
|
// const { status } = useSession({ required: true })
|
||||||
useSwitchTheme();
|
useSwitchTheme();
|
||||||
useLoadData();
|
useLoadData();
|
||||||
useHtmlLang();
|
useHtmlLang();
|
||||||
|
@ -22,6 +22,7 @@ declare global {
|
|||||||
ENABLE_BALANCE_QUERY?: string; // allow user to query balance or not
|
ENABLE_BALANCE_QUERY?: string; // allow user to query balance or not
|
||||||
DISABLE_FAST_LINK?: string; // disallow parse settings from url or not
|
DISABLE_FAST_LINK?: string; // disallow parse settings from url or not
|
||||||
CUSTOM_MODELS?: string; // to control custom models
|
CUSTOM_MODELS?: string; // to control custom models
|
||||||
|
DEFAULT_MODEL?: string; // to cnntrol default model in every new chat window
|
||||||
|
|
||||||
// azure only
|
// azure only
|
||||||
AZURE_URL?: string; // https://{azure-url}/openai/deployments/{deploy-name}
|
AZURE_URL?: string; // https://{azure-url}/openai/deployments/{deploy-name}
|
||||||
@ -61,12 +62,14 @@ export const getServerSideConfig = () => {
|
|||||||
|
|
||||||
const disableGPT4 = !!process.env.DISABLE_GPT4;
|
const disableGPT4 = !!process.env.DISABLE_GPT4;
|
||||||
let customModels = process.env.CUSTOM_MODELS ?? "";
|
let customModels = process.env.CUSTOM_MODELS ?? "";
|
||||||
|
let defaultModel = process.env.DEFAULT_MODEL ?? "";
|
||||||
|
|
||||||
if (disableGPT4) {
|
if (disableGPT4) {
|
||||||
if (customModels) customModels += ",";
|
if (customModels) customModels += ",";
|
||||||
customModels += DEFAULT_MODELS.filter((m) => m.name.startsWith("gpt-4"))
|
customModels += DEFAULT_MODELS.filter((m) => m.name.startsWith("gpt-4"))
|
||||||
.map((m) => "-" + m.name)
|
.map((m) => "-" + m.name)
|
||||||
.join(",");
|
.join(",");
|
||||||
|
if (defaultModel.startsWith("gpt-4")) defaultModel = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// const isAzure = !!process.env.AZURE_URL;
|
// const isAzure = !!process.env.AZURE_URL;
|
||||||
@ -124,6 +127,7 @@ export const getServerSideConfig = () => {
|
|||||||
hideBalanceQuery: !process.env.ENABLE_BALANCE_QUERY,
|
hideBalanceQuery: !process.env.ENABLE_BALANCE_QUERY,
|
||||||
disableFastLink: !!process.env.DISABLE_FAST_LINK,
|
disableFastLink: !!process.env.DISABLE_FAST_LINK,
|
||||||
customModels,
|
customModels,
|
||||||
|
defaultModel,
|
||||||
whiteWebDevEndpoints,
|
whiteWebDevEndpoints,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -103,8 +103,8 @@ export const Azure = {
|
|||||||
export const Google = {
|
export const Google = {
|
||||||
ExampleEndpoint: "https://generativelanguage.googleapis.com/",
|
ExampleEndpoint: "https://generativelanguage.googleapis.com/",
|
||||||
ChatPath: (modelName: string) => `v1beta/models/${modelName}:generateContent`,
|
ChatPath: (modelName: string) => `v1beta/models/${modelName}:generateContent`,
|
||||||
VisionChatPath: (modelName: string) =>
|
// VisionChatPath: (modelName: string) =>
|
||||||
`v1beta/models/${modelName}:generateContent`,
|
// `v1beta/models/${modelName}:generateContent`,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DEFAULT_INPUT_TEMPLATE = `{{input}}`; // input / time / model / lang
|
export const DEFAULT_INPUT_TEMPLATE = `{{input}}`; // input / time / model / lang
|
||||||
@ -133,8 +133,6 @@ export const KnowledgeCutOffDate: Record<string, string> = {
|
|||||||
"gpt-4-turbo": "2023-12",
|
"gpt-4-turbo": "2023-12",
|
||||||
"gpt-4-turbo-2024-04-09": "2023-12",
|
"gpt-4-turbo-2024-04-09": "2023-12",
|
||||||
"gpt-4-turbo-preview": "2023-12",
|
"gpt-4-turbo-preview": "2023-12",
|
||||||
"gpt-4-1106-preview": "2023-04",
|
|
||||||
"gpt-4-0125-preview": "2023-12",
|
|
||||||
"gpt-4-vision-preview": "2023-04",
|
"gpt-4-vision-preview": "2023-04",
|
||||||
// After improvements,
|
// After improvements,
|
||||||
// it's now easier to add "KnowledgeCutOffDate" instead of stupid hardcoding it, as was done previously.
|
// it's now easier to add "KnowledgeCutOffDate" instead of stupid hardcoding it, as was done previously.
|
||||||
@ -144,19 +142,11 @@ export const KnowledgeCutOffDate: Record<string, string> = {
|
|||||||
|
|
||||||
const openaiModels = [
|
const openaiModels = [
|
||||||
"gpt-3.5-turbo",
|
"gpt-3.5-turbo",
|
||||||
"gpt-3.5-turbo-0301",
|
|
||||||
"gpt-3.5-turbo-0613",
|
|
||||||
"gpt-3.5-turbo-1106",
|
"gpt-3.5-turbo-1106",
|
||||||
"gpt-3.5-turbo-0125",
|
"gpt-3.5-turbo-0125",
|
||||||
"gpt-3.5-turbo-16k",
|
|
||||||
"gpt-3.5-turbo-16k-0613",
|
|
||||||
"gpt-4",
|
"gpt-4",
|
||||||
"gpt-4-0314",
|
|
||||||
"gpt-4-0613",
|
"gpt-4-0613",
|
||||||
"gpt-4-1106-preview",
|
|
||||||
"gpt-4-0125-preview",
|
|
||||||
"gpt-4-32k",
|
"gpt-4-32k",
|
||||||
"gpt-4-32k-0314",
|
|
||||||
"gpt-4-32k-0613",
|
"gpt-4-32k-0613",
|
||||||
"gpt-4-turbo",
|
"gpt-4-turbo",
|
||||||
"gpt-4-turbo-preview",
|
"gpt-4-turbo-preview",
|
||||||
|
@ -8,6 +8,7 @@ import { getHeaders } from "../client/api";
|
|||||||
import { getClientConfig } from "../config/client";
|
import { getClientConfig } from "../config/client";
|
||||||
import { createPersistStore } from "../utils/store";
|
import { createPersistStore } from "../utils/store";
|
||||||
import { ensure } from "../utils/clone";
|
import { ensure } from "../utils/clone";
|
||||||
|
import { DEFAULT_CONFIG } from "./config";
|
||||||
|
|
||||||
let fetchState = 0; // 0 not fetch, 1 fetching, 2 done
|
let fetchState = 0; // 0 not fetch, 1 fetching, 2 done
|
||||||
|
|
||||||
@ -51,6 +52,7 @@ const DEFAULT_ACCESS_STATE = {
|
|||||||
useMjImgSelfProxy: false,
|
useMjImgSelfProxy: false,
|
||||||
disableFastLink: false,
|
disableFastLink: false,
|
||||||
customModels: "",
|
customModels: "",
|
||||||
|
defaultModel: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useAccessStore = createPersistStore(
|
export const useAccessStore = createPersistStore(
|
||||||
@ -105,6 +107,31 @@ export const useAccessStore = createPersistStore(
|
|||||||
};
|
};
|
||||||
set(() => ({ ...res }));
|
set(() => ({ ...res }));
|
||||||
fetchState = 2; // 设置 fetchState 值为 "获取已完成"
|
fetchState = 2; // 设置 fetchState 值为 "获取已完成"
|
||||||
|
// fetch("/api/config", {
|
||||||
|
// method: "post",
|
||||||
|
// body: null,
|
||||||
|
// headers: {
|
||||||
|
// ...getHeaders(),
|
||||||
|
// },
|
||||||
|
// })
|
||||||
|
// .then((res) => res.json())
|
||||||
|
// .then((res) => {
|
||||||
|
// // Set default model from env request
|
||||||
|
// let defaultModel = res.defaultModel ?? "";
|
||||||
|
// DEFAULT_CONFIG.modelConfig.model =
|
||||||
|
// defaultModel !== "" ? defaultModel : "gpt-3.5-turbo";
|
||||||
|
// return res;
|
||||||
|
// })
|
||||||
|
// .then((res: DangerConfig) => {
|
||||||
|
// console.log("[Config] got config from server", res);
|
||||||
|
// set(() => ({ ...res }));
|
||||||
|
// })
|
||||||
|
// .catch(() => {
|
||||||
|
// console.error("[Config] failed to fetch config");
|
||||||
|
// })
|
||||||
|
// .finally(() => {
|
||||||
|
// fetchState = 2;
|
||||||
|
// });
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
|
@ -86,6 +86,7 @@
|
|||||||
@include dark;
|
@include dark;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
height: var(--full-height);
|
height: var(--full-height);
|
||||||
|
|
||||||
@ -110,6 +111,10 @@ body {
|
|||||||
@media only screen and (max-width: 600px) {
|
@media only screen and (max-width: 600px) {
|
||||||
background-color: var(--second);
|
background-color: var(--second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*:focus-visible {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { useAccessStore, useAppConfig } from "../store";
|
import { useAccessStore, useAppConfig } from "../store";
|
||||||
import { collectModels } from "./model";
|
import { collectModels, collectModelsWithDefaultModel } from "./model";
|
||||||
|
|
||||||
export function useAllModels() {
|
export function useAllModels() {
|
||||||
const accessStore = useAccessStore();
|
const accessStore = useAccessStore();
|
||||||
const configStore = useAppConfig();
|
const configStore = useAppConfig();
|
||||||
const models = useMemo(() => {
|
const models = useMemo(() => {
|
||||||
return collectModels(
|
return collectModelsWithDefaultModel(
|
||||||
configStore.models,
|
configStore.models,
|
||||||
[configStore.customModels, accessStore.customModels].join(","),
|
[configStore.customModels, accessStore.customModels].join(","),
|
||||||
|
accessStore.defaultModel,
|
||||||
).filter((m) => !configStore.dontUseModel.includes(m.name as any));
|
).filter((m) => !configStore.dontUseModel.includes(m.name as any));
|
||||||
}, [
|
}, [
|
||||||
accessStore.customModels,
|
accessStore.customModels,
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
import { LLMModel } from "../client/api";
|
import { LLMModel } from "../client/api";
|
||||||
|
|
||||||
|
const customProvider = (modelName: string) => ({
|
||||||
|
id: modelName,
|
||||||
|
providerName: "",
|
||||||
|
providerType: "custom",
|
||||||
|
});
|
||||||
|
|
||||||
export function collectModelTable(
|
export function collectModelTable(
|
||||||
models: readonly LLMModel[],
|
models: readonly LLMModel[],
|
||||||
customModels: string,
|
customModels: string,
|
||||||
@ -12,6 +18,7 @@ export function collectModelTable(
|
|||||||
displayName: string;
|
displayName: string;
|
||||||
describe: string;
|
describe: string;
|
||||||
provider?: LLMModel["provider"]; // Marked as optional
|
provider?: LLMModel["provider"]; // Marked as optional
|
||||||
|
isDefault?: boolean;
|
||||||
}
|
}
|
||||||
> = {};
|
> = {};
|
||||||
|
|
||||||
@ -23,12 +30,6 @@ export function collectModelTable(
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const customProvider = (modelName: string) => ({
|
|
||||||
id: modelName,
|
|
||||||
providerName: "",
|
|
||||||
providerType: "custom",
|
|
||||||
});
|
|
||||||
|
|
||||||
// server custom models
|
// server custom models
|
||||||
customModels
|
customModels
|
||||||
.split(",")
|
.split(",")
|
||||||
@ -54,6 +55,28 @@ export function collectModelTable(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return modelTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function collectModelTableWithDefaultModel(
|
||||||
|
models: readonly LLMModel[],
|
||||||
|
customModels: string,
|
||||||
|
defaultModel: string,
|
||||||
|
) {
|
||||||
|
let modelTable = collectModelTable(models, customModels);
|
||||||
|
if (defaultModel && defaultModel !== "") {
|
||||||
|
delete modelTable[defaultModel];
|
||||||
|
modelTable[defaultModel] = {
|
||||||
|
name: defaultModel,
|
||||||
|
displayName: defaultModel,
|
||||||
|
available: true,
|
||||||
|
describe: "默认模型",
|
||||||
|
provider:
|
||||||
|
modelTable[defaultModel]?.provider ?? customProvider(defaultModel),
|
||||||
|
isDefault: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
return modelTable;
|
return modelTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,3 +92,17 @@ export function collectModels(
|
|||||||
|
|
||||||
return allModels;
|
return allModels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function collectModelsWithDefaultModel(
|
||||||
|
models: readonly LLMModel[],
|
||||||
|
customModels: string,
|
||||||
|
defaultModel: string,
|
||||||
|
) {
|
||||||
|
const modelTable = collectModelTableWithDefaultModel(
|
||||||
|
models,
|
||||||
|
customModels,
|
||||||
|
defaultModel,
|
||||||
|
);
|
||||||
|
const allModels = Object.values(modelTable);
|
||||||
|
return allModels;
|
||||||
|
}
|
||||||
|
@ -15,6 +15,7 @@ export default async function middleware(req: NextRequest) {
|
|||||||
return NextResponse.redirect(new URL(path.replace('/app', ''), req.url), 301);
|
return NextResponse.redirect(new URL(path.replace('/app', ''), req.url), 301);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const session = await getToken({ req });
|
const session = await getToken({ req });
|
||||||
const isUser = await VerifiedUser(session);
|
const isUser = await VerifiedUser(session);
|
||||||
const isAdminUser = await VerifiedAdminUser(session);
|
const isAdminUser = await VerifiedAdminUser(session);
|
||||||
|
@ -3,8 +3,8 @@ import webpack from "webpack";
|
|||||||
const mode = process.env.BUILD_MODE ?? "standalone";
|
const mode = process.env.BUILD_MODE ?? "standalone";
|
||||||
console.log("[Next] build mode", mode);
|
console.log("[Next] build mode", mode);
|
||||||
|
|
||||||
// const disableChunk = !!process.env.DISABLE_CHUNK || mode === "export";
|
const disableChunk = !!process.env.DISABLE_CHUNK || mode === "export";
|
||||||
const disableChunk = true;
|
// const disableChunk = true;
|
||||||
console.log("[Next] build with chunk: ", disableChunk);
|
console.log("[Next] build with chunk: ", disableChunk);
|
||||||
|
|
||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
|
2
start.sh
2
start.sh
@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
# 加速
|
# 加速
|
||||||
#yarn config set registry 'https://registry.npmmirror.com/'
|
#yarn config set registry 'https://registry.npmmirror.com/'
|
||||||
#yarn config set sharp_binary_host "https://npm.taobao.org/mirrors/sharp"
|
#yarn config set sharp_binary_host "https://npm.taobao.org/mirrors/sharp"
|
||||||
|
Loading…
Reference in New Issue
Block a user