@postalsys/email-content 0.0.1
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/LICENSE +21 -0
- package/README.md +288 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/analyze.d.ts +91 -0
- package/dist/analyze.d.ts.map +1 -0
- package/dist/analyze.js +274 -0
- package/dist/analyze.js.map +1 -0
- package/dist/annotate/client.d.ts +64 -0
- package/dist/annotate/client.d.ts.map +1 -0
- package/dist/annotate/client.js +139 -0
- package/dist/annotate/client.js.map +1 -0
- package/dist/annotate/llm.d.ts +46 -0
- package/dist/annotate/llm.d.ts.map +1 -0
- package/dist/annotate/llm.js +107 -0
- package/dist/annotate/llm.js.map +1 -0
- package/dist/annotate/prompt.d.ts +38 -0
- package/dist/annotate/prompt.d.ts.map +1 -0
- package/dist/annotate/prompt.js +165 -0
- package/dist/annotate/prompt.js.map +1 -0
- package/dist/annotate/store.d.ts +43 -0
- package/dist/annotate/store.d.ts.map +1 -0
- package/dist/annotate/store.js +46 -0
- package/dist/annotate/store.js.map +1 -0
- package/dist/canonical/html.d.ts +33 -0
- package/dist/canonical/html.d.ts.map +1 -0
- package/dist/canonical/html.js +156 -0
- package/dist/canonical/html.js.map +1 -0
- package/dist/canonical/text.d.ts +75 -0
- package/dist/canonical/text.d.ts.map +1 -0
- package/dist/canonical/text.js +217 -0
- package/dist/canonical/text.js.map +1 -0
- package/dist/classify/confidence.d.ts +38 -0
- package/dist/classify/confidence.d.ts.map +1 -0
- package/dist/classify/confidence.js +59 -0
- package/dist/classify/confidence.js.map +1 -0
- package/dist/classify/reconcile.d.ts +52 -0
- package/dist/classify/reconcile.d.ts.map +1 -0
- package/dist/classify/reconcile.js +100 -0
- package/dist/classify/reconcile.js.map +1 -0
- package/dist/classify/rules.d.ts +51 -0
- package/dist/classify/rules.d.ts.map +1 -0
- package/dist/classify/rules.js +648 -0
- package/dist/classify/rules.js.map +1 -0
- package/dist/cli/annotate.d.ts +23 -0
- package/dist/cli/annotate.d.ts.map +1 -0
- package/dist/cli/annotate.js +328 -0
- package/dist/cli/annotate.js.map +1 -0
- package/dist/cli/args.d.ts +17 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +72 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/benchmark.d.ts +13 -0
- package/dist/cli/benchmark.d.ts.map +1 -0
- package/dist/cli/benchmark.js +172 -0
- package/dist/cli/benchmark.js.map +1 -0
- package/dist/cli/corpus.d.ts +9 -0
- package/dist/cli/corpus.d.ts.map +1 -0
- package/dist/cli/corpus.js +152 -0
- package/dist/cli/corpus.js.map +1 -0
- package/dist/cli/disagreements.d.ts +14 -0
- package/dist/cli/disagreements.d.ts.map +1 -0
- package/dist/cli/disagreements.js +133 -0
- package/dist/cli/disagreements.js.map +1 -0
- package/dist/cli/evaluate.d.ts +15 -0
- package/dist/cli/evaluate.d.ts.map +1 -0
- package/dist/cli/evaluate.js +215 -0
- package/dist/cli/evaluate.js.map +1 -0
- package/dist/cli/extract.d.ts +10 -0
- package/dist/cli/extract.d.ts.map +1 -0
- package/dist/cli/extract.js +139 -0
- package/dist/cli/extract.js.map +1 -0
- package/dist/cli/main.d.ts +9 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +147 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/corpus/analyze.d.ts +66 -0
- package/dist/corpus/analyze.d.ts.map +1 -0
- package/dist/corpus/analyze.js +214 -0
- package/dist/corpus/analyze.js.map +1 -0
- package/dist/corpus/migrations/index.d.ts +14 -0
- package/dist/corpus/migrations/index.d.ts.map +1 -0
- package/dist/corpus/migrations/index.js +158 -0
- package/dist/corpus/migrations/index.js.map +1 -0
- package/dist/corpus/sample.d.ts +66 -0
- package/dist/corpus/sample.d.ts.map +1 -0
- package/dist/corpus/sample.js +98 -0
- package/dist/corpus/sample.js.map +1 -0
- package/dist/corpus/scanner.d.ts +79 -0
- package/dist/corpus/scanner.d.ts.map +1 -0
- package/dist/corpus/scanner.js +256 -0
- package/dist/corpus/scanner.js.map +1 -0
- package/dist/corpus/stats.d.ts +76 -0
- package/dist/corpus/stats.d.ts.map +1 -0
- package/dist/corpus/stats.js +240 -0
- package/dist/corpus/stats.js.map +1 -0
- package/dist/corpus/store.d.ts +67 -0
- package/dist/corpus/store.d.ts.map +1 -0
- package/dist/corpus/store.js +196 -0
- package/dist/corpus/store.js.map +1 -0
- package/dist/corpus/thread-index.d.ts +31 -0
- package/dist/corpus/thread-index.d.ts.map +1 -0
- package/dist/corpus/thread-index.js +182 -0
- package/dist/corpus/thread-index.js.map +1 -0
- package/dist/corpus/worker.d.ts +21 -0
- package/dist/corpus/worker.d.ts.map +1 -0
- package/dist/corpus/worker.js +74 -0
- package/dist/corpus/worker.js.map +1 -0
- package/dist/detect/client.d.ts +28 -0
- package/dist/detect/client.d.ts.map +1 -0
- package/dist/detect/client.js +121 -0
- package/dist/detect/client.js.map +1 -0
- package/dist/detect/disclaimer.d.ts +12 -0
- package/dist/detect/disclaimer.d.ts.map +1 -0
- package/dist/detect/disclaimer.js +28 -0
- package/dist/detect/disclaimer.js.map +1 -0
- package/dist/detect/forward-header.d.ts +10 -0
- package/dist/detect/forward-header.d.ts.map +1 -0
- package/dist/detect/forward-header.js +35 -0
- package/dist/detect/forward-header.js.map +1 -0
- package/dist/detect/patterns/disclaimers.json +113 -0
- package/dist/detect/patterns/forward-headers.json +40 -0
- package/dist/detect/patterns/html-clients.json +157 -0
- package/dist/detect/patterns/quoted-headers.json +41 -0
- package/dist/detect/patterns/reply-headers.json +139 -0
- package/dist/detect/patterns/signatures.json +58 -0
- package/dist/detect/patterns.d.ts +43 -0
- package/dist/detect/patterns.d.ts.map +1 -0
- package/dist/detect/patterns.js +125 -0
- package/dist/detect/patterns.js.map +1 -0
- package/dist/detect/reply-header.d.ts +44 -0
- package/dist/detect/reply-header.d.ts.map +1 -0
- package/dist/detect/reply-header.js +134 -0
- package/dist/detect/reply-header.js.map +1 -0
- package/dist/detect/signature.d.ts +28 -0
- package/dist/detect/signature.d.ts.map +1 -0
- package/dist/detect/signature.js +77 -0
- package/dist/detect/signature.js.map +1 -0
- package/dist/detect/traffic.d.ts +26 -0
- package/dist/detect/traffic.d.ts.map +1 -0
- package/dist/detect/traffic.js +98 -0
- package/dist/detect/traffic.js.map +1 -0
- package/dist/eval/metrics.d.ts +87 -0
- package/dist/eval/metrics.d.ts.map +1 -0
- package/dist/eval/metrics.js +185 -0
- package/dist/eval/metrics.js.map +1 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +163 -0
- package/dist/index.js.map +1 -0
- package/dist/match/history.d.ts +62 -0
- package/dist/match/history.d.ts.map +1 -0
- package/dist/match/history.js +128 -0
- package/dist/match/history.js.map +1 -0
- package/dist/match/normalize.d.ts +33 -0
- package/dist/match/normalize.d.ts.map +1 -0
- package/dist/match/normalize.js +63 -0
- package/dist/match/normalize.js.map +1 -0
- package/dist/match/shingle.d.ts +44 -0
- package/dist/match/shingle.d.ts.map +1 -0
- package/dist/match/shingle.js +78 -0
- package/dist/match/shingle.js.map +1 -0
- package/dist/mime/charset.d.ts +33 -0
- package/dist/mime/charset.d.ts.map +1 -0
- package/dist/mime/charset.js +118 -0
- package/dist/mime/charset.js.map +1 -0
- package/dist/mime/headers.d.ts +32 -0
- package/dist/mime/headers.d.ts.map +1 -0
- package/dist/mime/headers.js +127 -0
- package/dist/mime/headers.js.map +1 -0
- package/dist/mime/model.d.ts +111 -0
- package/dist/mime/model.d.ts.map +1 -0
- package/dist/mime/model.js +17 -0
- package/dist/mime/model.js.map +1 -0
- package/dist/mime/parse.d.ts +27 -0
- package/dist/mime/parse.d.ts.map +1 -0
- package/dist/mime/parse.js +343 -0
- package/dist/mime/parse.js.map +1 -0
- package/dist/segment/features.d.ts +29 -0
- package/dist/segment/features.d.ts.map +1 -0
- package/dist/segment/features.js +102 -0
- package/dist/segment/features.js.map +1 -0
- package/dist/segment/html-blocks.d.ts +28 -0
- package/dist/segment/html-blocks.d.ts.map +1 -0
- package/dist/segment/html-blocks.js +596 -0
- package/dist/segment/html-blocks.js.map +1 -0
- package/dist/segment/text-blocks.d.ts +30 -0
- package/dist/segment/text-blocks.d.ts.map +1 -0
- package/dist/segment/text-blocks.js +204 -0
- package/dist/segment/text-blocks.js.map +1 -0
- package/dist/segment/types.d.ts +88 -0
- package/dist/segment/types.d.ts.map +1 -0
- package/dist/segment/types.js +11 -0
- package/dist/segment/types.js.map +1 -0
- package/dist/types.d.ts +85 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +17 -0
- package/dist/types.js.map +1 -0
- package/dist/util/hash.d.ts +49 -0
- package/dist/util/hash.d.ts.map +1 -0
- package/dist/util/hash.js +0 -0
- package/dist/util/hash.js.map +1 -0
- package/dist/util/lang.d.ts +25 -0
- package/dist/util/lang.d.ts.map +1 -0
- package/dist/util/lang.js +135 -0
- package/dist/util/lang.js.map +1 -0
- package/dist/util/worker-pool.d.ts +51 -0
- package/dist/util/worker-pool.d.ts.map +1 -0
- package/dist/util/worker-pool.js +155 -0
- package/dist/util/worker-pool.js.map +1 -0
- package/package.json +74 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Stage 3: plain text block segmentation.
|
|
4
|
+
*
|
|
5
|
+
* Blocks tile the canonical text completely and without overlap. Every character belongs to exactly
|
|
6
|
+
* one block, including blank lines and trailing whitespace, so that concatenating block texts
|
|
7
|
+
* reproduces the input exactly. That is maintained by construction here, and asserted as a property
|
|
8
|
+
* test, because it is what guarantees content cannot vanish between stages.
|
|
9
|
+
*
|
|
10
|
+
* Boundaries are placed at:
|
|
11
|
+
* - a change of quote depth
|
|
12
|
+
* - a blank line, which separates paragraphs
|
|
13
|
+
* - a reply attribution line, which becomes its own block
|
|
14
|
+
* - a forward marker, which becomes its own block
|
|
15
|
+
* - a signature delimiter, which becomes its own block
|
|
16
|
+
* - a rule separator
|
|
17
|
+
* - the start of an embedded header block
|
|
18
|
+
*/
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.segmentTextBlocks = segmentTextBlocks;
|
|
21
|
+
const text_1 = require("../canonical/text");
|
|
22
|
+
const disclaimer_1 = require("../detect/disclaimer");
|
|
23
|
+
const forward_header_1 = require("../detect/forward-header");
|
|
24
|
+
const reply_header_1 = require("../detect/reply-header");
|
|
25
|
+
const signature_1 = require("../detect/signature");
|
|
26
|
+
const features_1 = require("./features");
|
|
27
|
+
/** Strip quote prefixes and trim surrounding blank lines for display and matching. */
|
|
28
|
+
function contentOf(lines) {
|
|
29
|
+
let start = 0;
|
|
30
|
+
let end = lines.length;
|
|
31
|
+
while (start < end && lines[start].blank) {
|
|
32
|
+
start++;
|
|
33
|
+
}
|
|
34
|
+
while (end > start && lines[end - 1].blank) {
|
|
35
|
+
end--;
|
|
36
|
+
}
|
|
37
|
+
return lines
|
|
38
|
+
.slice(start, end)
|
|
39
|
+
.map(line => line.content)
|
|
40
|
+
.join('\n');
|
|
41
|
+
}
|
|
42
|
+
function classifyKind(lines, forced) {
|
|
43
|
+
if (forced) {
|
|
44
|
+
return forced;
|
|
45
|
+
}
|
|
46
|
+
const body = lines.filter(line => !line.blank);
|
|
47
|
+
if (!body.length) {
|
|
48
|
+
return 'blank';
|
|
49
|
+
}
|
|
50
|
+
if (body[0].depth > 0) {
|
|
51
|
+
return 'quote';
|
|
52
|
+
}
|
|
53
|
+
const contents = body.map(line => line.content.trim());
|
|
54
|
+
if (contents.every(line => /^([-*+•‣◦]|\d+[.)])\s+/.test(line))) {
|
|
55
|
+
return 'list';
|
|
56
|
+
}
|
|
57
|
+
// A run of lines with aligned pipe or multi-space columns reads as a table in plain text.
|
|
58
|
+
if (contents.length > 1 && contents.every(line => line.includes('|') || /\S {3,}\S/.test(line))) {
|
|
59
|
+
return 'table';
|
|
60
|
+
}
|
|
61
|
+
return 'paragraph';
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Segment a plain text part into blocks.
|
|
65
|
+
*
|
|
66
|
+
* @param raw decoded text of the part
|
|
67
|
+
* @param mimePart part id for traceability
|
|
68
|
+
*/
|
|
69
|
+
function segmentTextBlocks(raw, mimePart) {
|
|
70
|
+
const canonical = (0, text_1.canonicaliseText)(raw);
|
|
71
|
+
const lines = canonical.lines;
|
|
72
|
+
if (!lines.length) {
|
|
73
|
+
return { canonical, blocks: [] };
|
|
74
|
+
}
|
|
75
|
+
const contents = lines.map(line => line.content);
|
|
76
|
+
const boundaries = new Map();
|
|
77
|
+
const addBoundary = (boundary) => {
|
|
78
|
+
const existing = boundaries.get(boundary.line);
|
|
79
|
+
if (!existing || (boundary.evidence?.strength ?? 0) > (existing.evidence?.strength ?? 0)) {
|
|
80
|
+
boundaries.set(boundary.line, boundary);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
// Line level anchors.
|
|
84
|
+
for (const line of lines) {
|
|
85
|
+
if (line.blank) {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const attribution = (0, reply_header_1.detectAttributionLine)(line.content);
|
|
89
|
+
if (attribution) {
|
|
90
|
+
addBoundary({ line: line.index, kind: 'reply_header', evidence: attribution, single: true });
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const forward = (0, forward_header_1.detectForwardMarker)(line.content);
|
|
94
|
+
if (forward) {
|
|
95
|
+
addBoundary({ line: line.index, kind: 'forward_header', evidence: forward, single: true });
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
const signature = (0, signature_1.detectSignatureDelimiter)(line.content);
|
|
99
|
+
if (signature) {
|
|
100
|
+
addBoundary({ line: line.index, kind: 'separator', evidence: signature, single: true });
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const rule = (0, reply_header_1.detectRuleSeparator)(line.content);
|
|
104
|
+
if (rule) {
|
|
105
|
+
addBoundary({ line: line.index, kind: 'separator', evidence: rule, single: true });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Embedded header blocks, scanning repeatedly so that several can be found in one body.
|
|
109
|
+
let cursor = 0;
|
|
110
|
+
while (cursor < lines.length) {
|
|
111
|
+
const match = (0, reply_header_1.detectQuotedHeaderBlock)(contents, cursor);
|
|
112
|
+
if (!match) {
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
addBoundary({ line: match.startLine, kind: 'quoted_header_block', evidence: match.evidence });
|
|
116
|
+
// The block ends after the last field line, so the next block starts there.
|
|
117
|
+
if (match.endLine + 1 < lines.length) {
|
|
118
|
+
const next = boundaries.get(match.endLine + 1);
|
|
119
|
+
if (!next) {
|
|
120
|
+
addBoundary({ line: match.endLine + 1 });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
cursor = match.endLine + 1;
|
|
124
|
+
}
|
|
125
|
+
// Structural boundaries: depth changes and blank line separations.
|
|
126
|
+
let previousDepth = lines[0].depth;
|
|
127
|
+
let sawBlank = false;
|
|
128
|
+
for (const line of lines) {
|
|
129
|
+
if (line.index === 0) {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (line.blank) {
|
|
133
|
+
sawBlank = true;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
const forcedSingleBefore = boundaries.get(line.index - 1)?.single;
|
|
137
|
+
if (line.depth !== previousDepth || sawBlank || forcedSingleBefore) {
|
|
138
|
+
if (!boundaries.has(line.index)) {
|
|
139
|
+
addBoundary({ line: line.index });
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
previousDepth = line.depth;
|
|
143
|
+
sawBlank = false;
|
|
144
|
+
}
|
|
145
|
+
// A single line boundary must also close, so the following line starts a new block.
|
|
146
|
+
for (const boundary of [...boundaries.values()]) {
|
|
147
|
+
if (boundary.single && boundary.line + 1 < lines.length && !boundaries.has(boundary.line + 1)) {
|
|
148
|
+
boundaries.set(boundary.line + 1, { line: boundary.line + 1 });
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const starts = [...new Set([0, ...boundaries.keys()])].sort((a, b) => a - b);
|
|
152
|
+
const blocks = [];
|
|
153
|
+
for (let i = 0; i < starts.length; i++) {
|
|
154
|
+
const startLine = starts[i];
|
|
155
|
+
const endLine = i + 1 < starts.length ? starts[i + 1] : lines.length;
|
|
156
|
+
const slice = lines.slice(startLine, endLine);
|
|
157
|
+
if (!slice.length) {
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
const first = slice[0];
|
|
161
|
+
const last = slice[slice.length - 1];
|
|
162
|
+
// Include the newline that terminates the last line, unless this is the end of the text.
|
|
163
|
+
const end = endLine < lines.length ? lines[endLine].start : last.end;
|
|
164
|
+
const boundary = boundaries.get(startLine);
|
|
165
|
+
blocks.push({
|
|
166
|
+
index: blocks.length,
|
|
167
|
+
kind: classifyKind(slice, boundary?.kind),
|
|
168
|
+
representation: 'text',
|
|
169
|
+
mimePart,
|
|
170
|
+
text: canonical.text.slice(first.start, end),
|
|
171
|
+
content: contentOf(slice),
|
|
172
|
+
start: first.start,
|
|
173
|
+
end,
|
|
174
|
+
features: (0, features_1.computeFeatures)(contentOf(slice), {
|
|
175
|
+
index: blocks.length,
|
|
176
|
+
total: starts.length,
|
|
177
|
+
start: first.start,
|
|
178
|
+
totalChars: canonical.text.length,
|
|
179
|
+
quoteDepth: Math.max(...slice.map(line => line.depth))
|
|
180
|
+
}),
|
|
181
|
+
evidence: boundary?.evidence ? [boundary.evidence] : []
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
// Block level evidence, once positions are known.
|
|
185
|
+
for (const block of blocks) {
|
|
186
|
+
block.features.indexFromEnd = blocks.length - 1 - block.index;
|
|
187
|
+
if (block.kind === 'blank') {
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
const blockLines = block.content.split('\n');
|
|
191
|
+
for (const evidence of (0, signature_1.detectSignaturePhrases)(blockLines)) {
|
|
192
|
+
block.evidence.push(evidence);
|
|
193
|
+
}
|
|
194
|
+
const shape = (0, signature_1.detectSignatureShape)(block.features);
|
|
195
|
+
if (shape) {
|
|
196
|
+
block.evidence.push(shape);
|
|
197
|
+
}
|
|
198
|
+
for (const evidence of (0, disclaimer_1.detectDisclaimer)(block.content, block.features)) {
|
|
199
|
+
block.evidence.push(evidence);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return { canonical, blocks };
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=text-blocks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-blocks.js","sourceRoot":"","sources":["../../src/segment/text-blocks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Block model shared by both segmenters.
|
|
3
|
+
*
|
|
4
|
+
* A block is a contiguous run of a single representation. Blocks tile their representation
|
|
5
|
+
* completely: concatenating every block's `text` in order reproduces the canonical text exactly.
|
|
6
|
+
* That property is what makes the lossless reconstruction invariant testable, so it is maintained
|
|
7
|
+
* by construction rather than checked afterwards.
|
|
8
|
+
*/
|
|
9
|
+
import { type Representation } from '../types';
|
|
10
|
+
/** Structural kind assigned during segmentation, before final classification. */
|
|
11
|
+
export type BlockKind = 'paragraph' | 'quote' | 'reply_header' | 'forward_header' | 'quoted_header_block' | 'signature_candidate' | 'disclaimer_candidate' | 'list' | 'table' | 'separator' | 'image' | 'blank' | 'unknown';
|
|
12
|
+
/** A single piece of evidence produced by a detector. Detectors never emit verdicts. */
|
|
13
|
+
export interface Evidence {
|
|
14
|
+
/** Detector id, matching a pattern id or a selector id. */
|
|
15
|
+
id: string;
|
|
16
|
+
/** What the evidence suggests. */
|
|
17
|
+
kind: 'reply-anchor' | 'forward-anchor' | 'quote-container' | 'attribution' | 'separator' | 'signature' | 'disclaimer' | 'new-content' | 'hint';
|
|
18
|
+
/** How strongly, in [0, 1]. */
|
|
19
|
+
strength: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Inspectable feature vector.
|
|
23
|
+
*
|
|
24
|
+
* Every field here is dumped by `extract --explain`, and every field is a candidate input to a
|
|
25
|
+
* learned model later. Nothing is computed that cannot be shown to a human.
|
|
26
|
+
*/
|
|
27
|
+
export interface BlockFeatures {
|
|
28
|
+
/** Normalised position of the block start within the representation, in [0, 1]. */
|
|
29
|
+
position: number;
|
|
30
|
+
/** Index from the end, so that trailing structures are easy to express. */
|
|
31
|
+
indexFromEnd: number;
|
|
32
|
+
charCount: number;
|
|
33
|
+
lineCount: number;
|
|
34
|
+
/** Mean characters per non blank line. */
|
|
35
|
+
meanLineLength: number;
|
|
36
|
+
wordCount: number;
|
|
37
|
+
quoteDepth: number;
|
|
38
|
+
/** Nesting depth inside blockquote elements. HTML only. */
|
|
39
|
+
blockquoteDepth: number;
|
|
40
|
+
/** Number of HTML elements this block spans. HTML only. */
|
|
41
|
+
elementCount: number;
|
|
42
|
+
linkCount: number;
|
|
43
|
+
imageCount: number;
|
|
44
|
+
hasQuestionMark: boolean;
|
|
45
|
+
hasDate: boolean;
|
|
46
|
+
hasEmailAddress: boolean;
|
|
47
|
+
hasUrl: boolean;
|
|
48
|
+
hasPhoneNumber: boolean;
|
|
49
|
+
/** Lines that look like an embedded message header field. */
|
|
50
|
+
headerFieldLines: number;
|
|
51
|
+
/** Fraction of lines that are shorter than 40 characters, a signature-like shape. */
|
|
52
|
+
shortLineRatio: number;
|
|
53
|
+
/** Fraction of characters that are uppercase letters. */
|
|
54
|
+
upperCaseRatio: number;
|
|
55
|
+
/** Fraction of characters that are punctuation or symbols. */
|
|
56
|
+
punctuationRatio: number;
|
|
57
|
+
isAllBlank: boolean;
|
|
58
|
+
/** HTML tag names present, lowercased and deduplicated. */
|
|
59
|
+
tags: string[];
|
|
60
|
+
/** HTML class names present, lowercased and deduplicated. */
|
|
61
|
+
classes: string[];
|
|
62
|
+
/** True when the block has a top border, which several clients use as a reply separator. */
|
|
63
|
+
hasTopBorder: boolean;
|
|
64
|
+
}
|
|
65
|
+
export interface Block {
|
|
66
|
+
index: number;
|
|
67
|
+
kind: BlockKind;
|
|
68
|
+
representation: Representation;
|
|
69
|
+
/** MIME part this block came from, for example "1.2". */
|
|
70
|
+
mimePart: string;
|
|
71
|
+
/**
|
|
72
|
+
* Exact slice of the canonical representation, including quote prefixes and trailing blank
|
|
73
|
+
* lines. Concatenating this across all blocks reproduces the canonical text.
|
|
74
|
+
*/
|
|
75
|
+
text: string;
|
|
76
|
+
/** Display and matching text: quote prefixes removed, surrounding blank lines trimmed. */
|
|
77
|
+
content: string;
|
|
78
|
+
/** Offsets into the canonical representation. */
|
|
79
|
+
start: number;
|
|
80
|
+
end: number;
|
|
81
|
+
/** Original HTML source for HTML blocks. Never regenerated. */
|
|
82
|
+
html?: string;
|
|
83
|
+
/** Stable child index path from the document root, for example "0/2/1". HTML only. */
|
|
84
|
+
domPath?: string;
|
|
85
|
+
features: BlockFeatures;
|
|
86
|
+
evidence: Evidence[];
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/segment/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C,iFAAiF;AACjF,MAAM,MAAM,SAAS,GACf,WAAW,GACX,OAAO,GACP,cAAc,GACd,gBAAgB,GAChB,qBAAqB,GACrB,qBAAqB,GACrB,sBAAsB,GACtB,MAAM,GACN,OAAO,GACP,WAAW,GACX,OAAO,GACP,OAAO,GACP,SAAS,CAAC;AAEhB,wFAAwF;AACxF,MAAM,WAAW,QAAQ;IACrB,2DAA2D;IAC3D,EAAE,EAAE,MAAM,CAAC;IACX,kCAAkC;IAClC,IAAI,EAAE,cAAc,GAAG,gBAAgB,GAAG,iBAAiB,GAAG,aAAa,GAAG,WAAW,GAAG,WAAW,GAAG,YAAY,GAAG,aAAa,GAAG,MAAM,CAAC;IAChJ,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC1B,mFAAmF;IACnF,QAAQ,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,0CAA0C;IAC1C,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,2DAA2D;IAC3D,eAAe,EAAE,MAAM,CAAC;IACxB,2DAA2D;IAC3D,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,OAAO,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,OAAO,CAAC;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,EAAE,OAAO,CAAC;IACxB,6DAA6D;IAC7D,gBAAgB,EAAE,MAAM,CAAC;IACzB,qFAAqF;IACrF,cAAc,EAAE,MAAM,CAAC;IACvB,yDAAyD;IACzD,cAAc,EAAE,MAAM,CAAC;IACvB,8DAA8D;IAC9D,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,OAAO,CAAC;IACpB,2DAA2D;IAC3D,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,6DAA6D;IAC7D,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,4FAA4F;IAC5F,YAAY,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,KAAK;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,CAAC;IAChB,cAAc,EAAE,cAAc,CAAC;IAC/B,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,0FAA0F;IAC1F,OAAO,EAAE,MAAM,CAAC;IAChB,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sFAAsF;IACtF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,aAAa,CAAC;IACxB,QAAQ,EAAE,QAAQ,EAAE,CAAC;CACxB"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Block model shared by both segmenters.
|
|
4
|
+
*
|
|
5
|
+
* A block is a contiguous run of a single representation. Blocks tile their representation
|
|
6
|
+
* completely: concatenating every block's `text` in order reproduces the canonical text exactly.
|
|
7
|
+
* That property is what makes the lossless reconstruction invariant testable, so it is maintained
|
|
8
|
+
* by construction rather than checked afterwards.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/segment/types.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public contract for the extraction pipeline.
|
|
3
|
+
*
|
|
4
|
+
* Everything a caller needs to reason about the output lives here. The guiding rule for the whole
|
|
5
|
+
* project is asymmetric: losing genuine new content is far worse than showing redundant history,
|
|
6
|
+
* so every type in this file is designed so that content can be demoted to a lower visibility
|
|
7
|
+
* band but never dropped.
|
|
8
|
+
*/
|
|
9
|
+
/** Version of the deterministic extraction logic. Bump on any change that can alter a label. */
|
|
10
|
+
export declare const EXTRACTOR_VERSION = "0.1.0";
|
|
11
|
+
/** Version of the corpus processing pipeline (scanner, feature extraction, storage schema). */
|
|
12
|
+
export declare const PROCESSING_VERSION = "0.1.0";
|
|
13
|
+
/** Final block classification. */
|
|
14
|
+
export type Label = 'NEW_CONTENT' | 'INLINE_QUOTE' | 'REPLY_HISTORY' | 'FORWARDED_CONTENT' | 'SIGNATURE' | 'DISCLAIMER' | 'UNKNOWN';
|
|
15
|
+
export declare const LABELS: readonly Label[];
|
|
16
|
+
/**
|
|
17
|
+
* How a client should present a segment.
|
|
18
|
+
*
|
|
19
|
+
* `hide` is only ever assigned to high confidence REPLY_HISTORY or FORWARDED_CONTENT that is
|
|
20
|
+
* backed by a structural anchor. `collapse` means recoverable with one interaction. Anything the
|
|
21
|
+
* pipeline is unsure about stays `show`.
|
|
22
|
+
*/
|
|
23
|
+
export type Visibility = 'show' | 'collapse' | 'hide';
|
|
24
|
+
/** Which canonical representation a block came from. */
|
|
25
|
+
export type Representation = 'text' | 'html';
|
|
26
|
+
/**
|
|
27
|
+
* Traceability back to the original message. Every segment must carry one of these so a reviewer
|
|
28
|
+
* can always find the exact bytes the decision was made about.
|
|
29
|
+
*/
|
|
30
|
+
export interface SourceRef {
|
|
31
|
+
/** IMAP style MIME part path, for example "1.2". "TEXT" for a single part message root. */
|
|
32
|
+
mimePart: string;
|
|
33
|
+
representation: Representation;
|
|
34
|
+
/** Index of the block within its representation, in document order. */
|
|
35
|
+
blockIndex: number;
|
|
36
|
+
/** Character offsets into the decoded, canonicalised part content. */
|
|
37
|
+
start: number;
|
|
38
|
+
end: number;
|
|
39
|
+
/** HTML only. Stable child index path from the body element, for example "0/2/1". */
|
|
40
|
+
domPath?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Machine readable justification codes. Closed vocabulary: a decision that cannot name its reason
|
|
44
|
+
* is not allowed to influence visibility.
|
|
45
|
+
*/
|
|
46
|
+
export type Reason = 'preceded_by_reply_header' | 'preceded_by_forward_header' | 'inside_quote_container' | 'final_contiguous_quote_region' | 'no_new_content_after_region' | 'new_content_after_region' | 'interleaved_with_new_content' | 'contains_old_message_headers' | 'quote_depth_positive' | 'no_anchor_for_quote' | 'gmail_quote_container' | 'gmail_attr_line' | 'gmail_signature_container' | 'outlook_reply_separator' | 'outlook_mso_border_separator' | 'owa_element_to_proof' | 'apple_mail_cite' | 'thunderbird_moz_cite' | 'generic_blockquote' | 'dash_dash_delimiter' | 'mobile_signature_phrase' | 'signature_position_and_length' | 'disclaimer_phrase' | 'matched_parent_message' | 'matched_thread_ancestor' | 'shingle_overlap_high' | 'no_history_available' | 'html_primary_representation' | 'text_primary_representation' | 'representations_disagree' | 'evidence_transferred_from_html' | 'evidence_transferred_from_text' | 'new_content_default' | 'ambiguous_kept_visible' | 'degraded_to_unknown';
|
|
47
|
+
/** A classified run of content. */
|
|
48
|
+
export interface Segment {
|
|
49
|
+
type: Label;
|
|
50
|
+
/** Plain text of the segment. Always present, always taken verbatim from the source. */
|
|
51
|
+
text: string;
|
|
52
|
+
/** Original HTML for HTML sourced segments. Never regenerated or rewritten. */
|
|
53
|
+
html?: string;
|
|
54
|
+
/** Calibrated in [0, 1]. */
|
|
55
|
+
confidence: number;
|
|
56
|
+
visibility: Visibility;
|
|
57
|
+
reasons: Reason[];
|
|
58
|
+
source: SourceRef;
|
|
59
|
+
}
|
|
60
|
+
/** Warning codes emitted during parsing or extraction. Never contains message content. */
|
|
61
|
+
export type WarningCode = 'mime_parse_error' | 'mime_truncated' | 'missing_boundary' | 'max_nesting_exceeded' | 'max_parts_exceeded' | 'header_too_large' | 'unknown_charset' | 'charset_decode_replacement_chars' | 'transfer_encoding_error' | 'text_part_truncated' | 'html_parse_error' | 'no_body_parts' | 'non_contiguous_body' | 'extraction_degraded' | 'timeout';
|
|
62
|
+
export interface Warning {
|
|
63
|
+
code: WarningCode;
|
|
64
|
+
/** Human readable detail. Must never include message body text or addresses. */
|
|
65
|
+
detail?: string;
|
|
66
|
+
mimePart?: string;
|
|
67
|
+
}
|
|
68
|
+
/** Result of extracting one message. */
|
|
69
|
+
export interface ExtractionResult {
|
|
70
|
+
/** Segments the client should render, in document order. */
|
|
71
|
+
segments: Segment[];
|
|
72
|
+
/** Segments the client may hide or collapse. Retained in full so nothing is ever lost. */
|
|
73
|
+
hiddenSegments: Segment[];
|
|
74
|
+
/** Message level confidence, the weakest link across hide decisions. */
|
|
75
|
+
overallConfidence: number;
|
|
76
|
+
warnings: Warning[];
|
|
77
|
+
/** Always true. The pipeline never discards the source message. */
|
|
78
|
+
originalAvailable: true;
|
|
79
|
+
/** Which representation drove the final classification. */
|
|
80
|
+
primaryRepresentation: Representation | 'none';
|
|
81
|
+
extractorVersion: string;
|
|
82
|
+
/** True when thread history was available and used. */
|
|
83
|
+
historyUsed: boolean;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,gGAAgG;AAChG,eAAO,MAAM,iBAAiB,UAAU,CAAC;AAEzC,+FAA+F;AAC/F,eAAO,MAAM,kBAAkB,UAAU,CAAC;AAE1C,kCAAkC;AAClC,MAAM,MAAM,KAAK,GAAG,aAAa,GAAG,cAAc,GAAG,eAAe,GAAG,mBAAmB,GAAG,WAAW,GAAG,YAAY,GAAG,SAAS,CAAC;AAEpI,eAAO,MAAM,MAAM,EAAE,SAAS,KAAK,EAAyH,CAAC;AAE7J;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC;AAEtD,wDAAwD;AACxD,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,MAAM,CAAC;AAE7C;;;GAGG;AACH,MAAM,WAAW,SAAS;IACtB,2FAA2F;IAC3F,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,cAAc,CAAC;IAC/B,uEAAuE;IACvE,UAAU,EAAE,MAAM,CAAC;IACnB,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,qFAAqF;IACrF,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,MAAM,MAAM,GAEZ,0BAA0B,GAC1B,4BAA4B,GAC5B,wBAAwB,GACxB,+BAA+B,GAC/B,6BAA6B,GAC7B,0BAA0B,GAC1B,8BAA8B,GAC9B,8BAA8B,GAC9B,sBAAsB,GACtB,qBAAqB,GAErB,uBAAuB,GACvB,iBAAiB,GACjB,2BAA2B,GAC3B,yBAAyB,GACzB,8BAA8B,GAC9B,sBAAsB,GACtB,iBAAiB,GACjB,sBAAsB,GACtB,oBAAoB,GAEpB,qBAAqB,GACrB,yBAAyB,GACzB,+BAA+B,GAC/B,mBAAmB,GAEnB,wBAAwB,GACxB,yBAAyB,GACzB,sBAAsB,GACtB,sBAAsB,GAEtB,6BAA6B,GAC7B,6BAA6B,GAC7B,0BAA0B,GAC1B,gCAAgC,GAChC,gCAAgC,GAEhC,qBAAqB,GACrB,wBAAwB,GACxB,qBAAqB,CAAC;AAE5B,mCAAmC;AACnC,MAAM,WAAW,OAAO;IACpB,IAAI,EAAE,KAAK,CAAC;IACZ,wFAAwF;IACxF,IAAI,EAAE,MAAM,CAAC;IACb,+EAA+E;IAC/E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4BAA4B;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,UAAU,CAAC;IACvB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,SAAS,CAAC;CACrB;AAED,0FAA0F;AAC1F,MAAM,MAAM,WAAW,GACjB,kBAAkB,GAClB,gBAAgB,GAChB,kBAAkB,GAClB,sBAAsB,GACtB,oBAAoB,GACpB,kBAAkB,GAClB,iBAAiB,GACjB,kCAAkC,GAClC,yBAAyB,GACzB,qBAAqB,GACrB,kBAAkB,GAClB,eAAe,GACf,qBAAqB,GACrB,qBAAqB,GACrB,SAAS,CAAC;AAEhB,MAAM,WAAW,OAAO;IACpB,IAAI,EAAE,WAAW,CAAC;IAClB,gFAAgF;IAChF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wCAAwC;AACxC,MAAM,WAAW,gBAAgB;IAC7B,4DAA4D;IAC5D,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,0FAA0F;IAC1F,cAAc,EAAE,OAAO,EAAE,CAAC;IAC1B,wEAAwE;IACxE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,mEAAmE;IACnE,iBAAiB,EAAE,IAAI,CAAC;IACxB,2DAA2D;IAC3D,qBAAqB,EAAE,cAAc,GAAG,MAAM,CAAC;IAC/C,gBAAgB,EAAE,MAAM,CAAC;IACzB,uDAAuD;IACvD,WAAW,EAAE,OAAO,CAAC;CACxB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Public contract for the extraction pipeline.
|
|
4
|
+
*
|
|
5
|
+
* Everything a caller needs to reason about the output lives here. The guiding rule for the whole
|
|
6
|
+
* project is asymmetric: losing genuine new content is far worse than showing redundant history,
|
|
7
|
+
* so every type in this file is designed so that content can be demoted to a lower visibility
|
|
8
|
+
* band but never dropped.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.LABELS = exports.PROCESSING_VERSION = exports.EXTRACTOR_VERSION = void 0;
|
|
12
|
+
/** Version of the deterministic extraction logic. Bump on any change that can alter a label. */
|
|
13
|
+
exports.EXTRACTOR_VERSION = '0.1.0';
|
|
14
|
+
/** Version of the corpus processing pipeline (scanner, feature extraction, storage schema). */
|
|
15
|
+
exports.PROCESSING_VERSION = '0.1.0';
|
|
16
|
+
exports.LABELS = ['NEW_CONTENT', 'INLINE_QUOTE', 'REPLY_HISTORY', 'FORWARDED_CONTENT', 'SIGNATURE', 'DISCLAIMER', 'UNKNOWN'];
|
|
17
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAEH,gGAAgG;AACnF,QAAA,iBAAiB,GAAG,OAAO,CAAC;AAEzC,+FAA+F;AAClF,QAAA,kBAAkB,GAAG,OAAO,CAAC;AAK7B,QAAA,MAAM,GAAqB,CAAC,aAAa,EAAE,cAAc,EAAE,eAAe,EAAE,mBAAmB,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,CAAU,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hashing helpers.
|
|
3
|
+
*
|
|
4
|
+
* Two jobs: content addressing for exact duplicate detection, and privacy preserving identifiers so
|
|
5
|
+
* that the corpus database can group by sender or subject without storing either. Salted hashes use
|
|
6
|
+
* a per database salt, so a leaked database cannot be dictionary attacked against a known address
|
|
7
|
+
* list without also leaking the salt.
|
|
8
|
+
*/
|
|
9
|
+
export declare function sha256(buf: Buffer | string): string;
|
|
10
|
+
/** Short content hash, enough to group duplicates within a single corpus. */
|
|
11
|
+
export declare function shortHash(buf: Buffer | string): string;
|
|
12
|
+
/** Keyed hash for values that must be groupable but never recoverable. */
|
|
13
|
+
export declare function saltedHash(salt: string, value: string): string;
|
|
14
|
+
/** Generate a random salt for a new corpus database. */
|
|
15
|
+
export declare function newSalt(): string;
|
|
16
|
+
/**
|
|
17
|
+
* Deterministic 32 bit selector in [0, 1) derived from a key and a seed.
|
|
18
|
+
*
|
|
19
|
+
* Used for reproducible sampling: the same file always lands in the same position for a given seed,
|
|
20
|
+
* without needing to hold the corpus in memory or shuffle it.
|
|
21
|
+
*/
|
|
22
|
+
export declare function deterministicUnit(seed: string, key: string): number;
|
|
23
|
+
/** FNV-1a, 32 bit. Fast and good enough for shingling and simhash token weights. */
|
|
24
|
+
export declare function fnv1a32(value: string): number;
|
|
25
|
+
/** Second, independent 32 bit hash so that two of them can form a 64 bit value. */
|
|
26
|
+
export declare function fnv1a32b(value: string): number;
|
|
27
|
+
/**
|
|
28
|
+
* 64 bit SimHash over whitespace separated tokens, returned as a 16 character hex string.
|
|
29
|
+
*
|
|
30
|
+
* Near duplicate detection matters for split hygiene: a template that appears thousands of times
|
|
31
|
+
* must not be spread across train, validation and test. Hamming distance on this value is a cheap
|
|
32
|
+
* first pass filter before any expensive comparison.
|
|
33
|
+
*/
|
|
34
|
+
export declare function simhash64(text: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* Default Hamming distance below which two bodies are treated as near duplicates.
|
|
37
|
+
*
|
|
38
|
+
* Measured against a 300 character templated invoice mail: changing one identifier gives distance
|
|
39
|
+
* 4, changing two fields gives 7, adding a sentence gives 6, and an unrelated message gives 30.
|
|
40
|
+
* Eight therefore separates template variants from distinct content with a comfortable margin.
|
|
41
|
+
*
|
|
42
|
+
* Short bodies are noisier, because each token carries more of the signal. A one token change in a
|
|
43
|
+
* 14 token message already gives distance 8. Callers comparing very short texts should either
|
|
44
|
+
* tighten this or fall back to exact comparison.
|
|
45
|
+
*/
|
|
46
|
+
export declare const NEAR_DUPLICATE_THRESHOLD = 8;
|
|
47
|
+
/** Hamming distance between two hex SimHash values. Returns 64 when either is malformed. */
|
|
48
|
+
export declare function simhashDistance(a: string, b: string): number;
|
|
49
|
+
//# sourceMappingURL=hash.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/util/hash.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAEnD;AAED,6EAA6E;AAC7E,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAEtD;AAED,0EAA0E;AAC1E,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,wDAAwD;AACxD,wBAAgB,OAAO,IAAI,MAAM,CAEhC;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAGnE;AAED,oFAAoF;AACpF,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAS7C;AAED,mFAAmF;AACnF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAS9C;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAkC9C;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C,4FAA4F;AAC5F,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAkB5D"}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.js","sourceRoot":"","sources":["../../src/util/hash.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Language estimation.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately small and dependency free. This is an estimate used for stratified sampling and for
|
|
5
|
+
* reporting metrics per language, never for a classification decision. A wrong guess costs a
|
|
6
|
+
* slightly skewed sample, nothing more, which is why a stopword scorer is preferred over pulling in
|
|
7
|
+
* a model.
|
|
8
|
+
*
|
|
9
|
+
* Two stages: script detection first, because a Cyrillic or CJK body is unambiguous and cheap to
|
|
10
|
+
* spot, then stopword frequency for Latin script languages.
|
|
11
|
+
*/
|
|
12
|
+
export type LanguageCode = 'en' | 'et' | 'de' | 'fr' | 'es' | 'it' | 'pt' | 'nl' | 'sv' | 'fi' | 'pl' | 'ru' | 'zh' | 'ja' | 'ko' | 'ar' | 'el' | 'he' | 'unknown';
|
|
13
|
+
export interface LanguageEstimate {
|
|
14
|
+
lang: LanguageCode;
|
|
15
|
+
/** Share of sampled tokens that matched the winning language's stopword list. */
|
|
16
|
+
score: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Estimate the language of a body of text.
|
|
20
|
+
*
|
|
21
|
+
* @param text plain text. Only the first 20k characters are inspected, which is ample and keeps the
|
|
22
|
+
* cost bounded on newsletters and digests.
|
|
23
|
+
*/
|
|
24
|
+
export declare function estimateLanguage(text: string): LanguageEstimate;
|
|
25
|
+
//# sourceMappingURL=lang.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lang.d.ts","sourceRoot":"","sources":["../../src/util/lang.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,YAAY,GACpB,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC;AAE5I,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,YAAY,CAAC;IACnB,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAC;CACjB;AA8ED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CA8C/D"}
|