@heripo/pdf-parser 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
@@ -343,6 +343,29 @@ var LLMCaller = class {
343
343
  function formatTokens(usage) {
344
344
  return `${usage.inputTokens} input, ${usage.outputTokens} output, ${usage.totalTokens} total`;
345
345
  }
346
+ function emptyUsage() {
347
+ return { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
348
+ }
349
+ function addInto(target, src) {
350
+ target.inputTokens += src.inputTokens;
351
+ target.outputTokens += src.outputTokens;
352
+ target.totalTokens += src.totalTokens;
353
+ }
354
+ function sumUsage(a, b) {
355
+ return {
356
+ inputTokens: (a?.inputTokens ?? 0) + (b?.inputTokens ?? 0),
357
+ outputTokens: (a?.outputTokens ?? 0) + (b?.outputTokens ?? 0),
358
+ totalTokens: (a?.totalTokens ?? 0) + (b?.totalTokens ?? 0)
359
+ };
360
+ }
361
+ function accumulateModel(bucket, modelName, usage) {
362
+ let entry = bucket.get(modelName);
363
+ if (!entry) {
364
+ entry = emptyUsage();
365
+ bucket.set(modelName, entry);
366
+ }
367
+ addInto(entry, usage);
368
+ }
346
369
  var LLMTokenUsageAggregator = class {
347
370
  usage = {};
348
371
  /**
@@ -355,21 +378,15 @@ var LLMTokenUsageAggregator = class {
355
378
  this.usage[usage.component] = {
356
379
  component: usage.component,
357
380
  phases: {},
358
- total: {
359
- inputTokens: 0,
360
- outputTokens: 0,
361
- totalTokens: 0
362
- }
381
+ total: emptyUsage()
363
382
  };
364
383
  }
365
384
  const component = this.usage[usage.component];
366
385
  if (!component.phases[usage.phase]) {
367
386
  component.phases[usage.phase] = {
368
- total: {
369
- inputTokens: 0,
370
- outputTokens: 0,
371
- totalTokens: 0
372
- },
387
+ primary: /* @__PURE__ */ new Map(),
388
+ fallback: /* @__PURE__ */ new Map(),
389
+ total: emptyUsage(),
373
390
  metadata: []
374
391
  };
375
392
  }
@@ -378,41 +395,17 @@ var LLMTokenUsageAggregator = class {
378
395
  phase.metadata.push(usage.metadata);
379
396
  }
380
397
  if (usage.model === "primary") {
381
- if (!phase.primary) {
382
- phase.primary = {
383
- modelName: usage.modelName,
384
- inputTokens: 0,
385
- outputTokens: 0,
386
- totalTokens: 0
387
- };
388
- }
389
- phase.primary.inputTokens += usage.inputTokens;
390
- phase.primary.outputTokens += usage.outputTokens;
391
- phase.primary.totalTokens += usage.totalTokens;
398
+ accumulateModel(phase.primary, usage.modelName, usage);
392
399
  } else if (usage.model === "fallback") {
393
- if (!phase.fallback) {
394
- phase.fallback = {
395
- modelName: usage.modelName,
396
- inputTokens: 0,
397
- outputTokens: 0,
398
- totalTokens: 0
399
- };
400
- }
401
- phase.fallback.inputTokens += usage.inputTokens;
402
- phase.fallback.outputTokens += usage.outputTokens;
403
- phase.fallback.totalTokens += usage.totalTokens;
400
+ accumulateModel(phase.fallback, usage.modelName, usage);
404
401
  }
405
- phase.total.inputTokens += usage.inputTokens;
406
- phase.total.outputTokens += usage.outputTokens;
407
- phase.total.totalTokens += usage.totalTokens;
408
- component.total.inputTokens += usage.inputTokens;
409
- component.total.outputTokens += usage.outputTokens;
410
- component.total.totalTokens += usage.totalTokens;
402
+ addInto(phase.total, usage);
403
+ addInto(component.total, usage);
411
404
  }
412
405
  /**
413
406
  * Get aggregated usage grouped by component
414
407
  *
415
- * @returns Array of component aggregates with phase breakdown
408
+ * @returns Array of component aggregates with per-model phase breakdown
416
409
  */
