chb2024 commited on
Commit
184fa3d
·
verified ·
1 Parent(s): 0080993

Upload 4 files

Browse files
Files changed (4) hide show
  1. .gitignore +1 -0
  2. index.js +254 -0
  3. models.js +14 -0
  4. package.json +17 -0
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ node_modules
index.js ADDED
@@ -0,0 +1,254 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const Koa = require('koa')
2
+ const Router = require('koa-router')
3
+ const bodyParser = require('koa-bodyparser')
4
+ const models = require("./models")
5
+
6
+
7
+ const app = new Koa()
8
+ const router = new Router()
9
+
10
+ // 使用 bodyParser 中间件
11
+ app.use(bodyParser())
12
+
13
+ // 配置 bodyParser
14
+ app.use(bodyParser({
15
+ enableTypes: ['json', 'form', 'text'],
16
+ jsonLimit: '30mb', // JSON 数据大小限制
17
+ formLimit: '30mb', // form 数据大小限制
18
+ textLimit: '30mb', // text 数据大小限制
19
+ }))
20
+
21
+
22
+ const makeRequest = async (session_id, requestModel, messages) => {
23
+ // console.log(session_id, requestModel, messages)
24
+ try {
25
+ // 设置请求头
26
+ const myHeaders = new Headers()
27
+ myHeaders.append("Cookie", `session_id=${session_id}`)
28
+ myHeaders.append("User-Agent", "Apifox/1.0.0 (https://apifox.com)");
29
+ myHeaders.append("Content-Type", "application/json")
30
+ myHeaders.append("Accept", "*/*")
31
+ myHeaders.append("Host", "www.genspark.ai")
32
+ myHeaders.append("Connection", "keep-alive")
33
+
34
+
35
+ // 设置请求体
36
+ var body = JSON.stringify({
37
+ "type": "COPILOT_MOA_CHAT",
38
+ "current_query_string": "type=COPILOT_MOA_CHAT",
39
+ "messages": messages,
40
+ "action_params": {},
41
+ "extra_data": {
42
+ "models": [
43
+ models[`${requestModel}`] || models["claude-3-5-sonnet-20241022"]
44
+ ],
45
+ "run_with_another_model": false,
46
+ "writingContent": null
47
+ }
48
+ })
49
+
50
+ const requestConfig = {
51
+ method: 'POST',
52
+ headers: myHeaders,
53
+ body: body,
54
+ redirect: 'follow'
55
+ };
56
+
57
+ // console.log(requestConfig)
58
+ return await fetch("https://www.genspark.ai/api/copilot/ask", requestConfig)
59
+ } catch (error) {
60
+ console.log('error1', error)
61
+ }
62
+ }
63
+
64
+
65
+ router.post('/v1/chat/completions', async (ctx) => {
66
+ const { messages, stream = false, model = 'claude-3-5-sonnet' } = ctx.request.body
67
+ const session_id = ctx.get('Authorization')?.replace('Bearer ', '')
68
+
69
+ if (!session_id) {
70
+ ctx.status = 401
71
+ ctx.body = { error: '未提供有效的 session_id' }
72
+ return
73
+ }
74
+
75
+ try {
76
+ const response = await makeRequest(session_id, model, messages)
77
+ if (stream == "true" || stream == true) {
78
+ ctx.set({
79
+ 'Content-Type': 'text/event-stream',
80
+ 'Cache-Control': 'no-cache',
81
+ 'Connection': 'keep-alive',
82
+ })
83
+ } else {
84
+ ctx.set({
85
+ 'Content-Type': 'application/json',
86
+ })
87
+ }
88
+
89
+ const messageId = crypto.randomUUID()
90
+ const reader = response.body.getReader()
91
+ if (stream == "true" || stream == true) {
92
+ ctx.res.write(`data: ${JSON.stringify({
93
+ "id": `chatcmpl-${messageId}`,
94
+ "choices": [
95
+ {
96
+ "index": 0,
97
+ "delta": {
98
+ "content": "",
99
+ "role": "assistant"
100
+ }
101
+ }
102
+ ],
103
+ "created": Math.floor(Date.now() / 1000),
104
+ "model": models[`${model}`],
105
+ "object": "chat.completion.chunk"
106
+ })}\n\n`)
107
+ }
108
+
109
+ try {
110
+ let resBody = {}
111
+
112
+ while (true) {
113
+ const { done, value } = await reader.read()
114
+ if (done) {
115
+ if (stream == "true" || stream == true) {
116
+ // 发送完成标记
117
+ ctx.res.write('data: [DONE]\n\n')
118
+ }
119
+ break
120
+ }
121
+
122
+ if (stream) {
123
+
124
+ const text = new TextDecoder().decode(value)
125
+ const textContent = [...text.matchAll(/data:.*"}/g)]
126
+
127
+ textContent.forEach(item => {
128
+ if (!item[0]) {
129
+ return
130
+ }
131
+
132
+ const content = JSON.parse(item[0].replace("data: ", ''))
133
+ if (!content || !content.delta) {
134
+ return
135
+ }
136
+
137
+ // console.log(content.delta)
138
+
139
+ // 发送增量内容
140
+ ctx.res.write(`data: ${JSON.stringify({
141
+ "id": `chatcmpl-${messageId}`,
142
+ "choices": [
143
+ {
144
+ "index": 0,
145
+ "delta": {
146
+ "content": content.delta
147
+ }
148
+ }
149
+ ],
150
+ "created": Math.floor(Date.now() / 1000),
151
+ "model": models[`${model}`],
152
+ "object": "chat.completion.chunk"
153
+ })}\n\n`)
154
+ })
155
+ } else {
156
+ const text = new TextDecoder().decode(value)
157
+ const textContent = [...text.matchAll(/data:.*"}/g)]
158
+
159
+
160
+ textContent.forEach(item => {
161
+ if (!item[0]) {
162
+ return
163
+ }
164
+
165
+ const content = JSON.parse(item[0].replace("data: ", ''))
166
+ 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') {
167
+ return
168
+ }
169
+
170
+ // console.log(content)
171
+
172
+ resBody = {
173
+ id: `chatcmpl-${messageId}`,
174
+ object: 'chat.completion',
175
+ created: Math.floor(Date.now() / 1000),
176
+ model,
177
+ choices: [
178
+ {
179
+ index: 0,
180
+ message: {
181
+ role: 'assistant',
182
+ content: content.field_value,
183
+ },
184
+ finish_reason: 'stop',
185
+ },
186
+ ],
187
+ usage: {
188
+ prompt_tokens: 0,
189
+ completion_tokens: 0,
190
+ total_tokens: content.field_value.length,
191
+ },
192
+ }
193
+
194
+ })
195
+ }
196
+
197
+ }
198
+
199
+ if (stream == "false" || stream == false) {
200
+ // console.log(resBody)
201
+ ctx.body = resBody
202
+ } else {
203
+ ctx.res.end()
204
+ }
205
+ return
206
+ } catch (error) {
207
+ console.error('流式响应出错:', error)
208
+ ctx.res.end()
209
+ }
210
+
211
+ } catch (error) {
212
+ console.error('请求处理出错:', error)
213
+ ctx.status = 500
214
+ ctx.body = { error: '请求处理失败' }
215
+ }
216
+ })
217
+
218
+
219
+ // 获取models
220
+ router.get('/v1/models', async (ctx) => {
221
+ ctx.body = {
222
+ object: "list",
223
+ data: Object.keys(models).map(model => ({
224
+ id: model,
225
+ object: "model",
226
+ created: 1706745938,
227
+ owned_by: "genspark"
228
+ }))
229
+ }
230
+ })
231
+
232
+
233
+ // 注册路由
234
+ app.use(router.routes()).use(router.allowedMethods())
235
+
236
+ // 错误处理中间件
237
+ app.use(async (ctx, next) => {
238
+ try {
239
+ await next()
240
+ } catch (err) {
241
+ ctx.status = err.status || 500
242
+ ctx.body = {
243
+ success: false,
244
+ message: err.message
245
+ }
246
+ ctx.app.emit('error', err, ctx)
247
+ }
248
+ })
249
+
250
+ // 启动服务器
251
+ const PORT = process.env.PORT || 8666
252
+ app.listen(PORT, () => {
253
+ console.log(`服务器运行在 http://localhost:${PORT}`);
254
+ })
models.js ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const models = {
2
+ "o1-preview": "o1-preview",
3
+ "o1-mini": "o1-preview",
4
+ "claude-3-5-sonnet-20240620": "claude-3-5-sonnet",
5
+ "claude-3-5-sonnet-20241022": "claude-3-5-sonnet",
6
+ "claude-3-5-haiku-20241022": "claude-3-5-haiku",
7
+ "claude-3-haiku-20240307": "claude-3-5-haiku",
8
+ "gpt-4o": "gpt-4o",
9
+ "gpt-4o-mini": "gpt-4o-mini",
10
+ "gemini-1.5-pro-latest": "gemini-1.5-pro",
11
+ "gemini-1.5-flash-latest": "gemini-1.5-flash"
12
+ }
13
+
14
+ module.exports = models
package.json ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "genspark2api",
3
+ "version": "1.0.0",
4
+ "main": "index.js",
5
+ "scripts": {
6
+ "dev": "node src/index.js"
7
+ },
8
+ "keywords": [],
9
+ "author": "",
10
+ "license": "ISC",
11
+ "description": "",
12
+ "dependencies": {
13
+ "koa": "^2.15.3",
14
+ "koa-bodyparser": "^4.4.1",
15
+ "koa-router": "^13.0.1"
16
+ }
17
+ }