Compare commits

..

3 Commits

Author SHA1 Message Date
takestairs
27c2c14444 Merge 812c1c770c into f7cde17919 2025-03-02 14:31:28 +08:00
unknown
812c1c770c plugin schema 地址切换至 jsdelivr CDN 2025-02-18 22:13:56 +08:00
unknown
54e3753d93 切换jsdelivr镜像,更新prompts列表 2025-02-18 20:49:28 +08:00
11 changed files with 595 additions and 429 deletions

View File

@@ -7,7 +7,7 @@
<h1 align="center">NextChat</h1>
<h1 align="center">NextChat (ChatGPT Next Web)</h1>
English / [简体中文](./README_CN.md)
@@ -22,12 +22,12 @@ English / [简体中文](./README_CN.md)
[![MacOS][MacOS-image]][download-url]
[![Linux][Linux-image]][download-url]
[NextChatAI](https://nextchat.club?utm_source=readme) / [iOS APP](https://apps.apple.com/us/app/nextchat-ai/id6743085599) / [Web App Demo](https://app.nextchat.club) / [Desktop App](https://github.com/Yidadaa/ChatGPT-Next-Web/releases) / [Enterprise Edition](#enterprise-edition)
[NextChatAI](https://nextchat.club?utm_source=readme) / [Web App Demo](https://app.nextchat.dev) / [Desktop App](https://github.com/Yidadaa/ChatGPT-Next-Web/releases) / [Discord](https://discord.gg/YCkeafCafC) / [Enterprise Edition](#enterprise-edition) / [Twitter](https://twitter.com/NextChatDev)
[saas-url]: https://nextchat.club?utm_source=readme
[saas-image]: https://img.shields.io/badge/NextChat-Saas-green?logo=microsoftedge
[web-url]: https://app.nextchat.club/
[web-url]: https://app.nextchat.dev/
[download-url]: https://github.com/Yidadaa/ChatGPT-Next-Web/releases
[Web-image]: https://img.shields.io/badge/Web-PWA-orange?logo=microsoftedge
[Windows-image]: https://img.shields.io/badge/-Windows-blue?logo=windows
@@ -40,14 +40,31 @@ English / [简体中文](./README_CN.md)
</div>
## 🥳 Cheer for NextChat iOS Version Online!
> [👉 Click Here to Install Now](https://apps.apple.com/us/app/nextchat-ai/id6743085599)
## 👋 Hey, NextChat is going to develop a native app!
> [❤️ Source Code Coming Soon](https://github.com/ChatGPTNextWeb/NextChat-iOS)
> This week we are going to start working on iOS and Android APP, and we want to find some reliable friends to do it together!
![Github iOS Image](https://github.com/user-attachments/assets/e0aa334f-4c13-4dc9-8310-e3b09fa4b9f3)
✨ Several key points:
- Starting from 0, you are a veteran
- Completely open source, not hidden
- Native development, pursuing the ultimate experience
Will you come and do something together? 😎
https://github.com/ChatGPTNextWeb/NextChat/issues/6269
#Seeking for talents is thirsty #lack of people
## 🥳 Cheer for DeepSeek, China's AI star!
> Purpose-Built UI for DeepSeek Reasoner Model
<img src="https://github.com/user-attachments/assets/f3952210-3af1-4dc0-9b81-40eaa4847d9a"/>
## 🫣 NextChat Support MCP !
> Before build, please set env ENABLE_MCP=true

View File

@@ -56,7 +56,7 @@ export interface OpenAIListModelResponse {
export interface RequestPayload {
messages: {
role: "developer" | "system" | "user" | "assistant";
role: "system" | "user" | "assistant";
content: string | MultimodalContent[];
}[];
stream?: boolean;
@@ -198,8 +198,7 @@ export class ChatGPTApi implements LLMApi {
const isDalle3 = _isDalle3(options.config.model);
const isO1OrO3 =
options.config.model.startsWith("o1") ||
options.config.model.startsWith("o3") ||
options.config.model.startsWith("o4-mini");
options.config.model.startsWith("o3");
if (isDalle3) {
const prompt = getMessageTextContent(
options.messages.slice(-1)?.pop() as any,
@@ -238,21 +237,13 @@ export class ChatGPTApi implements LLMApi {
// Please do not ask me why not send max_tokens, no reason, this param is just shit, I dont want to explain anymore.
};
// O1 使用 max_completion_tokens 控制token数 (https://platform.openai.com/docs/guides/reasoning#controlling-costs)
if (isO1OrO3) {
// by default the o1/o3 models will not attempt to produce output that includes markdown formatting
// manually add "Formatting re-enabled" developer message to encourage markdown inclusion in model responses
// (https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/reasoning?tabs=python-secure#markdown-output)
requestPayload["messages"].unshift({
role: "developer",
content: "Formatting re-enabled",
});
// o1/o3 uses max_completion_tokens to control the number of tokens (https://platform.openai.com/docs/guides/reasoning#controlling-costs)
requestPayload["max_completion_tokens"] = modelConfig.max_tokens;
}
// add max_tokens to vision model
if (visionModel && !isO1OrO3) {
if (visionModel) {
requestPayload["max_tokens"] = Math.max(modelConfig.max_tokens, 4000);
}
}

View File

@@ -417,14 +417,6 @@ export const KnowledgeCutOffDate: Record<string, string> = {
"gpt-4-turbo": "2023-12",
"gpt-4-turbo-2024-04-09": "2023-12",
"gpt-4-turbo-preview": "2023-12",
"gpt-4.1": "2024-06",
"gpt-4.1-2025-04-14": "2024-06",
"gpt-4.1-mini": "2024-06",
"gpt-4.1-mini-2025-04-14": "2024-06",
"gpt-4.1-nano": "2024-06",
"gpt-4.1-nano-2025-04-14": "2024-06",
"gpt-4.5-preview": "2023-10",
"gpt-4.5-preview-2025-02-27": "2023-10",
"gpt-4o": "2023-10",
"gpt-4o-2024-05-13": "2023-10",
"gpt-4o-2024-08-06": "2023-10",
@@ -466,7 +458,6 @@ export const DEFAULT_TTS_VOICES = [
export const VISION_MODEL_REGEXES = [
/vision/,
/gpt-4o/,
/gpt-4\.1/,
/claude-3/,
/gemini-1\.5/,
/gemini-exp/,
@@ -478,8 +469,6 @@ export const VISION_MODEL_REGEXES = [
/^dall-e-3$/, // Matches exactly "dall-e-3"
/glm-4v/,
/vl/i,
/o3/,
/o4-mini/,
];
export const EXCLUDE_VISION_MODEL_REGEXES = [/claude-3-5-haiku-20241022/];
@@ -496,14 +485,6 @@ const openaiModels = [
"gpt-4-32k-0613",
"gpt-4-turbo",
"gpt-4-turbo-preview",
"gpt-4.1",
"gpt-4.1-2025-04-14",
"gpt-4.1-mini",
"gpt-4.1-mini-2025-04-14",
"gpt-4.1-nano",
"gpt-4.1-nano-2025-04-14",
"gpt-4.5-preview",
"gpt-4.5-preview-2025-02-27",
"gpt-4o",
"gpt-4o-2024-05-13",
"gpt-4o-2024-08-06",
@@ -518,20 +499,23 @@ const openaiModels = [
"o1-mini",
"o1-preview",
"o3-mini",
"o3",
"o4-mini",
];
const googleModels = [
"gemini-1.0-pro", // Deprecated on 2/15/2025
"gemini-1.5-pro-latest",
"gemini-1.5-pro",
"gemini-1.5-pro-002",
"gemini-1.5-pro-exp-0827",
"gemini-1.5-flash-latest",
"gemini-1.5-flash-8b-latest",
"gemini-1.5-flash",
"gemini-1.5-flash-8b",
"gemini-1.5-flash-002",
"gemini-1.5-flash-exp-0827",
"learnlm-1.5-pro-experimental",
"gemini-exp-1114",
"gemini-exp-1121",
"gemini-exp-1206",
"gemini-2.0-flash",
"gemini-2.0-flash-exp",
@@ -541,7 +525,6 @@ const googleModels = [
"gemini-2.0-flash-thinking-exp-01-21",
"gemini-2.0-pro-exp",
"gemini-2.0-pro-exp-02-05",
"gemini-2.5-pro-preview-06-05",
];
const anthropicModels = [
@@ -628,18 +611,6 @@ const xAIModes = [
"grok-2-vision-1212",
"grok-2-vision",
"grok-2-vision-latest",
"grok-3-mini-fast-beta",
"grok-3-mini-fast",
"grok-3-mini-fast-latest",
"grok-3-mini-beta",
"grok-3-mini",
"grok-3-mini-latest",
"grok-3-fast-beta",
"grok-3-fast",
"grok-3-fast-latest",
"grok-3-beta",
"grok-3",
"grok-3-latest",
];
const chatglmModels = [

View File

@@ -15,8 +15,6 @@ const config: Config = {
moduleNameMapper: {
"^@/(.*)$": "<rootDir>/$1",
},
extensionsToTreatAsEsm: [".ts", ".tsx"],
injectGlobals: true,
};
// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async

View File

@@ -1,22 +1,24 @@
// Learn more: https://github.com/testing-library/jest-dom
import "@testing-library/jest-dom";
import { jest } from "@jest/globals";
global.fetch = jest.fn(() =>
Promise.resolve({
ok: true,
status: 200,
json: () => Promise.resolve([]),
json: () => Promise.resolve({}),
headers: new Headers(),
redirected: false,
statusText: "OK",
type: "basic",
url: "",
clone: function () {
return this;
},
body: null,
bodyUsed: false,
arrayBuffer: () => Promise.resolve(new ArrayBuffer(0)),
blob: () => Promise.resolve(new Blob()),
formData: () => Promise.resolve(new FormData()),
text: () => Promise.resolve(""),
} as Response),
}),
);

View File

@@ -17,8 +17,8 @@
"prompts": "node ./scripts/fetch-prompts.mjs",
"prepare": "husky install",
"proxy-dev": "sh ./scripts/init-proxy.sh && proxychains -f ./scripts/proxychains.conf yarn dev",
"test": "node --no-warnings --experimental-vm-modules $(yarn bin jest) --watch",
"test:ci": "node --no-warnings --experimental-vm-modules $(yarn bin jest) --ci"
"test": "jest --watch",
"test:ci": "jest --ci"
},
"dependencies": {
"@fortaine/fetch-event-source": "^3.0.6",
@@ -83,7 +83,7 @@
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"lint-staged": "^13.2.2",
"prettier": "^3.6.2",
"prettier": "^3.0.2",
"ts-node": "^10.9.2",
"tsx": "^4.16.0",
"typescript": "5.2.2",

View File

@@ -2,16 +2,16 @@
{
"id": "dalle3",
"name": "Dalle3",
"schema": "https://ghp.ci/https://raw.githubusercontent.com/ChatGPTNextWeb/NextChat-Awesome-Plugins/main/plugins/dalle/openapi.json"
"schema": "https://cdn.jsdelivr.net/gh/ChatGPTNextWeb/NextChat-Awesome-Plugins@main/plugins/dalle/openapi.json"
},
{
"id": "arxivsearch",
"name": "ArxivSearch",
"schema": "https://ghp.ci/https://raw.githubusercontent.com/ChatGPTNextWeb/NextChat-Awesome-Plugins/main/plugins/arxivsearch/openapi.json"
"schema": "https://cdn.jsdelivr.net/gh/ChatGPTNextWeb/NextChat-Awesome-Plugins@main/plugins/arxivsearch/openapi.json"
},
{
"id": "duckduckgolite",
"name": "DuckDuckGoLiteSearch",
"schema": "https://ghp.ci/https://raw.githubusercontent.com/ChatGPTNextWeb/NextChat-Awesome-Plugins/main/plugins/duckduckgolite/openapi.json"
"schema": "https://cdn.jsdelivr.net/gh/ChatGPTNextWeb/NextChat-Awesome-Plugins@main/plugins/duckduckgolite/openapi.json"
}
]

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,13 @@
import fetch from "node-fetch";
import fs from "fs/promises";
const RAW_FILE_URL = "https://raw.githubusercontent.com/";
const MIRRORF_FILE_URL = "http://raw.fgit.ml/";
const MIRRORF_FILE_URL = "https://cdn.jsdelivr.net/gh/";
const RAW_CN_URL = "PlexPt/awesome-chatgpt-prompts-zh/main/prompts-zh.json";
const RAW_CN_URL = "PlexPt/awesome-chatgpt-prompts-zh@main/prompts-zh.json";
const CN_URL = MIRRORF_FILE_URL + RAW_CN_URL;
const RAW_TW_URL = "PlexPt/awesome-chatgpt-prompts-zh/main/prompts-zh-TW.json";
const RAW_TW_URL = "PlexPt/awesome-chatgpt-prompts-zh@main/prompts-zh-TW.json";
const TW_URL = MIRRORF_FILE_URL + RAW_TW_URL;
const RAW_EN_URL = "f/awesome-chatgpt-prompts/main/prompts.csv";
const RAW_EN_URL = "f/awesome-chatgpt-prompts@main/prompts.csv";
const EN_URL = MIRRORF_FILE_URL + RAW_EN_URL;
const FILE = "./public/prompts.json";
@@ -84,11 +83,11 @@ async function fetchEN() {
async function main() {
Promise.all([fetchCN(), fetchTW(), fetchEN()])
.then(([cn, tw, en]) => {
fs.writeFile(FILE, JSON.stringify({ cn, tw, en }));
fs.writeFile(FILE, JSON.stringify({ cn, tw, en }, null, 2));
})
.catch((e) => {
console.error("[Fetch] failed to fetch prompts");
fs.writeFile(FILE, JSON.stringify({ cn: [], tw: [], en: [] }));
fs.writeFile(FILE, JSON.stringify({ cn: [], tw: [], en: [] }, null, 2));
})
.finally(() => {
console.log("[Fetch] saved to " + FILE);

View File

@@ -1,4 +1,3 @@
import { jest } from "@jest/globals";
import { isVisionModel } from "../app/utils";
describe("isVisionModel", () => {
@@ -51,7 +50,7 @@ describe("isVisionModel", () => {
test("should identify models from VISION_MODELS env var", () => {
process.env.VISION_MODELS = "custom-vision-model,another-vision-model";
expect(isVisionModel("custom-vision-model")).toBe(true);
expect(isVisionModel("another-vision-model")).toBe(true);
expect(isVisionModel("unrelated-model")).toBe(false);
@@ -65,4 +64,4 @@ describe("isVisionModel", () => {
expect(isVisionModel("unrelated-model")).toBe(false);
expect(isVisionModel("gpt-4-vision")).toBe(true);
});
});
});

View File

@@ -7076,10 +7076,10 @@ prettier-linter-helpers@^1.0.0:
dependencies:
fast-diff "^1.1.2"
prettier@^3.6.2:
version "3.6.2"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.6.2.tgz#ccda02a1003ebbb2bfda6f83a074978f608b9393"
integrity sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==
prettier@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.2.tgz#78fcecd6d870551aa5547437cdae39d4701dca5b"
integrity sha512-o2YR9qtniXvwEZlOKbveKfDQVyqxbEIWn48Z8m3ZJjBjcCmUy3xZGIv+7AkaeuaTr6yPXJjwv07ZWlsWbEy1rQ==
pretty-format@^27.0.2:
version "27.5.1"