@heripo/document-processor 0.1.32 → 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.cjs +100 -106
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +100 -106
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -147,6 +147,8 @@ function detectProvider(model) {
|
|
|
147
147
|
if (providerId.includes("google")) return "google";
|
|
148
148
|
if (providerId.includes("anthropic")) return "anthropic";
|
|
149
149
|
if (providerId.includes("together")) return "togetherai";
|
|
150
|
+
if (providerId.includes("ollama")) return "ollama";
|
|
151
|
+
if (providerId.includes("lmstudio")) return "lmstudio";
|
|
150
152
|
return "unknown";
|
|
151
153
|
}
|
|
152
154
|
var LLMCaller = class {
|
|
@@ -234,14 +236,18 @@ var LLMCaller = class {
|
|
|
234
236
|
*
|
|
235
237
|
* Strategy per provider:
|
|
236
238
|
* - OpenAI / Anthropic / Google Gemini: `Output.object()` with schema retry
|
|
237
|
-
* - Together AI / unknown: forced tool call pattern
|
|
239
|
+
* - Together AI / Ollama / unknown: forced tool call pattern
|
|
240
|
+
*
|
|
241
|
+
* Ollama uses tool-call because MLX backends ignore the `format` grammar
|
|
242
|
+
* that `Output.object()` relies on, and gguf's grammar is unstable once
|
|
243
|
+
* thinking is disabled. Applies to both text and vision paths.
|
|
238
244
|
*
|
|
239
245
|
* Retries up to MAX_STRUCTURED_OUTPUT_RETRIES times on NoObjectGeneratedError
|
|
240
246
|
* (schema mismatch), re-throwing the last error if all attempts fail.
|
|
241
247
|
*/
|
|
242
248
|
static async generateStructuredOutput(model, schema, promptParams) {
|
|
243
249
|
const providerType = detectProvider(model);
|
|
244
|
-
if (providerType === "togetherai" || providerType === "unknown") {
|
|
250
|
+
if (providerType === "togetherai" || providerType === "ollama" || providerType === "unknown") {
|
|
245
251
|
return this.generateViaToolCall(model, schema, promptParams);
|
|
246
252
|
}
|
|
247
253
|
let lastError;
|
|
@@ -346,6 +352,29 @@ var LLMCaller = class {
|
|
|
346
352
|
function formatTokens(usage) {
|
|
347
353
|
return `${usage.inputTokens} input, ${usage.outputTokens} output, ${usage.totalTokens} total`;
|
|
348
354
|
}
|
|
355
|
+
function emptyUsage() {
|
|
356
|
+
return { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
|
|
357
|
+
}
|
|
358
|
+
function addInto(target, src) {
|
|
359
|
+
target.inputTokens += src.inputTokens;
|
|
360
|
+
target.outputTokens += src.outputTokens;
|
|
361
|
+
target.totalTokens += src.totalTokens;
|
|
362
|
+
}
|
|
363
|
+
function sumUsage(a, b) {
|
|
364
|
+
return {
|
|
365
|
+
inputTokens: (a?.inputTokens ?? 0) + (b?.inputTokens ?? 0),
|
|
366
|
+
outputTokens: (a?.outputTokens ?? 0) + (b?.outputTokens ?? 0),
|
|
367
|
+
totalTokens: (a?.totalTokens ?? 0) + (b?.totalTokens ?? 0)
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
function accumulateModel(bucket, modelName, usage) {
|
|
371
|
+
let entry = bucket.get(modelName);
|
|
372
|
+
if (!entry) {
|
|
373
|
+
entry = emptyUsage();
|
|
374
|
+
bucket.set(modelName, entry);
|
|
375
|
+
}
|
|
376
|
+
addInto(entry, usage);
|
|
377
|
+
}
|
|
349
378
|
var LLMTokenUsageAggregator = class {
|
|
350
379
|
usage = {};
|
|
351
380
|
/**
|
|
@@ -358,21 +387,15 @@ var LLMTokenUsageAggregator = class {
|
|
|
358
387
|
this.usage[usage.component] = {
|
|
359
388
|
component: usage.component,
|
|
360
389
|
phases: {},
|
|
361
|
-
total:
|
|
362
|
-
inputTokens: 0,
|
|
363
|
-
outputTokens: 0,
|
|
364
|
-
totalTokens: 0
|
|
365
|
-
}
|
|
390
|
+
total: emptyUsage()
|
|
366
391
|
};
|
|
367
392
|
}
|
|
368
393
|
const component = this.usage[usage.component];
|
|
369
394
|
if (!component.phases[usage.phase]) {
|
|
370
395
|
component.phases[usage.phase] = {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
totalTokens: 0
|
|
375
|
-
},
|
|
396
|
+
primary: /* @__PURE__ */ new Map(),
|
|
397
|
+
fallback: /* @__PURE__ */ new Map(),
|
|
398
|
+
total: emptyUsage(),
|
|
376
399
|
metadata: []
|
|
377
400
|
};
|
|
378
401
|
}
|
|
@@ -381,41 +404,17 @@ var LLMTokenUsageAggregator = class {
|
|
|
381
404
|
phase.metadata.push(usage.metadata);
|
|
382
405
|
}
|
|
383
406
|
if (usage.model === "primary") {
|
|
384
|
-
|
|
385
|
-
phase.primary = {
|
|
386
|
-
modelName: usage.modelName,
|
|
387
|
-
inputTokens: 0,
|
|
388
|
-
outputTokens: 0,
|
|
389
|
-
totalTokens: 0
|
|
390
|
-
};
|
|
391
|
-
}
|
|
392
|
-
phase.primary.inputTokens += usage.inputTokens;
|
|
393
|
-
phase.primary.outputTokens += usage.outputTokens;
|
|
394
|
-
phase.primary.totalTokens += usage.totalTokens;
|
|
407
|
+
accumulateModel(phase.primary, usage.modelName, usage);
|
|
395
408
|
} else if (usage.model === "fallback") {
|
|
396
|
-
|
|
397
|
-
phase.fallback = {
|
|
398
|
-
modelName: usage.modelName,
|
|
399
|
-
inputTokens: 0,
|
|
400
|
-
outputTokens: 0,
|
|
401
|
-
totalTokens: 0
|
|
402
|
-
};
|
|
403
|
-
}
|
|
404
|
-
phase.fallback.inputTokens += usage.inputTokens;
|
|
405
|
-
phase.fallback.outputTokens += usage.outputTokens;
|
|
406
|
-
phase.fallback.totalTokens += usage.totalTokens;
|
|
409
|
+
accumulateModel(phase.fallback, usage.modelName, usage);
|
|
407
410
|
}
|
|
408
|
-
phase.total
|
|
409
|
-
|
|
410
|
-
phase.total.totalTokens += usage.totalTokens;
|
|
411
|
-
component.total.inputTokens += usage.inputTokens;
|
|
412
|
-
component.total.outputTokens += usage.outputTokens;
|
|
413
|
-
component.total.totalTokens += usage.totalTokens;
|
|
411
|
+
addInto(phase.total, usage);
|
|
412
|
+
addInto(component.total, usage);
|
|
414
413
|
}
|
|
415
414
|
/**
|
|
416
415
|
* Get aggregated usage grouped by component
|
|
417
416
|
*
|
|
418
|
-
* @returns Array of component aggregates with phase breakdown
|
|
417
|
+
* @returns Array of component aggregates with per-model phase breakdown
|
|
419
418
|
*/
|
|
420
419
|
getByComponent() {
|
|
421
420
|
return Object.values(this.usage);
|
|
@@ -424,8 +423,16 @@ var LLMTokenUsageAggregator = class {
|
|
|
424
423
|
* Get token usage report in structured JSON format
|
|
425
424
|
*
|
|
426
425
|
* Converts internal usage data to external TokenUsageReport format suitable
|
|
427
|
-
* for serialization and reporting.
|
|
428
|
-
*
|
|
426
|
+
* for serialization and reporting.
|
|
427
|
+
*
|
|
428
|
+
* Each (phase, model) pair becomes its own PhaseUsageReport entry. A phase
|
|
429
|
+
* that used a single primary (and/or a single fallback) model yields exactly
|
|
430
|
+
* one entry — identical to the legacy shape — while a phase that mixed models
|
|
431
|
+
* yields one entry per model, all sharing the same `phase` name. Every
|
|
432
|
+
* (phase, tier, modelName) combination appears in exactly one entry, so
|
|
433
|
+
* consumers that key by `${component}|${phase}|${tier}|${modelName}`
|
|
434
|
+
* (heripo-web's token-usage emitter / ledger recorder) attribute each model's
|
|
435
|
+
* tokens — and cost — correctly without double counting.
|
|
429
436
|
*
|
|
430
437
|
* @returns Structured token usage report with components and total
|
|
431
438
|
*/
|
|
@@ -434,34 +441,41 @@ var LLMTokenUsageAggregator = class {
|
|
|
434
441
|
for (const component of Object.values(this.usage)) {
|
|
435
442
|
const phases = [];
|
|
436
443
|
for (const [phaseName, phaseData] of Object.entries(component.phases)) {
|
|
437
|
-
const
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
}
|
|
448
|
-
if (phaseData.primary) {
|
|
449
|
-
phaseReport.primary = {
|
|
450
|
-
modelName: phaseData.primary.modelName,
|
|
451
|
-
inputTokens: phaseData.primary.inputTokens,
|
|
452
|
-
outputTokens: phaseData.primary.outputTokens,
|
|
453
|
-
totalTokens: phaseData.primary.totalTokens
|
|
444
|
+
const primaryEntries = [...phaseData.primary.entries()];
|
|
445
|
+
const fallbackEntries = [...phaseData.fallback.entries()];
|
|
446
|
+
const entryCount = Math.max(
|
|
447
|
+
primaryEntries.length,
|
|
448
|
+
fallbackEntries.length
|
|
449
|
+
);
|
|
450
|
+
if (entryCount === 0) {
|
|
451
|
+
const phaseReport = {
|
|
452
|
+
phase: phaseName,
|
|
453
|
+
total: { ...phaseData.total }
|
|
454
454
|
};
|
|
455
|
+
if (phaseData.metadata.length > 0) {
|
|
456
|
+
phaseReport.metadata = [...phaseData.metadata];
|
|
457
|
+
}
|
|
458
|
+
phases.push(phaseReport);
|
|
459
|
+
continue;
|
|
455
460
|
}
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
461
|
+
for (let i = 0; i < entryCount; i++) {
|
|
462
|
+
const primary = primaryEntries[i];
|
|
463
|
+
const fallback = fallbackEntries[i];
|
|
464
|
+
const phaseReport = {
|
|
465
|
+
phase: phaseName,
|
|
466
|
+
total: sumUsage(primary?.[1], fallback?.[1])
|
|
462
467
|
};
|
|
468
|
+
if (primary) {
|
|
469
|
+
phaseReport.primary = { modelName: primary[0], ...primary[1] };
|
|
470
|
+
}
|
|
471
|
+
if (fallback) {
|
|
472
|
+
phaseReport.fallback = { modelName: fallback[0], ...fallback[1] };
|
|
473
|
+
}
|
|
474
|
+
if (i === 0 && phaseData.metadata.length > 0) {
|
|
475
|
+
phaseReport.metadata = [...phaseData.metadata];
|
|
476
|
+
}
|
|
477
|
+
phases.push(phaseReport);
|
|
463
478
|
}
|
|
464
|
-
phases.push(phaseReport);
|
|
465
479
|
}
|
|
466
480
|
components.push({
|
|
467
481
|
component: component.component,
|
|
@@ -506,8 +520,8 @@ var LLMTokenUsageAggregator = class {
|
|
|
506
520
|
/**
|
|
507
521
|
* Log comprehensive token usage summary
|
|
508
522
|
*
|
|
509
|
-
* Outputs usage grouped by component, with phase and model breakdown.
|
|
510
|
-
* Shows primary and fallback
|
|
523
|
+
* Outputs usage grouped by component, with phase and per-model breakdown.
|
|
524
|
+
* Shows each primary and fallback model on its own line for each phase.
|
|
511
525
|
* Call this once at the end of document processing.
|
|
512
526
|
*
|
|
513
527
|
* @param logger - Logger instance for output
|
|
@@ -523,31 +537,23 @@ var LLMTokenUsageAggregator = class {
|
|
|
523
537
|
let grandInputTokens = 0;
|
|
524
538
|
let grandOutputTokens = 0;
|
|
525
539
|
let grandTotalTokens = 0;
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
let grandPrimaryTotalTokens = 0;
|
|
529
|
-
let grandFallbackInputTokens = 0;
|
|
530
|
-
let grandFallbackOutputTokens = 0;
|
|
531
|
-
let grandFallbackTotalTokens = 0;
|
|
540
|
+
const grandPrimary = emptyUsage();
|
|
541
|
+
const grandFallback = emptyUsage();
|
|
532
542
|
for (const component of components) {
|
|
533
543
|
logger.info(`${component.component}:`);
|
|
534
|
-
for (const [
|
|
535
|
-
logger.info(` - ${
|
|
536
|
-
|
|
544
|
+
for (const [phaseName, phaseData] of Object.entries(component.phases)) {
|
|
545
|
+
logger.info(` - ${phaseName}:`);
|
|
546
|
+
for (const [modelName, modelUsage] of phaseData.primary) {
|
|
537
547
|
logger.info(
|
|
538
|
-
` primary (${
|
|
548
|
+
` primary (${modelName}): ${formatTokens(modelUsage)}`
|
|
539
549
|
);
|
|
540
|
-
|
|
541
|
-
grandPrimaryOutputTokens += phaseData.primary.outputTokens;
|
|
542
|
-
grandPrimaryTotalTokens += phaseData.primary.totalTokens;
|
|
550
|
+
addInto(grandPrimary, modelUsage);
|
|
543
551
|
}
|
|
544
|
-
|
|
552
|
+
for (const [modelName, modelUsage] of phaseData.fallback) {
|
|
545
553
|
logger.info(
|
|
546
|
-
` fallback (${
|
|
554
|
+
` fallback (${modelName}): ${formatTokens(modelUsage)}`
|
|
547
555
|
);
|
|
548
|
-
|
|
549
|
-
grandFallbackOutputTokens += phaseData.fallback.outputTokens;
|
|
550
|
-
grandFallbackTotalTokens += phaseData.fallback.totalTokens;
|
|
556
|
+
addInto(grandFallback, modelUsage);
|
|
551
557
|
}
|
|
552
558
|
logger.info(` subtotal: ${formatTokens(phaseData.total)}`);
|
|
553
559
|
}
|
|
@@ -560,23 +566,11 @@ var LLMTokenUsageAggregator = class {
|
|
|
560
566
|
grandTotalTokens += component.total.totalTokens;
|
|
561
567
|
}
|
|
562
568
|
logger.info("--- Summary ---");
|
|
563
|
-
if (
|
|
564
|
-
logger.info(
|
|
565
|
-
`Primary total: ${formatTokens({
|
|
566
|
-
inputTokens: grandPrimaryInputTokens,
|
|
567
|
-
outputTokens: grandPrimaryOutputTokens,
|
|
568
|
-
totalTokens: grandPrimaryTotalTokens
|
|
569
|
-
})}`
|
|
570
|
-
);
|
|
569
|
+
if (grandPrimary.totalTokens > 0) {
|
|
570
|
+
logger.info(`Primary total: ${formatTokens(grandPrimary)}`);
|
|
571
571
|
}
|
|
572
|
-
if (
|
|
573
|
-
logger.info(
|
|
574
|
-
`Fallback total: ${formatTokens({
|
|
575
|
-
inputTokens: grandFallbackInputTokens,
|
|
576
|
-
outputTokens: grandFallbackOutputTokens,
|
|
577
|
-
totalTokens: grandFallbackTotalTokens
|
|
578
|
-
})}`
|
|
579
|
-
);
|
|
572
|
+
if (grandFallback.totalTokens > 0) {
|
|
573
|
+
logger.info(`Fallback total: ${formatTokens(grandFallback)}`);
|
|
580
574
|
}
|
|
581
575
|
logger.info(
|
|
582
576
|
`Grand total: ${formatTokens({
|
|
@@ -3213,11 +3207,11 @@ var PageRangeParser = class extends VisionLLMComponent {
|
|
|
3213
3207
|
const pages = this.extractPages(doclingDoc);
|
|
3214
3208
|
if (pages.length === 0) {
|
|
3215
3209
|
this.log("warn", "No pages found");
|
|
3216
|
-
const
|
|
3217
|
-
this.trackUsage(
|
|
3210
|
+
const emptyUsage2 = this.createEmptyUsage("sampling");
|
|
3211
|
+
this.trackUsage(emptyUsage2);
|
|
3218
3212
|
return {
|
|
3219
3213
|
pageRangeMap: {},
|
|
3220
|
-
usage: [
|
|
3214
|
+
usage: [emptyUsage2]
|
|
3221
3215
|
};
|
|
3222
3216
|
}
|
|
3223
3217
|
const sizeGroups = this.analyzeSizes(pages);
|