dan92 commited on
Commit
e4be06a
·
verified ·
1 Parent(s): d48b362

Upload 2 files

Browse files
Files changed (1) hide show
  1. src/index.js +18 -212
src/index.js CHANGED
@@ -19,22 +19,6 @@ app.use(bodyParser({
19
  textLimit: '30mb', // text 数据大小限制
20
  }))
21
 
22
- // 添加重定向中间件 - 移到路由注册之前
23
- app.use(async (ctx, next) => {
24
- console.log('收到请求:', ctx.method, ctx.path, ctx.query)
25
- if (ctx.path.startsWith('/v1/')) {
26
- const newPath = '/hf' + ctx.path
27
- console.log('重定向:', ctx.path, '->', newPath)
28
- ctx.status = 307 // 临时重定向,保持 HTTP 方法
29
- ctx.redirect(newPath)
30
- return
31
- }
32
- await next()
33
- })
34
-
35
- // 注册路由
36
- app.use(router.routes()).use(router.allowedMethods())
37
-
38
  const makeRequest = async (session_id, requestModel, messages) => {
39
  console.log('开始请求 genspark.ai:', { session_id, requestModel })
40
  try {
@@ -93,8 +77,8 @@ const makeRequest = async (session_id, requestModel, messages) => {
93
  }
94
  }
95
 
96
-
97
- router.post('/v1/chat/completions', async (ctx) => {
98
  const { messages, stream = false, model = 'claude-3-5-sonnet' } = ctx.request.body
99
  const session_id = ctx.get('Authorization')?.replace('Bearer ', '')
100
 
@@ -150,30 +134,20 @@ router.post('/v1/chat/completions', async (ctx) => {
150
  const { done, value } = await reader.read()
151
  if (done) {
152
  if (stream == "true" || stream == true) {
153
- // 发送完成标记
154
  ctx.res.write('data: [DONE]\n\n')
155
  }
156
  break
157
  }
158
 
159
  if (stream) {
160
-
161
  const text = new TextDecoder().decode(value)
162
  const textContent = [...text.matchAll(/data:.*"}/g)]
163
 
164
  textContent.forEach(item => {
165
- if (!item[0]) {
166
- return
167
- }
168
-
169
  const content = JSON.parse(item[0].replace("data: ", ''))
170
- if (!content || !content.delta) {
171
- return
172
- }
173
 
174
- // console.log(content.delta)
175
-
176
- // 发送增量内容
177
  ctx.res.write(`data: ${JSON.stringify({
178
  "id": `chatcmpl-${messageId}`,
179
  "choices": [
@@ -193,18 +167,10 @@ router.post('/v1/chat/completions', async (ctx) => {
193
  const text = new TextDecoder().decode(value)
194
  const textContent = [...text.matchAll(/data:.*"}/g)]
195
 
196
-
197
  textContent.forEach(item => {
198
- if (!item[0]) {
199
- return
200
- }
201
-
202
  const content = JSON.parse(item[0].replace("data: ", ''))
203
- if (!content || !content.field_value || content.field_name == 'session_state.answer_is_finished' || content.field_name == 'content' || content.field_name == 'session_state' || content.delta || content.type == 'project_field') {
204
- return
205
- }
206
-
207
- // console.log(content)
208
 
209
  resBody = {
210
  id: `chatcmpl-${messageId}`,
@@ -227,14 +193,11 @@ router.post('/v1/chat/completions', async (ctx) => {
227
  total_tokens: content.field_value.length,
228
  },
229
  }
230
-
231
  })
232
  }
233
-
234
  }
235
 
236
  if (stream == "false" || stream == false) {
237
- // console.log(resBody)
238
  ctx.body = resBody
239
  } else {
240
  ctx.res.end()
@@ -244,7 +207,6 @@ router.post('/v1/chat/completions', async (ctx) => {
244
  console.error('流式响应出错:', error)
245
  ctx.res.end()
246
  }
247
-
248
  } catch (error) {
249
  console.error('请求处理出错:', error)
250
  ctx.status = error.status || 500
@@ -253,162 +215,10 @@ router.post('/v1/chat/completions', async (ctx) => {
253
  details: error.toString()
254
  }
255
  }
256
- })
257
-
258
- // hf/v1 路由(复制 v1 路由的处理逻辑)
259
- router.post('/hf/v1/chat/completions', async (ctx) => {
260
- const { messages, stream = false, model = 'claude-3-5-sonnet' } = ctx.request.body
261
- const session_id = ctx.get('Authorization')?.replace('Bearer ', '')
262
-
263
- if (!session_id) {
264
- ctx.status = 401
265
- ctx.body = { error: '未提供有效的 session_id' }
266
- return
267
- }
268
-
269
- try {
270
- const response = await makeRequest(session_id, model, messages)
271
-
272
- if (!response.body) {
273
- throw new Error('Response body is null')
274
- }
275
-
276
- if (stream == "true" || stream == true) {
277
- ctx.set({
278
- 'Content-Type': 'text/event-stream',
279
- 'Cache-Control': 'no-cache',
280
- 'Connection': 'keep-alive',
281
- })
282
- } else {
283
- ctx.set({
284
- 'Content-Type': 'application/json',
285
- })
286
- }
287
-
288
- const messageId = crypto.randomUUID()
289
- const reader = response.body.getReader()
290
- if (stream == "true" || stream == true) {
291
- ctx.res.write(`data: ${JSON.stringify({
292
- "id": `chatcmpl-${messageId}`,
293
- "choices": [
294
- {
295
- "index": 0,
296
- "delta": {
297
- "content": "",
298
- "role": "assistant"
299
- }
300
- }
301
- ],
302
- "created": Math.floor(Date.now() / 1000),
303
- "model": models[`${model}`],
304
- "object": "chat.completion.chunk"
305
- })}\n\n`)
306
- }
307
-
308
- try {
309
- let resBody = {}
310
-
311
- while (true) {
312
- const { done, value } = await reader.read()
313
- if (done) {
314
- if (stream == "true" || stream == true) {
315
- // 发送完成标记
316
- ctx.res.write('data: [DONE]\n\n')
317
- }
318
- break
319
- }
320
-
321
- if (stream) {
322
- const text = new TextDecoder().decode(value)
323
- const textContent = [...text.matchAll(/data:.*"}/g)]
324
-
325
- textContent.forEach(item => {
326
- if (!item[0]) {
327
- return
328
- }
329
-
330
- const content = JSON.parse(item[0].replace("data: ", ''))
331
- if (!content || !content.delta) {
332
- return
333
- }
334
-
335
- // 发送增量内容
336
- ctx.res.write(`data: ${JSON.stringify({
337
- "id": `chatcmpl-${messageId}`,
338
- "choices": [
339
- {
340
- "index": 0,
341
- "delta": {
342
- "content": content.delta
343
- }
344
- }
345
- ],
346
- "created": Math.floor(Date.now() / 1000),
347
- "model": models[`${model}`],
348
- "object": "chat.completion.chunk"
349
- })}\n\n`)
350
- })
351
- } else {
352
- const text = new TextDecoder().decode(value)
353
- const textContent = [...text.matchAll(/data:.*"}/g)]
354
-
355
- textContent.forEach(item => {
356
- if (!item[0]) {
357
- return
358
- }
359
-
360
- const content = JSON.parse(item[0].replace("data: ", ''))
361
- if (!content || !content.field_value || content.field_name == 'session_state.answer_is_finished' || content.field_name == 'content' || content.field_name == 'session_state' || content.delta || content.type == 'project_field') {
362
- return
363
- }
364
-
365
- resBody = {
366
- id: `chatcmpl-${messageId}`,
367
- object: 'chat.completion',
368
- created: Math.floor(Date.now() / 1000),
369
- model,
370
- choices: [
371
- {
372
- index: 0,
373
- message: {
374
- role: 'assistant',
375
- content: content.field_value,
376
- },
377
- finish_reason: 'stop',
378
- },
379
- ],
380
- usage: {
381
- prompt_tokens: 0,
382
- completion_tokens: 0,
383
- total_tokens: content.field_value.length,
384
- },
385
- }
386
- })
387
- }
388
- }
389
-
390
- if (stream == "false" || stream == false) {
391
- ctx.body = resBody
392
- } else {
393
- ctx.res.end()
394
- }
395
- return
396
- } catch (error) {
397
- console.error('流式响应出错:', error)
398
- ctx.res.end()
399
- }
400
- } catch (error) {
401
- console.error('请求处理出错:', error)
402
- ctx.status = error.status || 500
403
- ctx.body = {
404
- error: error.message || '请求处理失败',
405
- details: error.toString()
406
- }
407
- }
408
- })
409
 
410
- // 获取models的v1路由
411
- router.get('/v1/models', async (ctx) => {
412
  ctx.body = {
413
  object: "list",
414
  data: Object.keys(models).map(model => ({
@@ -418,20 +228,16 @@ router.get('/v1/models', async (ctx) => {
418
  owned_by: "genspark"
419
  }))
420
  }
421
- })
422
 
423
- // 获取models的hf/v1路由
424
- router.get('/hf/v1/models', async (ctx) => {
425
- ctx.body = {
426
- object: "list",
427
- data: Object.keys(models).map(model => ({
428
- id: model,
429
- object: "model",
430
- created: 1706745938,
431
- owned_by: "genspark"
432
- }))
433
- }
434
- })
435
 
436
  // 错误处理中间件
437
  app.use(async (ctx, next) => {
 
19
  textLimit: '30mb', // text 数据大小限制
20
  }))
21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  const makeRequest = async (session_id, requestModel, messages) => {
23
  console.log('开始请求 genspark.ai:', { session_id, requestModel })
24
  try {
 
77
  }
78
  }
79
 
80
+ // 创建处理函数
81
+ const handleChatCompletions = async (ctx) => {
82
  const { messages, stream = false, model = 'claude-3-5-sonnet' } = ctx.request.body
83
  const session_id = ctx.get('Authorization')?.replace('Bearer ', '')
84
 
 
134
  const { done, value } = await reader.read()
135
  if (done) {
136
  if (stream == "true" || stream == true) {
 
137
  ctx.res.write('data: [DONE]\n\n')
138
  }
139
  break
140
  }
141
 
142
  if (stream) {
 
143
  const text = new TextDecoder().decode(value)
144
  const textContent = [...text.matchAll(/data:.*"}/g)]
145
 
146
  textContent.forEach(item => {
147
+ if (!item[0]) return
 
 
 
148
  const content = JSON.parse(item[0].replace("data: ", ''))
149
+ if (!content || !content.delta) return
 
 
150
 
 
 
 
151
  ctx.res.write(`data: ${JSON.stringify({
152
  "id": `chatcmpl-${messageId}`,
153
  "choices": [
 
167
  const text = new TextDecoder().decode(value)
168
  const textContent = [...text.matchAll(/data:.*"}/g)]
169
 
 
170
  textContent.forEach(item => {
171
+ if (!item[0]) return
 
 
 
172
  const content = JSON.parse(item[0].replace("data: ", ''))
173
+ if (!content || !content.field_value || content.field_name == 'session_state.answer_is_finished' || content.field_name == 'content' || content.field_name == 'session_state' || content.delta || content.type == 'project_field') return
 
 
 
 
174
 
175
  resBody = {
176
  id: `chatcmpl-${messageId}`,
 
193
  total_tokens: content.field_value.length,
194
  },
195
  }
 
196
  })
197
  }
 
198
  }
199
 
200
  if (stream == "false" || stream == false) {
 
201
  ctx.body = resBody
202
  } else {
203
  ctx.res.end()
 
207
  console.error('流式响应出错:', error)
208
  ctx.res.end()
209
  }
 
210
  } catch (error) {
211
  console.error('请求处理出错:', error)
212
  ctx.status = error.status || 500
 
215
  details: error.toString()
216
  }
217
  }
218
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
219
 
220
+ // 创建获取模型列表的处理函数
221
+ const handleModels = async (ctx) => {
222
  ctx.body = {
223
  object: "list",
224
  data: Object.keys(models).map(model => ({
 
228
  owned_by: "genspark"
229
  }))
230
  }
231
+ }
232
 
233
+ // 注册路由 - 同时支持 /v1 和 /hf/v1 路径
234
+ router.post('/v1/chat/completions', handleChatCompletions)
235
+ router.post('/hf/v1/chat/completions', handleChatCompletions)
236
+ router.get('/v1/models', handleModels)
237
+ router.get('/hf/v1/models', handleModels)
238
+
239
+ // 注册路由中间件
240
+ app.use(router.routes()).use(router.allowedMethods())
 
 
 
 
241
 
242
  // 错误处理中间件
243
  app.use(async (ctx, next) => {