yxmiler commited on
Commit
00ad31b
·
verified ·
1 Parent(s): db537ae

Update index.js

Browse files
Files changed (1) hide show
  1. index.js +357 -357
index.js CHANGED
@@ -1,358 +1,358 @@
1
- import express from 'express';
2
- import WebSocket from 'ws';
3
- import { v4 as uuidv4 } from 'uuid';
4
- import { randomBytes } from 'crypto';
5
- import cors from 'cors';
6
- import dotenv from 'dotenv';
7
-
8
- // 配置加载
9
- dotenv.config();
10
-
11
- // 配置常量
12
- const CONFIG = {
13
- API: {
14
- BASE_URL: "wss://api.inkeep.com/graphql",
15
- API_KEY: process.env.API_KEY || "sk-123456",
16
- },
17
- MODELS: {
18
- 'claude-3-5-sonnet-20241022': 'claude-3-5-sonnet-20241022',
19
- },
20
- SERVER: {
21
- PORT: process.env.PORT || 3000,
22
- BODY_LIMIT: '5mb'
23
- },
24
- DEFAULT_HEADERS: {
25
- 'Host': 'api.inkeep.com',
26
- 'Connection': 'Upgrade',
27
- 'Pragma': 'no-cache',
28
- 'Cache-Control': 'no-cache',
29
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36',
30
- 'Upgrade': 'websocket',
31
- 'Origin': 'https://docs.anthropic.com',
32
- 'Sec-WebSocket-Version': '13',
33
- 'Accept-Encoding': 'gzip, deflate, br, zstd',
34
- 'Accept-Language': 'zh-CN,zh;q=0.9',
35
- 'Sec-WebSocket-Extensions': 'permessage-deflate; client_max_window_bits',
36
- 'Sec-WebSocket-Protocol': 'graphql-transport-ws'
37
- }
38
- };
39
-
40
- // AI API 客户端类
41
- class AiApiClient {
42
- constructor(modelId) {
43
- this.modelId = CONFIG.MODELS[modelId];
44
- if (!this.modelId) {
45
- throw new Error(`不支持的模型: ${modelId}`);
46
- }
47
- }
48
-
49
- // 处理消息内容
50
- processMessageContent(content) {
51
- if (typeof content === 'string') return content;
52
- if (Array.isArray(content)) {
53
- return content
54
- .filter(item => item.type === 'text')
55
- .map(item => item.text)
56
- .join('\n');
57
- }
58
- return typeof content === 'object' ? content.text || null : null;
59
- }
60
-
61
- // 转换消息格式
62
- async transformMessages(request) {
63
- let systemMessageList = [];
64
- let systemMergeMode = false;
65
- let closedSystemMergeMode = false;
66
-
67
- const contextMessages = await request.messages.reduce(async (accPromise, current) => {
68
- const acc = await accPromise;
69
- const currentContent = this.processMessageContent(current.content);
70
-
71
- if (currentContent === null) return acc;
72
-
73
- const currentMessageRole = current.role === "system" ? "USER" : current.role.toUpperCase();
74
-
75
- // 系统消息处理逻辑
76
- if (current.role === "system") {
77
- if (!closedSystemMergeMode) {
78
- systemMergeMode = true;
79
- const lastSystemMessage = systemMessageList[systemMessageList.length - 1];
80
-
81
- if (!lastSystemMessage) {
82
- systemMessageList.push(currentContent);
83
- } else {
84
- systemMessageList[systemMessageList.length - 1] = `${lastSystemMessage}\n${currentContent}`;
85
- }
86
- return acc;
87
- }
88
- }
89
-
90
- // 关闭系统消息合并模式
91
- if (current.role !== "system" && systemMergeMode) {
92
- systemMergeMode = false;
93
- closedSystemMergeMode = true;
94
- }
95
-
96
- // 消息合并逻辑
97
- const previousMessage = acc[acc.length - 1];
98
- const newMessage = `${currentMessageRole}: ${currentContent}`;
99
-
100
- if (!previousMessage || previousMessage.startsWith(currentMessageRole)) {
101
- return previousMessage
102
- ? [...acc.slice(0, -1), `${previousMessage}\n${currentContent}`]
103
- : [...acc, newMessage];
104
- }
105
-
106
- return [...acc, newMessage];
107
- }, Promise.resolve([]));
108
-
109
- return {
110
- contextMessages: contextMessages.join('\n'),
111
- systemMessage: systemMessageList.join('\n')
112
- };
113
- }
114
- }
115
-
116
- // 响应处理类
117
- class ResponseHandler {
118
- // 流式响应处理
119
- static async handleStreamResponse(responseContent, model, res) {
120
- res.setHeader('Content-Type', 'text/event-stream');
121
- res.setHeader('Cache-Control', 'no-cache');
122
- res.setHeader('Connection', 'keep-alive');
123
-
124
- let index = 0;
125
- while (index < responseContent.length) {
126
- const chunkSize = Math.floor(Math.random() * (30 - 16)) + 15;
127
- const chunk = responseContent.slice(index, index + chunkSize);
128
-
129
- res.write(`data: ${JSON.stringify({
130
- id: uuidv4(),
131
- object: 'chat.completion.chunk',
132
- created: Math.floor(Date.now() / 1000),
133
- model: model,
134
- choices: [{
135
- index: 0,
136
- delta: { content: chunk },
137
- finish_reason: null
138
- }]
139
- })}\n\n`);
140
-
141
- index += chunkSize;
142
- await new Promise(resolve => setTimeout(resolve, 50));
143
- }
144
-
145
- res.write('data: [DONE]\n\n');
146
- res.end();
147
- }
148
-
149
- // 普通响应处理
150
- static async handleNormalResponse(userMessage, responseContent, model, res) {
151
- res.json({
152
- id: uuidv4(),
153
- object: "chat.completion",
154
- created: Math.floor(Date.now() / 1000),
155
- model: model,
156
- choices: [{
157
- index: 0,
158
- message: {
159
- role: "assistant",
160
- content: responseContent
161
- },
162
- finish_reason: "stop"
163
- }],
164
- usage: {
165
- prompt_tokens: userMessage.length,
166
- completion_tokens: responseContent.length,
167
- total_tokens: userMessage.length + responseContent.length
168
- }
169
- });
170
- }
171
- }
172
-
173
- // WebSocket工具类
174
- class WebSocketUtils {
175
- // 生成WebSocket密钥
176
- static generateWebSocketKey() {
177
- return randomBytes(16).toString('base64');
178
- }
179
-
180
- // 创建WebSocket客户端
181
- static createWebSocketClient(requestPayload) {
182
- return new Promise((resolve, reject) => {
183
- const websocketKey = this.generateWebSocketKey();
184
- const ws = new WebSocket(CONFIG.API.BASE_URL, 'graphql-transport-ws', {
185
- headers: {
186
- ...CONFIG.DEFAULT_HEADERS,
187
- 'Sec-WebSocket-Key': websocketKey,
188
- }
189
- });
190
-
191
- let responseContent = '';
192
- let isComplete = false;
193
-
194
- ws.on('open', () => {
195
- console.log('WebSocket连接已建立');
196
- const connectionInitMessage = {
197
- type: 'connection_init',
198
- payload: {
199
- headers: {
200
- Authorization: 'Bearer ee5b7c15ed3553cd6abc407340aad09ac7cb3b9f76d8613a'
201
- }
202
- }
203
- };
204
- ws.send(JSON.stringify(connectionInitMessage));
205
- });
206
-
207
- ws.on('message', async (data) => {
208
- const message = data.toString();
209
- const parsedMessage = JSON.parse(message);
210
-
211
- switch (parsedMessage.type) {
212
- case 'connection_ack':
213
- console.log('WebSocket连接请求中');
214
- this.sendChatSubscription(ws, requestPayload);
215
- break;
216
- case 'next':
217
- const chatResponse = await this.handleChatResponse(parsedMessage);
218
- if (chatResponse) {
219
- responseContent = chatResponse;
220
- }
221
- break;
222
- case 'complete':
223
- isComplete = true;
224
- ws.close();
225
- resolve(responseContent);
226
- break;
227
- }
228
- });
229
-
230
- ws.on('error', (err) => {
231
- console.error('WebSocket错误:', err);
232
- reject(err);
233
- });
234
-
235
- ws.on('close', (code, reason) => {
236
- console.log('请求完毕,关闭连接');
237
- if (!isComplete) {
238
- reject(new Error('WebSocket closed unexpectedly'));
239
- }
240
- });
241
- });
242
- }
243
-
244
- // 发送聊天订阅
245
- static sendChatSubscription(ws, requestPayload) {
246
- const subscribeMessage = {
247
- id: uuidv4(),
248
- type: 'subscribe',
249
- payload: {
250
- variables: {
251
- messageInput: requestPayload.contextMessages,
252
- messageContext: null,
253
- organizationId: 'org_JfjtEvzbwOikUEUn',
254
- integrationId: 'clwtqz9sq001izszu8ms5g4om',
255
- chatMode: 'AUTO',
256
- context: requestPayload.systemMessage,
257
- messageAttributes: {},
258
- includeAIAnnotations: false,
259
- environment: 'production'
260
- },
261
- extensions: {},
262
- operationName: 'OnNewSessionChatResult',
263
- query: `subscription OnNewSessionChatResult($messageInput: String!, $messageContext: String, $organizationId: ID!, $integrationId: ID, $chatMode: ChatMode, $filters: ChatFiltersInput, $messageAttributes: JSON, $tags: [String!], $workflowId: String, $context: String, $guidance: String, $includeAIAnnotations: Boolean!, $environment: String) {
264
- newSessionChatResult(
265
- input: {messageInput: $messageInput, messageContext: $messageContext, organizationId: $organizationId, integrationId: $integrationId, chatMode: $chatMode, filters: $filters, messageAttributes: $messageAttributes, tags: $tags, workflowId: $workflowId, context: $context, guidance: $guidance, environment: $environment}
266
- ) {
267
- isEnd
268
- sessionId
269
- message {
270
- id
271
- content
272
- }
273
- __typename
274
- }
275
- }`
276
- }
277
- };
278
-
279
- ws.send(JSON.stringify(subscribeMessage));
280
- }
281
-
282
- // 处理聊天响应
283
- static async handleChatResponse(message) {
284
- if (message.payload && message.payload.data) {
285
- const chatResult = message.payload.data.newSessionChatResult;
286
- if (chatResult && chatResult.isEnd == true && chatResult.message) {
287
- return chatResult.message.content;
288
- }
289
- }
290
- return null;
291
- }
292
- }
293
-
294
- // 创建Express应用
295
- const app = express();
296
-
297
- // 中间件配置
298
- app.use(express.json({ limit: CONFIG.SERVER.BODY_LIMIT }));
299
- app.use(express.urlencoded({ extended: true, limit: CONFIG.SERVER.BODY_LIMIT }));
300
- app.use(cors({
301
- origin: '*',
302
- methods: ['GET', 'POST', 'OPTIONS'],
303
- allowedHeaders: ['Content-Type', 'Authorization']
304
- }));
305
-
306
- // 获取模型列表路由
307
- app.get('/hf/v1/models', (req, res) => {
308
- res.json({
309
- object: "list",
310
- data: [{
311
- id: "claude-3-5-sonnet-20241022",
312
- object: "model",
313
- created: Math.floor(Date.now() / 1000),
314
- owned_by: "claude",
315
- }]
316
- });
317
- });
318
-
319
- // 聊天完成路由
320
- app.post('/hf/v1/chat/completions', async (req, res) => {
321
- try {
322
- const { messages, model, stream } = req.body;
323
- const authToken = req.headers.authorization?.replace('Bearer ', '');
324
-
325
- if (authToken !== CONFIG.API.API_KEY) {
326
- return res.status(401).json({ error: "Unauthorized" });
327
- }
328
-
329
- const apiClient = new AiApiClient(req.body.model);
330
- const requestPayload = await apiClient.transformMessages(req.body);
331
-
332
- const userMessage = messages.reverse().find(message => message.role === 'user')?.content;
333
- if (!userMessage) {
334
- return res.status(400).json({ error: "缺失用户消息" });
335
- }
336
-
337
- const responseContent = await WebSocketUtils.createWebSocketClient(requestPayload);
338
-
339
- if (stream) {
340
- await ResponseHandler.handleStreamResponse(responseContent, model, res);
341
- } else {
342
- await ResponseHandler.handleNormalResponse(userMessage, responseContent, model, res);
343
- }
344
- } catch (error) {
345
- console.error('处理请求时发生错误:', error);
346
- res.status(500).json({ error: "内部服务器错误", details: error.message });
347
- }
348
- });
349
-
350
- // 404处理
351
- app.use((req, res) => {
352
- res.status(404).json({ message: "请使用正确请求路径" });
353
- });
354
-
355
- // 启动服务器
356
- app.listen(CONFIG.SERVER.PORT, () => {
357
- console.log(`服务器运行在 http://localhost:${CONFIG.SERVER.PORT}`);
358
  });
 
