nomid2 commited on
Commit
0b715ff
·
verified ·
1 Parent(s): 5cdca7f

Upload chat.js

Browse files
Files changed (1) hide show
  1. src/router/chat.js +123 -178
src/router/chat.js CHANGED
@@ -7,7 +7,6 @@ const accountManager = require('../lib/manager')
7
  const imageUploader = require('../lib/uploader')
8
  const logger = require('../lib/logger')
9
  const ErrorHandler = require('../lib/errorHandler')
10
- const ImageProcessingQueue = require('../lib/imageQueue')
11
 
12
  const router = express.Router()
13
 
@@ -122,207 +121,168 @@ async function convertOpenAIToMammouth(openaiRequest, requestId = null) {
122
  let hasProcessedText = false // 标记是否已处理文本
123
  let normalImageCount = 0 // 普通图片计数
124
 
125
- // 处理每个图片 - 使用严格的顺序处理机制
126
- console.log(`[图片处理开始] 共${imageParts.length}张图片待处理,开始时间: ${new Date().toISOString()}`)
127
 
128
- // 创建图片处理队列,确保严格按顺序处理
129
- const imageQueue = new ImageProcessingQueue()
130
- const imageProcessingPromises = []
131
-
132
- // 为每张图片创建处理任务
133
  for (let imagePartIndex = 0; imagePartIndex < imageParts.length; imagePartIndex++) {
134
  const imagePart = imageParts[imagePartIndex]
135
- const imageGlobalIndex = currentImageIndex + imagePartIndex
136
-
137
- console.log(`[队列任务] 创建第${imagePartIndex + 1}张图片的处理任务 (全局索引: ${imageGlobalIndex + 1})`)
138
-
139
- // 创建图片处理任务
140
- const imageProcessor = async () => {
141
- const processingStartTime = Date.now()
142
- console.log(`[队列执行] 开始处理图片${imageGlobalIndex + 1},时间: ${new Date().toISOString()}`)
143
 
144
- try {
145
- // 获取图片数据
146
- let imageUrl = imagePart.image_url
147
- if (typeof imageUrl === 'object' && imageUrl.url) {
148
- imageUrl = imageUrl.url
149
- }
150
 
151
- console.log(`[队列执行] 图片${imageGlobalIndex + 1}类型: ${imageUrl.startsWith('data:image') ? 'Base64' : 'URL'}`)
152
- console.log(`[队列执行] 图片${imageGlobalIndex + 1}URL长度: ${typeof imageUrl === 'string' ? imageUrl.length : 'N/A'}`)
153
-
154
- // 记录处理前的状态
155
- const beforeProcessTime = Date.now()
156
- console.log(`[队列执行] 图片${imageGlobalIndex + 1}开始上传处理,时间: ${new Date().toISOString()}`)
157
-
158
- // 使用智能上传方法处理图片(支持长图)
159
- // 启用preserveOrder=true来确保图片顺序正确
160
- let uploadedUrls = []
161
- if (imageUrl.startsWith('data:image')) {
162
- uploadedUrls = await imageUploader.uploadFromBase64Smart(
163
- imageUrl,
164
- null,
165
- requestId,
166
- imageGlobalIndex,
167
- true // preserveOrder = true,禁用缓存优化以保持顺序
168
- )
169
- } else {
170
- uploadedUrls = await imageUploader.uploadFromUrlSmart(
171
- imageUrl,
172
- null,
173
- requestId,
174
- imageGlobalIndex,
175
- true // preserveOrder = true,禁用缓存优化以保持顺序
176
- )
177
- }
178
 
179
- const afterProcessTime = Date.now()
180
- const processingDuration = afterProcessTime - beforeProcessTime
181
 
182
- console.log(`[队列执行] 图片${imageGlobalIndex + 1}上传完成,获得${uploadedUrls.length}个URL`)
183
- console.log(`[队列执行] 图片${imageGlobalIndex + 1}处理耗时: ${processingDuration}ms`)
184
- console.log(`[队列执行] 图片${imageGlobalIndex + 1}完成时间: ${new Date().toISOString()}`)
185
 
186
- return {
187
- imagePartIndex,
188
- imageGlobalIndex,
189
- uploadedUrls,
190
- processingDuration,
191
- processingStartTime,
192
- completedTime: afterProcessTime
193
  }
194
- } catch (error) {
195
- console.error(`[队列执行] 图片${imageGlobalIndex + 1}处理失败: ${error.message}`)
196
- throw error
197
- }
198
- }
199
-
200
- // 将任务添加到队列
201
- const promise = imageQueue.addTask(imagePartIndex, imageProcessor)
202
- imageProcessingPromises.push(promise)
203
- }
204
 
205
- console.log(`[队列管理] 所有${imageParts.length}个图片任务已添加到队列`)
 
 
 
 
 
206
 
207
- // 等待所有图片处理完成
208
- console.log(`[队列管理] 开始等待所有图片处理完成...`)
209
- const imageResults = await Promise.all(imageProcessingPromises)
210
- console.log(`[队列管理] 所有图片处理完成,共${imageResults.length}个结果`)
 
211
 
212
- // 处理队列返回的结果
213
- for (const result of imageResults) {
214
- const { imagePartIndex, imageGlobalIndex, uploadedUrls, processingDuration } = result
215
 
216
- console.log(`[结果处理] 处理图片${imageGlobalIndex + 1}的结果,位置索引: ${imagePartIndex}`)
 
 
 
 
 
 
 
 
 
 
 
217
 
218
- // 如果是长图(多个片段),为每个片段创建单独的消息
219
- if (uploadedUrls.length > 1) {
220
- console.log(`[长图处理] 图片${imageGlobalIndex + 1}被切割为${uploadedUrls.length}个片段,将按顺序发送`)
221
 
222
- if (requestId) {
223
- logger.logMessageSegmentation(requestId, imageGlobalIndex, uploadedUrls.length)
224
  }
225
 
226
- uploadedUrls.forEach((url, segmentIndex) => {
227
- // 只在第一个长图的第一个片段包含原始文本
228
- const includeOriginalText = !hasProcessedText && segmentIndex === 0 && combinedText
229
- const segmentText = includeOriginalText
230
- ? `${combinedText}\n\n[长图片段 ${segmentIndex + 1}/${uploadedUrls.length}]`
231
- : `[长图片段 ${segmentIndex + 1}/${uploadedUrls.length}]`
232
-
233
- processedMessages.push({
234
- content: segmentText || '.',
235
- imagesData: [url],
236
- documentsData: []
237
  })
238
-
239
- console.log(`[消息生成] 长图片段${segmentIndex + 1}: "${segmentText.substring(0, 50)}..."`)
240
-
241
- if (includeOriginalText) {
242
- hasProcessedText = true
243
- }
244
- })
245
- } else {
246
- // 普通图片,按顺序存储��结果数组中
247
- const collectTime = Date.now()
248
- const imageResult = {
249
- index: imagePartIndex, // 在消息中的位置索引
250
- urls: uploadedUrls,
251
- originalIndex: imageGlobalIndex, // 全局图片索引
252
- processOrder: normalImageCount, // 处理顺序
253
- collectTime: collectTime, // 收集时间戳
254
- processingDuration: processingDuration // 处理耗时
255
  }
256
 
257
- normalImageResults.push(imageResult)
258
  normalImageCount++
259
 
260
- console.log(`[图片收集] 普通图片${imageGlobalIndex + 1}已收集,收集时间: ${new Date(collectTime).toISOString()}`)
261
- console.log(` - 消息位置索引: ${imagePartIndex}`)
262
- console.log(` - 全局图片索引: ${imageGlobalIndex}`)
263
- console.log(` - 处理顺序: ${normalImageCount}`)
264
- console.log(` - 处理耗时: ${processingDuration}ms`)
265
- console.log(` - 当前普通图片总数: ${normalImageCount}`)
266
- console.log(` - 第一个URL: ${uploadedUrls[0] ? uploadedUrls[0].substring(uploadedUrls[0].lastIndexOf('/') + 1) : 'N/A'}`)
267
  }
268
  }
269
 
270
- // 更新全局图片索引
271
- currentImageIndex += imageParts.length
272
-
273
  console.log(`[图片处理完成] 共处理${imageParts.length}张图片,成功收集${normalImageResults.length}张普通图片`)
274
 
275
- // 如果有普通图片,按原始顺序创建一个包含所有普通图片的消息
276
  if (normalImageResults.length > 0) {
277
- console.log(`[排序前验证] 收集到${normalImageResults.length}张普通图片,验证时间: ${new Date().toISOString()}`)
278
  normalImageResults.forEach((result, idx) => {
279
- console.log(` 图片${idx + 1}: 位置=${result.index}, 全局=${result.originalIndex}, 顺序=${result.processOrder}, 耗时=${result.processingDuration}ms, 收集时间=${new Date(result.collectTime).toISOString()}`)
280
  })
281
 
282
- // 按照imagePartIndex排序,确保严格按客户端上传顺序
283
- console.log(`[开始排序] 按消息中的位置索引排序,排序时间: ${new Date().toISOString()}`)
284
-
285
- // 记录排序前的顺序
286
- const beforeSort = normalImageResults.map(r => ({pos: r.index, global: r.originalIndex, order: r.processOrder}))
287
- console.log(`[排序前顺序] ${beforeSort.map(r => `位置${r.pos}(全局${r.global},顺序${r.order})`).join(' -> ')}`)
288
-
289
  normalImageResults.sort((a, b) => {
290
- const result = a.index - b.index
291
- console.log(` 比较: 位置${a.index}(全局${a.originalIndex + 1}) vs 位置${b.index}(全局${b.originalIndex + 1}) = ${result}`)
292
- return result
293
  })
294
 
295
- console.log(`[排序后验证] 最终图片顺序,完成时间: ${new Date().toISOString()}`)
296
  normalImageResults.forEach((result, idx) => {
297
- console.log(` 第${idx + 1}位: 位置=${result.index}, 全局=${result.originalIndex}, 顺序=${result.processOrder}, 耗时=${result.processingDuration}ms`)
298
  })
299
 
300
- // 验证排序是否正确(检查index是否连续递增)
301
- let sortingValid = true
302
- for (let i = 1; i < normalImageResults.length; i++) {
303
- if (normalImageResults[i].index <= normalImageResults[i-1].index) {
304
- console.error(`[排序错误] 位置${i}: 当前index=${normalImageResults[i].index} <= 前一个index=${normalImageResults[i-1].index}`)
305
- sortingValid = false
306
- }
307
- }
308
-
309
- if (sortingValid) {
310
- console.log(`[排序验证] ✅ 图片顺序正确`)
311
- } else {
312
- console.error(`[排序验证] ❌ 图片顺序存在问题`)
313
- }
314
-
315
- // 提取所有URL,保持顺序
316
  const orderedImageUrls = []
 
 
317
  normalImageResults.forEach((result, idx) => {
318
- console.log(`[URL提取] 第${idx + 1}张图片(位置${result.index}): ${result.urls.length}个URL`)
319
- orderedImageUrls.push(...result.urls)
 
 
 
 
 
320
  })
321
 
322
  const includeOriginalText = !hasProcessedText && combinedText
323
- const normalImageText = includeOriginalText
324
- ? `${combinedText}\n\n[包含 ${orderedImageUrls.length} 张图片]`
325
- : `[包含 ${orderedImageUrls.length} 张图片]`
 
 
 
 
 
 
 
 
 
 
 
 
 
326
 
327
  processedMessages.push({
328
  content: normalImageText || '.',
@@ -330,14 +290,8 @@ async function convertOpenAIToMammouth(openaiRequest, requestId = null) {
330
  documentsData: []
331
  })
332
 
333
- console.log(`[消息生成] 普通图片批量消息: ${orderedImageUrls.length}张图片,按顺序排列`)
334
- console.log(`[最终顺序] ${normalImageResults.map(r => `位置${r.index}(图片${r.originalIndex + 1})`).join(' -> ')}`)
335
-
336
- // 最终验证:确保发送给模型的图片顺序与客户端上传顺序一致
337
- console.log(`[最终验证] 发送给模型的图片URL顺序:`)
338
- orderedImageUrls.forEach((url, idx) => {
339
- console.log(` 第${idx + 1}张: ${url.substring(url.lastIndexOf('/') + 1)}`)
340
- })
341
  }
342
 
343
  // 如果没有图片,只有文本
@@ -358,18 +312,9 @@ async function convertOpenAIToMammouth(openaiRequest, requestId = null) {
358
  }
359
 
360
  // 将所有处理后的消息添加到表单
361
- console.log(`[消息发送前验证] 共${processedMessages.length}条消息将发送给模型`)
362
- processedMessages.forEach((msg, msgIndex) => {
363
- console.log(`[消息${msgIndex + 1}] 包含${msg.imagesData.length}张图片`)
364
- if (msg.imagesData.length > 0) {
365
- msg.imagesData.forEach((imageUrl, imgIndex) => {
366
- console.log(` 图片${imgIndex + 1}: ${imageUrl.substring(imageUrl.lastIndexOf('/') + 1)}`)
367
- })
368
- }
369
  form.append('messages', JSON.stringify(msg))
370
  })
371
-
372
- console.log(`[最终确认] 所有消息已按正确顺序添加到请求表单`)
373
  }
374
 
375
  return form
 
7
  const imageUploader = require('../lib/uploader')
8
  const logger = require('../lib/logger')
9
  const ErrorHandler = require('../lib/errorHandler')
 
10
 
11
  const router = express.Router()
12
 
 
121
  let hasProcessedText = false // 标记是否已处理文本
122
  let normalImageCount = 0 // 普通图片计数
123
 
124
+ // 处理每个图片 - 严格按顺序处理,确保不会出现顺序混乱
125
+ console.log(`[图片处理开始] 共${imageParts.length}张图片待处理,将严格按顺序处理`)
126
 
 
 
 
 
 
127
  for (let imagePartIndex = 0; imagePartIndex < imageParts.length; imagePartIndex++) {
128
  const imagePart = imageParts[imagePartIndex]
129
+ console.log(`[图片处理] 开始处理第${imagePartIndex + 1}张图片 (消息位置: ${imagePartIndex}, 全局索引: ${currentImageIndex + 1})`)
 
 
 
 
 
 
 
130
 
131
+ try {
132
+ // 获取图片数据
133
+ let imageUrl = imagePart.image_url
134
+ if (typeof imageUrl === 'object' && imageUrl.url) {
135
+ imageUrl = imageUrl.url
136
+ }
137
 
138
+ console.log(`[图片处理] 图片${currentImageIndex + 1}类型: ${imageUrl.startsWith('data:image') ? 'Base64' : 'URL'}`)
139
+
140
+ // 使用智能上传方法处理图片(支持长图)
141
+ let uploadedUrls = []
142
+ if (imageUrl.startsWith('data:image')) {
143
+ uploadedUrls = await imageUploader.uploadFromBase64Smart(
144
+ imageUrl,
145
+ null,
146
+ requestId,
147
+ currentImageIndex,
148
+ false // 恢复正常缓存机制
149
+ )
150
+ } else {
151
+ uploadedUrls = await imageUploader.uploadFromUrlSmart(
152
+ imageUrl,
153
+ null,
154
+ requestId,
155
+ currentImageIndex,
156
+ false // 恢复正常缓存机制
157
+ )
158
+ }
 
 
 
 
 
 
159
 
160
+ console.log(`[图片处理] 图片${currentImageIndex + 1}上传完成,获得${uploadedUrls.length}个URL,位置索引: ${imagePartIndex}`)
 
161
 
162
+ // 如果是长图(多个片段),为每个片段创建单独的消息
163
+ if (uploadedUrls.length > 1) {
164
+ console.log(`[长图处理] 图片${currentImageIndex + 1}被切割为${uploadedUrls.length}个片段,将按顺序发送`)
165
 
166
+ if (requestId) {
167
+ logger.logMessageSegmentation(requestId, currentImageIndex, uploadedUrls.length)
 
 
 
 
 
168
  }
 
 
 
 
 
 
 
 
 
 
169
 
170
+ uploadedUrls.forEach((url, segmentIndex) => {
171
+ // 只在第一个长图的第一个片段包含原始文本
172
+ const includeOriginalText = !hasProcessedText && segmentIndex === 0 && combinedText
173
+ const segmentText = includeOriginalText
174
+ ? `${combinedText}\n\n[长图片段 ${segmentIndex + 1}/${uploadedUrls.length}]`
175
+ : `[长图片段 ${segmentIndex + 1}/${uploadedUrls.length}]`
176
 
177
+ processedMessages.push({
178
+ content: segmentText || '.',
179
+ imagesData: [url],
180
+ documentsData: []
181
+ })
182
 
183
+ console.log(`[消息生成] 长图片段${segmentIndex + 1}: "${segmentText.substring(0, 50)}..."`)
 
 
184
 
185
+ if (includeOriginalText) {
186
+ hasProcessedText = true
187
+ }
188
+ })
189
+ } else {
190
+ // 普通图片,严格按顺序存储到结果数组中
191
+ const imageResult = {
192
+ index: imagePartIndex, // 在消息中的位置索引(关键排序字段)
193
+ urls: uploadedUrls,
194
+ originalIndex: currentImageIndex, // 全局图片索引
195
+ processOrder: normalImageCount // 处理顺序
196
+ }
197
 
198
+ normalImageResults.push(imageResult)
199
+ normalImageCount++
 
200
 
201
+ console.log(`[图片收集] 普通图片${currentImageIndex + 1}已收集 (消息位置: ${imagePartIndex}, 处理顺序: ${normalImageCount}),当前共${normalImageCount}张普通图片`)
 
202
  }
203
 
204
+ currentImageIndex++
205
+ } catch (error) {
206
+ if (requestId) {
207
+ logger.logError(requestId, 'IMAGE_PROCESSING_ERROR', error.message, {
208
+ imageIndex: currentImageIndex,
209
+ imagePartIndex: imagePartIndex,
210
+ imageUrl: typeof imagePart.image_url === 'string' ? imagePart.image_url.substring(0, 100) : 'object'
 
 
 
 
211
  })
212
+ }
213
+ console.error(`图片处理错误 (位置${imagePartIndex}, 全局${currentImageIndex + 1}):`, error.message)
214
+
215
+ // 图片处理失败时,添加一个错误占位符,避免完全跳过
216
+ const errorPlaceholder = {
217
+ index: imagePartIndex,
218
+ urls: [],
219
+ originalIndex: currentImageIndex,
220
+ processOrder: normalImageCount,
221
+ error: true,
222
+ errorMessage: error.message
 
 
 
 
 
 
223
  }
224
 
225
+ normalImageResults.push(errorPlaceholder)
226
  normalImageCount++
227
 
228
+ console.log(`[图片错误] 图片${currentImageIndex + 1}处理失败,已添加错误占位符`)
229
+ currentImageIndex++
 
 
 
 
 
230
  }
231
  }
232
 
 
 
 
233
  console.log(`[图片处理完成] 共处理${imageParts.length}张图片,成功收集${normalImageResults.length}张普通图片`)
234
 
235
+ // 如果有普通图片,严格按原始顺序创建一个包含所有普通图片的消息
236
  if (normalImageResults.length > 0) {
237
+ console.log(`[排序前验证] 收集到${normalImageResults.length}张普通图片`)
238
  normalImageResults.forEach((result, idx) => {
239
+ console.log(` 图片${idx + 1}: 消息位置=${result.index}, 全局索引=${result.originalIndex}, 处理顺序=${result.processOrder}`)
240
  })
241
 
242
+ // 严格按照imagePartIndex排序,确保完全按客户端上传顺序
243
+ console.log(`[开始排序] 严格按消息中的位置索引排序...`)
 
 
 
 
 
244
  normalImageResults.sort((a, b) => {
245
+ const diff = a.index - b.index
246
+ console.log(`[排序比较] 位置${a.index} vs 位置${b.index} = ${diff}`)
247
+ return diff
248
  })
249
 
250
+ console.log(`[排序后验证] 最终图片顺序:`)
251
  normalImageResults.forEach((result, idx) => {
252
+ console.log(` 第${idx + 1}位: 消息位置=${result.index}, 全局索引=${result.originalIndex}, 处理顺序=${result.processOrder}`)
253
  })
254
 
255
+ // 提取所有URL,严格保持顺序,跳过错误的图片
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
256
  const orderedImageUrls = []
257
+ const errorMessages = []
258
+
259
  normalImageResults.forEach((result, idx) => {
260
+ if (result.error) {
261
+ console.log(`[URL提取] 第${idx + 1}个结果,位置${result.index},图片处理失败: ${result.errorMessage}`)
262
+ errorMessages.push(`图片${result.originalIndex + 1}处理失败`)
263
+ } else {
264
+ console.log(`[URL提取] 第${idx + 1}个结果,位置${result.index},添加${result.urls.length}个URL`)
265
+ orderedImageUrls.push(...result.urls)
266
+ }
267
  })
268
 
269
  const includeOriginalText = !hasProcessedText && combinedText
270
+ let normalImageText = includeOriginalText ? combinedText : ''
271
+
272
+ // 构建图片状态信息
273
+ const successCount = orderedImageUrls.length
274
+ const errorCount = errorMessages.length
275
+
276
+ if (successCount > 0 && errorCount > 0) {
277
+ const statusText = `[包含 ${successCount} 张图片,${errorCount} 张图片处理失败]`
278
+ normalImageText = normalImageText ? `${normalImageText}\n\n${statusText}` : statusText
279
+ } else if (successCount > 0) {
280
+ const statusText = `[包含 ${successCount} 张图片]`
281
+ normalImageText = normalImageText ? `${normalImageText}\n\n${statusText}` : statusText
282
+ } else if (errorCount > 0) {
283
+ const statusText = `[${errorCount} 张图片处理失败]`
284
+ normalImageText = normalImageText ? `${normalImageText}\n\n${statusText}` : statusText
285
+ }
286
 
287
  processedMessages.push({
288
  content: normalImageText || '.',
 
290
  documentsData: []
291
  })
292
 
293
+ console.log(`[消息生成] 普通图片批量消息: ${successCount}张成功,${errorCount}张失败,严格按顺序排列`)
294
+ console.log(`[最终顺序验证] 图片顺序: ${normalImageResults.map(r => `位置${r.index}(图片${r.originalIndex + 1}${r.error ? '-失败' : ''})`).join(' -> ')}`)
 
 
 
 
 
 
295
  }
296
 
297
  // 如果没有图片,只有文本
 
312
  }
313
 
314
  // 将所有处理后的消息添加到表单
315
+ processedMessages.forEach(msg => {
 
 
 
 
 
 
 
316
  form.append('messages', JSON.stringify(msg))
317
  })
 
 
318
  }
319
 
320
  return form