liuw15 commited on
Commit
2e9246b
·
1 Parent(s): 701685c

使用axios替换fetch,优化代码结构,添加超时和代理支持,改为从.env加载

Browse files
.env.example ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 服务器配置
2
+ PORT=8045
3
+ HOST=0.0.0.0
4
+
5
+ # API 配置
6
+ API_URL=https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:streamGenerateContent?alt=sse
7
+ API_MODELS_URL=https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:fetchAvailableModels
8
+ API_NO_STREAM_URL=https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:generateContent
9
+ API_HOST=daily-cloudcode-pa.sandbox.googleapis.com
10
+ API_USER_AGENT=antigravity/1.11.3 windows/amd64
11
+
12
+ # 默认参数
13
+ DEFAULT_TEMPERATURE=1
14
+ DEFAULT_TOP_P=0.85
15
+ DEFAULT_TOP_K=50
16
+ DEFAULT_MAX_TOKENS=8096
17
+
18
+ # 安全配置
19
+ MAX_REQUEST_SIZE=50mb
20
+ API_KEY=sk-text
21
+
22
+ # 其他配置
23
+ USE_NATIVE_AXIOS=false
24
+ TIMEOUT=180000
25
+ # PROXY=http://127.0.0.1:7897
26
+
27
+ # 系统提示词
28
+ SYSTEM_INSTRUCTION=你是聊天机器人,名字叫萌萌,如同名字这般,你的性格是软软糯糯萌萌哒的,专门为用户提供聊天和情绪价值,协助进行小说创作或者角色扮演
README.md CHANGED
@@ -25,20 +25,20 @@
25
  npm install
26
  ```
27
 
28
- ### 2. 配置文件
29
 
30
- 编辑 `config.json` 配置服务器和 API 参数:
31
 
32
- ```json
33
- {
34
- "server": {
35
- "port": 8045,
36
- "host": "0.0.0.0"
37
- },
38
- "security": {
39
- "apiKey": "sk-text"
40
- }
41
- }
42
  ```
43
 
44
  ### 3. 登录获取 Token
@@ -178,19 +178,24 @@ curl http://localhost:8045/v1/chat/completions \
178
 
179
  ## 配置说明
180
 
181
- ### config.json
182
 
183
- | 配置项 | 说明 | 默认值 |
184
  |--------|------|--------|
185
- | `server.port` | 服务端口 | 8045 |
186
- | `server.host` | 监听地址 | 0.0.0.0 |
187
- | `security.apiKey` | API 认证密钥 | sk-text |
188
- | `security.maxRequestSize` | 最大请求体大小 | 50mb |
189
- | `defaults.temperature` | 默认温度参数 | 1 |
190
- | `defaults.top_p` | 默认 top_p | 0.85 |
191
- | `defaults.top_k` | 默认 top_k | 50 |
192
- | `defaults.max_tokens` | 默认最大 token 数 | 8096 |
193
- | `systemInstruction` | 系统提示词 | - |
 
 
 
 
 
194
 
195
  ## 开发命令
196
 
@@ -212,28 +217,39 @@ npm run login
212
  ├── data/
213
  │ └── accounts.json # Token 存储(自动生成)
214
  ├── scripts/
215
- └── oauth-server.js # OAuth 登录服务
 
216
  ├── src/
217
  │ ├── api/
218
  │ │ └── client.js # API 调用逻辑
219
  │ ├── auth/
220
  │ │ └── token_manager.js # Token 管理
 
 
 
 
221
  │ ├── config/
222
  │ │ └── config.js # 配置加载
223
  │ ├── server/
224
  │ │ └── index.js # 主服务器
225
- └── utils/
226
- ├── logger.js # 日志模块
227
- └── utils.js # 工具函数
228
- ├── config.json # 配置文件
 
 
 
 
 
 
229
  └── package.json # 项目配置
230
  ```
231
 
232
  ## 注意事项
233
 
234
- 1. 首次使用需要运行 `npm run login` 获取 Token
235
- 2. `data/accounts.json` 包含敏感信息,请勿泄露
236
- 3. API Key 可在 `config.json` 中自定义
237
  4. 支持多账号轮换,提高可用性
238
  5. Token 会自动刷新,无需手动维护
239
 
 
25
  npm install
