Upload 2 files
Browse files- src/config.js +1 -14
- 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 |
-
|
| 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(
|
| 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 |
})
|