1
+ import express from 'express';
2
+ import WebSocket from 'ws';
3
+ import { v4 as uuidv4 } from 'uuid';
4
+ import { randomBytes } from 'crypto';
5
+ import cors from 'cors';
6
+ import dotenv from 'dotenv';
7
+
8
+ // 配置加载
9
+ dotenv.config();
10
+
11
+ // 配置常量
12
+ const CONFIG = {
13
+ API: {
14
+ BASE_URL: "wss://api.inkeep.com/graphql",
15
+ API_KEY: process.env.API_KEY || "sk-123456",
16
+ },
17
+ MODELS: {
18
+ 'claude-3-5-sonnet-20241022': 'claude-3-5-sonnet-20241022',
19
+ },
20
+ SERVER: {
21
+ PORT: process.env.PORT || 3000,
22
+ BODY_LIMIT: '5mb'
23
+ },
24
+ DEFAULT_HEADERS: {
25
+ 'Host': 'api.inkeep.com',
26
+ 'Connection': 'Upgrade',
27
+ 'Pragma': 'no-cache',
28
+ 'Cache-Control': 'no-cache',
29
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36',
30
+ 'Upgrade': 'websocket',
31
+ 'Origin': 'https://docs.anthropic.com',
32
+ 'Sec-WebSocket-Version': '13',
33
+ 'Accept-Encoding': 'gzip, deflate, br, zstd',
34
+ 'Accept-Language': 'zh-CN,zh;q=0.9',
35
+ 'Sec-WebSocket-Extensions': 'permessage-deflate; client_max_window_bits',
36
+ 'Sec-WebSocket-Protocol': 'graphql-transport-ws'
37
+ }
38
+ };
39
+
40
+ // AI API 客户端类
41
+ class AiApiClient {
42
+ constructor(modelId) {
43
+ this.modelId = CONFIG.MODELS[modelId];
44
+ if (!this.modelId) {
45
+ throw new Error(`不支持的模型: ${modelId}`);
46
+ }
47
+ }
48
+
49
+ // 处理消息内容
50
+ processMessageContent(content) {
51
+ if (typeof content === 'string') return content;
52
+ if (Array.isArray(content)) {
53
+ return content
54
+ .filter(item => item.type === 'text')
55
+ .map(item => item.text)
56
+ .join('\n');
57
+ }
58
+ return typeof content === 'object' ? content.text || null : null;
59
+ }
60
+
61
+ // 转换消息格式
62
+ async transformMessages(request) {
63
+ let systemMessageList = [];
64
+ let systemMergeMode = false;
65
+ let closedSystemMergeMode = false;
66
+
67
+ const contextMessages = await request.messages.reduce(async (accPromise, current) => {
68
+ const acc = await accPromise;
69
+ const currentContent = this.processMessageContent(current.content);
70
+
71
+ if (currentContent === null) return acc;
72
+
73
+ const currentMessageRole = current.role === "system" || current.role === "user" ? "HUMAN" : "ASSISTANT";
74
+
75
+ // 系统消息处理逻辑
76
+ if (current.role === "system") {
77
+ if (!closedSystemMergeMode) {
78
+ systemMergeMode = true;
79
+ const lastSystemMessage = systemMessageList[systemMessageList.length - 1];
80
+
81
+ if (!lastSystemMessage) {
82
+ systemMessageList.push(currentContent);
83
+ } else {
84
+ systemMessageList[systemMessageList.length - 1] = `${lastSystemMessage}\n${currentContent}`;
85
+ }
86
+ return acc;
87
+ }
88
+ }
89
+
90
+ // 关闭系统消息合并模式
91
+ if (current.role !== "system" && systemMergeMode) {
92
+ systemMergeMode = false;
93
+ closedSystemMergeMode = true;
94
+ }
95
+
96
+ // 消息合并逻辑
97
+ const previousMessage = acc[acc.length - 1];
98
+ const newMessage = `${currentMessageRole}: ${currentContent}`;
99
+
100
+ if (!previousMessage || previousMessage.startsWith(currentMessageRole)) {
101
+ return previousMessage
102
+ ? [...acc.slice(0, -1), `${previousMessage}\n${currentContent}`]
103
+ : [...acc, newMessage];
104
+ }
105
+
106
+ return [...acc, newMessage];
107
+ }, Promise.resolve([]));
108
+
109
+ return {
110
+ contextMessages: contextMessages.join('\n'),
111
+ systemMessage: systemMessageList.join('\n')
112
+ };
113
+ }
114
+ }
115
+
116
+ // 响应处理类
117
+ class ResponseHandler {
118
+ // 流式响应处理
119
+ static async handleStreamResponse(responseContent, model, res) {
120
+ res.setHeader('Content-Type', 'text/event-stream');
121
+ res.setHeader('Cache-Control', 'no-cache');
122
+ res.setHeader('Connection', 'keep-alive');
123
+
124
+ let index = 0;
125
+ while (index < responseContent.length) {
126
+ const chunkSize = Math.floor(Math.random() * (30 - 16)) + 15;
127
+ const chunk = responseContent.slice(index, index + chunkSize);
128
+
129
+ res.write(`data: ${JSON.stringify({
130
+ id: uuidv4(),
131
+ object: 'chat.completion.chunk',
132
+ created: Math.floor(Date.now() / 1000),
133
+ model: model,
134
+ choices: [{
135
+ index: 0,
136
+ delta: { content: chunk },
137
+ finish_reason: null
138
+ }]
139
+ })}\n\n`);
140
+
141
+ index += chunkSize;
142
+ await new Promise(resolve => setTimeout(resolve, 50));
143
+ }
144
+
145
+ res.write('data: [DONE]\n\n');
146
+ res.end();
147
+ }
148
+
149
+ // 普通响应处理
150
+ static async handleNormalResponse(userMessage, responseContent, model, res) {
151
+ res.json({
152
+ id: uuidv4(),
153
+ object: "chat.completion",
154
+ created: Math.floor(Date.now() / 1000),
155
+ model: model,
156
+ choices: [{
157
+ index: 0,
158
+ message: {
159
+ role: "assistant",
160
+ content: responseContent
161
+ },
162
+ finish_reason: "stop"
163
+ }],
164
+ usage: {
165
+ prompt_tokens: userMessage.length,
166
+ completion_tokens: responseContent.length,
167
+ total_tokens: userMessage.length + responseContent.length
168
+ }
169
+ });
170
+ }
171
+ }
172
+
173
+ // WebSocket工具类
174
+ class WebSocketUtils {
175
+ // 生成WebSocket密钥
176
+ static generateWebSocketKey() {
177
+ return randomBytes(16).toString('base64');
178
+ }
179
+
180
+ // 创建WebSocket客户端
181
+ static createWebSocketClient(requestPayload) {
182
+ return new Promise((resolve, reject) => {
183
+ const websocketKey = this.generateWebSocketKey();
184
+ const ws = new WebSocket(CONFIG.API.BASE_URL, 'graphql-transport-ws', {
185
+ headers: {
186
+ ...CONFIG.DEFAULT_HEADERS,
187
+ 'Sec-WebSocket-Key': websocketKey,
188
+ }
189
+ });
190
+
191
+ let responseContent = '';
192
+ let isComplete = false;
193
+
194
+ ws.on('open', () => {
195
+ console.log('WebSocket连接已建立');
196
+ const connectionInitMessage = {
197
+ type: 'connection_init',
198
+ payload: {
199
+ headers: {
200
+ Authorization: 'Bearer ee5b7c15ed3553cd6abc407340aad09ac7cb3b9f76d8613a'
201
+ }
202
+ }
203
+ };
204
+ ws.send(JSON.stringify(connectionInitMessage));
205
+ });
206
+
207
+ ws.on('message', async (data) => {
208
+ const message = data.toString();
209
+ const parsedMessage = JSON.parse(message);
210
+
211
+ switch (parsedMessage.type) {
212
+ case 'connection_ack':
213
+ console.log('WebSocket连接请求中');
214
+ this.sendChatSubscription(ws, requestPayload);
215
+ break;
216
+ case 'next':
217
+ const chatResponse = await this.handleChatResponse(parsedMessage);
218
+ if (chatResponse) {
219
+ responseContent = chatResponse;
220
+ }
221
+ break;
222
+ case 'complete':
223
+ isComplete = true;
224
+ ws.close();
225
+ resolve(responseContent);
226
+ break;
227
+ }
228
+ });
229
+
230
+ ws.on('error', (err) => {
231
+ console.error('WebSocket错误:', err);
232
+ reject(err);
233
+ });
234
+
235
+ ws.on('close', (code, reason) => {
236
+ console.log('请求完毕,关闭连接');
237
+ if (!isComplete) {
238
+ reject(new Error('WebSocket closed unexpectedly'));
239
+ }
240
+ });
241
+ });
242
+ }
243
+
244
+ // 发送聊天订阅
245
+ static sendChatSubscription(ws, requestPayload) {
246
+ const subscribeMessage = {
247
+ id: uuidv4(),
248
+ type: 'subscribe',
249
+ payload: {
250
+ variables: {
251
+ messageInput: requestPayload.contextMessages,
252
+ messageContext: null,
253
+ organizationId: 'org_JfjtEvzbwOikUEUn',
254
+ integrationId: 'clwtqz9sq001izszu8ms5g4om',
255
+ chatMode: 'AUTO',
256
+ context: requestPayload.systemMessage,
257
+ messageAttributes: {},
258
+ includeAIAnnotations: false,
259
+ environment: 'production'
260
+ },
261
+ extensions: {},
262
+ operationName: 'OnNewSessionChatResult',
263
+ query: `subscription OnNewSessionChatResult($messageInput: String!, $messageContext: String, $organizationId: ID!, $integrationId: ID, $chatMode: ChatMode, $filters: ChatFiltersInput, $messageAttributes: JSON, $tags: [String!], $workflowId: String, $context: String, $guidance: String, $includeAIAnnotations: Boolean!, $environment: String) {
264
+ newSessionChatResult(
265
+ input: {messageInput: $messageInput, messageContext: $messageContext, organizationId: $organizationId, integrationId: $integrationId, chatMode: $chatMode, filters: $filters, messageAttributes: $messageAttributes, tags: $tags, workflowId: $workflowId, context: $context, guidance: $guidance, environment: $environment}
266
+ ) {
267
+ isEnd
268
+ sessionId
269
+ message {
270
+ id
271
+ content
272
+ }
273
+ __typename
274
+ }
275
+ }`
276
+ }
277
+ };
278
+
279
+ ws.send(JSON.stringify(subscribeMessage));
280
+ }
281
+
282
+ // 处理聊天响应
283
+ static async handleChatResponse(message) {
284
+ if (message.payload && message.payload.data) {
285
+ const chatResult = message.payload.data.newSessionChatResult;
286
+ if (chatResult && chatResult.isEnd == true && chatResult.message) {
287
+ return chatResult.message.content;
288
+ }
289
+ }
290
+ return null;
291
+ }
292
+ }
293
+
294
+ // 创建Express应用
295
+ const app = express();
296
+
297
+ // 中间件配置
298
+ app.use(express.json({ limit: CONFIG.SERVER.BODY_LIMIT }));
299
+ app.use(express.urlencoded({ extended: true, limit: CONFIG.SERVER.BODY_LIMIT }));
300
+ app.use(cors({
301
+ origin: '*',
302
+ methods: ['GET', 'POST', 'OPTIONS'],
303
+ allowedHeaders: ['Content-Type', 'Authorization']
304
+ }));
305
+
306
+ // 获取模型列表路由
307
+ app.get('/hf/v1/models', (req, res) => {
308
+ res.json({
309
+ object: "list",
310
+ data: [{
311
+ id: "claude-3-5-sonnet-20241022",
312
+ object: "model",
313
+ created: Math.floor(Date.now() / 1000),
314
+ owned_by: "claude",
315
+ }]
316
+ });
317
+ });
318
+
319
+ // 聊天完成路由
320
+ app.post('/hf/v1/chat/completions', async (req, res) => {
321
+ try {
322
+ const { messages, model, stream } = req.body;
323
+ const authToken = req.headers.authorization?.replace('Bearer ', '');
324
+
325
+ if (authToken !== CONFIG.API.API_KEY) {
326
+ return res.status(401).json({ error: "Unauthorized" });
327
+ }
328
+
329
+ const apiClient = new AiApiClient(req.body.model);
330
+ const requestPayload = await apiClient.transformMessages(req.body);
331
+
332
+ const userMessage = messages.reverse().find(message => message.role === 'user')?.content;
333
+ if (!userMessage) {
334
+ return res.status(400).json({ error: "缺失用户消息" });
335
+ }
336
+
337
+ const responseContent = await WebSocketUtils.createWebSocketClient(requestPayload);
338
+
339
+ if (stream) {
340
+ await ResponseHandler.handleStreamResponse(responseContent, model, res);
341
+ } else {
342
+ await ResponseHandler.handleNormalResponse(userMessage, responseContent, model, res);
343
+ }
344
+ } catch (error) {
345
+ console.error('处理请求时发生错误:', error);
346
+ res.status(500).json({ error: "内部服务器错误", details: error.message });
347
+ }
348
+ });
349
+
350
+ // 404处理
351
+ app.use((req, res) => {
352
+ res.status(404).json({ message: "请使用正确请求路径" });
353
+ });
354
+
355
+ // 启动服务器
356
+ app.listen(CONFIG.SERVER.PORT, () => {
357
+ console.log(`服务器运行在 http://localhost:${CONFIG.SERVER.PORT}`);
358
  });