Skip to content

Commit e1cb8e3

Browse files
authored
Merge pull request ChatGPTNextWeb#5989 from bestsanmao/add_deepseek
since ChatGPTNextWeb#5984, add DeepSeek as a new ModelProvider (with deepseek-chat&deepseek-coder models), so that user can use openai and deepseek at same time with different api url & key
2 parents c0062ff + 67338ff commit e1cb8e3

File tree

9 files changed

+396
-1
lines changed

9 files changed

+396
-1
lines changed

app/api/[provider]/[...path]/route.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { handle as alibabaHandler } from "../../alibaba";
1010
import { handle as moonshotHandler } from "../../moonshot";
1111
import { handle as stabilityHandler } from "../../stability";
1212
import { handle as iflytekHandler } from "../../iflytek";
13+
import { handle as deepseekHandler } from "../../deepseek";
1314
import { handle as xaiHandler } from "../../xai";
1415
import { handle as chatglmHandler } from "../../glm";
1516
import { handle as proxyHandler } from "../../proxy";
@@ -40,6 +41,8 @@ async function handle(
4041
return stabilityHandler(req, { params });
4142
case ApiPath.Iflytek:
4243
return iflytekHandler(req, { params });
44+
case ApiPath.DeepSeek:
45+
return deepseekHandler(req, { params });
4346
case ApiPath.XAI:
4447
return xaiHandler(req, { params });
4548
case ApiPath.ChatGLM:

app/api/auth.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ export function auth(req: NextRequest, modelProvider: ModelProvider) {
9292
systemApiKey =
9393
serverConfig.iflytekApiKey + ":" + serverConfig.iflytekApiSecret;
9494
break;
95+
case ModelProvider.DeepSeek:
96+
systemApiKey = serverConfig.deepseekApiKey;
97+
break;
9598
case ModelProvider.XAI:
9699
systemApiKey = serverConfig.xaiApiKey;
97100
break;

app/api/common.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ export async function requestOpenai(req: NextRequest) {
124124
[
125125
ServiceProvider.OpenAI,
126126
ServiceProvider.Azure,
127-
jsonBody?.model as string, // support provider-unspecified model
127+
jsonBody?.model as string, // support provider-unspecified model
128128
],
129129
)
130130
) {

app/api/deepseek.ts

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import { getServerSideConfig } from "@/app/config/server";
2+
import {
3+
DEEPSEEK_BASE_URL,
4+
ApiPath,
5+
ModelProvider,
6+
ServiceProvider,
7+
} from "@/app/constant";
8+
import { prettyObject } from "@/app/utils/format";
9+
import { NextRequest, NextResponse } from "next/server";
10+
import { auth } from "@/app/api/auth";
11+
import { isModelNotavailableInServer } from "@/app/utils/model";
12+
13+
const serverConfig = getServerSideConfig();
14+
15+
export async function handle(
16+
req: NextRequest,
17+
{ params }: { params: { path: string[] } },
18+
) {
19+
console.log("[DeepSeek Route] params ", params);
20+
21+
if (req.method === "OPTIONS") {
22+
return NextResponse.json({ body: "OK" }, { status: 200 });
23+
}
24+
25+
const authResult = auth(req, ModelProvider.DeepSeek);
26+
if (authResult.error) {
27+
return NextResponse.json(authResult, {
28+
status: 401,
29+
});
30+
}
31+
32+
try {
33+
const response = await request(req);
34+
return response;
35+
} catch (e) {
36+
console.error("[DeepSeek] ", e);
37+
return NextResponse.json(prettyObject(e));
38+
}
39+
}
40+
41+
async function request(req: NextRequest) {
42+
const controller = new AbortController();
43+
44+
// alibaba use base url or just remove the path
45+
let path = `${req.nextUrl.pathname}`.replaceAll(ApiPath.DeepSeek, "");
46+
47+
let baseUrl = serverConfig.deepseekUrl || DEEPSEEK_BASE_URL;
48+
49+
if (!baseUrl.startsWith("http")) {
50+
baseUrl = `https://${baseUrl}`;
51+
}
52+
53+
if (baseUrl.endsWith("/")) {
54+
baseUrl = baseUrl.slice(0, -1);
55+
}
56+
57+
console.log("[Proxy] ", path);
58+
console.log("[Base Url]", baseUrl);
59+
60+
const timeoutId = setTimeout(
61+
() => {
62+
controller.abort();
63+
},
64+
10 * 60 * 1000,
65+
);
66+
67+
const fetchUrl = `${baseUrl}${path}`;
68+
const fetchOptions: RequestInit = {
69+
headers: {
70+
"Content-Type": "application/json",
71+
Authorization: req.headers.get("Authorization") ?? "",
72+
},
73+
method: req.method,
74+
body: req.body,
75+
redirect: "manual",
76+
// @ts-ignore
77+
duplex: "half",
78+
signal: controller.signal,
79+
};
80+
81+
// #1815 try to refuse some request to some models
82+
if (serverConfig.customModels && req.body) {
83+
try {
84+
const clonedBody = await req.text();
85+
fetchOptions.body = clonedBody;
86+
87+
const jsonBody = JSON.parse(clonedBody) as { model?: string };
88+
89+
// not undefined and is false
90+
if (
91+
isModelNotavailableInServer(
92+
serverConfig.customModels,
93+
jsonBody?.model as string,
94+
ServiceProvider.Moonshot as string,
95+
)
96+
) {
97+
return NextResponse.json(
98+
{
99+
error: true,
100+
message: `you are not allowed to use ${jsonBody?.model} model`,
101+
},
102+
{
103+
status: 403,
104+
},
105+
);
106+
}
107+
} catch (e) {
108+
console.error(`[DeepSeek] filter`, e);
109+
}
110+
}
111+
try {
112+
const res = await fetch(fetchUrl, fetchOptions);
113+
114+
// to prevent browser prompt for credentials
115+
const newHeaders = new Headers(res.headers);
116+
newHeaders.delete("www-authenticate");
117+
// to disable nginx buffering
118+
newHeaders.set("X-Accel-Buffering", "no");
119+
120+
return new Response(res.body, {
121+
status: res.status,
122+
statusText: res.statusText,
123+
headers: newHeaders,
124+
});
125+
} finally {
126+
clearTimeout(timeoutId);
127+
}
128+
}

app/client/api.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { QwenApi } from "./platforms/alibaba";
2020
import { HunyuanApi } from "./platforms/tencent";
2121
import { MoonshotApi } from "./platforms/moonshot";
2222
import { SparkApi } from "./platforms/iflytek";
23+
import { DeepSeekApi } from "./platforms/deepseek";
2324
import { XAIApi } from "./platforms/xai";
2425
import { ChatGLMApi } from "./platforms/glm";
2526

@@ -154,6 +155,9 @@ export class ClientApi {
154155
case ModelProvider.Iflytek:
155156
this.llm = new SparkApi();
156157
break;
158+
case ModelProvider.DeepSeek:
159+
this.llm = new DeepSeekApi();
160+
break;
157161
case ModelProvider.XAI:
158162
this.llm = new XAIApi();
159163
break;
@@ -247,6 +251,7 @@ export function getHeaders(ignoreHeaders: boolean = false) {
247251
const isAlibaba = modelConfig.providerName === ServiceProvider.Alibaba;
248252
const isMoonshot = modelConfig.providerName === ServiceProvider.Moonshot;
249253
const isIflytek = modelConfig.providerName === ServiceProvider.Iflytek;
254+
const isDeepSeek = modelConfig.providerName === ServiceProvider.DeepSeek;
250255
const isXAI = modelConfig.providerName === ServiceProvider.XAI;
251256
const isChatGLM = modelConfig.providerName === ServiceProvider.ChatGLM;
252257
const isEnabledAccessControl = accessStore.enabledAccessControl();
@@ -264,6 +269,8 @@ export function getHeaders(ignoreHeaders: boolean = false) {
264269
? accessStore.moonshotApiKey
265270
: isXAI
266271
? accessStore.xaiApiKey
272+
: isDeepSeek
273+
? accessStore.deepseekApiKey
267274
: isChatGLM
268275
? accessStore.chatglmApiKey
269276
: isIflytek
@@ -280,6 +287,7 @@ export function getHeaders(ignoreHeaders: boolean = false) {
280287
isAlibaba,
281288
isMoonshot,
282289
isIflytek,
290+
isDeepSeek,
283291
isXAI,
284292
isChatGLM,
285293
apiKey,
@@ -302,6 +310,13 @@ export function getHeaders(ignoreHeaders: boolean = false) {
302310
isAzure,
303311
isAnthropic,
304312
isBaidu,
313+
isByteDance,
314+
isAlibaba,
315+
isMoonshot,
316+
isIflytek,
317+
isDeepSeek,
318+
isXAI,
319+
isChatGLM,
305320
apiKey,
306321
isEnabledAccessControl,
307322
} = getConfig();
@@ -344,6 +359,8 @@ export function getClientApi(provider: ServiceProvider): ClientApi {
344359
return new ClientApi(ModelProvider.Moonshot);
345360
case ServiceProvider.Iflytek:
346361
return new ClientApi(ModelProvider.Iflytek);
362+
case ServiceProvider.DeepSeek:
363+
return new ClientApi(ModelProvider.DeepSeek);
347364
case ServiceProvider.XAI:
348365
return new ClientApi(ModelProvider.XAI);
349366
case ServiceProvider.ChatGLM:

0 commit comments

Comments
 (0)