417
410
  getByComponent() {
418
411
  return Object.values(this.usage);
@@ -421,8 +414,16 @@ var LLMTokenUsageAggregator = class {
421
414
  * Get token usage report in structured JSON format
422
415
  *
423
416
  * Converts internal usage data to external TokenUsageReport format suitable
424
- * for serialization and reporting. The report includes component breakdown,
425
- * phase-level details, and both primary and fallback model usage.
417
+ * for serialization and reporting.
418
+ *
419
+ * Each (phase, model) pair becomes its own PhaseUsageReport entry. A phase
420
+ * that used a single primary (and/or a single fallback) model yields exactly
421
+ * one entry — identical to the legacy shape — while a phase that mixed models
422
+ * yields one entry per model, all sharing the same `phase` name. Every
423
+ * (phase, tier, modelName) combination appears in exactly one entry, so
424
+ * consumers that key by `${component}|${phase}|${tier}|${modelName}`
425
+ * (heripo-web's token-usage emitter / ledger recorder) attribute each model's
426
+ * tokens — and cost — correctly without double counting.
426
427
  *
427
428
  * @returns Structured token usage report with components and total
428
429
  */
@@ -431,34 +432,41 @@ var LLMTokenUsageAggregator = class {
431
432
  for (const component of Object.values(this.usage)) {
432
433
  const phases = [];
433
434
  for (const [phaseName, phaseData] of Object.entries(component.phases)) {
434
- const phaseReport = {
435
- phase: phaseName,
436
- total: {
437
- inputTokens: phaseData.total.inputTokens,
438
- outputTokens: phaseData.total.outputTokens,
439
- totalTokens: phaseData.total.totalTokens
440
- }
441
- };
442
- if (phaseData.metadata.length > 0) {
443
- phaseReport.metadata = [...phaseData.metadata];
444
- }
445
- if (phaseData.primary) {
446
- phaseReport.primary = {
447
- modelName: phaseData.primary.modelName,
448
- inputTokens: phaseData.primary.inputTokens,
449
- outputTokens: phaseData.primary.outputTokens,
450
- totalTokens: phaseData.primary.totalTokens
435
+ const primaryEntries = [...phaseData.primary.entries()];
436
+ const fallbackEntries = [...phaseData.fallback.entries()];
437
+ const entryCount = Math.max(
438
+ primaryEntries.length,
439
+ fallbackEntries.length
440
+ );
441
+ if (entryCount === 0) {
442
+ const phaseReport = {
443
+ phase: phaseName,
444
+ total: { ...phaseData.total }
451
445
  };
446
+ if (phaseData.metadata.length > 0) {
447
+ phaseReport.metadata = [...phaseData.metadata];
448
+ }
449
+ phases.push(phaseReport);
450
+ continue;
452
451
  }
453
- if (phaseData.fallback) {
454
- phaseReport.fallback = {
455
- modelName: phaseData.fallback.modelName,
456
- inputTokens: phaseData.fallback.inputTokens,
457
- outputTokens: phaseData.fallback.outputTokens,
458
- totalTokens: phaseData.fallback.totalTokens
452
+ for (let i = 0; i < entryCount; i++) {
453
+ const primary = primaryEntries[i];
454
+ const fallback = fallbackEntries[i];
455
+ const phaseReport = {
456
+ phase: phaseName,
457
+ total: sumUsage(primary?.[1], fallback?.[1])
459
458
  };
459
+ if (primary) {
460
+ phaseReport.primary = { modelName: primary[0], ...primary[1] };
461
+ }
462
+ if (fallback) {
463
+ phaseReport.fallback = { modelName: fallback[0], ...fallback[1] };
464
+ }
465
+ if (i === 0 && phaseData.metadata.length > 0) {
466
+ phaseReport.metadata = [...phaseData.metadata];
467
+ }
468
+ phases.push(phaseReport);
460
469
  }
461
- phases.push(phaseReport);
462
470
  }
463
471
  components.push({
464
472
  component: component.component,
@@ -503,8 +511,8 @@ var LLMTokenUsageAggregator = class {
503
511
  /**
504
512
  * Log comprehensive token usage summary
505
513
  *
506
- * Outputs usage grouped by component, with phase and model breakdown.
507
- * Shows primary and fallback token usage separately for each phase.
514
+ * Outputs usage grouped by component, with phase and per-model breakdown.
515
+ * Shows each primary and fallback model on its own line for each phase.
508
516
  * Call this once at the end of document processing.
509
517
  *
510
518
  * @param logger - Logger instance for output
@@ -520,31 +528,23 @@ var LLMTokenUsageAggregator = class {
520
528
  let grandInputTokens = 0;
521
529
  let grandOutputTokens = 0;
522
530
  let grandTotalTokens = 0;
523
- let grandPrimaryInputTokens = 0;
524
- let grandPrimaryOutputTokens = 0;
525
- let grandPrimaryTotalTokens = 0;
526
- let grandFallbackInputTokens = 0;
527
- let grandFallbackOutputTokens = 0;
528
- let grandFallbackTotalTokens = 0;
531
+ const grandPrimary = emptyUsage();
532
+ const grandFallback = emptyUsage();
529
533
  for (const component of components) {
530
534
  logger.info(`${component.component}:`);
531
- for (const [phase, phaseData] of Object.entries(component.phases)) {
532
- logger.info(` - ${phase}:`);
533
- if (phaseData.primary) {
535
+ for (const [phaseName, phaseData] of Object.entries(component.phases)) {
536
+ logger.info(` - ${phaseName}:`);
537
+ for (const [modelName, modelUsage] of phaseData.primary) {
534
538
  logger.info(
535
- ` primary (${phaseData.primary.modelName}): ${formatTokens(phaseData.primary)}`
539
+ ` primary (${modelName}): ${formatTokens(modelUsage)}`
536
540
  );
537
- grandPrimaryInputTokens += phaseData.primary.inputTokens;
538
- grandPrimaryOutputTokens += phaseData.primary.outputTokens;
539
- grandPrimaryTotalTokens += phaseData.primary.totalTokens;
541
+ addInto(grandPrimary, modelUsage);
540
542
  }
541
- if (phaseData.fallback) {
543
+ for (const [modelName, modelUsage] of phaseData.fallback) {
542
544
  logger.info(
543
- ` fallback (${phaseData.fallback.modelName}): ${formatTokens(phaseData.fallback)}`
545
+ ` fallback (${modelName}): ${formatTokens(modelUsage)}`
544
546
  );
545
- grandFallbackInputTokens += phaseData.fallback.inputTokens;
546
- grandFallbackOutputTokens += phaseData.fallback.outputTokens;
547
- grandFallbackTotalTokens += phaseData.fallback.totalTokens;
547
+ addInto(grandFallback, modelUsage);
548
548
  }
549
549
  logger.info(` subtotal: ${formatTokens(phaseData.total)}`);
550
550
  }
@@ -557,23 +557,11 @@ var LLMTokenUsageAggregator = class {
557
557
  grandTotalTokens += component.total.totalTokens;
558
558
  }
559
559
  logger.info("--- Summary ---");
560
- if (grandPrimaryTotalTokens > 0) {
561
- logger.info(
562
- `Primary total: ${formatTokens({
563
- inputTokens: grandPrimaryInputTokens,
564
- outputTokens: grandPrimaryOutputTokens,
565
- totalTokens: grandPrimaryTotalTokens
566
- })}`
567
- );
560
+ if (grandPrimary.totalTokens > 0) {
561
+ logger.info(`Primary total: ${formatTokens(grandPrimary)}`);
568
562
  }
569
- if (grandFallbackTotalTokens > 0) {
570
- logger.info(
571
- `Fallback total: ${formatTokens({
572
- inputTokens: grandFallbackInputTokens,
573
- outputTokens: grandFallbackOutputTokens,
574
- totalTokens: grandFallbackTotalTokens
575
- })}`
576
- );
563
+ if (grandFallback.totalTokens > 0) {
564
+ logger.info(`Fallback total: ${formatTokens(grandFallback)}`);
577
565
  }
578
566
  logger.info(
579
567
  `Grand total: ${formatTokens({