@heripo/document-processor 0.1.33 → 0.1.34

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.
package/dist/index.js CHANGED
@@ -291,6 +291,29 @@ var LLMCaller = class {
291
291
  function formatTokens(usage) {
292
292
  return `${usage.inputTokens} input, ${usage.outputTokens} output, ${usage.totalTokens} total`;
293
293
  }
294
+ function emptyUsage() {
295
+ return { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
296
+ }
297
+ function addInto(target, src) {
298
+ target.inputTokens += src.inputTokens;
299
+ target.outputTokens += src.outputTokens;
300
+ target.totalTokens += src.totalTokens;
301
+ }
302
+ function sumUsage(a, b) {
303
+ return {
304
+ inputTokens: (a?.inputTokens ?? 0) + (b?.inputTokens ?? 0),
305
+ outputTokens: (a?.outputTokens ?? 0) + (b?.outputTokens ?? 0),
306
+ totalTokens: (a?.totalTokens ?? 0) + (b?.totalTokens ?? 0)
307
+ };
308
+ }
309
+ function accumulateModel(bucket, modelName, usage) {
310
+ let entry = bucket.get(modelName);
311
+ if (!entry) {
312
+ entry = emptyUsage();
313
+ bucket.set(modelName, entry);
314
+ }
315
+ addInto(entry, usage);
316
+ }
294
317
  var LLMTokenUsageAggregator = class {
295
318
  usage = {};
296
319
  /**
@@ -303,21 +326,15 @@ var LLMTokenUsageAggregator = class {
303
326
  this.usage[usage.component] = {
304
327
  component: usage.component,
305
328
  phases: {},
306
- total: {
307
- inputTokens: 0,
308
- outputTokens: 0,
309
- totalTokens: 0
310
- }
329
+ total: emptyUsage()
311
330
  };
312
331
  }
313
332
  const component = this.usage[usage.component];
314
333
  if (!component.phases[usage.phase]) {
315
334
  component.phases[usage.phase] = {
316
- total: {
317
- inputTokens: 0,
318
- outputTokens: 0,
319
- totalTokens: 0
320
- },
335
+ primary: /* @__PURE__ */ new Map(),
336
+ fallback: /* @__PURE__ */ new Map(),
337
+ total: emptyUsage(),
321
338
  metadata: []
322
339
  };
323
340
  }
@@ -326,41 +343,17 @@ var LLMTokenUsageAggregator = class {
326
343
  phase.metadata.push(usage.metadata);
327
344
  }
328
345
  if (usage.model === "primary") {
329
- if (!phase.primary) {
330
- phase.primary = {
331
- modelName: usage.modelName,
332
- inputTokens: 0,
333
- outputTokens: 0,
334
- totalTokens: 0
335
- };
336
- }
337
- phase.primary.inputTokens += usage.inputTokens;
338
- phase.primary.outputTokens += usage.outputTokens;
339
- phase.primary.totalTokens += usage.totalTokens;
346
+ accumulateModel(phase.primary, usage.modelName, usage);
340
347
  } else if (usage.model === "fallback") {
341
- if (!phase.fallback) {
342
- phase.fallback = {
343
- modelName: usage.modelName,
344
- inputTokens: 0,
345
- outputTokens: 0,
346
- totalTokens: 0
347
- };
348
- }
349
- phase.fallback.inputTokens += usage.inputTokens;
350
- phase.fallback.outputTokens += usage.outputTokens;
351
- phase.fallback.totalTokens += usage.totalTokens;
348
+ accumulateModel(phase.fallback, usage.modelName, usage);
352
349
  }
353
- phase.total.inputTokens += usage.inputTokens;
354
- phase.total.outputTokens += usage.outputTokens;
355
- phase.total.totalTokens += usage.totalTokens;
356
- component.total.inputTokens += usage.inputTokens;
357
- component.total.outputTokens += usage.outputTokens;
358
- component.total.totalTokens += usage.totalTokens;
350
+ addInto(phase.total, usage);
351
+ addInto(component.total, usage);
359
352
  }
360
353
  /**
361
354
  * Get aggregated usage grouped by component
362
355
  *
363
- * @returns Array of component aggregates with phase breakdown
356
+ * @returns Array of component aggregates with per-model phase breakdown
364
357
  */