26
  ```
27
 
28
+ ### 2. 配置环境变量
29
 
30
+ 复制 `.env.example` `.env` 并编辑配置:
31
 
32
+ ```bash
33
+ cp .env.example .env
34
+ ```
35
+
36
+ 编辑 `.env` 文件配置服务器和 API 参数:
37
+
38
+ ```env
39
+ PORT=8045
40
+ HOST=0.0.0.0
41
+ API_KEY=sk-text
42
  ```
43
 
44
  ### 3. 登录获取 Token
 
178
 
179
  ## 配置说明
180
 
181
+ ### 环境变量 (.env)
182
 
183
+ | 环境变量 | 说明 | 默认值 |
184
  |--------|------|--------|
185
+ | `PORT` | 服务端口 | 8045 |
186
+ | `HOST` | 监听地址 | 127.0.0.1 |
187
+ | `API_KEY` | API 认证密钥 | - |
188
+ | `MAX_REQUEST_SIZE` | 最大请求体大小 | 50mb |
189
+ | `DEFAULT_TEMPERATURE` | 默认温度参数 | 1 |
190
+ | `DEFAULT_TOP_P` | 默认 top_p | 0.85 |
191
+ | `DEFAULT_TOP_K` | 默认 top_k | 50 |
192
+ | `DEFAULT_MAX_TOKENS` | 默认最大 token 数 | 8096 |
193
+ | `USE_NATIVE_FETCH` | 使用原生 axios | false |
194
+ | `TIMEOUT` | 请求超时时间(毫秒) | 30000 |
195
+ | `PROXY` | 代理地址 | - |
196
+ | `SYSTEM_INSTRUCTION` | 系统提示词 | - |
197
+
198
+ 完整配置示例请参考 `.env.example` 文件。
199
 
200
  ## 开发命令
201
 
 
217
  ├── data/
218
  │ └── accounts.json # Token 存储(自动生成)
219
  ├── scripts/
220
+ ├── oauth-server.js # OAuth 登录服务
221
+ │ └── refresh-tokens.js # Token 刷新脚本
222
  ├── src/
223
  │ ├── api/
224
  │ │ └── client.js # API 调用逻辑
225
  │ ├── auth/
226
  │ │ └── token_manager.js # Token 管理
227
+ │ ├── bin/
228
+ │ │ ├── antigravity_requester_android_arm64 # Android ARM64 TLS 请求器
229
+ │ │ ├── antigravity_requester_linux_amd64 # Linux AMD64 TLS 请求器
230
+ │ │ └── antigravity_requester_windows_amd64.exe # Windows AMD64 TLS 请求器
231
  │ ├── config/
232
  │ │ └── config.js # 配置加载
233
  │ ├── server/
234
  │ │ └── index.js # 主服务器
235
+ ├── utils/
236
+ ├── idGenerator.js # ID 生成器
237
+ │ ├── logger.js # 日志模块
238
+ │ │ └── utils.js # 工具函数
239
+ │ └── AntigravityRequester.js # TLS 指纹请求器封装
240
+ ├── test/
241
+ │ ├── test-request.js # 请求测试
242
+ │ └── test-transform.js # 转换测试
243
+ ├── .env # 环境变量配置
244
+ ├── .env.example # 环境变量配置示例
245
  └── package.json # 项目配置
246
  ```
247
 
248
  ## 注意事项
249
 
250
+ 1. 首次使用需要复制 `.env.example` `.env` 并配置
251
+ 2. 运行 `npm run login` 获取 Token
252
+ 3. `.env` `data/accounts.json` 包含敏感信息,请勿泄露
253
  4. 支持多账号轮换,提高可用性
254
  5. Token 会自动刷新,无需手动维护
255
 
config.json DELETED
@@ -1,25 +0,0 @@
1
- {
2
- "server": {
3
- "port": 8045,
4
- "host": "0.0.0.0"
5
- },
6
- "api": {
7
- "url": "https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:streamGenerateContent?alt=sse",
8
- "modelsUrl": "https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:fetchAvailableModels",
9
- "noStreamUrl": "https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:generateContent",
10
- "host": "daily-cloudcode-pa.sandbox.googleapis.com",
11
- "userAgent": "antigravity/1.11.3 windows/amd64"
12
- },
13
- "defaults": {
14
- "temperature": 1,
15
- "top_p": 0.85,
16
- "top_k": 50,
17
- "max_tokens": 8096
18
- },
19
- "security": {
20
- "maxRequestSize": "50mb",
21
- "apiKey": "sk-text"
22
- },
23
- "useNativeFetch": false,
24
- "systemInstruction": "你是聊天机器人,名字叫萌萌,如同名字这般,你的性格是软软糯糯萌萌哒的,专门为用户提供聊天和情绪价值,协助进行小说创作或者角色扮演"
25
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
package-lock.json CHANGED
@@ -9,6 +9,8 @@
9
  "version": "1.0.0",
10
  "license": "MIT",
11
  "dependencies": {
 
 
12
  "express": "^5.1.0"
13
  },
14
  "engines": {
@@ -28,6 +30,23 @@
28
  "node": ">= 0.6"
29
  }
30
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  "node_modules/body-parser": {
32
  "version": "2.2.0",
33
  "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
@@ -86,6 +105,18 @@
86
  "url": "https://github.com/sponsors/ljharb"
87
  }
88
  },
 
 
 
 
 
 
 
 
 
 
 
 
89
  "node_modules/content-disposition": {
90
  "version": "1.0.1",
91
  "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz",
@@ -143,6 +174,15 @@
143
  }
144
  }
145
  },
 
 
 
 
 
 
 
 
 
146
  "node_modules/depd": {
147
  "version": "2.0.0",
148
  "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
@@ -152,6 +192,18 @@
152
  "node": ">= 0.8"
153
  }
154
  },
 
 
 
 
 
 
 
 
 
 
 
 
155
  "node_modules/dunder-proto": {
156
  "version": "1.0.1",
157
  "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
@@ -211,6 +263,21 @@
211
  "node": ">= 0.4"
212
  }
213
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  "node_modules/escape-html": {
215
  "version": "1.0.3",
216
  "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@@ -285,6 +352,63 @@
285
  "node": ">= 0.8"
286
  }
287
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
288
  "node_modules/forwarded": {
289
  "version": "0.2.0",
290
  "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@@ -373,6 +497,21 @@
373
  "url": "https://github.com/sponsors/ljharb"
374
  }
375
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
376
  "node_modules/hasown": {
377
  "version": "2.0.2",
378
  "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
@@ -574,6 +713,12 @@
574
  "node": ">= 0.10"
575
  }
576
  },
 
 
 
 
 
 
577
  "node_modules/qs": {
578
  "version": "6.14.0",
579
  "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
 
9
  "version": "1.0.0",
10
  "license": "MIT",
11
  "dependencies": {
12
+ "axios": "^1.13.2",
13
+ "dotenv": "^17.2.3",
14
  "express": "^5.1.0"
15
  },
16
  "engines": {
 
30
  "node": ">= 0.6"
31
  }
32
  },
