@reconcrap/boss-recommend-mcp 1.3.30 → 1.3.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -293,133 +293,47 @@ function browserProbeResumeContext(options = {}) {
293
293
  };
294
294
  }
295
295
 
296
- async function stitchWithSharp(chunks, stitchedImage) {
297
- const sorted = chunks
298
- .map((chunk, index) => ({
299
- ...chunk,
300
- index: Number.isInteger(chunk.index) ? chunk.index : index,
301
- scrollTop: Number(chunk.scrollTop || 0),
302
- clipHeightCss: Number(chunk.clipHeightCss || 0),
303
- }))
304
- .sort((left, right) => {
305
- if (left.scrollTop !== right.scrollTop) return left.scrollTop - right.scrollTop;
306
- return left.index - right.index;
307
- });
308
-
309
- const composites = [];
310
- const used = [];
311
- let outWidth = 1;
312
- let outHeight = 0;
313
- let prevChunk = null;
314
-
315
- for (const chunk of sorted) {
316
- const info = await sharp(chunk.file).metadata();
317
- const width = Number(info?.width || 0);
318
- const height = Number(info?.height || 0);
319
- if (width <= 0 || height <= 0) {
320
- throw new Error(`Invalid chunk image size: ${chunk.file}`);
321
- }
296
+ async function detectLikelyBlankChunks(chunkFiles = []) {
297
+ const normalizedFiles = Array.isArray(chunkFiles) ? chunkFiles.filter(Boolean) : [];
298
+ if (normalizedFiles.length <= 0) {
299
+ return { likelyBlank: false, luma: 0, avgStd: 0, blankChunks: 0, totalChunks: 0 };
300
+ }
322
301
 
323
- if (prevChunk) {
324
- const deltaCss = chunk.scrollTop - prevChunk.scrollTop;
325
- if (!(deltaCss > 0.5)) {
326
- prevChunk = chunk;
327
- continue;
328
- }
329
- const clipHeightCss = chunk.clipHeightCss > 1 ? chunk.clipHeightCss : prevChunk.clipHeightCss;
330
- const ratio = clipHeightCss > 1 ? height / clipHeightCss : 1;
331
- const newPixels = clamp(Math.round(deltaCss * ratio), 1, height);
332
- const cropTop = clamp(height - newPixels, 0, height - 1);
333
- const segHeight = height - cropTop;
334
- const segment = await sharp(chunk.file)
335
- .removeAlpha()
336
- .extract({
337
- left: 0,
338
- top: cropTop,
339
- width,
340
- height: segHeight,
341
- })
342
- .png()
343
- .toBuffer();
344
- composites.push({
345
- input: segment,
346
- top: outHeight,
347
- left: 0,
348
- });
349
- used.push({
350
- file: chunk.file,
351
- scrollTop: chunk.scrollTop,
352
- cropTopPx: cropTop,
353
- keptHeightPx: segHeight,
354
- });
355
- outWidth = Math.max(outWidth, width);
356
- outHeight += segHeight;
357
- prevChunk = chunk;
302
+ let lumaTotal = 0;
303
+ let stdTotal = 0;
304
+ let blankChunks = 0;
305
+
306
+ for (const file of normalizedFiles) {
307
+ const stats = await sharp(file).stats();
308
+ const channels = stats?.channels || [];
309
+ if (channels.length < 3) {
358
310
  continue;
359
311
  }
360
-
361
- const segment = await sharp(chunk.file).removeAlpha().png().toBuffer();
362
- composites.push({
363
- input: segment,
364
- top: outHeight,
365
- left: 0,
366
- });
367
- used.push({
368
- file: chunk.file,
369
- scrollTop: chunk.scrollTop,
370
- cropTopPx: 0,
371
- keptHeightPx: height,
372
- });
373
- outWidth = Math.max(outWidth, width);
374
- outHeight += height;
375
- prevChunk = chunk;
376
- }
377
-
378
- if (composites.length === 0 || outHeight <= 0 || outWidth <= 0) {
379
- throw new Error('No valid segments to stitch with sharp.');
312
+ const meanR = Number(channels[0]?.mean || 0);
313
+ const meanG = Number(channels[1]?.mean || 0);
314
+ const meanB = Number(channels[2]?.mean || 0);
315
+ const stdR = Number(channels[0]?.stdev || 0);
316
+ const stdG = Number(channels[1]?.stdev || 0);
317
+ const stdB = Number(channels[2]?.stdev || 0);
318
+ const luma = 0.299 * meanR + 0.587 * meanG + 0.114 * meanB;
319
+ const avgStd = (stdR + stdG + stdB) / 3;
320
+ lumaTotal += luma;
321
+ stdTotal += avgStd;
322
+ if (luma >= 244 && avgStd <= 9) {
323
+ blankChunks += 1;
324
+ }
380
325
  }
381
326
 
382
- await sharp({
383
- create: {
384
- width: outWidth,
385
- height: outHeight,
386
- channels: 3,
387
- background: { r: 255, g: 255, b: 255 },
388
- },
389
- })
390
- .composite(composites)
391
- .png()
392
- .toFile(stitchedImage);
393
-
394
- return {
395
- segments: composites.length,
396
- size: {
397
- width: outWidth,
398
- height: outHeight,
399
- },
400
- used,
401
- };
402
- }
403
-
404
- async function detectLikelyBlankImage(imagePath) {
405
- const stats = await sharp(imagePath).stats();
406
- const channels = stats?.channels || [];
407
- if (channels.length < 3) {
408
- return { likelyBlank: false, luma: 0, avgStd: 0 };
409
- }
410
- const meanR = Number(channels[0]?.mean || 0);
411
- const meanG = Number(channels[1]?.mean || 0);
412
- const meanB = Number(channels[2]?.mean || 0);
413
- const stdR = Number(channels[0]?.stdev || 0);
414
- const stdG = Number(channels[1]?.stdev || 0);
415
- const stdB = Number(channels[2]?.stdev || 0);
416
- const luma = 0.299 * meanR + 0.587 * meanG + 0.114 * meanB;
417
- const avgStd = (stdR + stdG + stdB) / 3;
418
- const likelyBlank = luma >= 244 && avgStd <= 9;
327
+ const totalChunks = normalizedFiles.length;
328
+ const avgLuma = totalChunks > 0 ? lumaTotal / totalChunks : 0;
329
+ const avgStd = totalChunks > 0 ? stdTotal / totalChunks : 0;
330
+ const likelyBlank = blankChunks === totalChunks;
419
331
  return {
420
332
  likelyBlank,
421
- luma: Number(luma.toFixed(2)),
333
+ luma: Number(avgLuma.toFixed(2)),
422
334
  avgStd: Number(avgStd.toFixed(2)),
335
+ blankChunks,
336
+ totalChunks,
423
337
  };
424
338
  }
425
339
 
@@ -459,7 +373,6 @@ export class ResumeCaptureService {
459
373
  const chunkDir = path.join(artifactDir, 'chunks');
460
374
  await mkdir(chunkDir, { recursive: true });
461
375
  const metadataFile = path.join(artifactDir, 'chunks.json');
462
- const stitchedImage = path.join(artifactDir, 'resume.png');
463
376
 
464
377
  const probe = await this.waitForProbe({ waitResumeMs });
465
378
  const maxScroll = Math.max(0, Number(probe.maxScroll || 0));
@@ -535,19 +448,21 @@ export class ResumeCaptureService {
535
448
  chunks,
536
449
  };
537
450
  await writeFile(metadataFile, `${JSON.stringify(metadata, null, 2)}\n`, 'utf8');
538
- const stitched = await stitchWithSharp(chunks, stitchedImage);
539
- const blank = await detectLikelyBlankImage(stitchedImage);
451
+ const chunkFiles = chunks.map((chunk) => path.resolve(chunk.file));
452
+ const blank = await detectLikelyBlankChunks(chunkFiles);
540
453
  this.logger.log(
541
- `简历截图完成: chunks=${chunks.length}, stitched=${stitchedImage}, size=${stitched.size.width}x${stitched.size.height}, likelyBlank=${blank.likelyBlank}, luma=${blank.luma}, std=${blank.avgStd}`,
454
+ `简历截图完成: chunks=${chunks.length}, modelImages=${chunkFiles.length}, likelyBlank=${blank.likelyBlank}, blankChunks=${blank.blankChunks}/${blank.totalChunks}, luma=${blank.luma}, std=${blank.avgStd}`,
542
455
  );
543
456
 
544
457
  return {
545
- stitchedImage,
546
458
  metadataFile,
547
459
  chunkDir,
548
460
  chunkCount: chunks.length,
549
- stitchEngine: 'sharp',
550
- stitched,
461
+ chunkFiles,
462
+ modelImagePaths: chunkFiles,
463
+ stitchedImage: '',
464
+ stitchEngine: 'skipped',
465
+ stitched: null,
551
466
  quality: blank,
552
467
  };
553
468
  }