nomid2 commited on
Commit
b3784bd
·
verified ·
1 Parent(s): 5fa596e

Upload 2 files

Browse files
Files changed (2) hide show
  1. src/config.js +1 -14
  2. src/server.js +2 -453
src/config.js CHANGED
@@ -25,17 +25,6 @@ const SERVER_CONFIG = {
25
  const COOKIES = process.env.COOKIES || ""
26
  const AUTH_TOKEN = process.env.AUTH_TOKEN || "sk-123456"
27
 
28
- // Imgbb图床配置
29
- const IMGBB_API_KEY = process.env.IMGBB_API_KEY || "78f0c4360135e80c46b24b44e1e20a20"
30
-
31
- // 图片处理配置
32
- const IMAGE_CONFIG = {
33
- MAX_SIZE: parseInt(process.env.IMAGE_MAX_SIZE) || 8000, // 最大图片尺寸
34
- OVERLAP_PIXELS: parseInt(process.env.IMAGE_OVERLAP_PIXELS) || 75, // 重叠像素数
35
- USE_IMGBB: process.env.USE_IMGBB !== 'false', // 是否使用Imgbb图床,默认true
36
- UPLOAD_STRATEGY: process.env.UPLOAD_STRATEGY || 'hybrid' // 上传策略:mammouth, imgbb, hybrid
37
- }
38
-
39
 
40
  module.exports = {
41
  MODEL_MAPPING,
@@ -44,6 +33,4 @@ module.exports = {
44
  MAMMOUTH_API_URL,
45
  COOKIES,
46
  AUTH_TOKEN,
47
- IMGBB_API_KEY,
48
- IMAGE_CONFIG,
49
- }
 
25
  const COOKIES = process.env.COOKIES || ""
26
  const AUTH_TOKEN = process.env.AUTH_TOKEN || "sk-123456"
27
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
  module.exports = {
30
  MODEL_MAPPING,
 
33
  MAMMOUTH_API_URL,
34
  COOKIES,
35
  AUTH_TOKEN,
36
+ }
 
 
src/server.js CHANGED
@@ -5,469 +5,18 @@ const modelRouter = require('./router/model')
5
  const chatRouter = require('./router/chat')
6
 
7
  const app = express()
8
-
9
- // 添加请求日志中间件
10
- app.use((req, res, next) => {
11
- const timestamp = new Date().toISOString()
12
- const method = req.method
13
- const url = req.url
14
- const userAgent = req.get('User-Agent') || 'Unknown'
15
- const ip = req.ip || req.connection.remoteAddress || 'Unknown'
16
-
17
- console.log(`[${timestamp}] 📥 ${method} ${url} - IP: ${ip}`)
18
- console.log(`[${timestamp}] 🔍 User-Agent: ${userAgent}`)
19
-
20
- // 记录请求头信息
21
- if (req.headers.authorization) {
22
- console.log(`[${timestamp}] 🔑 Authorization: ${req.headers.authorization.substring(0, 20)}...`)
23
- }
24
-
25
- // 记录请求体大小(不记录具体内容,避免泄露敏感信息)
26
- const originalSend = res.send
27
- res.send = function(data) {
28
- const responseSize = data ? data.length : 0
29
- console.log(`[${timestamp}] 📤 Response sent - Status: ${res.statusCode} - Size: ${responseSize} bytes`)
30
- return originalSend.call(this, data)
31
- }
32
-
33
- next()
34
- })
35
-
36
  app.use(cors())
37
 
38
  // 增加请求体积限制,设置为50MB
39
- app.use(express.json({
40
- limit: '128mb',
41
- verify: (req, res, buf, encoding) => {
42
- // 在JSON解析前检查原始数据
43
- if (req.url === '/v1/chat/completions') {
44
- const timestamp = new Date().toISOString()
45
- const rawBody = buf.toString()
46
- console.log(`[${timestamp}] 📦 原始请求体大小: ${rawBody.length} 字符`)
47
-
48
- if (rawBody.includes('data:image/')) {
49
- console.log(`[${timestamp}] 🖼️ 原始请求体中发现base64图片数据`)
50
- const base64Count = (rawBody.match(/data:image\//g) || []).length
51
- console.log(`[${timestamp}] 📊 base64图片数量: ${base64Count}`)
52
- } else {
53
- console.log(`[${timestamp}] ❌ 原始请求体中未发现图片数据`)
54
- }
55
- }
56
- }
57
- }))
58
  app.use(express.urlencoded({ extended: true, limit: '128mb' }))
59
  app.use(express.raw({ limit: '128mb' }))
60
 
61
-
62
-
63
- // 健康检查端点
64
- app.get('/health', (req, res) => {
65
- const timestamp = new Date().toISOString()
66
- console.log(`[${timestamp}] 💓 健康检查请求`)
67
-
68
- const healthInfo = {
69
- status: 'healthy',
70
- timestamp: timestamp,
71
- uptime: process.uptime(),
72
- memory: process.memoryUsage(),
73
- environment: {
74
- nodeVersion: process.version,
75
- platform: process.platform,
76
- port: SERVER_CONFIG.PORT
77
- },
78
- config: {
79
- hasCookies: !!process.env.COOKIES,
80
- hasAuthToken: !!process.env.AUTH_TOKEN,
81
- hasImgbbKey: !!process.env.IMGBB_API_KEY,
82
- useImgbb: process.env.USE_IMGBB !== 'false'
83
- }
84
- }
85
-
86
- res.json(healthInfo)
87
- })
88
-
89
- // 根路径重定向到健康检查
90
- app.get('/', (req, res) => {
91
- res.redirect('/health')
92
- })
93
-
94
- // Mammouth API连接测试端点
95
- app.get('/test/mammouth', async (req, res) => {
96
- const timestamp = new Date().toISOString()
97
- console.log(`[${timestamp}] 🧪 测试Mammouth API连接`)
98
-
99
- try {
100
- const axios = require('axios')
101
- const FormData = require('form-data')
102
- const accountManager = require('./src/lib/manager')
103
-
104
- // 获取一个Cookie
105
- const cookieValue = accountManager.getNextAvailableCookie()
106
- if (!cookieValue) {
107
- return res.json({
108
- success: false,
109
- error: '没有可用的Cookie',
110
- timestamp: timestamp
111
- })
112
- }
113
-
114
- // 创建一个简单的测试请求
115
- const form = new FormData()
116
- form.append('model', 'anthropic-claude-4-2025-05-14')
117
- form.append('preprompt', '')
118
- form.append('messages', JSON.stringify({
119
- content: '测试连接',
120
- imagesData: [],
121
- documentsData: []
122
- }))
123
-
124
- const config = {
125
- method: 'post',
126
- url: 'https://mammouth.ai/api/models/llms',
127
- headers: {
128
- ...form.getHeaders(),
129
- 'Cookie': `auth_session=${cookieValue}`,
130
- 'origin': 'https://mammouth.ai'
131
- },
132
- data: form,
133
- responseType: 'json',
134
- timeout: 10000
135
- }
136
-
137
- console.log(`[${timestamp}] 🚀 发送测试请求到Mammouth`)
138
- const response = await axios(config)
139
-
140
- res.json({
141
- success: true,
142
- status: response.status,
143
- responseSize: JSON.stringify(response.data).length,
144
- timestamp: timestamp,
145
- message: 'Mammouth API连接正常'
146
- })
147
-
148
- } catch (error) {
149
- console.error(`[${timestamp}] ❌ Mammouth API测试失败:`, error.message)
150
-
151
- res.json({
152
- success: false,
153
- error: error.message,
154
- status: error.response?.status,
155
- responseData: error.response?.data,
156
- timestamp: timestamp
157
- })
158
- }
159
- })
160
-
161
- // 纯文本测试端点(GET方式获取示例)
162
- app.get('/test/text', (req, res) => {
163
- const timestamp = new Date().toISOString()
164
- console.log(`[${timestamp}] 🧪 纯文本测试端点`)
165
-
166
- // 创建一个简单的纯文本测试请求
167
- const testRequest = {
168
- model: "claude-sonnet-4-20250514",
169
- messages: [
170
- {
171
- role: "user",
172
- content: "你好,这是一个测试消息"
173
- }
174
- ],
175
- stream: false
176
- }
177
-
178
- res.json({
179
- message: "纯文本测试请求示例",
180
- testRequest: testRequest,
181
- instructions: [
182
- "这是一个不包含图片的纯文本测试请求",
183
- "可以用来测试Mammouth API基本功能",
184
- "将此JSON发送到 /v1/chat/completions 端点"
185
- ]
186
- })
187
- })
188
-
189
- // 长图裁切测试端点
190
- app.get('/test/slice-debug', (req, res) => {
191
- const timestamp = new Date().toISOString()
192
- console.log(`[${timestamp}] 🧪 长图裁切调试端点`)
193
-
194
- res.json({
195
- message: "长图裁切调试信息",
196
- currentIssue: "修复了长图裁切算法中的边界计算问题",
197
- fixes: [
198
- "重新计算行数和列数,确保覆盖整个图片",
199
- "添加详细的边界检查和验证",
200
- "优化步长计算,避免超出图片边界",
201
- "增强错误日志,便于调试"
202
- ],
203
- testCase: {
204
- originalImage: "1080x10319 (垂直长图)",
205
- expectedSlices: "2片,每片1080x8000,重叠150px",
206
- sliceStrategy: "垂直长图策略,沿高度方向裁切"
207
- },
208
- debugLogs: [
209
- "📐 图片分析: 显示原始尺寸",
210
- "📏 长图检测: 识别长图类型",
211
- "📏 垂直长图策略: 显示裁切方案",
212
- "🔪 生成切片: 显示每片的位置和尺寸"
213
- ]
214
- })
215
- })
216
-
217
- // 长图测试端点
218
- app.get('/test/long-image', (req, res) => {
219
- const timestamp = new Date().toISOString()
220
- console.log(`[${timestamp}] 🧪 长图测试端点`)
221
-
222
- // 创建一个模拟长图的测试请求(使用一个很长的base64字符串模拟)
223
- const testRequest = {
224
- model: "claude-sonnet-4-20250514",
225
- messages: [
226
- {
227
- role: "user",
228
- content: [
229
- {
230
- type: "text",
231
- text: "这是一张长图,请分析其内容"
232
- },
233
- {
234
- type: "image_url",
235
- image_url: {
236
- url: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAPoCAYAAACkZApTAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
237
- }
238
- }
239
- ]
240
- }
241
- ]
242
- }
243
-
244
- res.json({
245
- message: "长图测试请求示例",
246
- testRequest: testRequest,
247
- instructions: [
248
- "这是一个模拟长图的测试请求",
249
- "实际使用时请替换为真实的长图base64数据",
250
- "系统会自动检测长图并使用优化裁切策略",
251
- "将此JSON发送到 /v1/chat/completions 端点"
252
- ],
253
- longImageFeatures: [
254
- "自动检测长图(高宽比 > 2:1 或 < 1:2)",
255
- "智能裁切策略,增加重叠区域",
256
- "按顺序上传所有片段",
257
- "AI按顺序理解完整长图内容"
258
- ]
259
- })
260
- })
261
-
262
- // 简单的图片测试端点(GET方式获取示例)
263
- app.get('/test/image', (req, res) => {
264
- const timestamp = new Date().toISOString()
265
- console.log(`[${timestamp}] 🧪 图片测试端点`)
266
-
267
- // 创建一个简单的测试图片请求
268
- const testRequest = {
269
- model: "claude-sonnet-4-20250514",
270
- messages: [
271
- {
272
- role: "user",
273
- content: [
274
- {
275
- type: "text",
276
- text: "这是一个测试图片"
277
- },
278
- {
279
- type: "image_url",
280
- image_url: {
281
- url: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
282
- }
283
- }
284
- ]
285
- }
286
- ]
287
- }
288
-
289
- res.json({
290
- message: "图片测试请求示例",
291
- testRequest: testRequest,
292
- instructions: [
293
- "这是一个包含1x1像素透明PNG图片的测试请求",
294
- "可以用这个格式测试图片处理功能",
295
- "将此JSON发送到 /v1/chat/completions 端点"
296
- ]
297
- })
298
- })
299
-
300
- // 图片格式示例端点
301
- app.get('/image-format-examples', (req, res) => {
302
- const examples = {
303
- "标准OpenAI格式": {
304
- "model": "claude-sonnet-4-20250514",
305
- "messages": [
306
- {
307
- "role": "user",
308
- "content": [
309
- {
310
- "type": "text",
311
- "text": "图中什么内容?"
312
- },
313
- {
314
- "type": "image_url",
315
- "image_url": {
316
- "url": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD..."
317
- }
318
- }
319
- ]
320
- }
321
- ]
322
- },
323
- "文本中包含base64": {
324
- "model": "claude-sonnet-4-20250514",
325
- "messages": [
326
- {
327
- "role": "user",
328
- "content": [
329
- {
330
- "type": "text",
331
- "text": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD..."
332
- }
333
- ]
334
- }
335
- ]
336
- },
337
- "非标准格式": {
338
- "model": "claude-sonnet-4-20250514",
339
- "messages": [
340
- {
341
- "role": "user",
342
- "content": [
343
- {
344
- "type": "image",
345
- "image": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD..."
346
- }
347
- ]
348
- }
349
- ]
350
- }
351
- }
352
-
353
- res.json({
354
- message: "支持的图片格式示例",
355
- examples: examples,
356
- notes: [
357
- "请确保base64数据完整且格式正确",
358
- "支持的图片格式:JPEG, PNG, GIF, WebP",
359
- "建议使用标准OpenAI格式以获得最佳兼容性"
360
- ]
361
- })
362
- })
363
-
364
- // 调试端点 - 用于测试请求格式
365
- app.post('/debug/request', (req, res) => {
366
- const timestamp = new Date().toISOString()
367
- console.log(`[${timestamp}] 🐛 调试请求接收`)
368
- console.log(`[${timestamp}] 📋 请求头:`, JSON.stringify(req.headers, null, 2))
369
- console.log(`[${timestamp}] 📋 请求体:`, JSON.stringify(req.body, null, 2))
370
-
371
- // 详细分析消息结构
372
- let imageAnalysis = []
373
- if (req.body && req.body.messages) {
374
- req.body.messages.forEach((msg, msgIndex) => {
375
- if (Array.isArray(msg.content)) {
376
- msg.content.forEach((part, partIndex) => {
377
- const analysis = {
378
- messageIndex: msgIndex,
379
- partIndex: partIndex,
380
- type: part.type,
381
- keys: Object.keys(part),
382
- hasImageUrl: !!part.image_url,
383
- hasImage: !!part.image,
384
- hasImageData: !!part.image_data,
385
- hasData: !!part.data,
386
- textLength: part.text ? part.text.length : 0,
387
- containsBase64: part.text ? part.text.includes('data:image/') : false
388
- }
389
- imageAnalysis.push(analysis)
390
- })
391
- }
392
- })
393
- }
394
-
395
- res.json({
396
- timestamp: timestamp,
397
- headers: req.headers,
398
- body: req.body,
399
- bodyType: typeof req.body,
400
- bodyKeys: Object.keys(req.body || {}),
401
- hasMessages: !!(req.body && req.body.messages),
402
- messagesCount: req.body?.messages?.length || 0,
403
- imageAnalysis: imageAnalysis,
404
- suggestions: [
405
- "如果要发送图片,请确保使用以下格式之一:",
406
- "1. 标准OpenAI格式: {type: 'image_url', image_url: {url: 'data:image/...'}}",
407
- "2. 在text字段中包含base64: {type: 'text', text: 'data:image/...'}",
408
- "3. 直接图片字段: {type: 'image', image: 'data:image/...'}"
409
- ]
410
- })
411
- })
412
-
413
  // 注册路由
414
  app.use('/v1/models', modelRouter)
415
  app.use('/v1/chat', chatRouter)
416
 
417
- // 全局错误处理中间件
418
- app.use((error, req, res, next) => {
419
- const timestamp = new Date().toISOString()
420
- console.error(`[${timestamp}] 💥 未处理的错误:`, error.message)
421
- console.error(`[${timestamp}] 🔍 错误堆栈:`, error.stack)
422
-
423
- res.status(500).json({
424
- error: {
425
- message: '服务器内部错误',
426
- type: 'internal_server_error',
427
- timestamp: timestamp
428
- }
429
- })
430
- })
431
-
432
- // 404处理
433
- app.use((req, res) => {
434
- const timestamp = new Date().toISOString()
435
- console.log(`[${timestamp}] 🔍 404 - 路径未找到: ${req.method} ${req.url}`)
436
-
437
- res.status(404).json({
438
- error: {
439
- message: '路径未找到',
440
- type: 'not_found',
441
- path: req.url,
442
- method: req.method,
443
- timestamp: timestamp
444
- }
445
- })
446
- })
447
-
448
- // 进程级别错误处理
449
- process.on('uncaughtException', (error) => {
450
- const timestamp = new Date().toISOString()
451
- console.error(`[${timestamp}] 💥 未捕获的异常:`, error.message)
452
- console.error(`[${timestamp}] 🔍 错误堆栈:`, error.stack)
453
- process.exit(1)
454
- })
455
-
456
- process.on('unhandledRejection', (reason, promise) => {
457
- const timestamp = new Date().toISOString()
458
- console.error(`[${timestamp}] 💥 未处理的Promise拒绝:`, reason)
459
- console.error(`[${timestamp}] 🔍 Promise:`, promise)
460
- })
461
-
462
  // 启动服务器
463
  app.listen(SERVER_CONFIG.PORT, () => {
464
- console.log(`🚀 服务已启动在 http://localhost:${SERVER_CONFIG.PORT}`)
465
- console.log(`📅 启动时间: ${new Date().toISOString()}`)
466
- console.log(`🔧 环境变量检查:`)
467
- console.log(` - PORT: ${SERVER_CONFIG.PORT}`)
468
- console.log(` - COOKIES: ${process.env.COOKIES ? '已设置' : '未设置'}`)
469
- console.log(` - AUTH_TOKEN: ${process.env.AUTH_TOKEN ? '已设置' : '未设置'}`)
470
- console.log(` - IMGBB_API_KEY: ${process.env.IMGBB_API_KEY ? '已设置' : '未设置'}`)
471
- console.log(` - USE_IMGBB: ${process.env.USE_IMGBB || 'true'}`)
472
- console.log(`📋 服务就绪,等待请求...`)
473
  })
 
5
  const chatRouter = require('./router/chat')
6
 
7
  const app = express()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  app.use(cors())
9
 
10
  // 增加请求体积限制,设置为50MB
11
+ app.use(express.json({ limit: '128mb' }))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  app.use(express.urlencoded({ extended: true, limit: '128mb' }))
13
  app.use(express.raw({ limit: '128mb' }))
14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  // 注册路由
16
  app.use('/v1/models', modelRouter)
17
  app.use('/v1/chat', chatRouter)
18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  // 启动服务器
20
  app.listen(SERVER_CONFIG.PORT, () => {
21
+ console.log(`服务已启动在 http://loaclhost:${SERVER_CONFIG.PORT}`)
 
 
 
 
 
 
 
 
22
  })