33
+ "node_modules/asynckit": {
34
+ "version": "0.4.0",
35
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
36
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
37
+ "license": "MIT"
38
+ },
39
+ "node_modules/axios": {
40
+ "version": "1.13.2",
41
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz",
42
+ "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==",
43
+ "license": "MIT",
44
+ "dependencies": {
45
+ "follow-redirects": "^1.15.6",
46
+ "form-data": "^4.0.4",
47
+ "proxy-from-env": "^1.1.0"
48
+ }
49
+ },
50
  "node_modules/body-parser": {
51
  "version": "2.2.0",
52
  "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
 
105
  "url": "https://github.com/sponsors/ljharb"
106
  }
107
  },
108
+ "node_modules/combined-stream": {
109
+ "version": "1.0.8",
110
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
111
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
112
+ "license": "MIT",
113
+ "dependencies": {
114
+ "delayed-stream": "~1.0.0"
115
+ },
116
+ "engines": {
117
+ "node": ">= 0.8"
118
+ }
119
+ },
120
  "node_modules/content-disposition": {
121
  "version": "1.0.1",
122
  "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz",
 
174
  }
175
  }
176
  },
177
+ "node_modules/delayed-stream": {
178
+ "version": "1.0.0",
179
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
180
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
181
+ "license": "MIT",
182
+ "engines": {
183
+ "node": ">=0.4.0"
184
+ }
185
+ },
186
  "node_modules/depd": {
187
  "version": "2.0.0",
188
  "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
 
192
  "node": ">= 0.8"
193
  }
194
  },
195
+ "node_modules/dotenv": {
196
+ "version": "17.2.3",
197
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz",
198
+ "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==",
199
+ "license": "BSD-2-Clause",
200
+ "engines": {
201
+ "node": ">=12"
202
+ },
203
+ "funding": {
204
+ "url": "https://dotenvx.com"
205
+ }
206
+ },
207
  "node_modules/dunder-proto": {
208
  "version": "1.0.1",
209
  "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
 
263
  "node": ">= 0.4"
264
  }
265
  },
266
+ "node_modules/es-set-tostringtag": {
267
+ "version": "2.1.0",
268
+ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
269
+ "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
270
+ "license": "MIT",
271
+ "dependencies": {
272
+ "es-errors": "^1.3.0",
273
+ "get-intrinsic": "^1.2.6",
274
+ "has-tostringtag": "^1.0.2",
275
+ "hasown": "^2.0.2"
276
+ },
277
+ "engines": {
278
+ "node": ">= 0.4"
279
+ }
280
+ },
281
  "node_modules/escape-html": {
282
  "version": "1.0.3",
283
  "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
 
352
  "node": ">= 0.8"
353
  }
354
  },
355
+ "node_modules/follow-redirects": {
356
+ "version": "1.15.11",
357
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
358
+ "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
359
+ "funding": [
360
+ {
361
+ "type": "individual",
362
+ "url": "https://github.com/sponsors/RubenVerborgh"
363
+ }
364
+ ],
365
+ "license": "MIT",
366
+ "engines": {
367
+ "node": ">=4.0"
368
+ },
369
+ "peerDependenciesMeta": {
370
+ "debug": {
371
+ "optional": true
372
+ }
373
+ }
374
+ },
375
+ "node_modules/form-data": {
376
+ "version": "4.0.5",
377
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
378
+ "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
379
+ "license": "MIT",
380
+ "dependencies": {
381
+ "asynckit": "^0.4.0",
382
+ "combined-stream": "^1.0.8",
383
+ "es-set-tostringtag": "^2.1.0",
384
+ "hasown": "^2.0.2",
385
+ "mime-types": "^2.1.12"
386
+ },
387
+ "engines": {
388
+ "node": ">= 6"
389
+ }
390
+ },
391
+ "node_modules/form-data/node_modules/mime-db": {
392
+ "version": "1.52.0",
393
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
394
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
395
+ "license": "MIT",
396
+ "engines": {
397
+ "node": ">= 0.6"
398
+ }
399
+ },
400
+ "node_modules/form-data/node_modules/mime-types": {
401
+ "version": "2.1.35",
402
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
403
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
404
+ "license": "MIT",
405
+ "dependencies": {
406
+ "mime-db": "1.52.0"
407
+ },
408
+ "engines": {
409
+ "node": ">= 0.6"
410
+ }
411
+ },
412
  "node_modules/forwarded": {
413
  "version": "0.2.0",
414
  "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
 
497
  "url": "https://github.com/sponsors/ljharb"
498
  }
499
  },
500
+ "node_modules/has-tostringtag": {
501
+ "version": "1.0.2",
502
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
503
+ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
504
+ "license": "MIT",
505
+ "dependencies": {
506
+ "has-symbols": "^1.0.3"
507
+ },
508
+ "engines": {
509
+ "node": ">= 0.4"
510
+ },
511
+ "funding": {
512
+ "url": "https://github.com/sponsors/ljharb"
513
+ }
514
+ },
515
  "node_modules/hasown": {
516
  "version": "2.0.2",
517
  "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
 
713
  "node": ">= 0.10"
714
  }
715
  },
716
+ "node_modules/proxy-from-env": {
717
+ "version": "1.1.0",
718
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
719
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
720
+ "license": "MIT"
721
+ },
722
  "node_modules/qs": {
723
  "version": "6.14.0",
724
  "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
package.json CHANGED
@@ -10,10 +10,17 @@
10
  "refresh": "node scripts/refresh-tokens.js",
11
  "dev": "node --watch src/server/index.js"
12
  },
13
- "keywords": ["antigravity", "openai", "api", "proxy"],
 
 
 
 
 
14
  "author": "",
