med-pdf-nmo 0.1.0
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 +298 -0
- package/README.ru.md +298 -0
- package/dist/bm25.d.ts +47 -0
- package/dist/bm25.js +86 -0
- package/dist/browser-shims/buffer.d.ts +30 -0
- package/dist/browser-shims/buffer.js +31 -0
- package/dist/browser-shims/crypto.d.ts +33 -0
- package/dist/browser-shims/crypto.js +45 -0
- package/dist/browser-shims/fs-promises.d.ts +13 -0
- package/dist/browser-shims/fs-promises.js +25 -0
- package/dist/browser-shims/fs.d.ts +14 -0
- package/dist/browser-shims/fs.js +24 -0
- package/dist/browser-shims/globals.d.ts +9 -0
- package/dist/browser-shims/globals.js +23 -0
- package/dist/browser-shims/path.d.ts +57 -0
- package/dist/browser-shims/path.js +65 -0
- package/dist/browser-shims/process.d.ts +22 -0
- package/dist/browser-shims/process.js +27 -0
- package/dist/browser.d.ts +9 -0
- package/dist/browser.js +12 -0
- package/dist/chunk.d.ts +15 -0
- package/dist/chunk.js +76 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +87 -0
- package/dist/index.d.ts +82 -0
- package/dist/index.js +51 -0
- package/dist/med-pdf-nmo.browser.js +40413 -0
- package/dist/med-pdf-nmo.browser.mjs +40395 -0
- package/dist/normalize.d.ts +73 -0
- package/dist/normalize.js +477 -0
- package/dist/pdf.d.ts +35 -0
- package/dist/pdf.js +396 -0
- package/dist/predictor/config.d.ts +28 -0
- package/dist/predictor/config.js +26 -0
- package/dist/predictor/constants.d.ts +3 -0
- package/dist/predictor/constants.js +59 -0
- package/dist/predictor/runtime.d.ts +15 -0
- package/dist/predictor/runtime.js +59 -0
- package/dist/predictor/scorers/biomedical-symbols.d.ts +36 -0
- package/dist/predictor/scorers/biomedical-symbols.js +347 -0
- package/dist/predictor/scorers/coordinate-table.d.ts +82 -0
- package/dist/predictor/scorers/coordinate-table.js +1210 -0
- package/dist/predictor/scorers/direction.d.ts +71 -0
- package/dist/predictor/scorers/direction.js +345 -0
- package/dist/predictor/scorers/drug-dose.d.ts +6 -0
- package/dist/predictor/scorers/drug-dose.js +221 -0
- package/dist/predictor/scorers/exact-answer.d.ts +10 -0
- package/dist/predictor/scorers/exact-answer.js +75 -0
- package/dist/predictor/scorers/fibrosis-stage.d.ts +6 -0
- package/dist/predictor/scorers/fibrosis-stage.js +103 -0
- package/dist/predictor/scorers/focused.d.ts +40 -0
- package/dist/predictor/scorers/focused.js +204 -0
- package/dist/predictor/scorers/frequency.d.ts +10 -0
- package/dist/predictor/scorers/frequency.js +203 -0
- package/dist/predictor/scorers/numeric.d.ts +77 -0
- package/dist/predictor/scorers/numeric.js +1161 -0
- package/dist/predictor/scorers/recommendation-item.d.ts +27 -0
- package/dist/predictor/scorers/recommendation-item.js +469 -0
- package/dist/predictor/scorers/search.d.ts +41 -0
- package/dist/predictor/scorers/search.js +515 -0
- package/dist/predictor/selection.d.ts +30 -0
- package/dist/predictor/selection.js +370 -0
- package/dist/predictor/text-utils.d.ts +49 -0
- package/dist/predictor/text-utils.js +497 -0
- package/dist/predictor/types.d.ts +23 -0
- package/dist/predictor/types.js +1 -0
- package/dist/predictor.d.ts +52 -0
- package/dist/predictor.js +3834 -0
- package/package.json +82 -0
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
import { coverage, normalizeForSearch, tokenize, uniqueTokens } from "../../normalize.js";
|
|
2
|
+
import { betterEvidence, cachedPageTokens, containsNormalizedPhrase, evidenceSnippet, tokenizeNormalized, tokenHitCount, } from "../text-utils.js";
|
|
3
|
+
const OCR_LATIN_MAP = new Map(Object.entries({
|
|
4
|
+
А: "a",
|
|
5
|
+
В: "b",
|
|
6
|
+
Е: "e",
|
|
7
|
+
К: "k",
|
|
8
|
+
М: "m",
|
|
9
|
+
Н: "h",
|
|
10
|
+
О: "o",
|
|
11
|
+
Р: "p",
|
|
12
|
+
С: "c",
|
|
13
|
+
Т: "t",
|
|
14
|
+
У: "y",
|
|
15
|
+
Х: "x",
|
|
16
|
+
а: "a",
|
|
17
|
+
в: "b",
|
|
18
|
+
е: "e",
|
|
19
|
+
к: "k",
|
|
20
|
+
м: "m",
|
|
21
|
+
н: "h",
|
|
22
|
+
о: "o",
|
|
23
|
+
р: "p",
|
|
24
|
+
с: "c",
|
|
25
|
+
т: "t",
|
|
26
|
+
у: "y",
|
|
27
|
+
х: "x",
|
|
28
|
+
Б: "b",
|
|
29
|
+
Г: "r",
|
|
30
|
+
Д: "d",
|
|
31
|
+
З: "z",
|
|
32
|
+
И: "n",
|
|
33
|
+
Й: "n",
|
|
34
|
+
Л: "l",
|
|
35
|
+
П: "n",
|
|
36
|
+
Ф: "f",
|
|
37
|
+
Ц: "c",
|
|
38
|
+
Ч: "y",
|
|
39
|
+
Ш: "w",
|
|
40
|
+
Щ: "w",
|
|
41
|
+
Ы: "h",
|
|
42
|
+
Ь: "b",
|
|
43
|
+
Ъ: "b",
|
|
44
|
+
Ю: "io",
|
|
45
|
+
Я: "r",
|
|
46
|
+
б: "b",
|
|
47
|
+
г: "r",
|
|
48
|
+
д: "d",
|
|
49
|
+
з: "z",
|
|
50
|
+
и: "n",
|
|
51
|
+
й: "n",
|
|
52
|
+
л: "l",
|
|
53
|
+
п: "n",
|
|
54
|
+
ф: "f",
|
|
55
|
+
ц: "c",
|
|
56
|
+
ч: "y",
|
|
57
|
+
ш: "w",
|
|
58
|
+
щ: "w",
|
|
59
|
+
ы: "h",
|
|
60
|
+
ь: "b",
|
|
61
|
+
ъ: "b",
|
|
62
|
+
ю: "io",
|
|
63
|
+
я: "r",
|
|
64
|
+
"§": "g",
|
|
65
|
+
"%": "g",
|
|
66
|
+
}));
|
|
67
|
+
/**
|
|
68
|
+
* Возвращает короткие латинские/буквенно-цифровые токены из варианта ответа:
|
|
69
|
+
* гены, маркеры, коды и похожие biomedical-обозначения.
|
|
70
|
+
*/
|
|
71
|
+
export function latinAnswerTokens(text) {
|
|
72
|
+
return String(text ?? "").match(/[A-Za-z][A-Za-z0-9-]{1,}/g) ?? [];
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Генерирует безопасные варианты написания латинского токена без медицинских
|
|
76
|
+
* знаний: чистая форма и несколько частых OCR/типографских сокращений.
|
|
77
|
+
*/
|
|
78
|
+
function latinTokenVariants(token) {
|
|
79
|
+
const normalized = token.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
80
|
+
const variants = new Set([normalized]);
|
|
81
|
+
const th = normalized.match(/^th(\d+)$/);
|
|
82
|
+
if (th) {
|
|
83
|
+
if (th[1] === "1")
|
|
84
|
+
variants.add("th");
|
|
85
|
+
variants.add(`th${th[1].slice(-1)}`);
|
|
86
|
+
}
|
|
87
|
+
return [...variants].filter(Boolean);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Расширяет латинский gene-token набором OCR-подмен, которые часто возникают
|
|
91
|
+
* при смешении кириллицы, латиницы и цифр в PDF.
|
|
92
|
+
*/
|
|
93
|
+
function geneTokenVariants(token) {
|
|
94
|
+
const normalized = token.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
95
|
+
const variants = new Set(latinTokenVariants(normalized));
|
|
96
|
+
if (!normalized || normalized.length > 10)
|
|
97
|
+
return [...variants].filter(Boolean);
|
|
98
|
+
const alternatives = {
|
|
99
|
+
f: ["f", "p"],
|
|
100
|
+
g: ["g", "o", "q"],
|
|
101
|
+
r: ["r", "k"],
|
|
102
|
+
o: ["o", "0"],
|
|
103
|
+
d: ["d", "0"],
|
|
104
|
+
z: ["z", "3"],
|
|
105
|
+
3: ["3", "z"],
|
|
106
|
+
b: ["b", "8"],
|
|
107
|
+
s: ["s", "5"],
|
|
108
|
+
l: ["l", "1", "i"],
|
|
109
|
+
i: ["i", "1", "l"],
|
|
110
|
+
};
|
|
111
|
+
let generated = [""];
|
|
112
|
+
for (const char of normalized) {
|
|
113
|
+
const choices = alternatives[char] ?? [char];
|
|
114
|
+
const next = [];
|
|
115
|
+
for (const prefix of generated) {
|
|
116
|
+
for (const choice of choices) {
|
|
117
|
+
next.push(`${prefix}${choice}`);
|
|
118
|
+
if (next.length >= 96)
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
if (next.length >= 96)
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
generated = next;
|
|
125
|
+
}
|
|
126
|
+
for (const variant of generated)
|
|
127
|
+
variants.add(variant);
|
|
128
|
+
return [...variants].filter(Boolean);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Переводит визуально похожие кириллические символы в латинские аналоги и
|
|
132
|
+
* оставляет только буквы/цифры, чтобы сравнивать OCR-искаженные коды.
|
|
133
|
+
*/
|
|
134
|
+
function relaxedLatinText(text) {
|
|
135
|
+
let out = "";
|
|
136
|
+
for (const char of String(text ?? "").normalize("NFKC")) {
|
|
137
|
+
out += OCR_LATIN_MAP.get(char) ?? char;
|
|
138
|
+
}
|
|
139
|
+
return out.toLowerCase().replace(/[^a-z0-9]+/g, " ");
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Возвращает нормализованные латинские токены страницы и дополнительно склеивает
|
|
143
|
+
* случаи вида `N 0 0 2`, которые PDF extractor часто разрывает по символам.
|
|
144
|
+
*/
|
|
145
|
+
function relaxedLatinTokens(text) {
|
|
146
|
+
const rawTokens = relaxedLatinText(text).match(/[a-z0-9]+/g) ?? [];
|
|
147
|
+
const joined = [];
|
|
148
|
+
for (let index = 0; index < rawTokens.length - 1; index += 1) {
|
|
149
|
+
if (/^[a-z]+$/.test(rawTokens[index]) && /^\d+$/.test(rawTokens[index + 1]))
|
|
150
|
+
joined.push(`${rawTokens[index]}${rawTokens[index + 1]}`);
|
|
151
|
+
if (/^[a-z]{1,5}$/.test(rawTokens[index])) {
|
|
152
|
+
let digits = "";
|
|
153
|
+
for (let cursor = index + 1; cursor < rawTokens.length && cursor <= index + 5; cursor += 1) {
|
|
154
|
+
if (!/^\d$/.test(rawTokens[cursor]))
|
|
155
|
+
break;
|
|
156
|
+
digits += rawTokens[cursor];
|
|
157
|
+
if (digits.length >= 2)
|
|
158
|
+
joined.push(`${rawTokens[index]}${digits}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const tokens = rawTokens.filter((token) => token.length >= 2);
|
|
163
|
+
return [...tokens, ...joined];
|
|
164
|
+
}
|
|
165
|
+
/** Кеширует relaxed Latin tokens на странице, чтобы scorer'ы не пересчитывали OCR-формы. */
|
|
166
|
+
function cachedLatinTokens(page) {
|
|
167
|
+
if (!page.__latinTokens)
|
|
168
|
+
Object.defineProperty(page, "__latinTokens", { value: relaxedLatinTokens(page.text), enumerable: false });
|
|
169
|
+
return page.__latinTokens;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Считает мягкое сходство двух коротких латинских токенов по биграммам.
|
|
173
|
+
* Для очень коротких токенов намеренно используется только строгий prefix-match.
|
|
174
|
+
*/
|
|
175
|
+
function diceSimilarity(left, right) {
|
|
176
|
+
const a = String(left ?? "").toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
177
|
+
const b = String(right ?? "").toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
178
|
+
if (!a || !b)
|
|
179
|
+
return 0;
|
|
180
|
+
if (a === b)
|
|
181
|
+
return 1;
|
|
182
|
+
if (a.length <= 3 || b.length <= 3) {
|
|
183
|
+
if (/\d/.test(a) || /\d/.test(b))
|
|
184
|
+
return 0;
|
|
185
|
+
return a.startsWith(b) || b.startsWith(a) ? 0.72 : 0;
|
|
186
|
+
}
|
|
187
|
+
const counts = new Map();
|
|
188
|
+
for (let index = 0; index < a.length - 1; index += 1) {
|
|
189
|
+
const gram = a.slice(index, index + 2);
|
|
190
|
+
counts.set(gram, (counts.get(gram) ?? 0) + 1);
|
|
191
|
+
}
|
|
192
|
+
let hit = 0;
|
|
193
|
+
for (let index = 0; index < b.length - 1; index += 1) {
|
|
194
|
+
const gram = b.slice(index, index + 2);
|
|
195
|
+
const count = counts.get(gram) ?? 0;
|
|
196
|
+
if (count > 0) {
|
|
197
|
+
hit += 1;
|
|
198
|
+
counts.set(gram, count - 1);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return (2 * hit) / Math.max(1, a.length + b.length - 2);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Ищет OCR-поддержку латинского варианта ответа на релевантных страницах.
|
|
205
|
+
* Это общий fallback для коротких biomedical-кодов, а не медицинский словарь.
|
|
206
|
+
*/
|
|
207
|
+
export function bestLatinFuzzySupport({ pages, topQuestionPages, questionTokens, answer }) {
|
|
208
|
+
const latinTokens = latinAnswerTokens(answer.text);
|
|
209
|
+
if (!latinTokens.length)
|
|
210
|
+
return null;
|
|
211
|
+
let best = null;
|
|
212
|
+
for (const page of pages) {
|
|
213
|
+
if (topQuestionPages?.size && !topQuestionPages.has(page.page))
|
|
214
|
+
continue;
|
|
215
|
+
const questionCoverage = coverage(questionTokens, cachedPageTokens(page));
|
|
216
|
+
if (questionCoverage < 0.12)
|
|
217
|
+
continue;
|
|
218
|
+
const pageTokens = cachedLatinTokens(page);
|
|
219
|
+
if (!pageTokens.length)
|
|
220
|
+
continue;
|
|
221
|
+
let total = 0;
|
|
222
|
+
let strong = 0;
|
|
223
|
+
for (const token of latinTokens) {
|
|
224
|
+
let tokenBest = 0;
|
|
225
|
+
for (const variant of latinTokenVariants(token)) {
|
|
226
|
+
for (const pageToken of pageTokens) {
|
|
227
|
+
tokenBest = Math.max(tokenBest, diceSimilarity(variant, pageToken));
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (tokenBest >= 0.58)
|
|
231
|
+
strong += 1;
|
|
232
|
+
total += tokenBest;
|
|
233
|
+
}
|
|
234
|
+
const average = total / latinTokens.length;
|
|
235
|
+
if (average < 0.32 && strong < latinTokens.length)
|
|
236
|
+
continue;
|
|
237
|
+
const score = 4.2 + average * 5.0 + strong * 0.9 + questionCoverage * 2.0;
|
|
238
|
+
best = betterEvidence(best, {
|
|
239
|
+
answerId: answer.id,
|
|
240
|
+
page: page.page,
|
|
241
|
+
text: evidenceSnippet(page.text, latinTokens[0]),
|
|
242
|
+
score,
|
|
243
|
+
kind: "latin_fuzzy_ocr",
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
return best;
|
|
247
|
+
}
|
|
248
|
+
const GENE_QUESTION_GENERIC_TOKENS = new Set([
|
|
249
|
+
"\u0433\u0435\u043d",
|
|
250
|
+
"\u0433\u0435\u043d\u0430",
|
|
251
|
+
"\u0433\u0435\u043d\u0430\u0445",
|
|
252
|
+
"\u0433\u0435\u043d\u043e\u0432",
|
|
253
|
+
"\u043c\u0443\u0442\u0430\u0446\u0438\u044f",
|
|
254
|
+
"\u043c\u0443\u0442\u0430\u0446\u0438\u0438",
|
|
255
|
+
"\u043c\u0443\u0442\u0430\u0446\u0438\u0439",
|
|
256
|
+
"\u043f\u043e\u043b\u0438\u043c\u043e\u0440\u0444\u0438\u0437\u043c",
|
|
257
|
+
"\u043f\u043e\u043b\u0438\u043c\u043e\u0440\u0444\u0438\u0437\u043c\u044b",
|
|
258
|
+
"\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0442\u0441\u044f",
|
|
259
|
+
"\u0441\u0432\u044f\u0437\u044b\u0432\u0430\u044e\u0442",
|
|
260
|
+
"\u0440\u0438\u0441\u043a",
|
|
261
|
+
"\u0440\u0430\u0437\u0432\u0438\u0442\u0438\u044f",
|
|
262
|
+
].flatMap((item) => uniqueTokens(item)));
|
|
263
|
+
/**
|
|
264
|
+
* Проверяет, что вопрос действительно про мутации/полиморфизмы генов.
|
|
265
|
+
* Такой gate нужен, чтобы gene-specific OCR-логика не влияла на обычные вопросы.
|
|
266
|
+
*/
|
|
267
|
+
export function geneMutationQuestion(question) {
|
|
268
|
+
const normalized = normalizeForSearch(question);
|
|
269
|
+
const tokens = new Set(tokenize(question, { keepStopwords: true }));
|
|
270
|
+
const geneRoot = normalizeForSearch("\u0433\u0435\u043d");
|
|
271
|
+
const hasGeneToken = [...tokens].some((token) => token === geneRoot || token.startsWith(geneRoot));
|
|
272
|
+
const hasMutationCue = containsNormalizedPhrase(normalized, "\u043c\u0443\u0442\u0430\u0446") ||
|
|
273
|
+
containsNormalizedPhrase(normalized, "\u043f\u043e\u043b\u0438\u043c\u043e\u0440\u0444");
|
|
274
|
+
return hasGeneToken && hasMutationCue;
|
|
275
|
+
}
|
|
276
|
+
/** Оставляет из вопроса только негeneric-токены для привязки gene-предложения. */
|
|
277
|
+
function geneQuestionFocusTokens(question) {
|
|
278
|
+
return uniqueTokens(question).filter((token) => token.length >= 4 && !GENE_QUESTION_GENERIC_TOKENS.has(token));
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Делит текст PDF на достаточно длинные предложения. Для biomedical-symbol
|
|
282
|
+
* задач предложение часто надежнее широкого окна, потому что список генов
|
|
283
|
+
* обычно находится в одной фразе.
|
|
284
|
+
*/
|
|
285
|
+
export function sentenceSegments(text) {
|
|
286
|
+
return String(text ?? "")
|
|
287
|
+
.replace(/\s+/g, " ")
|
|
288
|
+
.split(/(?<=[.!?])\s+/u)
|
|
289
|
+
.map((segment) => segment.trim())
|
|
290
|
+
.filter((segment) => segment.length >= 24);
|
|
291
|
+
}
|
|
292
|
+
/** Возвращает точное или OCR-вариантное попадание gene-token в предложении. */
|
|
293
|
+
function geneSentenceHit(sentence, answerText) {
|
|
294
|
+
const answerTokens = latinAnswerTokens(answerText);
|
|
295
|
+
if (!answerTokens.length || answerTokens.length > 2)
|
|
296
|
+
return null;
|
|
297
|
+
const sentenceTokens = new Set(relaxedLatinTokens(sentence));
|
|
298
|
+
for (const token of answerTokens) {
|
|
299
|
+
let bestVariant = null;
|
|
300
|
+
for (const variant of geneTokenVariants(token)) {
|
|
301
|
+
if (sentenceTokens.has(variant)) {
|
|
302
|
+
bestVariant = variant;
|
|
303
|
+
break;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
if (bestVariant)
|
|
307
|
+
return { token, variant: bestVariant };
|
|
308
|
+
}
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Для вопросов про мутации генов выбирает предложение с фокусом вопроса и
|
|
313
|
+
* проверяет, есть ли в нем вариант ответа как латинский или OCR-искаженный код.
|
|
314
|
+
*/
|
|
315
|
+
export function bestGeneSentenceSupport({ pages, topQuestionPages, question, answer }) {
|
|
316
|
+
if (!geneMutationQuestion(question))
|
|
317
|
+
return null;
|
|
318
|
+
const focusTokens = geneQuestionFocusTokens(question);
|
|
319
|
+
let best = null;
|
|
320
|
+
for (const page of pages) {
|
|
321
|
+
const nearTopPage = !topQuestionPages?.size || topQuestionPages.has(page.page) || topQuestionPages.has(page.page - 1) || topQuestionPages.has(page.page + 1);
|
|
322
|
+
if (!nearTopPage)
|
|
323
|
+
continue;
|
|
324
|
+
for (const sentence of sentenceSegments(page.text)) {
|
|
325
|
+
const normalized = normalizeForSearch(sentence);
|
|
326
|
+
const hasGeneCue = containsNormalizedPhrase(normalized, "\u0433\u0435\u043d");
|
|
327
|
+
if (!hasGeneCue)
|
|
328
|
+
continue;
|
|
329
|
+
const sentenceTokens = tokenizeNormalized(normalized);
|
|
330
|
+
const focusHits = tokenHitCount(focusTokens, sentenceTokens);
|
|
331
|
+
if (focusTokens.length && focusHits <= 0)
|
|
332
|
+
continue;
|
|
333
|
+
const hit = geneSentenceHit(sentence, answer.text);
|
|
334
|
+
if (!hit)
|
|
335
|
+
continue;
|
|
336
|
+
const score = 13.6 + Math.min(3, focusHits) * 1.35 + (hit.variant === hit.token.toLowerCase() ? 2.2 : 1.4);
|
|
337
|
+
best = betterEvidence(best, {
|
|
338
|
+
answerId: answer.id,
|
|
339
|
+
page: page.page,
|
|
340
|
+
text: sentence,
|
|
341
|
+
score,
|
|
342
|
+
kind: "gene_sentence_segment",
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return best;
|
|
347
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Быстрый gate для coordinate-table scorer'ов: включает их только когда вопрос
|
|
3
|
+
* похож на таблицу, шкалу, классификацию, степень, стадию или числовой критерий.
|
|
4
|
+
*/
|
|
5
|
+
export declare function hasCoordinateTableCue(question: any, focusTokens: any): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Более широкий gate для multi-групп: кроме явных таблиц допускает list-like
|
|
8
|
+
* вопросы и формулировки про группы/состав/комбинации, где ответы часто живут
|
|
9
|
+
* в одной табличной строке.
|
|
10
|
+
*/
|
|
11
|
+
export declare function hasCoordinateTableGroupCue(question: any, focusTokens: any, intent: any): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Строит по страницам обычные coordinate rows: строка PDF разбивается на
|
|
14
|
+
* x-ячейки, рядом лежащие continuation-строки приклеиваются к базовой строке.
|
|
15
|
+
*/
|
|
16
|
+
export declare function buildCoordinateTableRowsByPage(pages: any, topQuestionPages: any): Map<any, any>;
|
|
17
|
+
/**
|
|
18
|
+
* Строит группы вида `левая метка -> правые значения` для multi-вопросов, где
|
|
19
|
+
* несколько правильных вариантов перечислены в одной строке или ее продолжениях.
|
|
20
|
+
*/
|
|
21
|
+
export declare function buildCoordinateTableGroupsByPage(pages: any, topQuestionPages: any): Map<any, any>;
|
|
22
|
+
/**
|
|
23
|
+
* Строит multi-cell rows для таблиц, где одна строка содержит несколько
|
|
24
|
+
* самостоятельных значений/кандидатов, связанных общей меткой и заголовком.
|
|
25
|
+
*/
|
|
26
|
+
export declare function buildCoordinateMultiCellRowsByPage(pages: any, topQuestionPages: any): Map<any, any>;
|
|
27
|
+
/**
|
|
28
|
+
* Строит membership-блоки явных таблиц. В отличие от row-scorer'ов, этот слой
|
|
29
|
+
* отвечает на вопрос "входит ли вариант в релевантную таблицу целиком".
|
|
30
|
+
*/
|
|
31
|
+
export declare function buildCoordinateTableMembershipsByPage(pages: any, topQuestionPages: any): Map<any, any>;
|
|
32
|
+
/**
|
|
33
|
+
* Ищет multi-вариант внутри тела явной таблицы, caption/заголовок которой
|
|
34
|
+
* совпадает с фокусом вопроса. Это помогает полным table-list вопросам, где
|
|
35
|
+
* несколько правильных ответов находятся в разных строках одной таблицы.
|
|
36
|
+
*/
|
|
37
|
+
export declare function bestCoordinateTableMembershipSupport({ mode, question, answer, answers, answerTokens, focusTokens, intent, coordinateTableMembershipsByPage, }: {
|
|
38
|
+
mode: any;
|
|
39
|
+
question: any;
|
|
40
|
+
answer: any;
|
|
41
|
+
answers: any;
|
|
42
|
+
answerTokens: any;
|
|
43
|
+
focusTokens: any;
|
|
44
|
+
intent: any;
|
|
45
|
+
coordinateTableMembershipsByPage: any;
|
|
46
|
+
}): any;
|
|
47
|
+
/**
|
|
48
|
+
* Оценивает single-answer поддержку из coordinate row: вариант должен совпасть
|
|
49
|
+
* с конкретной ячейкой, а соседние ячейки/заголовок должны объяснять фокус вопроса.
|
|
50
|
+
*/
|
|
51
|
+
export declare function bestCoordinateTableRowSupport({ mode, question, answer, answerTokens, focusTokens, coordinateTableRowsByPage, }: {
|
|
52
|
+
mode: any;
|
|
53
|
+
question: any;
|
|
54
|
+
answer: any;
|
|
55
|
+
answerTokens: any;
|
|
56
|
+
focusTokens: any;
|
|
57
|
+
coordinateTableRowsByPage: any;
|
|
58
|
+
}): any;
|
|
59
|
+
/**
|
|
60
|
+
* Оценивает multi-answer поддержку из явной табличной группы и допускает
|
|
61
|
+
* обратное связывание `value -> label`, когда значение находится в вопросе.
|
|
62
|
+
*/
|
|
63
|
+
export declare function bestCoordinateTableGroupSupport({ mode, question, answer, answerTokens, focusTokens, coordinateTableGroupsByPage, }: {
|
|
64
|
+
mode: any;
|
|
65
|
+
question: any;
|
|
66
|
+
answer: any;
|
|
67
|
+
answerTokens: any;
|
|
68
|
+
focusTokens: any;
|
|
69
|
+
coordinateTableGroupsByPage: any;
|
|
70
|
+
}): any;
|
|
71
|
+
/**
|
|
72
|
+
* Оценивает multi-cell row, где правильный ответ может находиться в любой
|
|
73
|
+
* ячейке строки, но строка должна быть привязана к фокусу вопроса и заголовку.
|
|
74
|
+
*/
|
|
75
|
+
export declare function bestCoordinateMultiCellRowSupport({ mode, question, answer, answerTokens, focusTokens, coordinateMultiCellRowsByPage, }: {
|
|
76
|
+
mode: any;
|
|
77
|
+
question: any;
|
|
78
|
+
answer: any;
|
|
79
|
+
answerTokens: any;
|
|
80
|
+
focusTokens: any;
|
|
81
|
+
coordinateMultiCellRowsByPage: any;
|
|
82
|
+
}): any;
|