365
358
  getByComponent() {
366
359
  return Object.values(this.usage);
@@ -369,8 +362,16 @@ var LLMTokenUsageAggregator = class {
369
362
  * Get token usage report in structured JSON format
370
363
  *
371
364
  * Converts internal usage data to external TokenUsageReport format suitable
372
- * for serialization and reporting. The report includes component breakdown,
373
- * phase-level details, and both primary and fallback model usage.
365
+ * for serialization and reporting.
366
+ *
367
+ * Each (phase, model) pair becomes its own PhaseUsageReport entry. A phase
368
+ * that used a single primary (and/or a single fallback) model yields exactly
369
+ * one entry — identical to the legacy shape — while a phase that mixed models
370
+ * yields one entry per model, all sharing the same `phase` name. Every
371
+ * (phase, tier, modelName) combination appears in exactly one entry, so
372
+ * consumers that key by `${component}|${phase}|${tier}|${modelName}`
373
+ * (heripo-web's token-usage emitter / ledger recorder) attribute each model's
374
+ * tokens — and cost — correctly without double counting.
374
375
  *
375
376
  * @returns Structured token usage report with components and total
376
377
  */
@@ -379,34 +380,41 @@ var LLMTokenUsageAggregator = class {
379
380
  for (const component of Object.values(this.usage)) {
380
381
  const phases = [];
381
382
  for (const [phaseName, phaseData] of Object.entries(component.phases)) {
382
- const phaseReport = {
383
- phase: phaseName,
384
- total: {
385
- inputTokens: phaseData.total.inputTokens,
386
- outputTokens: phaseData.total.outputTokens,
387
- totalTokens: phaseData.total.totalTokens
388
- }
389
- };
390
- if (phaseData.metadata.length > 0) {
391
- phaseReport.metadata = [...phaseData.metadata];
392
- }
393
- if (phaseData.primary) {
394
- phaseReport.primary = {
395
- modelName: phaseData.primary.modelName,
396
- inputTokens: phaseData.primary.inputTokens,
397
- outputTokens: phaseData.primary.outputTokens,
398
- totalTokens: phaseData.primary.totalTokens
383
+ const primaryEntries = [...phaseData.primary.entries()];
384
+ const fallbackEntries = [...phaseData.fallback.entries()];
385
+ const entryCount = Math.max(
386
+ primaryEntries.length,
387
+ fallbackEntries.length
388
+ );
389
+ if (entryCount === 0) {
390
+ const phaseReport = {
391
+ phase: phaseName,
392
+ total: { ...phaseData.total }
399
393
  };
394
+ if (phaseData.metadata.length > 0) {
395
+ phaseReport.metadata = [...phaseData.metadata];
396
+ }
397
+ phases.push(phaseReport);
398
+ continue;
400
399
  }
401
- if (phaseData.fallback) {
402
- phaseReport.fallback = {
403
- modelName: phaseData.fallback.modelName,
404
- inputTokens: phaseData.fallback.inputTokens,
405
- outputTokens: phaseData.fallback.outputTokens,
406
- totalTokens: phaseData.fallback.totalTokens
400
+ for (let i = 0; i < entryCount; i++) {
401
+ const primary = primaryEntries[i];
402
+ const fallback = fallbackEntries[i];
403
+ const phaseReport = {
404
+ phase: phaseName,
405
+ total: sumUsage(primary?.[1], fallback?.[1])
407
406
  };
407
+ if (primary) {
408
+ phaseReport.primary = { modelName: primary[0], ...primary[1] };
409
+ }
410
+ if (fallback) {
411
+ phaseReport.fallback = { modelName: fallback[0], ...fallback[1] };
412
+ }
413
+ if (i === 0 && phaseData.metadata.length > 0) {
414
+ phaseReport.metadata = [...phaseData.metadata];
415
+ }
416
+ phases.push(phaseReport);
408
417
  }
409
- phases.push(phaseReport);
410
418
  }
411
419
  components.push({
412
420
  component: component.component,
@@ -451,8 +459,8 @@ var LLMTokenUsageAggregator = class {
451
459
  /**
452
460
  * Log comprehensive token usage summary
453
461
  *
454
- * Outputs usage grouped by component, with phase and model breakdown.
455
- * Shows primary and fallback token usage separately for each phase.
462
+ * Outputs usage grouped by component, with phase and per-model breakdown.
463
+ * Shows each primary and fallback model on its own line for each phase.
456
464
  * Call this once at the end of document processing.
457
465
  *
458
466
  * @param logger - Logger instance for output
@@ -468,31 +476,23 @@ var LLMTokenUsageAggregator = class {
468
476
  let grandInputTokens = 0;
469
477
  let grandOutputTokens = 0;
470
478
  let grandTotalTokens = 0;
471
- let grandPrimaryInputTokens = 0;
472
- let grandPrimaryOutputTokens = 0;
473
- let grandPrimaryTotalTokens = 0;
474
- let grandFallbackInputTokens = 0;
475
- let grandFallbackOutputTokens = 0;
476
- let grandFallbackTotalTokens = 0;
479
+ const grandPrimary = emptyUsage();
480
+ const grandFallback = emptyUsage();
477
481
  for (const component of components) {
478
482
  logger.info(`${component.component}:`);
479
- for (const [phase, phaseData] of Object.entries(component.phases)) {
480
- logger.info(` - ${phase}:`);
481
- if (phaseData.primary) {
483
+ for (const [phaseName, phaseData] of Object.entries(component.phases)) {
484
+ logger.info(` - ${phaseName}:`);
485
+ for (const [modelName, modelUsage] of phaseData.primary) {
482
486
  logger.info(
483
- ` primary (${phaseData.primary.modelName}): ${formatTokens(phaseData.primary)}`
487
+ ` primary (${modelName}): ${formatTokens(modelUsage)}`
484
488
  );
485
- grandPrimaryInputTokens += phaseData.primary.inputTokens;
486
- grandPrimaryOutputTokens += phaseData.primary.outputTokens;
487
- grandPrimaryTotalTokens += phaseData.primary.totalTokens;
489
+ addInto(grandPrimary, modelUsage);
488
490
  }
489
- if (phaseData.fallback) {
491
+ for (const [modelName, modelUsage] of phaseData.fallback) {
490
492
  logger.info(
491
- ` fallback (${phaseData.fallback.modelName}): ${formatTokens(phaseData.fallback)}`
493
+ ` fallback (${modelName}): ${formatTokens(modelUsage)}`
492
494
  );
493
- grandFallbackInputTokens += phaseData.fallback.inputTokens;
494
- grandFallbackOutputTokens += phaseData.fallback.outputTokens;
495
- grandFallbackTotalTokens += phaseData.fallback.totalTokens;
495
+ addInto(grandFallback, modelUsage);
496
496
  }
497
497
  logger.info(` subtotal: ${formatTokens(phaseData.total)}`);
498
498
  }
@@ -505,23 +505,11 @@ var LLMTokenUsageAggregator = class {
505
505
  grandTotalTokens += component.total.totalTokens;
506
506
  }
507
507
  logger.info("--- Summary ---");
508
- if (grandPrimaryTotalTokens > 0) {
509
- logger.info(
510
- `Primary total: ${formatTokens({
511
- inputTokens: grandPrimaryInputTokens,
512
- outputTokens: grandPrimaryOutputTokens,
513
- totalTokens: grandPrimaryTotalTokens
514
- })}`
515
- );
508
+ if (grandPrimary.totalTokens > 0) {
509
+ logger.info(`Primary total: ${formatTokens(grandPrimary)}`);
516
510
  }
517
- if (grandFallbackTotalTokens > 0) {
518
- logger.info(
519
- `Fallback total: ${formatTokens({
520
- inputTokens: grandFallbackInputTokens,
521
- outputTokens: grandFallbackOutputTokens,
522
- totalTokens: grandFallbackTotalTokens
523
- })}`
524
- );
511
+ if (grandFallback.totalTokens > 0) {
512
+ logger.info(`Fallback total: ${formatTokens(grandFallback)}`);
525
513
  }
526
514
  logger.info(
527
515
  `Grand total: ${formatTokens({
@@ -3158,11 +3146,11 @@ var PageRangeParser = class extends VisionLLMComponent {
3158
3146
  const pages = this.extractPages(doclingDoc);
3159
3147
  if (pages.length === 0) {
3160
3148
  this.log("warn", "No pages found");
3161
- const emptyUsage = this.createEmptyUsage("sampling");
3162
- this.trackUsage(emptyUsage);
3149
+ const emptyUsage2 = this.createEmptyUsage("sampling");
3150
+ this.trackUsage(emptyUsage2);
3163
3151
  return {
3164
3152
  pageRangeMap: {},
3165
- usage: [emptyUsage]
3153
+ usage: [emptyUsage2]
3166
3154
  };
3167
3155
  }
3168
3156
  const sizeGroups = this.analyzeSizes(pages);