15
  "license": "MIT",
16
  "dependencies": {
 
 
17
  "express": "^5.1.0"
18
  },
19
  "engines": {
 
10
  "refresh": "node scripts/refresh-tokens.js",
11
  "dev": "node --watch src/server/index.js"
12
  },
13
+ "keywords": [
14
+ "antigravity",
15
+ "openai",
16
+ "api",
17
+ "proxy"
18
+ ],
19
  "author": "",
20
  "license": "MIT",
21
  "dependencies": {
22
+ "axios": "^1.13.2",
23
+ "dotenv": "^17.2.3",
24
  "express": "^5.1.0"
25
  },
26
  "engines": {
src/api/client.js CHANGED
@@ -1,23 +1,101 @@
 
1
  import tokenManager from '../auth/token_manager.js';
2
  import config from '../config/config.js';
3
  import { generateToolCallId } from '../utils/idGenerator.js';
4
  import AntigravityRequester from '../AntigravityRequester.js';
5
 
 
6
  let requester = null;
7
- let useNativeFetch = false;
8
 
9
- if (config.useNativeFetch !== true) {
 
 
10
  try {
11
  requester = new AntigravityRequester();
12
  } catch (error) {
13
- console.warn('AntigravityRequester initialization failed, falling back to native fetch:', error.message);
14
- useNativeFetch = true;
15
  }
16
- } else {
17
- useNativeFetch = true;
18
  }
19
 
20
- function processStreamLine(line, state, callback) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  if (!line.startsWith('data: ')) return;
22
 
23
  try {
@@ -27,30 +105,27 @@ function processStreamLine(line, state, callback) {
27
  if (parts) {
28
  for (const part of parts) {
29
  if (part.thought === true) {
 
30
  if (!state.thinkingStarted) {
31
  callback({ type: 'thinking', content: '<think>\n' });
32
  state.thinkingStarted = true;
33
  }
34
  callback({ type: 'thinking', content: part.text || '' });
35
  } else if (part.text !== undefined) {
 
36
  if (state.thinkingStarted) {
37
  callback({ type: 'thinking', content: '\n</think>\n' });
38
  state.thinkingStarted = false;
39
  }
40
  callback({ type: 'text', content: part.text });
41
  } else if (part.functionCall) {
42
- state.toolCalls.push({
43
- id: part.functionCall.id || generateToolCallId(),
44
- type: 'function',
45
- function: {
46
- name: part.functionCall.name,
47
- arguments: JSON.stringify(part.functionCall.args)
48
- }
49
- });
50
  }
51
  }
52
  }
53
 
 
54
  if (data.response?.candidates?.[0]?.finishReason && state.toolCalls.length > 0) {
55
  if (state.thinkingStarted) {
56
  callback({ type: 'thinking', content: '\n</think>\n' });
@@ -60,63 +135,43 @@ function processStreamLine(line, state, callback) {
60
  state.toolCalls = [];
61
  }
62
  } catch (e) {
63
- // 忽略解析错误
64
  }
65
  }
66
 
 
 
67
  export async function generateAssistantResponse(requestBody, callback) {
68
  const token = await tokenManager.getToken();
 
69
 
70
- if (!token) {
71
- throw new Error('没有可用的token,请运行 npm run login 获取token');
72
- }
73
-
74
- const headers = {
75
- 'Host': config.api.host,
76
- 'User-Agent': config.api.userAgent,
77
- 'Authorization': `Bearer ${token.access_token}`,
78
- 'Content-Type': 'application/json',
79
- 'Accept-Encoding': 'gzip'
80
- };
81
-
82
  const state = { thinkingStarted: false, toolCalls: [] };
83
- let buffer = '';
84
 
85
  const processChunk = (chunk) => {
86
  buffer += chunk;
87
  const lines = buffer.split('\n');
88
- buffer = lines.pop();
89
- lines.forEach(line => processStreamLine(line, state, callback));
90
  };
91
 
92
- if (useNativeFetch) {
93
- const response = await fetch(config.api.url, {
94
- method: 'POST',
95
- headers,
96
- body: JSON.stringify(requestBody)
97
- });
98
-
99
- if (!response.ok) {
100
- const errorBody = await response.text();
101
  if (response.status === 403) tokenManager.disableCurrentToken(token);
102
- throw new Error(`API请求失败 (${response.status}): ${errorBody}`);
103
- }
104
 
105
- const reader = response.body.getReader();
106
- const decoder = new TextDecoder();
107
-
108
- while (true) {
109
- const { done, value } = await reader.read();
110
- if (done) break;
111
- processChunk(decoder.decode(value, { stream: true }));
112
  }
113
  } else {
114
- const streamResponse = requester.antigravity_fetchStream(config.api.url, {
115
- method: 'POST',
116
- headers,
117
- body: JSON.stringify(requestBody)
118
- });
119
-
120
  let errorBody = '';
121
  let statusCode = null;
122
 
@@ -126,20 +181,8 @@ export async function generateAssistantResponse(requestBody, callback) {
126
  statusCode = status;
127
  if (status === 403) tokenManager.disableCurrentToken(token);
128
  })
129
- .onData((chunk) => {
130
- if (statusCode !== 200) {
131
- errorBody += chunk;
132
- } else {
133
- processChunk(chunk);
134
- }
135
- })
136
- .onEnd(() => {
137
- if (statusCode !== 200) {
138
- reject(new Error(`API请求失败 (${statusCode}): ${errorBody}`));
139
- } else {
140
- resolve();
141
- }
142
- })
143
  .onError(reject);
144
  });
145
  }
@@ -147,75 +190,54 @@ export async function generateAssistantResponse(requestBody, callback) {
147
 
148
  export async function getAvailableModels() {
149
  const token = await tokenManager.getToken();
 
150
 
151
- if (!token) {
152
- throw new Error('没有可用的token,请运行 npm run login 获取token');
153
- }
154
-
155
- const headers = {
156
- 'Host': config.api.host,
157
- 'User-Agent': config.api.userAgent,
158
- 'Authorization': `Bearer ${token.access_token}`,
159
- 'Content-Type': 'application/json',
160
- 'Accept-Encoding': 'gzip'
161
- };
162
-
163
- const fetchFn = useNativeFetch ? fetch : (url, opts) => requester.antigravity_fetch(url, opts);
164
- const response = await fetchFn(config.api.modelsUrl, {
165
- method: 'POST',
166
- headers,
167
- body: JSON.stringify({})
168
- });
169
-
170
- const data = await response.json();
171
 
172
- return {
173
- object: 'list',
174
- data: Object.keys(data.models).map(id => ({
175
- id,
176
- object: 'model',
177
- created: Math.floor(Date.now() / 1000),
178
- owned_by: 'google'
179
- }))
180
- };
 
 
 
 
 
 
 
 
181
  }
182
 
183
-
184
-
185
  export async function generateAssistantResponseNoStream(requestBody) {
186
  const token = await tokenManager.getToken();
 
187
 
188
- if (!token) {
189
- throw new Error('没有可用的token,请运行 npm run login 获取token');
190
- }
191
-
192
- const headers = {
193
- 'Host': config.api.host,
194
- 'User-Agent': config.api.userAgent,
195
- 'Authorization': `Bearer ${token.access_token}`,
196
- 'Content-Type': 'application/json',
197
- 'Accept-Encoding': 'gzip'
198
- };
199
 
200
- const fetchFn = useNativeFetch ? fetch : (url, opts) => requester.antigravity_fetch(url, opts);
201
- const response = await fetchFn(config.api.noStreamUrl, {
202
- method: 'POST',
203
- headers,
204
- body: JSON.stringify(requestBody)
205
- });
206
- if (response.status !== 200) {
207
- const errorBody = await response.text();
208
- if (response.status === 403) {
209
- tokenManager.disableCurrentToken(token);
210
- throw new Error(`该账号没有使用权限,已自动禁用。错误详情: ${errorBody}`);
211
  }
212
- throw new Error(`API请求失败 (${response.status}): ${errorBody}`);
 
213
  }
214
-
215
- const data = await response.json();
216
- //console.log(JSON.stringify(data,null,2))
217
- const parts = data.response?.candidates?.[0]?.content?.parts || [];
218
 
 
 
219
  let content = '';
220
  let thinkingContent = '';
221
  const toolCalls = [];
@@ -226,17 +248,11 @@ export async function generateAssistantResponseNoStream(requestBody) {
226
  } else if (part.text !== undefined) {
227
  content += part.text;
228
  } else if (part.functionCall) {
229
- toolCalls.push({
230
- id: part.functionCall.id || generateToolCallId(),
231
- type: 'function',
232
- function: {
233
- name: part.functionCall.name,
234
- arguments: JSON.stringify(part.functionCall.args)
235
- }
236
- });
237
  }
238
  }
239
 
 
240
  if (thinkingContent) {
241
  content = `<think>\n${thinkingContent}\n</think>\n${content}`;
242
  }
@@ -245,7 +261,5 @@ export async function generateAssistantResponseNoStream(requestBody) {
245
  }
246
 
247
  export function closeRequester() {
248
- if (requester) {
249
- requester.close();
250
- }
251
  }
 
1
+ import axios from 'axios';
2
  import tokenManager from '../auth/token_manager.js';
3
  import config from '../config/config.js';
4
  import { generateToolCallId } from '../utils/idGenerator.js';
5
  import AntigravityRequester from '../AntigravityRequester.js';
6
 
7
+ // 请求客户端:优先使用 AntigravityRequester,失败则降级到 axios
8
  let requester = null;
9
+ let useAxios = false;
10
 
11
+ if (config.useNativeAxios === true) {
12
+ useAxios = true;
13
+ } else {
14
  try {
15
  requester = new AntigravityRequester();
16
  } catch (error) {
17
+ console.warn('AntigravityRequester 初始化失败,降级使用 axios:', error.message);
18
+ useAxios = true;
19
  }
 
 
20
  }
21
 
22
+ // ==================== 辅助函数 ====================
23
+
24
+ function buildHeaders(token) {
25
+ return {
26
+ 'Host': config.api.host,
27
+ 'User-Agent': config.api.userAgent,
28
+ 'Authorization': `Bearer ${token.access_token}`,
29
+ 'Content-Type': 'application/json',
30
+ 'Accept-Encoding': 'gzip'
31
+ };
32
+ }
33
+
34
+ function buildAxiosConfig(url, headers, body = null) {
35
+ const axiosConfig = {
36
+ method: 'POST',
37
+ url,
38
+ headers,
39
+ timeout: config.timeout,
40
+ proxy: config.proxy ? (() => {
41
+ const proxyUrl = new URL(config.proxy);
42
+ return { protocol: proxyUrl.protocol.replace(':', ''), host: proxyUrl.hostname, port: parseInt(proxyUrl.port) };
43
+ })() : false
44
+ };
45
+ if (body !== null) axiosConfig.data = body;
46
+ return axiosConfig;
47
+ }
48
+
49
+ function buildRequesterConfig(headers, body = null) {
50
+ const reqConfig = {
51
+ method: 'POST',
52
+ headers,
53
+ timeout_ms: config.timeout,
54
+ proxy: config.proxy
55
+ };
56
+ if (body !== null) reqConfig.body = JSON.stringify(body);
57
+ return reqConfig;
58
+ }
59
+
60
+ // 统一错误处理
61
+ async function handleApiError(error, token) {
62
+ const status = error.response?.status || error.status;
63
+ let errorBody = error.message;
64
+
65
+ if (error.response?.data?.readable) {
66
+ const chunks = [];
67
+ for await (const chunk of error.response.data) {
68
+ chunks.push(chunk);
69
+ }
70
+ errorBody = Buffer.concat(chunks).toString();
71
+ } else if (typeof error.response?.data === 'object') {
72
+ errorBody = JSON.stringify(error.response.data, null, 2);
73
+ } else if (error.response?.data) {
74
+ errorBody = error.response.data;
75
+ }
76
+
77
+ if (status === 403) {
78
+ tokenManager.disableCurrentToken(token);
79
+ throw new Error(`该账号没有使用权限,已自动禁用。错误详情: ${errorBody}`);
80
+ }
81
+
82
+ throw new Error(`API请求失败 (${status}): ${errorBody}`);
83
+ }
84
+
85
+ // 转换 functionCall 为 OpenAI 格式
86
+ function convertToToolCall(functionCall) {
87
+ return {
88
+ id: functionCall.id || generateToolCallId(),
89
+ type: 'function',
90
+ function: {
91
+ name: functionCall.name,
92
+ arguments: JSON.stringify(functionCall.args)
93
+ }
94
+ };
95
+ }
96
+
97
+ // 解析并发送流式响应片段(会修改 state 并触发 callback)
98
+ function parseAndEmitStreamChunk(line, state, callback) {
99
  if (!line.startsWith('data: ')) return;
100
 
101
  try {
 
105
  if (parts) {
106
  for (const part of parts) {
107
  if (part.thought === true) {
108
+ // 思维链内容
109
  if (!state.thinkingStarted) {
110
  callback({ type: 'thinking', content: '<think>\n' });
111
  state.thinkingStarted = true;
112
  }
113
  callback({ type: 'thinking', content: part.text || '' });
114
  } else if (part.text !== undefined) {
115
+ // 普通文本内容
116
  if (state.thinkingStarted) {
117
  callback({ type: 'thinking', content: '\n</think>\n' });
118
  state.thinkingStarted = false;
119
  }
120
  callback({ type: 'text', content: part.text });
121
  } else if (part.functionCall) {
122
+ // 工具调用
123
+ state.toolCalls.push(convertToToolCall(part.functionCall));
 
 
 
 
 
 
124
  }
125
  }
126
  }
127
 
128
+ // 响应结束时发送工具调用
129
  if (data.response?.candidates?.[0]?.finishReason && state.toolCalls.length > 0) {
130
  if (state.thinkingStarted) {
131
  callback({ type: 'thinking', content: '\n</think>\n' });
 
135
  state.toolCalls = [];
136
  }
137
  } catch (e) {
138
+ // 忽略 JSON 解析错误
139
  }
140
  }
141
 
142
+ // ==================== 导出函数 ====================
143
+
144
  export async function generateAssistantResponse(requestBody, callback) {
145
  const token = await tokenManager.getToken();
146
+ if (!token) throw new Error('没有可用的token,请运行 npm run login 获取token');
147
 
148
+ const headers = buildHeaders(token);
 
 
 
 
 
 
 
 
 
 
 
149
  const state = { thinkingStarted: false, toolCalls: [] };
150
+ let buffer = ''; // 缓冲区:处理跨 chunk 的不完整行
151
 
152
  const processChunk = (chunk) => {
153
  buffer += chunk;
154
  const lines = buffer.split('\n');
155
+ buffer = lines.pop(); // 保留最后一行(可能不完整)
156
+ lines.forEach(line => parseAndEmitStreamChunk(line, state, callback));
157
  };
158
 
159
+ if (useAxios) {
160
+ try {
161
+ const axiosConfig = { ...buildAxiosConfig(config.api.url, headers, requestBody), responseType: 'stream' };
162
+ const response = await axios(axiosConfig);
 
 
 
 
 
163
  if (response.status === 403) tokenManager.disableCurrentToken(token);
 
 
164
 
165
+ response.data.on('data', chunk => processChunk(chunk.toString()));
166
+ await new Promise((resolve, reject) => {
167
+ response.data.on('end', resolve);
168
+ response.data.on('error', reject);
169
+ });
170
+ } catch (error) {
171
+ await handleApiError(error, token);
172
  }
173
  } else {
174
+ const streamResponse = requester.antigravity_fetchStream(config.api.url, buildRequesterConfig(headers, requestBody));
 
 
 
 
 
175
  let errorBody = '';
176
  let statusCode = null;
177
 
 
181
  statusCode = status;
182
  if (status === 403) tokenManager.disableCurrentToken(token);
183
  })
184
+ .onData((chunk) => statusCode !== 200 ? errorBody += chunk : processChunk(chunk))
185
+ .onEnd(() => statusCode !== 200 ? reject(new Error(`API请求失败 (${statusCode}): ${errorBody}`)) : resolve())
 
 
 
 
 
 
 
 
 
 
 
 
186
  .onError(reject);
187
  });
188
  }
 
