@precisa-saude/fhir-ocr-utils 0.38.0 → 0.38.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/README.md +7 -3
- package/dist/cli.js +58 -37
- package/dist/index.cjs +57 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +57 -36
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -90,9 +90,13 @@ Por isso a correspondência é conservadora:
|
|
|
90
90
|
`RBC_Urine`, "PH" ancora `pH_Urine`, e "COLOR", "KETONES", "PROTEIN" e
|
|
91
91
|
companhia ancoram mesmo sem valor na linha (texto em colunas). O código do
|
|
92
92
|
sangue não ancora pela mesma linha. A seção acaba na primeira linha com
|
|
93
|
-
exame de outro painel
|
|
94
|
-
|
|
95
|
-
|
|
93
|
+
exame de outro painel, no cabeçalho de outro painel ou no fim do texto. Uma
|
|
94
|
+
linha sem valor e sem nome conhecido pode ser as duas coisas ("COMPREHENSIVE
|
|
95
|
+
METABOLIC PANEL" ou "MUCUS"), e quem decide é a próxima linha decisiva: se só
|
|
96
|
+
pode ser da urina (código da urina, a palavra urina, ou /HPF e /LPF), a seção
|
|
97
|
+
segue; se é exame de outro painel, ou se o texto acaba sem nada decisivo, a
|
|
98
|
+
seção acaba ali, e o nome volta ao sentido de fora da seção. Fora dela nada
|
|
99
|
+
muda.
|
|
96
100
|
- **Contexto genético é descartado** — símbolos de gene colidem com nomes de
|
|
97
101
|
biomarcador (o gene `APOB` vs. a lipoproteína `ApoB`). Linhas com acesso
|
|
98
102
|
RefSeq (`NM_000384.2`), notação HGVS (`p.Trp448*`, `c.1234A>G`), `rs` do dbSNP
|
package/dist/cli.js
CHANGED
|
@@ -135,6 +135,34 @@ var QUALITATIVE_VALUE_TERMS = /* @__PURE__ */ new Set([
|
|
|
135
135
|
"undetectable",
|
|
136
136
|
"yellow"
|
|
137
137
|
]);
|
|
138
|
+
var GENETIC_CONTEXT_PATTERNS = [
|
|
139
|
+
/\b[nx][mrpc]_\d{6,}/,
|
|
140
|
+
// RefSeq: NM_000384.2, NP_, NR_, XM_
|
|
141
|
+
/\bens[gtp]\d{6,}/,
|
|
142
|
+
// Ensembl: ENSG00000084674
|
|
143
|
+
/\bp\.[a-z]{3}\d/,
|
|
144
|
+
// HGVS proteína: p.Trp448*
|
|
145
|
+
/\bc\.\d+[acgt]?[>_+-]/,
|
|
146
|
+
// HGVS codificante: c.1234A>G, c.76_78del
|
|
147
|
+
/\brs\d{4,}\b/,
|
|
148
|
+
// dbSNP
|
|
149
|
+
/\bgenes?\b/,
|
|
150
|
+
/\bvariante?s?\b/,
|
|
151
|
+
/\bexons?\b/,
|
|
152
|
+
/\bzygosity\b/,
|
|
153
|
+
/\bzigosidade\b/,
|
|
154
|
+
/\balleles?\b/,
|
|
155
|
+
/\balelos?\b/,
|
|
156
|
+
/\bmutations?\b/,
|
|
157
|
+
/\bmutac(ao|oes)\b/,
|
|
158
|
+
/\bpathogenic/,
|
|
159
|
+
/\bpatogenic/,
|
|
160
|
+
/\bheterozyg/,
|
|
161
|
+
/\bhomozyg/,
|
|
162
|
+
/\bheterozigot/,
|
|
163
|
+
/\bhomozigot/,
|
|
164
|
+
/\bsequence change\b/
|
|
165
|
+
];
|
|
138
166
|
|
|
139
167
|
// src/body-region.ts
|
|
140
168
|
var WHOLE_BODY_COMPOSITION_CODES = /* @__PURE__ */ new Set([
|
|
@@ -283,19 +311,37 @@ function isSectionName(matched) {
|
|
|
283
311
|
return URINALYSIS_SECTION_NAMES.has(matched) || URINALYSIS_SECTION_NAMES.has(matched.replace(/s$/, ""));
|
|
284
312
|
}
|
|
285
313
|
var MENTIONS_URINE = /(?<![\p{L}\p{N}])urin[ae](?![\p{L}\p{N}])/u;
|
|
314
|
+
var SEDIMENT_FIELD_UNIT = /\/(?:hpf|lpf)(?![\p{L}\p{N}])/u;
|
|
315
|
+
function hasUrineCue(line) {
|
|
316
|
+
return MENTIONS_URINE.test(line) || SEDIMENT_FIELD_UNIT.test(line);
|
|
317
|
+
}
|
|
318
|
+
function kindOf(line) {
|
|
319
|
+
const text = line.text.trim();
|
|
320
|
+
if (!text) return "blank";
|
|
321
|
+
if (URINALYSIS_HEADER.test(text) && !/\d/.test(text)) return "header";
|
|
322
|
+
if (line.foreign) return "foreign";
|
|
323
|
+
if (line.urine) return "urine";
|
|
324
|
+
return line.known || line.hasValue ? "neutral" : "unknown";
|
|
325
|
+
}
|
|
286
326
|
function urinalysisLineIndexes(lines) {
|
|
327
|
+
const kinds = lines.map(kindOf);
|
|
328
|
+
const continuesAsUrine = (from) => {
|
|
329
|
+
const next = kinds.findIndex(
|
|
330
|
+
(kind, index) => index > from && (kind === "urine" || kind === "foreign" || kind === "header")
|
|
331
|
+
);
|
|
332
|
+
return next !== -1 && kinds[next] === "urine";
|
|
333
|
+
};
|
|
287
334
|
const inside = /* @__PURE__ */ new Set();
|
|
288
335
|
let open = false;
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
if (URINALYSIS_HEADER.test(text) && !/\d/.test(text)) {
|
|
336
|
+
kinds.forEach((kind, index) => {
|
|
337
|
+
if (kind === "header") {
|
|
292
338
|
open = true;
|
|
293
339
|
return;
|
|
294
340
|
}
|
|
295
|
-
if (!open ||
|
|
341
|
+
if (!open || kind === "blank") {
|
|
296
342
|
return;
|
|
297
343
|
}
|
|
298
|
-
if (
|
|
344
|
+
if (kind === "foreign" || kind === "unknown" && !continuesAsUrine(index)) {
|
|
299
345
|
open = false;
|
|
300
346
|
return;
|
|
301
347
|
}
|
|
@@ -339,7 +385,7 @@ function applyUrinalysisSection(normalizedText, candidates, deps) {
|
|
|
339
385
|
const known = deps.patterns.some(
|
|
340
386
|
({ name, regex }) => !matchesIn(text, name, regex).next().done
|
|
341
387
|
);
|
|
342
|
-
return { foreign: false, hasValue: deps.hasValue(text), known, text };
|
|
388
|
+
return { foreign: false, hasValue: deps.hasValue(text), known, text, urine: hasUrineCue(text) };
|
|
343
389
|
});
|
|
344
390
|
for (const candidate of resolved) {
|
|
345
391
|
let index = lineStarts.length - 1;
|
|
@@ -347,7 +393,9 @@ function applyUrinalysisSection(normalizedText, candidates, deps) {
|
|
|
347
393
|
const line = lines[index];
|
|
348
394
|
line.known = true;
|
|
349
395
|
const matched = normalizedText.slice(candidate.start, candidate.end);
|
|
350
|
-
if (
|
|
396
|
+
if (candidate.entries.some((e) => deps.urineCodes.has(e.code))) {
|
|
397
|
+
line.urine = true;
|
|
398
|
+
} else if (!isSectionName(matched)) {
|
|
351
399
|
line.foreign = true;
|
|
352
400
|
}
|
|
353
401
|
}
|
|
@@ -420,40 +468,13 @@ function foldCommas(text) {
|
|
|
420
468
|
(comma, space, offset) => startsWithCatalogName(text.slice(offset + 1 + space.length)) ? comma : " "
|
|
421
469
|
);
|
|
422
470
|
}
|
|
423
|
-
var GENETIC_CONTEXT_PATTERNS = [
|
|
424
|
-
/\b[nx][mrpc]_\d{6,}/,
|
|
425
|
-
// RefSeq: NM_000384.2, NP_, NR_, XM_
|
|
426
|
-
/\bens[gtp]\d{6,}/,
|
|
427
|
-
// Ensembl: ENSG00000084674
|
|
428
|
-
/\bp\.[a-z]{3}\d/,
|
|
429
|
-
// HGVS proteína: p.Trp448*
|
|
430
|
-
/\bc\.\d+[acgt]?[>_+-]/,
|
|
431
|
-
// HGVS codificante: c.1234A>G, c.76_78del
|
|
432
|
-
/\brs\d{4,}\b/,
|
|
433
|
-
// dbSNP
|
|
434
|
-
/\bgenes?\b/,
|
|
435
|
-
/\bvariante?s?\b/,
|
|
436
|
-
/\bexons?\b/,
|
|
437
|
-
/\bzygosity\b/,
|
|
438
|
-
/\bzigosidade\b/,
|
|
439
|
-
/\balleles?\b/,
|
|
440
|
-
/\balelos?\b/,
|
|
441
|
-
/\bmutations?\b/,
|
|
442
|
-
/\bmutac(ao|oes)\b/,
|
|
443
|
-
/\bpathogenic/,
|
|
444
|
-
/\bpatogenic/,
|
|
445
|
-
/\bheterozyg/,
|
|
446
|
-
/\bhomozyg/,
|
|
447
|
-
/\bheterozigot/,
|
|
448
|
-
/\bhomozigot/,
|
|
449
|
-
/\bsequence change\b/
|
|
450
|
-
];
|
|
451
471
|
var DIGIT_PATTERN = /\d/;
|
|
452
472
|
var cachedUnitTokens = null;
|
|
453
473
|
function getUnitTokens() {
|
|
454
474
|
if (!cachedUnitTokens) {
|
|
475
|
+
const isExamName = (t) => URINALYSIS_SECTION_NAMES.has(t) || getNamePatterns().has(t);
|
|
455
476
|
cachedUnitTokens = new Set(
|
|
456
|
-
Object.keys(UNIT_TO_UCUM).map((unit) => normalize(unit).trim()).filter(
|
|
477
|
+
Object.keys(UNIT_TO_UCUM).map((unit) => normalize(unit).trim()).filter((unit) => unit && !isExamName(unit))
|
|
457
478
|
);
|
|
458
479
|
}
|
|
459
480
|
return cachedUnitTokens;
|
|
@@ -1218,7 +1239,7 @@ async function main() {
|
|
|
1218
1239
|
strict: false
|
|
1219
1240
|
});
|
|
1220
1241
|
if (values.version) {
|
|
1221
|
-
process.stdout.write(`${"0.38.
|
|
1242
|
+
process.stdout.write(`${"0.38.1"}
|
|
1222
1243
|
`);
|
|
1223
1244
|
return;
|
|
1224
1245
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -119,6 +119,34 @@ var QUALITATIVE_VALUE_TERMS = /* @__PURE__ */ new Set([
|
|
|
119
119
|
"undetectable",
|
|
120
120
|
"yellow"
|
|
121
121
|
]);
|
|
122
|
+
var GENETIC_CONTEXT_PATTERNS = [
|
|
123
|
+
/\b[nx][mrpc]_\d{6,}/,
|
|
124
|
+
// RefSeq: NM_000384.2, NP_, NR_, XM_
|
|
125
|
+
/\bens[gtp]\d{6,}/,
|
|
126
|
+
// Ensembl: ENSG00000084674
|
|
127
|
+
/\bp\.[a-z]{3}\d/,
|
|
128
|
+
// HGVS proteína: p.Trp448*
|
|
129
|
+
/\bc\.\d+[acgt]?[>_+-]/,
|
|
130
|
+
// HGVS codificante: c.1234A>G, c.76_78del
|
|
131
|
+
/\brs\d{4,}\b/,
|
|
132
|
+
// dbSNP
|
|
133
|
+
/\bgenes?\b/,
|
|
134
|
+
/\bvariante?s?\b/,
|
|
135
|
+
/\bexons?\b/,
|
|
136
|
+
/\bzygosity\b/,
|
|
137
|
+
/\bzigosidade\b/,
|
|
138
|
+
/\balleles?\b/,
|
|
139
|
+
/\balelos?\b/,
|
|
140
|
+
/\bmutations?\b/,
|
|
141
|
+
/\bmutac(ao|oes)\b/,
|
|
142
|
+
/\bpathogenic/,
|
|
143
|
+
/\bpatogenic/,
|
|
144
|
+
/\bheterozyg/,
|
|
145
|
+
/\bhomozyg/,
|
|
146
|
+
/\bheterozigot/,
|
|
147
|
+
/\bhomozigot/,
|
|
148
|
+
/\bsequence change\b/
|
|
149
|
+
];
|
|
122
150
|
|
|
123
151
|
// src/body-region.ts
|
|
124
152
|
var WHOLE_BODY_COMPOSITION_CODES = /* @__PURE__ */ new Set([
|
|
@@ -267,19 +295,37 @@ function isSectionName(matched) {
|
|
|
267
295
|
return URINALYSIS_SECTION_NAMES.has(matched) || URINALYSIS_SECTION_NAMES.has(matched.replace(/s$/, ""));
|
|
268
296
|
}
|
|
269
297
|
var MENTIONS_URINE = /(?<![\p{L}\p{N}])urin[ae](?![\p{L}\p{N}])/u;
|
|
298
|
+
var SEDIMENT_FIELD_UNIT = /\/(?:hpf|lpf)(?![\p{L}\p{N}])/u;
|
|
299
|
+
function hasUrineCue(line) {
|
|
300
|
+
return MENTIONS_URINE.test(line) || SEDIMENT_FIELD_UNIT.test(line);
|
|
301
|
+
}
|
|
302
|
+
function kindOf(line) {
|
|
303
|
+
const text = line.text.trim();
|
|
304
|
+
if (!text) return "blank";
|
|
305
|
+
if (URINALYSIS_HEADER.test(text) && !/\d/.test(text)) return "header";
|
|
306
|
+
if (line.foreign) return "foreign";
|
|
307
|
+
if (line.urine) return "urine";
|
|
308
|
+
return line.known || line.hasValue ? "neutral" : "unknown";
|
|
309
|
+
}
|
|
270
310
|
function urinalysisLineIndexes(lines) {
|
|
311
|
+
const kinds = lines.map(kindOf);
|
|
312
|
+
const continuesAsUrine = (from) => {
|
|
313
|
+
const next = kinds.findIndex(
|
|
314
|
+
(kind, index) => index > from && (kind === "urine" || kind === "foreign" || kind === "header")
|
|
315
|
+
);
|
|
316
|
+
return next !== -1 && kinds[next] === "urine";
|
|
317
|
+
};
|
|
271
318
|
const inside = /* @__PURE__ */ new Set();
|
|
272
319
|
let open = false;
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
if (URINALYSIS_HEADER.test(text) && !/\d/.test(text)) {
|
|
320
|
+
kinds.forEach((kind, index) => {
|
|
321
|
+
if (kind === "header") {
|
|
276
322
|
open = true;
|
|
277
323
|
return;
|
|
278
324
|
}
|
|
279
|
-
if (!open ||
|
|
325
|
+
if (!open || kind === "blank") {
|
|
280
326
|
return;
|
|
281
327
|
}
|
|
282
|
-
if (
|
|
328
|
+
if (kind === "foreign" || kind === "unknown" && !continuesAsUrine(index)) {
|
|
283
329
|
open = false;
|
|
284
330
|
return;
|
|
285
331
|
}
|
|
@@ -323,7 +369,7 @@ function applyUrinalysisSection(normalizedText, candidates, deps) {
|
|
|
323
369
|
const known = deps.patterns.some(
|
|
324
370
|
({ name, regex }) => !matchesIn(text, name, regex).next().done
|
|
325
371
|
);
|
|
326
|
-
return { foreign: false, hasValue: deps.hasValue(text), known, text };
|
|
372
|
+
return { foreign: false, hasValue: deps.hasValue(text), known, text, urine: hasUrineCue(text) };
|
|
327
373
|
});
|
|
328
374
|
for (const candidate of resolved) {
|
|
329
375
|
let index = lineStarts.length - 1;
|
|
@@ -331,7 +377,9 @@ function applyUrinalysisSection(normalizedText, candidates, deps) {
|
|
|
331
377
|
const line = lines[index];
|
|
332
378
|
line.known = true;
|
|
333
379
|
const matched = normalizedText.slice(candidate.start, candidate.end);
|
|
334
|
-
if (
|
|
380
|
+
if (candidate.entries.some((e) => deps.urineCodes.has(e.code))) {
|
|
381
|
+
line.urine = true;
|
|
382
|
+
} else if (!isSectionName(matched)) {
|
|
335
383
|
line.foreign = true;
|
|
336
384
|
}
|
|
337
385
|
}
|
|
@@ -404,40 +452,13 @@ function foldCommas(text) {
|
|
|
404
452
|
(comma, space, offset) => startsWithCatalogName(text.slice(offset + 1 + space.length)) ? comma : " "
|
|
405
453
|
);
|
|
406
454
|
}
|
|
407
|
-
var GENETIC_CONTEXT_PATTERNS = [
|
|
408
|
-
/\b[nx][mrpc]_\d{6,}/,
|
|
409
|
-
// RefSeq: NM_000384.2, NP_, NR_, XM_
|
|
410
|
-
/\bens[gtp]\d{6,}/,
|
|
411
|
-
// Ensembl: ENSG00000084674
|
|
412
|
-
/\bp\.[a-z]{3}\d/,
|
|
413
|
-
// HGVS proteína: p.Trp448*
|
|
414
|
-
/\bc\.\d+[acgt]?[>_+-]/,
|
|
415
|
-
// HGVS codificante: c.1234A>G, c.76_78del
|
|
416
|
-
/\brs\d{4,}\b/,
|
|
417
|
-
// dbSNP
|
|
418
|
-
/\bgenes?\b/,
|
|
419
|
-
/\bvariante?s?\b/,
|
|
420
|
-
/\bexons?\b/,
|
|
421
|
-
/\bzygosity\b/,
|
|
422
|
-
/\bzigosidade\b/,
|
|
423
|
-
/\balleles?\b/,
|
|
424
|
-
/\balelos?\b/,
|
|
425
|
-
/\bmutations?\b/,
|
|
426
|
-
/\bmutac(ao|oes)\b/,
|
|
427
|
-
/\bpathogenic/,
|
|
428
|
-
/\bpatogenic/,
|
|
429
|
-
/\bheterozyg/,
|
|
430
|
-
/\bhomozyg/,
|
|
431
|
-
/\bheterozigot/,
|
|
432
|
-
/\bhomozigot/,
|
|
433
|
-
/\bsequence change\b/
|
|
434
|
-
];
|
|
435
455
|
var DIGIT_PATTERN = /\d/;
|
|
436
456
|
var cachedUnitTokens = null;
|
|
437
457
|
function getUnitTokens() {
|
|
438
458
|
if (!cachedUnitTokens) {
|
|
459
|
+
const isExamName = (t) => URINALYSIS_SECTION_NAMES.has(t) || getNamePatterns().has(t);
|
|
439
460
|
cachedUnitTokens = new Set(
|
|
440
|
-
Object.keys(_fhir.UNIT_TO_UCUM).map((unit) => normalize(unit).trim()).filter(
|
|
461
|
+
Object.keys(_fhir.UNIT_TO_UCUM).map((unit) => normalize(unit).trim()).filter((unit) => unit && !isExamName(unit))
|
|
441
462
|
);
|
|
442
463
|
}
|
|
443
464
|
return cachedUnitTokens;
|