@semiont/jobs 0.5.18 → 0.5.20
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.d.ts +21 -6
- package/dist/index.js +21 -75
- package/dist/index.js.map +1 -1
- package/dist/worker-main.js +110 -56
- package/dist/worker-main.js.map +1 -1
- package/package.json +8 -8
package/dist/index.d.ts
CHANGED
|
@@ -535,7 +535,22 @@ interface GenerationCitation {
|
|
|
535
535
|
* jobs over SSE and dispatches by jobType to these functions.
|
|
536
536
|
*/
|
|
537
537
|
|
|
538
|
-
|
|
538
|
+
/** A detected span — offsets into the extracted `.text`, plus optional context. */
|
|
539
|
+
type SpanMatch = {
|
|
540
|
+
exact: string;
|
|
541
|
+
start: number;
|
|
542
|
+
end: number;
|
|
543
|
+
prefix?: string;
|
|
544
|
+
suffix?: string;
|
|
545
|
+
};
|
|
546
|
+
/**
|
|
547
|
+
* Turn a detected span into a stored annotation. The media type, resource, and
|
|
548
|
+
* attribution context are closed over by the caller (see `prepareDetection`);
|
|
549
|
+
* the detection processor supplies only the motivation, the span, and any
|
|
550
|
+
* motivation-specific body. This is the single axis that varies by media type,
|
|
551
|
+
* so the detection processors themselves stay media-agnostic.
|
|
552
|
+
*/
|
|
553
|
+
type BuildAnnotation = (motivation: string, match: SpanMatch, body?: Record<string, unknown> | Record<string, unknown>[]) => Record<string, unknown>;
|
|
539
554
|
/**
|
|
540
555
|
* Progress callback. The three positional args satisfy the minimum
|
|
541
556
|
* `JobProgress` required fields (`percentage`, `message`, `stage`).
|
|
@@ -549,11 +564,11 @@ interface ProcessorResult<R> {
|
|
|
549
564
|
annotations: Record<string, unknown>[];
|
|
550
565
|
result: R;
|
|
551
566
|
}
|
|
552
|
-
declare function processHighlightJob(content: string, inferenceClient: InferenceClient, params: HighlightDetectionParams,
|
|
553
|
-
declare function processCommentJob(content: string, inferenceClient: InferenceClient, params: CommentDetectionParams,
|
|
554
|
-
declare function processAssessmentJob(content: string, inferenceClient: InferenceClient, params: AssessmentDetectionParams,
|
|
555
|
-
declare function processReferenceJob(content: string, inferenceClient: InferenceClient, params: DetectionParams,
|
|
556
|
-
declare function processTagJob(content: string, inferenceClient: InferenceClient, params: TagDetectionParams,
|
|
567
|
+
declare function processHighlightJob(content: string, inferenceClient: InferenceClient, params: HighlightDetectionParams, buildAnnotation: BuildAnnotation, onProgress: OnProgress): Promise<ProcessorResult<HighlightDetectionResult>>;
|
|
568
|
+
declare function processCommentJob(content: string, inferenceClient: InferenceClient, params: CommentDetectionParams, buildAnnotation: BuildAnnotation, onProgress: OnProgress): Promise<ProcessorResult<CommentDetectionResult>>;
|
|
569
|
+
declare function processAssessmentJob(content: string, inferenceClient: InferenceClient, params: AssessmentDetectionParams, buildAnnotation: BuildAnnotation, onProgress: OnProgress): Promise<ProcessorResult<AssessmentDetectionResult>>;
|
|
570
|
+
declare function processReferenceJob(content: string, inferenceClient: InferenceClient, params: DetectionParams, buildAnnotation: BuildAnnotation, onProgress: OnProgress, logger: Logger): Promise<ProcessorResult<DetectionResult>>;
|
|
571
|
+
declare function processTagJob(content: string, inferenceClient: InferenceClient, params: TagDetectionParams, buildAnnotation: BuildAnnotation, onProgress: OnProgress): Promise<ProcessorResult<TagDetectionResult>>;
|
|
557
572
|
declare function processGenerationJob(inferenceClient: InferenceClient, params: GenerationParams, onProgress: OnProgress, logger: Logger): Promise<{
|
|
558
573
|
content: string;
|
|
559
574
|
title: string;
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { promises } from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
|
-
import { jobId, deriveViews, reconcileSelector, isObject, isString, getLocaleEnglishName,
|
|
4
|
-
import
|
|
3
|
+
import { jobId, deriveViews, reconcileSelector, isObject, isString, getLocaleEnglishName, isArray } from '@semiont/core';
|
|
4
|
+
import '@semiont/event-sourcing';
|
|
5
5
|
import '@semiont/content';
|
|
6
6
|
import '@semiont/observability';
|
|
7
7
|
import '@semiont/sdk';
|
|
@@ -1388,12 +1388,15 @@ function annotationDedupeKey(ann) {
|
|
|
1388
1388
|
const target = ann.target;
|
|
1389
1389
|
const selectors = Array.isArray(target?.selector) ? target.selector : [];
|
|
1390
1390
|
const pos = selectors.find((s) => s.type === "TextPositionSelector");
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
pos
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1391
|
+
let anchor;
|
|
1392
|
+
if (pos) {
|
|
1393
|
+
anchor = `pos:${pos.start ?? "?"}:${pos.end ?? "?"}`;
|
|
1394
|
+
} else {
|
|
1395
|
+
const frags = selectors.filter((s) => s.type === "FragmentSelector").map((s) => s.value ?? "").join(",");
|
|
1396
|
+
const quote = selectors.find((s) => s.type === "TextQuoteSelector");
|
|
1397
|
+
anchor = `frag:${frags}|quote:${quote?.exact ?? ""}:${quote?.prefix ?? ""}:${quote?.suffix ?? ""}`;
|
|
1398
|
+
}
|
|
1399
|
+
return [ann.motivation, anchor, JSON.stringify(ann.body ?? null)].join("|");
|
|
1397
1400
|
}
|
|
1398
1401
|
function dedupeAnnotations(annotations) {
|
|
1399
1402
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -1406,56 +1409,7 @@ function dedupeAnnotations(annotations) {
|
|
|
1406
1409
|
}
|
|
1407
1410
|
return out;
|
|
1408
1411
|
}
|
|
1409
|
-
function
|
|
1410
|
-
if (content.substring(match.start, match.end) !== match.exact) {
|
|
1411
|
-
throw new Error(
|
|
1412
|
-
`buildTextAnnotation invariant: content.substring(${match.start}, ${match.end}) !== exact for resource ${resourceId}, motivation ${motivation}`
|
|
1413
|
-
);
|
|
1414
|
-
}
|
|
1415
|
-
if (match.prefix !== void 0) {
|
|
1416
|
-
const actualPrefix = content.substring(Math.max(0, match.start - match.prefix.length), match.start);
|
|
1417
|
-
if (actualPrefix !== match.prefix) {
|
|
1418
|
-
throw new Error(
|
|
1419
|
-
`buildTextAnnotation invariant: content prefix-slice !== prefix for resource ${resourceId}, motivation ${motivation}`
|
|
1420
|
-
);
|
|
1421
|
-
}
|
|
1422
|
-
}
|
|
1423
|
-
if (match.suffix !== void 0) {
|
|
1424
|
-
const actualSuffix = content.substring(match.end, Math.min(content.length, match.end + match.suffix.length));
|
|
1425
|
-
if (actualSuffix !== match.suffix) {
|
|
1426
|
-
throw new Error(
|
|
1427
|
-
`buildTextAnnotation invariant: content suffix-slice !== suffix for resource ${resourceId}, motivation ${motivation}`
|
|
1428
|
-
);
|
|
1429
|
-
}
|
|
1430
|
-
}
|
|
1431
|
-
const creator = didToAgent(userId);
|
|
1432
|
-
const wasAttributedTo = creator["@id"] === generator["@id"] ? [generator] : [creator, generator];
|
|
1433
|
-
return {
|
|
1434
|
-
"@context": "http://www.w3.org/ns/anno.jsonld",
|
|
1435
|
-
"type": "Annotation",
|
|
1436
|
-
"id": generateAnnotationId(),
|
|
1437
|
-
motivation,
|
|
1438
|
-
creator,
|
|
1439
|
-
generator,
|
|
1440
|
-
wasAttributedTo,
|
|
1441
|
-
created: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1442
|
-
target: {
|
|
1443
|
-
type: "SpecificResource",
|
|
1444
|
-
source: resourceId,
|
|
1445
|
-
selector: [
|
|
1446
|
-
{ type: "TextPositionSelector", start: match.start, end: match.end },
|
|
1447
|
-
{
|
|
1448
|
-
type: "TextQuoteSelector",
|
|
1449
|
-
exact: match.exact,
|
|
1450
|
-
...match.prefix && { prefix: match.prefix },
|
|
1451
|
-
...match.suffix && { suffix: match.suffix }
|
|
1452
|
-
}
|
|
1453
|
-
]
|
|
1454
|
-
},
|
|
1455
|
-
...body !== void 0 ? { body } : {}
|
|
1456
|
-
};
|
|
1457
|
-
}
|
|
1458
|
-
async function processHighlightJob(content, inferenceClient, params, userId, generator, onProgress) {
|
|
1412
|
+
async function processHighlightJob(content, inferenceClient, params, buildAnnotation, onProgress) {
|
|
1459
1413
|
onProgress(10, "Loading resource...", "analyzing");
|
|
1460
1414
|
onProgress(30, "Analyzing text...", "analyzing");
|
|
1461
1415
|
const highlights = await AnnotationDetection.detectHighlights(
|
|
@@ -1467,7 +1421,7 @@ async function processHighlightJob(content, inferenceClient, params, userId, gen
|
|
|
1467
1421
|
);
|
|
1468
1422
|
onProgress(60, `Creating ${highlights.length} annotations...`, "creating");
|
|
1469
1423
|
const annotations = dedupeAnnotations(highlights.map(
|
|
1470
|
-
(h) =>
|
|
1424
|
+
(h) => buildAnnotation("highlighting", h)
|
|
1471
1425
|
));
|
|
1472
1426
|
onProgress(100, `Complete! Created ${annotations.length} highlights`, "creating");
|
|
1473
1427
|
return {
|
|
@@ -1475,7 +1429,7 @@ async function processHighlightJob(content, inferenceClient, params, userId, gen
|
|
|
1475
1429
|
result: { highlightsFound: highlights.length, highlightsCreated: annotations.length }
|
|
1476
1430
|
};
|
|
1477
1431
|
}
|
|
1478
|
-
async function processCommentJob(content, inferenceClient, params,
|
|
1432
|
+
async function processCommentJob(content, inferenceClient, params, buildAnnotation, onProgress) {
|
|
1479
1433
|
onProgress(10, "Loading resource...", "analyzing");
|
|
1480
1434
|
onProgress(30, "Analyzing text...", "analyzing");
|
|
1481
1435
|
const comments = await AnnotationDetection.detectComments(
|
|
@@ -1494,7 +1448,7 @@ async function processCommentJob(content, inferenceClient, params, userId, gener
|
|
|
1494
1448
|
// Match the pre-#651 CommentAnnotationWorker: include format and
|
|
1495
1449
|
// language on the body TextualBody. Optional in the schema, but
|
|
1496
1450
|
// consumers that do language-aware rendering rely on them.
|
|
1497
|
-
|
|
1451
|
+
buildAnnotation("commenting", c, [
|
|
1498
1452
|
{ type: "TextualBody", value: c.comment, purpose: "commenting", format: "text/plain", language: bodyLanguage }
|
|
1499
1453
|
])
|
|
1500
1454
|
)
|
|
@@ -1505,7 +1459,7 @@ async function processCommentJob(content, inferenceClient, params, userId, gener
|
|
|
1505
1459
|
result: { commentsFound: comments.length, commentsCreated: annotations.length }
|
|
1506
1460
|
};
|
|
1507
1461
|
}
|
|
1508
|
-
async function processAssessmentJob(content, inferenceClient, params,
|
|
1462
|
+
async function processAssessmentJob(content, inferenceClient, params, buildAnnotation, onProgress) {
|
|
1509
1463
|
onProgress(10, "Loading resource...", "analyzing");
|
|
1510
1464
|
onProgress(30, "Analyzing text...", "analyzing");
|
|
1511
1465
|
const assessments = await AnnotationDetection.detectAssessments(
|
|
@@ -1527,7 +1481,7 @@ async function processAssessmentJob(content, inferenceClient, params, userId, ge
|
|
|
1527
1481
|
// purpose='describing' — that loses the "this is an assessment, not
|
|
1528
1482
|
// a description" signal and breaks existing readers that access
|
|
1529
1483
|
// `body.value` directly on the object.
|
|
1530
|
-
|
|
1484
|
+
buildAnnotation("assessing", a, {
|
|
1531
1485
|
type: "TextualBody",
|
|
1532
1486
|
value: a.assessment,
|
|
1533
1487
|
purpose: "assessing",
|
|
@@ -1542,7 +1496,7 @@ async function processAssessmentJob(content, inferenceClient, params, userId, ge
|
|
|
1542
1496
|
result: { assessmentsFound: assessments.length, assessmentsCreated: annotations.length }
|
|
1543
1497
|
};
|
|
1544
1498
|
}
|
|
1545
|
-
async function processReferenceJob(content, inferenceClient, params,
|
|
1499
|
+
async function processReferenceJob(content, inferenceClient, params, buildAnnotation, onProgress, logger) {
|
|
1546
1500
|
const entityTypeNames = params.entityTypes.map(String);
|
|
1547
1501
|
const requestParams = [{ label: "Entity types", value: entityTypeNames.join(", ") }];
|
|
1548
1502
|
const completedEntityTypes = [];
|
|
@@ -1599,15 +1553,7 @@ async function processReferenceJob(content, inferenceClient, params, userId, gen
|
|
|
1599
1553
|
anchorMethod: reconciled.anchorMethod
|
|
1600
1554
|
});
|
|
1601
1555
|
}
|
|
1602
|
-
const ann =
|
|
1603
|
-
content,
|
|
1604
|
-
params.resourceId,
|
|
1605
|
-
userId,
|
|
1606
|
-
generator,
|
|
1607
|
-
"linking",
|
|
1608
|
-
toMatch(reconciled),
|
|
1609
|
-
unresolvedBody
|
|
1610
|
-
);
|
|
1556
|
+
const ann = buildAnnotation("linking", toMatch(reconciled), unresolvedBody);
|
|
1611
1557
|
allAnnotations.push(ann);
|
|
1612
1558
|
totalEmitted++;
|
|
1613
1559
|
}
|
|
@@ -1619,7 +1565,7 @@ async function processReferenceJob(content, inferenceClient, params, userId, gen
|
|
|
1619
1565
|
result: { totalFound, totalEmitted: annotations.length, errors }
|
|
1620
1566
|
};
|
|
1621
1567
|
}
|
|
1622
|
-
async function processTagJob(content, inferenceClient, params,
|
|
1568
|
+
async function processTagJob(content, inferenceClient, params, buildAnnotation, onProgress) {
|
|
1623
1569
|
onProgress(10, "Loading resource...", "analyzing");
|
|
1624
1570
|
onProgress(30, "Analyzing text for tags...", "analyzing");
|
|
1625
1571
|
const allTags = [];
|
|
@@ -1638,7 +1584,7 @@ async function processTagJob(content, inferenceClient, params, userId, generator
|
|
|
1638
1584
|
const bodyLanguage = params.language ?? "en";
|
|
1639
1585
|
const annotations = dedupeAnnotations(tags.map((t) => {
|
|
1640
1586
|
const category = t.category ?? "unknown";
|
|
1641
|
-
return
|
|
1587
|
+
return buildAnnotation("tagging", t, [
|
|
1642
1588
|
{ type: "TextualBody", value: category, purpose: "tagging", format: "text/plain", language: bodyLanguage },
|
|
1643
1589
|
{ type: "TextualBody", value: params.schema.id, purpose: "classifying", format: "text/plain" }
|
|
1644
1590
|
]);
|