190
 
191
  export async function getAvailableModels() {
192
  const token = await tokenManager.getToken();
193
+ if (!token) throw new Error('没有可用的token,请运行 npm run login 获取token');
194
 
195
+ const headers = buildHeaders(token);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
196
 
197
+ try {
198
+ const data = useAxios
199
+ ? (await axios(buildAxiosConfig(config.api.modelsUrl, headers, {}))).data
200
+ : await (await requester.antigravity_fetch(config.api.modelsUrl, buildRequesterConfig(headers, {}))).json();
201
+
202
+ return {
203
+ object: 'list',
204
+ data: Object.keys(data.models).map(id => ({
205
+ id,
206
+ object: 'model',
207
+ created: Math.floor(Date.now() / 1000),
208
+ owned_by: 'google'
209
+ }))
210
+ };
211
+ } catch (error) {
212
+ await handleApiError(error, token);
213
+ }
214
  }
215
 
 
 
216
  export async function generateAssistantResponseNoStream(requestBody) {
217
  const token = await tokenManager.getToken();
218
+ if (!token) throw new Error('没有可用的token,请运行 npm run login 获取token');
219
 
220
+ const headers = buildHeaders(token);
221
+ let data;
 
 
 
 
 
 
 
 
 
222
 
223
+ try {
224
+ if (useAxios) {
225
+ data = (await axios(buildAxiosConfig(config.api.noStreamUrl, headers, requestBody))).data;
226
+ } else {
227
+ const response = await requester.antigravity_fetch(config.api.noStreamUrl, buildRequesterConfig(headers, requestBody));
228
+ if (response.status !== 200) {
229
+ const errorBody = await response.text();
230
+ if (response.status === 403) tokenManager.disableCurrentToken(token);
231
+ throw new Error(response.status === 403 ? `该账号没有使用权限,已自动禁用。错误详情: ${errorBody}` : `API请求失败 (${response.status}): ${errorBody}`);
232
+ }
233
+ data = await response.json();
234
  }
235
+ } catch (error) {
236
+ await handleApiError(error, token);
237
  }
 
 
 
 
238
 
239
+ // 解析响应内容
240
+ const parts = data.response?.candidates?.[0]?.content?.parts || [];
241
  let content = '';
242
  let thinkingContent = '';
243
  const toolCalls = [];
 
248
  } else if (part.text !== undefined) {
249
  content += part.text;
250
  } else if (part.functionCall) {
251
+ toolCalls.push(convertToToolCall(part.functionCall));
 
 
 
 
 
 
 
252
  }
