diff --git a/app/config/server.ts b/app/config/server.ts
index 70c20ce644f..6544fe5641d 100644
--- a/app/config/server.ts
+++ b/app/config/server.ts
@@ -1,5 +1,5 @@
import md5 from "spark-md5";
-import { DEFAULT_MODELS } from "../constant";
+import { DEFAULT_MODELS, DEFAULT_GA_ID } from "../constant";
declare global {
namespace NodeJS {
@@ -66,6 +66,11 @@ declare global {
MOONSHOT_URL?: string;
MOONSHOT_API_KEY?: string;
+ // iflytek only
+ IFLYTEK_URL?: string;
+ IFLYTEK_API_KEY?: string;
+ IFLYTEK_API_SECRET?: string;
+
// custom template for preprocessing user input
DEFAULT_INPUT_TEMPLATE?: string;
}
@@ -114,10 +119,19 @@ export const getServerSideConfig = () => {
if (disableGPT4) {
if (customModels) customModels += ",";
- customModels += DEFAULT_MODELS.filter((m) => m.name.startsWith("gpt-4"))
+ customModels += DEFAULT_MODELS.filter(
+ (m) =>
+ (m.name.startsWith("gpt-4") || m.name.startsWith("chatgpt-4o")) &&
+ !m.name.startsWith("gpt-4o-mini"),
+ )
.map((m) => "-" + m.name)
.join(",");
- if (defaultModel.startsWith("gpt-4")) defaultModel = "";
+ if (
+ (defaultModel.startsWith("gpt-4") ||
+ defaultModel.startsWith("chatgpt-4o")) &&
+ !defaultModel.startsWith("gpt-4o-mini")
+ )
+ defaultModel = "";
}
const isStability = !!process.env.STABILITY_API_KEY;
@@ -131,6 +145,7 @@ export const getServerSideConfig = () => {
const isBytedance = !!process.env.BYTEDANCE_API_KEY;
const isAlibaba = !!process.env.ALIBABA_API_KEY;
const isMoonshot = !!process.env.MOONSHOT_API_KEY;
+ const isIflytek = !!process.env.IFLYTEK_API_KEY;
// const apiKeyEnvVar = process.env.OPENAI_API_KEY ?? "";
// const apiKeys = apiKeyEnvVar.split(",").map((v) => v.trim());
// const randomIndex = Math.floor(Math.random() * apiKeys.length);
@@ -139,8 +154,8 @@ export const getServerSideConfig = () => {
// `[Server Config] using ${randomIndex + 1} of ${apiKeys.length} api key`,
// );
- const allowedWebDevEndpoints = (
- process.env.WHITE_WEBDEV_ENDPOINTS ?? ""
+ const allowedWebDavEndpoints = (
+ process.env.WHITE_WEBDAV_ENDPOINTS ?? ""
).split(",");
return {
@@ -188,12 +203,18 @@ export const getServerSideConfig = () => {
moonshotUrl: process.env.MOONSHOT_URL,
moonshotApiKey: getApiKey(process.env.MOONSHOT_API_KEY),
+ isIflytek,
+ iflytekUrl: process.env.IFLYTEK_URL,
+ iflytekApiKey: process.env.IFLYTEK_API_KEY,
+ iflytekApiSecret: process.env.IFLYTEK_API_SECRET,
+
cloudflareAccountId: process.env.CLOUDFLARE_ACCOUNT_ID,
cloudflareKVNamespaceId: process.env.CLOUDFLARE_KV_NAMESPACE_ID,
cloudflareKVApiKey: getApiKey(process.env.CLOUDFLARE_KV_API_KEY),
cloudflareKVTTL: process.env.CLOUDFLARE_KV_TTL,
gtmId: process.env.GTM_ID,
+ gaId: process.env.GA_ID || DEFAULT_GA_ID,
needCode: ACCESS_CODES.size > 0,
code: process.env.CODE,
@@ -208,6 +229,6 @@ export const getServerSideConfig = () => {
disableFastLink: !!process.env.DISABLE_FAST_LINK,
customModels,
defaultModel,
- allowedWebDevEndpoints,
+ allowedWebDavEndpoints,
};
};
diff --git a/app/constant.ts b/app/constant.ts
index 212351d5691..a54a973daa6 100644
--- a/app/constant.ts
+++ b/app/constant.ts
@@ -1,6 +1,7 @@
export const OWNER = "ChatGPTNextWeb";
export const REPO = "ChatGPT-Next-Web";
export const REPO_URL = `https://github.com/${OWNER}/${REPO}`;
+export const PLUGINS_REPO_URL = `https://github.com/${OWNER}/NextChat-Awesome-Plugins`;
export const ISSUE_URL = `https://github.com/${OWNER}/${REPO}/issues`;
export const UPDATE_URL = `${REPO_URL}#keep-updated`;
export const RELEASE_URL = `${REPO_URL}/releases`;
@@ -26,6 +27,7 @@ export const ALIBABA_BASE_URL = "https://dashscope.aliyuncs.com/api/";
export const TENCENT_BASE_URL = "https://hunyuan.tencentcloudapi.com";
export const MOONSHOT_BASE_URL = "https://api.moonshot.cn";
+export const IFLYTEK_BASE_URL = "https://spark-api-open.xf-yun.com";
export const CACHE_URL_PREFIX = "/api/cache";
export const UPLOAD_URL = `${CACHE_URL_PREFIX}/upload`;
@@ -36,10 +38,12 @@ export enum Path {
Settings = "/settings",
NewChat = "/new-chat",
Masks = "/masks",
+ Plugins = "/plugins",
Auth = "/auth",
Sd = "/sd",
SdNew = "/sd-new",
Artifacts = "/artifacts",
+ SearchChat = "/search-chat",
}
export enum ApiPath {
@@ -53,6 +57,7 @@ export enum ApiPath {
Alibaba = "/api/alibaba",
Tencent = "/api/tencent",
Moonshot = "/api/moonshot",
+ Iflytek = "/api/iflytek",
Stability = "/api/stability",
Artifacts = "/api/artifacts",
}
@@ -67,12 +72,9 @@ export enum FileName {
Prompts = "prompts.json",
}
-export enum Plugin {
- Artifacts = "artifacts",
-}
-
export enum StoreKey {
Chat = "chat-next-web-store",
+ Plugin = "chat-next-web-plugin",
Access = "access-control",
Config = "app-config",
Mask = "mask-store",
@@ -109,6 +111,7 @@ export enum ServiceProvider {
Tencent = "Tencent",
Moonshot = "Moonshot",
Stability = "Stability",
+ Iflytek = "Iflytek",
}
// Google API safety settings, see https://ai.google.dev/gemini-api/docs/safety-settings
@@ -130,6 +133,7 @@ export enum ModelProvider {
Qwen = "Qwen",
Hunyuan = "Hunyuan",
Moonshot = "Moonshot",
+ Iflytek = "Iflytek",
}
export const Stability = {
@@ -146,6 +150,7 @@ export const Anthropic = {
export const OpenaiPath = {
ChatPath: "v1/chat/completions",
+ SpeechPath: "v1/audio/speech",
ImagePath: "v1/images/generations",
UsagePath: "dashboard/billing/usage",
SubsPath: "dashboard/billing/subscription",
@@ -206,6 +211,11 @@ export const Moonshot = {
ChatPath: "v1/chat/completions",
};
+export const Iflytek = {
+ ExampleEndpoint: IFLYTEK_BASE_URL,
+ ChatPath: "v1/chat/completions",
+};
+
export const DEFAULT_INPUT_TEMPLATE = `{{input}}`; // input / time / model / lang
// export const DEFAULT_SYSTEM_TEMPLATE = `
// You are ChatGPT, a large language model trained by {{ServiceProvider}}.
@@ -234,15 +244,33 @@ export const KnowledgeCutOffDate: Record
= {
"gpt-4-turbo-preview": "2023-12",
"gpt-4o": "2023-10",
"gpt-4o-2024-05-13": "2023-10",
+ "gpt-4o-2024-08-06": "2023-10",
+ "chatgpt-4o-latest": "2023-10",
"gpt-4o-mini": "2023-10",
"gpt-4o-mini-2024-07-18": "2023-10",
"gpt-4-vision-preview": "2023-04",
+ "o1-mini": "2023-10",
+ "o1-preview": "2023-10",
// After improvements,
// it's now easier to add "KnowledgeCutOffDate" instead of stupid hardcoding it, as was done previously.
"gemini-pro": "2023-12",
"gemini-pro-vision": "2023-12",
};
+export const DEFAULT_TTS_ENGINE = "OpenAI-TTS";
+export const DEFAULT_TTS_ENGINES = ["OpenAI-TTS", "Edge-TTS"];
+export const DEFAULT_TTS_MODEL = "tts-1";
+export const DEFAULT_TTS_VOICE = "alloy";
+export const DEFAULT_TTS_MODELS = ["tts-1", "tts-1-hd"];
+export const DEFAULT_TTS_VOICES = [
+ "alloy",
+ "echo",
+ "fable",
+ "onyx",
+ "nova",
+ "shimmer",
+];
+
const openaiModels = [
"gpt-3.5-turbo",
"gpt-3.5-turbo-1106",
@@ -255,12 +283,16 @@ const openaiModels = [
"gpt-4-turbo-preview",
"gpt-4o",
"gpt-4o-2024-05-13",
+ "gpt-4o-2024-08-06",
+ "chatgpt-4o-latest",
"gpt-4o-mini",
"gpt-4o-mini-2024-07-18",
"gpt-4-vision-preview",
"gpt-4-turbo-2024-04-09",
"gpt-4-1106-preview",
"dall-e-3",
+ "o1-mini",
+ "o1-preview",
];
const googleModels = [
@@ -325,6 +357,14 @@ const tencentModels = [
const moonshotModes = ["moonshot-v1-8k", "moonshot-v1-32k", "moonshot-v1-128k"];
+const iflytekModels = [
+ "general",
+ "generalv3",
+ "pro-128k",
+ "generalv3.5",
+ "4.0Ultra",
+];
+
let seq = 1000; // 内置的模型序号生成器从1000开始
export const DEFAULT_MODELS = [
...openaiModels.map((name) => ({
@@ -426,6 +466,17 @@ export const DEFAULT_MODELS = [
sorted: 9,
},
})),
+ ...iflytekModels.map((name) => ({
+ name,
+ available: true,
+ sorted: seq++,
+ provider: {
+ id: "iflytek",
+ providerName: "Iflytek",
+ providerType: "iflytek",
+ sorted: 10,
+ },
+ })),
] as const;
export const CHAT_PAGE_SIZE = 15;
@@ -444,4 +495,12 @@ export const internalAllowedWebDavEndpoints = [
"https://app.koofr.net/dav/Koofr",
];
-export const PLUGINS = [{ name: "Stable Diffusion", path: Path.Sd }];
+export const DEFAULT_GA_ID = "G-89WN60ZK2E";
+export const PLUGINS = [
+ { name: "Plugins", path: Path.Plugins },
+ { name: "Stable Diffusion", path: Path.Sd },
+ { name: "Search Chat", path: Path.SearchChat },
+];
+
+export const SAAS_CHAT_URL = "https://nextchat.dev/chat";
+export const SAAS_CHAT_UTM_URL = "https://nextchat.dev/chat?utm=github";
diff --git a/app/global.d.ts b/app/global.d.ts
index 31e2b6e8a84..8ee636bcd3c 100644
--- a/app/global.d.ts
+++ b/app/global.d.ts
@@ -21,10 +21,16 @@ declare interface Window {
writeBinaryFile(path: string, data: Uint8Array): Promise;
writeTextFile(path: string, data: string): Promise;
};
- notification:{
+ notification: {
requestPermission(): Promise;
isPermissionGranted(): Promise;
sendNotification(options: string | Options): void;
};
+ http: {
+ fetch(
+ url: string,
+ options?: Record,
+ ): Promise>;
+ };
};
}
diff --git a/app/icons/arrow.svg b/app/icons/arrow.svg
new file mode 100644
index 00000000000..ddd69e61472
--- /dev/null
+++ b/app/icons/arrow.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/icons/fire.svg b/app/icons/fire.svg
new file mode 100644
index 00000000000..446d532aaca
--- /dev/null
+++ b/app/icons/fire.svg
@@ -0,0 +1 @@
+
diff --git a/app/icons/hd.svg b/app/icons/hd.svg
new file mode 100644
index 00000000000..baae66af0f2
--- /dev/null
+++ b/app/icons/hd.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/app/icons/logo.svg b/app/icons/logo.svg
new file mode 100644
index 00000000000..b80263b8638
--- /dev/null
+++ b/app/icons/logo.svg
@@ -0,0 +1,19 @@
+
diff --git a/app/icons/palette.svg b/app/icons/palette.svg
new file mode 100644
index 00000000000..474d0e2177d
--- /dev/null
+++ b/app/icons/palette.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/app/icons/shortcutkey.svg b/app/icons/shortcutkey.svg
new file mode 100644
index 00000000000..32a4e7d3e04
--- /dev/null
+++ b/app/icons/shortcutkey.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/icons/speak-stop.svg b/app/icons/speak-stop.svg
new file mode 100644
index 00000000000..926ae7bb3d6
--- /dev/null
+++ b/app/icons/speak-stop.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/icons/speak.svg b/app/icons/speak.svg
new file mode 100644
index 00000000000..e02212c9a42
--- /dev/null
+++ b/app/icons/speak.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/icons/voice-white.svg b/app/icons/voice-white.svg
new file mode 100644
index 00000000000..e7d5cbcc86f
--- /dev/null
+++ b/app/icons/voice-white.svg
@@ -0,0 +1,16 @@
+
diff --git a/app/icons/zoom.svg b/app/icons/zoom.svg
new file mode 100644
index 00000000000..507b4957fdc
--- /dev/null
+++ b/app/icons/zoom.svg
@@ -0,0 +1 @@
+
diff --git a/app/layout.tsx b/app/layout.tsx
index eda5f43dd83..7d14cb88d70 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -6,7 +6,7 @@ import { getClientConfig } from "./config/client";
import type { Metadata, Viewport } from "next";
import { SpeedInsights } from "@vercel/speed-insights/next";
import { getServerSideConfig } from "./config/server";
-import { GoogleTagManager } from "@next/third-parties/google";
+import { GoogleTagManager, GoogleAnalytics } from "@next/third-parties/google";
const serverConfig = getServerSideConfig();
export const metadata: Metadata = {
@@ -41,7 +41,11 @@ export default function RootLayout({
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
-
+
@@ -56,6 +60,11 @@ export default function RootLayout({
>
)}
+ {serverConfig?.gaId && (
+ <>
+
+ >
+ )}