253
  }
254
 
255
+ // 拼接思维链标签
256
  if (thinkingContent) {
257
  content = `<think>\n${thinkingContent}\n</think>\n${content}`;
258
  }
 
261
  }
262
 
263
  export function closeRequester() {
264
+ if (requester) requester.close();
 
 
265
  }
src/auth/token_manager.js CHANGED
@@ -1,8 +1,10 @@
1
  import fs from 'fs';
2
  import path from 'path';
3
  import { fileURLToPath } from 'url';
 
4
  import { log } from '../utils/logger.js';
5
  import { generateProjectId, generateSessionId } from '../utils/idGenerator.js';
 
6
 
7
  const __filename = fileURLToPath(import.meta.url);
8
  const __dirname = path.dirname(__filename);
@@ -64,27 +66,31 @@ class TokenManager {
64
  refresh_token: token.refresh_token
65
  });
66
 
67
- const response = await fetch('https://oauth2.googleapis.com/token', {
68
- method: 'POST',
69
- headers: {
70
- 'Host': 'oauth2.googleapis.com',
71
- 'User-Agent': 'Go-http-client/1.1',
72
- 'Content-Length': body.toString().length.toString(),
73
- 'Content-Type': 'application/x-www-form-urlencoded',
74
- 'Accept-Encoding': 'gzip'
75
- },
76
- body: body.toString()
77
- });
 
 
 
 
 
 
78
 
79
- if (response.ok) {
80
- const data = await response.json();
81
- token.access_token = data.access_token;
82
- token.expires_in = data.expires_in;
83
  token.timestamp = Date.now();
84
  this.saveToFile();
85
  return token;
86
- } else {
87
- throw { statusCode: response.status, message: await response.text() };
88
  }
89
  }
90
 
 
1
  import fs from 'fs';
2
  import path from 'path';
3
  import { fileURLToPath } from 'url';
4
+ import axios from 'axios';
5
  import { log } from '../utils/logger.js';
6
  import { generateProjectId, generateSessionId } from '../utils/idGenerator.js';
7
+ import config from '../config/config.js';
8
 
9
  const __filename = fileURLToPath(import.meta.url);
10
  const __dirname = path.dirname(__filename);
 
66
  refresh_token: token.refresh_token
67
  });
68
 
69
+ try {
70
+ const response = await axios({
71
+ method: 'POST',
72
+ url: 'https://oauth2.googleapis.com/token',
73
+ headers: {
74
+ 'Host': 'oauth2.googleapis.com',
75
+ 'User-Agent': 'Go-http-client/1.1',
76
+ 'Content-Type': 'application/x-www-form-urlencoded',
77
+ 'Accept-Encoding': 'gzip'
78
+ },
79
+ data: body.toString(),
80
+ timeout: config.timeout,
81
+ proxy: config.proxy ? (() => {
82
+ const proxyUrl = new URL(config.proxy);
83
+ return { protocol: proxyUrl.protocol.replace(':', ''), host: proxyUrl.hostname, port: parseInt(proxyUrl.port) };
84
+ })() : false
85
+ });
86
 
87
+ token.access_token = response.data.access_token;
88
+ token.expires_in = response.data.expires_in;
 
 
89
  token.timestamp = Date.now();
90
  this.saveToFile();
91
  return token;
92
+ } catch (error) {
93
+ throw { statusCode: error.response?.status, message: error.response?.data || error.message };
94
  }
95
  }
96
 
src/config/config.js CHANGED
@@ -1,28 +1,73 @@
 
1
  import fs from 'fs';
2
  import log from '../utils/logger.js';
3
 
4
- const defaultConfig = {
5
- server: { port: 8045, host: '127.0.0.1' },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  api: {
7
- url: 'https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:streamGenerateContent?alt=sse',
8
- modelsUrl: 'https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:fetchAvailableModels',
9
- noStreamUrl: "https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:generateContent",
10
- host: 'daily-cloudcode-pa.sandbox.googleapis.com',
11
- userAgent: 'antigravity/1.11.3 windows/amd64'
12
  },
13
- defaults: { temperature: 1, top_p: 0.85, top_k: 50, max_tokens: 8096 },
14
- security: { maxRequestSize: '50mb', apiKey: null },
15
- useNativeFetch: false,
16
- systemInstruction: '你是聊天机器人,专门为用户提供聊天和情绪价值,协助进行小说创作或者角色扮演,也可以提供数学或者代码上的建议'
 
 
 
 
 
 
 
 
 
 
17
  };
18
 
19
- let config;
20
- try {
21
- config = JSON.parse(fs.readFileSync('./config.json', 'utf8'));
22
- log.info('✓ 配置文件加载成功');
23
- } catch {
24
- config = defaultConfig;
25
- log.warn('⚠ 配置文件未找到,使用默认配置');
26
- }
27
 
28
  export default config;
 
1
+ import dotenv from 'dotenv';
2
  import fs from 'fs';
3
  import log from '../utils/logger.js';
4
 
5
+ const envPath = '.env';
6
+ const defaultEnv = `# 服务器配置
7
+ PORT=8045
8
+ HOST=0.0.0.0
9
+
10
+ # API 配置
11
+ API_URL=https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:streamGenerateContent?alt=sse
12
+ API_MODELS_URL=https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:fetchAvailableModels
13
+ API_NO_STREAM_URL=https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:generateContent
14
+ API_HOST=daily-cloudcode-pa.sandbox.googleapis.com
15
+ API_USER_AGENT=antigravity/1.11.3 windows/amd64
16
+
17
+ # 默认参数
18
+ DEFAULT_TEMPERATURE=1
19
+ DEFAULT_TOP_P=0.85
20
+ DEFAULT_TOP_K=50
21
+ DEFAULT_MAX_TOKENS=8096
22
+
23
+ # 安全配置
24
+ MAX_REQUEST_SIZE=50mb
25
+ API_KEY=sk-text
26
+
27
+ # 其他配置
28
+ USE_NATIVE_AXIOS=false
29
+ TIMEOUT=30000
30
+ # PROXY=http://127.0.0.1:7897
31
+
32
+ # 系统提示词
33
+ SYSTEM_INSTRUCTION=你是聊天机器人,名字叫萌萌,如同名字这般,你的性格是软软糯糯萌萌哒的,专门为用户提供聊天和情绪价值,协助进行小说创作或者角色扮演
34
+ `;
35
+
36
+ if (!fs.existsSync(envPath)) {
37
+ fs.writeFileSync(envPath, defaultEnv, 'utf8');
38
+ log.info('✓ 已创建默认 .env 文件');
39
+ }
40
+
41
+ dotenv.config();
42
+
43
+ const config = {
44
+ server: {
45
+ port: parseInt(process.env.PORT) || 8045,
46
+ host: process.env.HOST || '127.0.0.1'
47
+ },
48
  api: {
49
+ url: process.env.API_URL || 'https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:streamGenerateContent?alt=sse',
50
+ modelsUrl: process.env.API_MODELS_URL || 'https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:fetchAvailableModels',
51
+ noStreamUrl: process.env.API_NO_STREAM_URL || 'https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:generateContent',
52
+ host: process.env.API_HOST || 'daily-cloudcode-pa.sandbox.googleapis.com',
53
+ userAgent: process.env.API_USER_AGENT || 'antigravity/1.11.3 windows/amd64'
54
  },
55
+ defaults: {
56
+ temperature: parseFloat(process.env.DEFAULT_TEMPERATURE) || 1,
57
+ top_p: parseFloat(process.env.DEFAULT_TOP_P) || 0.85,
58
+ top_k: parseInt(process.env.DEFAULT_TOP_K) || 50,
59
+ max_tokens: parseInt(process.env.DEFAULT_MAX_TOKENS) || 8096
60
+ },
61
+ security: {
62
+ maxRequestSize: process.env.MAX_REQUEST_SIZE || '50mb',
63
+ apiKey: process.env.API_KEY || null
64
+ },
65
+ useNativeAxios: process.env.USE_NATIVE_AXIOS !== 'false',
66
+ timeout: parseInt(process.env.TIMEOUT) || 30000,
67
+ proxy: process.env.PROXY || null,
68
+ systemInstruction: process.env.SYSTEM_INSTRUCTION || '你是聊天机器人,名字叫萌萌,如同名字这般,你的性格是软软糯糯萌萌哒的,专门为用户提供聊天和情绪价值,协助进行小说创作或者角色扮演'
69
  };
70
 
71
+ log.info('✓ 配置加载成功');
 
 
 
 
 
 
 
72
 
73
  export default config;
src/server/index.js CHANGED
@@ -57,7 +57,7 @@ app.post('/v1/chat/completions', async (req, res) => {
57
  }
58
 
59
  const requestBody = await generateRequestBody(messages, model, params, tools);
60
- //console.log(JSON.stringify(requestBody,null,2));
61
 
62
  if (stream) {
63
  res.setHeader('Content-Type', 'text/event-stream');
 
57
  }
58
 
59
  const requestBody = await generateRequestBody(messages, model, params, tools);
60
+ // console.log(JSON.stringify(requestBody,null,2));
61
 
62
  if (stream) {
63
  res.setHeader('Content-Type', 'text/event-stream');