med-pdf-nmo 0.1.0 → 0.1.2
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 +1 -0
- package/README.ru.md +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -1
- package/dist/med-pdf-nmo.browser.js +739 -91
- package/dist/med-pdf-nmo.browser.mjs +739 -91
- package/dist/pdf.d.ts +1 -1
- package/dist/pdf.js +7 -1
- package/dist/predictor/config.d.ts +2 -0
- package/dist/predictor/config.js +2 -0
- package/dist/predictor/scorer-registry.d.ts +28 -0
- package/dist/predictor/scorer-registry.js +290 -0
- package/dist/predictor/scorers/direction.d.ts +22 -0
- package/dist/predictor/scorers/direction.js +134 -0
- package/dist/predictor/scorers/drug-dose.js +36 -3
- package/dist/predictor/scorers/option-family.d.ts +59 -0
- package/dist/predictor/scorers/option-family.js +201 -0
- package/dist/predictor/scorers/recommendation-item.d.ts +12 -0
- package/dist/predictor/scorers/recommendation-item.js +63 -1
- package/dist/predictor/selection.js +1 -44
- package/dist/predictor.js +351 -37
- package/package.json +1 -1
|
@@ -32079,6 +32079,10 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
32079
32079
|
);
|
|
32080
32080
|
}
|
|
32081
32081
|
}
|
|
32082
|
+
function pdfVerbosity(pdfjs, options = {}) {
|
|
32083
|
+
if (typeof options.pdfVerbosity === "number") return options.pdfVerbosity;
|
|
32084
|
+
return pdfjs.VerbosityLevel?.ERRORS ?? 0;
|
|
32085
|
+
}
|
|
32082
32086
|
async function toUint8Array(input) {
|
|
32083
32087
|
if (input instanceof Uint8Array) {
|
|
32084
32088
|
return new Uint8Array(input.buffer.slice(input.byteOffset, input.byteOffset + input.byteLength));
|
|
@@ -32277,7 +32281,8 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
32277
32281
|
data,
|
|
32278
32282
|
disableWorker: true,
|
|
32279
32283
|
useSystemFonts: true,
|
|
32280
|
-
isEvalSupported: false
|
|
32284
|
+
isEvalSupported: false,
|
|
32285
|
+
verbosity: pdfVerbosity(pdfjs, options)
|
|
32281
32286
|
});
|
|
32282
32287
|
const pdf = await loadingTask.promise;
|
|
32283
32288
|
const pages = [];
|
|
@@ -32396,6 +32401,8 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
32396
32401
|
singleTieSpecificityGap: 0.5,
|
|
32397
32402
|
sharedMultiSegmentBoost: true,
|
|
32398
32403
|
countRelationBoost: true,
|
|
32404
|
+
optionFamilyComparatorGuard: true,
|
|
32405
|
+
optionFamilyCompactComboGuard: true,
|
|
32399
32406
|
topQuestionChunks: 28,
|
|
32400
32407
|
evidenceLimit: 8
|
|
32401
32408
|
};
|
|
@@ -32576,6 +32583,100 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
32576
32583
|
keyedRuntimeCache.clear();
|
|
32577
32584
|
}
|
|
32578
32585
|
|
|
32586
|
+
// src/predictor/scorer-registry.ts
|
|
32587
|
+
var SELECTION_STRUCTURAL_EVIDENCE_WEIGHTS_RECORD = {
|
|
32588
|
+
coordinate_table_row: 1.25,
|
|
32589
|
+
coordinate_table_group: 1.25,
|
|
32590
|
+
coordinate_table_group_inverse: 1.25,
|
|
32591
|
+
coordinate_table_multicell_row: 1.25,
|
|
32592
|
+
coordinate_table_membership: 1.15,
|
|
32593
|
+
parenthetical_group_segment: 1.05,
|
|
32594
|
+
preceding_question_label: 1.05,
|
|
32595
|
+
question_continuation_list: 1.05,
|
|
32596
|
+
exact_numeric_option_segment: 1.05,
|
|
32597
|
+
exact_hour_alias_segment: 1.05,
|
|
32598
|
+
short_medical_alias_segment: 0.9,
|
|
32599
|
+
visual_table_column: 1.2,
|
|
32600
|
+
exact_short_label_visual_row: 1.15,
|
|
32601
|
+
short_label_visual_row: 1.05,
|
|
32602
|
+
answer_ordinal_row: 1.05,
|
|
32603
|
+
fibrosis_stage_row: 1.2,
|
|
32604
|
+
gene_sentence_segment: 1.1,
|
|
32605
|
+
clinical_feature_segment: 1,
|
|
32606
|
+
mkb_class_exclusion_absent: 1,
|
|
32607
|
+
classification_code_segment: 1.15,
|
|
32608
|
+
label_number_proximity: 1,
|
|
32609
|
+
label_definition_segment: 1,
|
|
32610
|
+
definition_exact_answer_segment: 1,
|
|
32611
|
+
definition_completion_specificity: 0.95,
|
|
32612
|
+
row_label_segment: 0.95,
|
|
32613
|
+
bounded_list_segment: 0.95,
|
|
32614
|
+
ordinal_list_segment: 0.9,
|
|
32615
|
+
drug_dose_segment: 0.9,
|
|
32616
|
+
frequency_polarity_segment: 0.9,
|
|
32617
|
+
frequency_polarity_list_item: 0.95,
|
|
32618
|
+
clinical_course_cue_segment: 0.9,
|
|
32619
|
+
recommendation_block_segment: 0.85,
|
|
32620
|
+
recommendation_item_segment: 0.85,
|
|
32621
|
+
explicit_recommendation_target_segment: 0.85,
|
|
32622
|
+
numeric_condition_less_than: 0.85,
|
|
32623
|
+
numeric_condition_more_than: 0.85,
|
|
32624
|
+
numeric_condition_equal: 0.85,
|
|
32625
|
+
conditioned_number_segment: 0.8,
|
|
32626
|
+
cloze_gap_local: 0.8
|
|
32627
|
+
};
|
|
32628
|
+
var SELECTION_STRUCTURAL_EVIDENCE_WEIGHTS = new Map(Object.entries(SELECTION_STRUCTURAL_EVIDENCE_WEIGHTS_RECORD));
|
|
32629
|
+
var CONFIDENCE_STRUCTURAL_EVIDENCE_KINDS = /* @__PURE__ */ new Set([
|
|
32630
|
+
"coordinate_table_row",
|
|
32631
|
+
"coordinate_table_group",
|
|
32632
|
+
"coordinate_table_group_inverse",
|
|
32633
|
+
"coordinate_table_multicell_row",
|
|
32634
|
+
"coordinate_table_membership",
|
|
32635
|
+
"parenthetical_group_segment",
|
|
32636
|
+
"preceding_question_label",
|
|
32637
|
+
"question_continuation_list",
|
|
32638
|
+
"exact_numeric_option_segment",
|
|
32639
|
+
"exact_hour_alias_segment",
|
|
32640
|
+
"visual_table_column",
|
|
32641
|
+
"exact_short_label_visual_row",
|
|
32642
|
+
"short_label_visual_row",
|
|
32643
|
+
"answer_ordinal_row",
|
|
32644
|
+
"fibrosis_stage_row",
|
|
32645
|
+
"gene_sentence_segment",
|
|
32646
|
+
"clinical_feature_segment",
|
|
32647
|
+
"mkb_class_exclusion_absent",
|
|
32648
|
+
"classification_code_segment",
|
|
32649
|
+
"label_number_proximity",
|
|
32650
|
+
"label_definition_segment",
|
|
32651
|
+
"definition_exact_answer_segment",
|
|
32652
|
+
"definition_completion_specificity",
|
|
32653
|
+
"row_label_segment",
|
|
32654
|
+
"bounded_list_segment",
|
|
32655
|
+
"ordinal_list_segment",
|
|
32656
|
+
"drug_dose_segment",
|
|
32657
|
+
"frequency_polarity_segment",
|
|
32658
|
+
"frequency_polarity_list_item",
|
|
32659
|
+
"clinical_course_cue_segment",
|
|
32660
|
+
"recommendation_block_segment",
|
|
32661
|
+
"recommendation_item_segment",
|
|
32662
|
+
"explicit_recommendation_target_segment",
|
|
32663
|
+
"numeric_condition_less_than",
|
|
32664
|
+
"numeric_condition_more_than",
|
|
32665
|
+
"numeric_condition_equal",
|
|
32666
|
+
"conditioned_number_segment",
|
|
32667
|
+
"cloze_gap_local"
|
|
32668
|
+
]);
|
|
32669
|
+
var BROAD_EVIDENCE_KINDS = /* @__PURE__ */ new Set([
|
|
32670
|
+
"bm25_question_answer",
|
|
32671
|
+
"question_chunk_answer",
|
|
32672
|
+
"answer_chunk_question",
|
|
32673
|
+
"answer_window",
|
|
32674
|
+
"focused_answer_window",
|
|
32675
|
+
"shared_multi_segment"
|
|
32676
|
+
]);
|
|
32677
|
+
var DIAGNOSTIC_BROAD_EVIDENCE_KINDS = /* @__PURE__ */ new Set([...BROAD_EVIDENCE_KINDS, "answer_directional_window"]);
|
|
32678
|
+
var NOISY_SHARED_EVIDENCE_KINDS = /* @__PURE__ */ new Set(["question_chunk_answer", "bm25_question_answer", "shared_multi_segment"]);
|
|
32679
|
+
|
|
32579
32680
|
// src/predictor/text-utils.ts
|
|
32580
32681
|
function nearestCueName(local, entries) {
|
|
32581
32682
|
const center = Math.floor(local.length / 2);
|
|
@@ -32991,6 +33092,11 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
32991
33092
|
"\u0434\u043E\u0437\u0430",
|
|
32992
33093
|
"\u0434\u043E\u0437\u044B",
|
|
32993
33094
|
"\u0434\u043E\u0437\u0435",
|
|
33095
|
+
"\u0440\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u0443\u0435\u043C\u0430\u044F",
|
|
33096
|
+
"\u0440\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u0443\u0435\u043C\u044B\u0439",
|
|
33097
|
+
"\u0440\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u0443\u0435\u0442\u0441\u044F",
|
|
33098
|
+
"\u043D\u0430\u0437\u043D\u0430\u0447\u0430\u0435\u0442\u0441\u044F",
|
|
33099
|
+
"\u043D\u0430\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435",
|
|
32994
33100
|
"\u043F\u0440\u0438",
|
|
32995
33101
|
"\u043B\u0435\u0447\u0435\u043D\u0438\u0438",
|
|
32996
33102
|
"\u043B\u0435\u0447\u0435\u043D\u0438\u044F",
|
|
@@ -33054,7 +33160,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
33054
33160
|
}
|
|
33055
33161
|
function doseSlashNumbers(sourceText, drugTokens) {
|
|
33056
33162
|
const out = [];
|
|
33057
|
-
const slashPattern = /(\d+(?:[.,]\d+)?)\s*\/\s*(\d+(?:[.,]\d+)?)\s
|
|
33163
|
+
const slashPattern = /(\d+(?:[.,]\d+)?)\s*\/\s*(\d+(?:[.,]\d+)?)\s*[\u006d\u043c]\u0433/giu;
|
|
33058
33164
|
for (const match of sourceText.matchAll(slashPattern)) {
|
|
33059
33165
|
const rawIndex = match.index ?? 0;
|
|
33060
33166
|
const beforeText = sourceText.slice(Math.max(0, rawIndex - 150), rawIndex);
|
|
@@ -33083,7 +33189,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
33083
33189
|
if (drugIndex < 0) return [];
|
|
33084
33190
|
const local = normalized.slice(drugIndex, Math.min(normalized.length, drugIndex + 95));
|
|
33085
33191
|
if (!containsNormalizedPhrase(local, "\u043C\u0433")) return [];
|
|
33086
|
-
if (/\d+(?:[.,]\d+)?\s*\/\s*\d+(?:[.,]\d+)?\s*
|
|
33192
|
+
if (/\d+(?:[.,]\d+)?\s*\/\s*\d+(?:[.,]\d+)?\s*[\u006d\u043c][\u0433g]/iu.test(local)) return [];
|
|
33087
33193
|
const firstNumber = local.match(/\d+(?:[.,]\d+)?/u);
|
|
33088
33194
|
if (!firstNumber || (firstNumber.index ?? 0) > 55) return [];
|
|
33089
33195
|
if (local.slice(0, firstNumber.index ?? 0).includes("+")) return [];
|
|
@@ -33097,6 +33203,21 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
33097
33203
|
if (hasOtherDrugMarker) return [];
|
|
33098
33204
|
return extractNumbers(local).slice(0, 2).map((number) => String(number).replace(",", "."));
|
|
33099
33205
|
}
|
|
33206
|
+
function doseAssignedToDrugNumbers(sourceText, drugTokens) {
|
|
33207
|
+
const normalized = normalizeForSearch(sourceText);
|
|
33208
|
+
const out = [];
|
|
33209
|
+
const dosePattern = /(\d+(?:[.,]\d+)?)\s*[\u006d\u043c]\u0433/giu;
|
|
33210
|
+
for (const match of normalized.matchAll(dosePattern)) {
|
|
33211
|
+
const index = match.index ?? 0;
|
|
33212
|
+
if (normalized.slice(Math.max(0, index - 2), index).includes("/")) continue;
|
|
33213
|
+
const afterWindow = normalized.slice(index + match[0].length, Math.min(normalized.length, index + match[0].length + 70));
|
|
33214
|
+
const boundary = afterWindow.search(/[+.]|(?:^|\s)o\s|\s\d+(?:[.,]\d+)?\s*[\u0440p]\s*\/?\s*\u0434/u);
|
|
33215
|
+
const after = boundary >= 0 ? afterWindow.slice(0, boundary) : afterWindow;
|
|
33216
|
+
if (softCoverage(drugTokens, tokenizeNormalized(after)) < 0.8) continue;
|
|
33217
|
+
out.push(normalizeDoseNumber(match[1]));
|
|
33218
|
+
}
|
|
33219
|
+
return out;
|
|
33220
|
+
}
|
|
33100
33221
|
function normalizeDoseNumber(value) {
|
|
33101
33222
|
return String(value ?? "").replace(",", ".").replace(/\.0$/u, "");
|
|
33102
33223
|
}
|
|
@@ -33115,12 +33236,22 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
33115
33236
|
const normalized = normalizeForSearch(sourceText);
|
|
33116
33237
|
const drugIndex = drugTokenIndex(normalized, drugTokens);
|
|
33117
33238
|
if (drugIndex < 0) return [];
|
|
33239
|
+
const assignedNumbers = doseAssignedToDrugNumbers(sourceText, drugTokens);
|
|
33240
|
+
if (assignedNumbers.length) {
|
|
33241
|
+
return assignedNumbers.map((number) => ({ dose: number, doseRange: null, frequency: null }));
|
|
33242
|
+
}
|
|
33118
33243
|
const local = normalized.slice(drugIndex, Math.min(normalized.length, drugIndex + 125));
|
|
33119
33244
|
const facts = [];
|
|
33245
|
+
const slashNumbers = doseSlashNumbers(sourceText, drugTokens);
|
|
33246
|
+
if (slashNumbers.length) {
|
|
33247
|
+
return slashNumbers.map((number) => ({ dose: normalizeDoseNumber(number), doseRange: null, frequency: null }));
|
|
33248
|
+
}
|
|
33120
33249
|
const dosePattern = /(\d+(?:[.,]\d+)?)(?:\s*-\s*(\d+(?:[.,]\d+)?))?\s*[\u006d\u043c]\u0433(?:\s*[\u0078\u0445]\s*(\d+(?:[.,]\d+)?))?/giu;
|
|
33121
33250
|
for (const match of local.matchAll(dosePattern)) {
|
|
33122
33251
|
const index = match.index ?? 0;
|
|
33123
33252
|
if (index > 80) continue;
|
|
33253
|
+
const beforeNumber = local.slice(0, index).replace(/\s+$/u, "");
|
|
33254
|
+
if (beforeNumber.endsWith("/")) continue;
|
|
33124
33255
|
facts.push({
|
|
33125
33256
|
dose: normalizeDoseNumber(match[2] ?? match[1]),
|
|
33126
33257
|
doseRange: match[2] ? [normalizeDoseNumber(match[1]), normalizeDoseNumber(match[2])] : null,
|
|
@@ -33128,7 +33259,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
33128
33259
|
});
|
|
33129
33260
|
break;
|
|
33130
33261
|
}
|
|
33131
|
-
for (const number of
|
|
33262
|
+
for (const number of doseNearDrugNumbers(sourceText, drugTokens)) {
|
|
33132
33263
|
facts.push({ dose: normalizeDoseNumber(number), doseRange: null, frequency: null });
|
|
33133
33264
|
}
|
|
33134
33265
|
return facts;
|
|
@@ -35267,6 +35398,220 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
35267
35398
|
}
|
|
35268
35399
|
return best;
|
|
35269
35400
|
}
|
|
35401
|
+
function broadRecommendationQuestion(question) {
|
|
35402
|
+
const normalized = normalizeForSearch(question);
|
|
35403
|
+
return containsNormalizedPhrase(normalized, "\u0440\u0435\u043A\u043E\u043C\u0435\u043D\u0434") || containsNormalizedPhrase(normalized, "\u043D\u0430\u0437\u043D\u0430\u0447") || containsNormalizedPhrase(normalized, "\u043F\u0440\u043E\u0432\u043E\u0434") || containsNormalizedPhrase(normalized, "\u043B\u0435\u0447\u0435\u043D") || containsNormalizedPhrase(normalized, "\u0442\u0435\u0440\u0430\u043F") || containsNormalizedPhrase(normalized, "\u043F\u0440\u043E\u0444\u0438\u043B\u0430\u043A\u0442");
|
|
35404
|
+
}
|
|
35405
|
+
function recommendationCueSegment(segmentNorm) {
|
|
35406
|
+
return containsNormalizedPhrase(segmentNorm, "\u0440\u0435\u043A\u043E\u043C\u0435\u043D\u0434") || containsNormalizedPhrase(segmentNorm, "\u043D\u0430\u0437\u043D\u0430\u0447") || containsNormalizedPhrase(segmentNorm, "\u043F\u0440\u043E\u0432\u043E\u0434") || containsNormalizedPhrase(segmentNorm, "\u043F\u0440\u0438\u043C\u0435\u043D");
|
|
35407
|
+
}
|
|
35408
|
+
function bestRecommendationBlockSupport({ mode, pages, topQuestionPages, question, answer, answerTokens }) {
|
|
35409
|
+
if (mode !== "multi") return null;
|
|
35410
|
+
if (!broadRecommendationQuestion(question)) return null;
|
|
35411
|
+
const questionNorm = normalizeForSearch(question);
|
|
35412
|
+
if (containsNormalizedPhrase(questionNorm, "\u043D\u0430\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435")) return null;
|
|
35413
|
+
const qTokens = recommendationQuestionTokens(question);
|
|
35414
|
+
if (qTokens.length < 3) return null;
|
|
35415
|
+
let best = null;
|
|
35416
|
+
for (const segment of recommendationSegments(pages)) {
|
|
35417
|
+
if (topQuestionPages?.size && !topQuestionPages.has(segment.page)) continue;
|
|
35418
|
+
if (!recommendationCueSegment(segment.normalized)) continue;
|
|
35419
|
+
if (recommendationPresenceMismatch(answer.text, segment.normalized)) continue;
|
|
35420
|
+
const segmentTokens = tokenizeNormalized(segment.normalized);
|
|
35421
|
+
const qCoverage = recommendationQuestionCoverage(questionNorm, qTokens, segment.normalized);
|
|
35422
|
+
const qHits = tokenHitCount(qTokens, segmentTokens);
|
|
35423
|
+
if (qCoverage < 0.54 || qHits < Math.min(4, qTokens.length)) continue;
|
|
35424
|
+
const answerHit = recommendationSegmentAnswerHit(answer, answerTokens, segment.normalized, segmentTokens);
|
|
35425
|
+
if (!answerHit.supportHit) continue;
|
|
35426
|
+
const score = 12.4 + Math.min(1, qCoverage) * 4.6 + Math.min(5, qHits) * 0.7 + answerHit.answerCoverage * 4.8 + answerHit.numericCoverage * 1.8 + (answerHit.strongPhraseHit ? 2.4 : answerHit.phraseHit ? 1.2 : 0);
|
|
35427
|
+
best = betterEvidence(best, {
|
|
35428
|
+
answerId: answer.id,
|
|
35429
|
+
page: segment.page,
|
|
35430
|
+
text: segment.text,
|
|
35431
|
+
score,
|
|
35432
|
+
kind: "recommendation_block_segment"
|
|
35433
|
+
});
|
|
35434
|
+
}
|
|
35435
|
+
return best;
|
|
35436
|
+
}
|
|
35437
|
+
|
|
35438
|
+
// src/predictor/scorers/option-family.ts
|
|
35439
|
+
var LESS_CUES = ["\u0434\u043E", "\u043C\u0435\u043D\u0435\u0435", "\u043C\u0435\u043D\u044C\u0448\u0435", "\u043D\u0438\u0436\u0435", "\u043C\u043E\u043B\u043E\u0436\u0435"].map(
|
|
35440
|
+
(item) => normalizeForSearch(item)
|
|
35441
|
+
);
|
|
35442
|
+
var GREATER_CUES = ["\u0431\u043E\u043B\u0435\u0435", "\u0431\u043E\u043B\u044C\u0448\u0435", "\u0432\u044B\u0448\u0435", "\u0441\u0432\u044B\u0448\u0435", "\u0441\u0442\u0430\u0440\u0448\u0435"].map(
|
|
35443
|
+
(item) => normalizeForSearch(item)
|
|
35444
|
+
);
|
|
35445
|
+
var COMBO_QUESTION_CUES = [
|
|
35446
|
+
"\u0440\u0435\u043A\u043E\u043C\u0435\u043D\u0434",
|
|
35447
|
+
"\u043D\u0430\u0437\u043D\u0430\u0447",
|
|
35448
|
+
"\u043F\u0440\u0438\u043C\u0435\u043D",
|
|
35449
|
+
"\u0442\u0435\u0440\u0430\u043F",
|
|
35450
|
+
"\u043B\u0435\u0447\u0435\u043D"
|
|
35451
|
+
].map((item) => normalizeForSearch(item));
|
|
35452
|
+
var COMBO_GENERIC_TOKENS = new Set(
|
|
35453
|
+
[
|
|
35454
|
+
"\u043C\u043E\u043D\u043E\u0442\u0435\u0440\u0430\u043F\u0438\u044F",
|
|
35455
|
+
"\u043C\u043E\u043D\u043E\u0442\u0435\u0440\u0430\u043F\u0438\u044E",
|
|
35456
|
+
"\u043A\u043E\u043C\u0431\u0438\u043D\u0430\u0446\u0438\u044F",
|
|
35457
|
+
"\u043A\u043E\u043C\u0431\u0438\u043D\u0430\u0446\u0438\u044E",
|
|
35458
|
+
"\u0438\u043B\u0438",
|
|
35459
|
+
"\u0433\u0440\u0443\u043F\u043F",
|
|
35460
|
+
"\u043F\u0440\u0435\u043F\u0430\u0440\u0430\u0442",
|
|
35461
|
+
"\u043D\u0430\u0437\u043D\u0430\u0447",
|
|
35462
|
+
"\u043F\u0440\u0438\u043C\u0435\u043D"
|
|
35463
|
+
].flatMap((item) => uniqueTokens(item))
|
|
35464
|
+
);
|
|
35465
|
+
var COMBO_UNIT_PARTS = /* @__PURE__ */ new Set(["m\u0433", "m\u043B", "k\u0433", "me", "mm", "m\u0438h", "cyt", "\u0434h", "pa\u0437", "mg", "ml", "kg"]);
|
|
35466
|
+
function answerComparatorSpecs(answerText) {
|
|
35467
|
+
const normalized = normalizeForSearch(answerText);
|
|
35468
|
+
const numbers = extractNumbers(answerText).map((number) => number.replace(",", "."));
|
|
35469
|
+
const specs = [];
|
|
35470
|
+
for (const number of numbers) {
|
|
35471
|
+
const escaped = number.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
35472
|
+
const lessPattern = new RegExp(`(?:<|\\b(?:${LESS_CUES.join("|")})\\b\\s*)${escaped}(?:\\b|\\s|%|$)`, "iu");
|
|
35473
|
+
const greaterPattern = new RegExp(`(?:>|\\b(?:${GREATER_CUES.join("|")})\\b\\s*)${escaped}(?:\\b|\\s|%|$)`, "iu");
|
|
35474
|
+
if (lessPattern.test(normalized)) specs.push({ number, direction: "less" });
|
|
35475
|
+
if (greaterPattern.test(normalized)) specs.push({ number, direction: "greater" });
|
|
35476
|
+
}
|
|
35477
|
+
return specs;
|
|
35478
|
+
}
|
|
35479
|
+
function opposite(direction) {
|
|
35480
|
+
return direction === "less" ? "greater" : "less";
|
|
35481
|
+
}
|
|
35482
|
+
function answerFamilyHasOppositeComparator(answer, answers, spec) {
|
|
35483
|
+
return answers.some((candidate) => {
|
|
35484
|
+
if (candidate.id === answer.id) return false;
|
|
35485
|
+
return answerComparatorSpecs(candidate.text).some((candidateSpec) => candidateSpec.number === spec.number && candidateSpec.direction === opposite(spec.direction));
|
|
35486
|
+
});
|
|
35487
|
+
}
|
|
35488
|
+
function sourceDirectionsForNumber(text, number) {
|
|
35489
|
+
const normalized = normalizeForSearch(text).replace(/\u2264/gu, "<").replace(/\u2265/gu, ">");
|
|
35490
|
+
const escaped = number.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
35491
|
+
const directions = /* @__PURE__ */ new Set();
|
|
35492
|
+
const pattern = new RegExp(escaped, "giu");
|
|
35493
|
+
for (const match of normalized.matchAll(pattern)) {
|
|
35494
|
+
const index = match.index ?? 0;
|
|
35495
|
+
const before = normalized.slice(Math.max(0, index - 26), index).trim();
|
|
35496
|
+
const after = normalized.slice(index + match[0].length, Math.min(normalized.length, index + match[0].length + 12));
|
|
35497
|
+
const local = `${before} ${match[0]} ${after}`;
|
|
35498
|
+
const previous = before.split(/\s+/u).filter(Boolean).slice(-3).join(" ");
|
|
35499
|
+
if (/[<]\s*$/u.test(before) || LESS_CUES.some((cue) => containsNormalizedPhrase(previous, cue))) directions.add("less");
|
|
35500
|
+
if (/[>]\s*$/u.test(before) || GREATER_CUES.some((cue) => containsNormalizedPhrase(previous, cue))) directions.add("greater");
|
|
35501
|
+
if (containsNormalizedPhrase(local, normalizeForSearch(`\u043D\u0435 \u043C\u0435\u043D\u0435\u0435 ${number}`))) directions.add("greater");
|
|
35502
|
+
if (containsNormalizedPhrase(local, normalizeForSearch(`\u043D\u0435 \u0431\u043E\u043B\u0435\u0435 ${number}`))) directions.add("less");
|
|
35503
|
+
}
|
|
35504
|
+
return directions;
|
|
35505
|
+
}
|
|
35506
|
+
function optionFamilyComparatorAdjustment({
|
|
35507
|
+
answer,
|
|
35508
|
+
answers,
|
|
35509
|
+
evidence
|
|
35510
|
+
}) {
|
|
35511
|
+
const answerSpecs = answerComparatorSpecs(answer.text);
|
|
35512
|
+
if (answerSpecs.length !== 1) return { adjustment: 0, evidence: null };
|
|
35513
|
+
const specs = answerSpecs.filter((spec) => answerFamilyHasOppositeComparator(answer, answers, spec));
|
|
35514
|
+
if (!specs.length) return { adjustment: 0, evidence: null };
|
|
35515
|
+
for (const item of evidence) {
|
|
35516
|
+
if ((item.score ?? 0) < 5.5 || !item.text) continue;
|
|
35517
|
+
for (const spec of specs) {
|
|
35518
|
+
const sourceDirections = sourceDirectionsForNumber(item.text, spec.number);
|
|
35519
|
+
if (!sourceDirections.size || sourceDirections.has(spec.direction)) continue;
|
|
35520
|
+
if (!sourceDirections.has(opposite(spec.direction))) continue;
|
|
35521
|
+
return {
|
|
35522
|
+
adjustment: -4.2,
|
|
35523
|
+
evidence: {
|
|
35524
|
+
answerId: answer.id,
|
|
35525
|
+
page: item.page,
|
|
35526
|
+
text: item.text,
|
|
35527
|
+
score: Math.max(6.8, Math.min(12.5, item.score)),
|
|
35528
|
+
kind: "option_family_comparator_mismatch"
|
|
35529
|
+
}
|
|
35530
|
+
};
|
|
35531
|
+
}
|
|
35532
|
+
}
|
|
35533
|
+
return { adjustment: 0, evidence: null };
|
|
35534
|
+
}
|
|
35535
|
+
function compactComboPhrases(answerText) {
|
|
35536
|
+
const normalized = normalizeForSearch(answerText);
|
|
35537
|
+
const phrases = /* @__PURE__ */ new Set();
|
|
35538
|
+
for (const match of normalized.matchAll(/[a-z\u0430-\u044f0-9]{2,}(?:[+/][a-z\u0430-\u044f0-9]{2,})+/giu)) {
|
|
35539
|
+
if (validCompactComboPhrase(match[0])) phrases.add(match[0]);
|
|
35540
|
+
}
|
|
35541
|
+
return [...phrases].filter((phrase) => phrase.length >= 5);
|
|
35542
|
+
}
|
|
35543
|
+
function validCompactComboPhrase(phrase) {
|
|
35544
|
+
const parts = phrase.split(/[+/]/u).filter(Boolean);
|
|
35545
|
+
if (parts.length < 2) return false;
|
|
35546
|
+
return parts.every((part) => part.length >= 3 && part.length <= 10 && !COMBO_UNIT_PARTS.has(part) && !/^\d/u.test(part));
|
|
35547
|
+
}
|
|
35548
|
+
function comboQuestion(question) {
|
|
35549
|
+
const normalized = normalizeForSearch(question);
|
|
35550
|
+
return COMBO_QUESTION_CUES.some((cue) => normalized.includes(cue));
|
|
35551
|
+
}
|
|
35552
|
+
function alternativeComboTokens(answerText) {
|
|
35553
|
+
const normalized = normalizeForSearch(answerText);
|
|
35554
|
+
const alternative = containsNormalizedPhrase(normalized, "\u0438\u043B\u0438") || containsNormalizedPhrase(normalized, "\u043C\u043E\u043D\u043E\u0442\u0435\u0440\u0430\u043F");
|
|
35555
|
+
if (!alternative) return [];
|
|
35556
|
+
return uniqueTokens(answerText).filter((token) => token.length >= 3 && !/^\d/u.test(token) && !COMBO_GENERIC_TOKENS.has(token)).slice(0, 8);
|
|
35557
|
+
}
|
|
35558
|
+
function evidenceHasCompactTokenPair(text, tokens) {
|
|
35559
|
+
const normalized = normalizeForSearch(text);
|
|
35560
|
+
if (!/[+/]/u.test(normalized)) return false;
|
|
35561
|
+
for (let leftIndex = 0; leftIndex < tokens.length - 1; leftIndex += 1) {
|
|
35562
|
+
for (let rightIndex = leftIndex + 1; rightIndex < tokens.length; rightIndex += 1) {
|
|
35563
|
+
const left = tokens[leftIndex];
|
|
35564
|
+
const right = tokens[rightIndex];
|
|
35565
|
+
const leftHit = normalized.indexOf(left);
|
|
35566
|
+
const rightHit = normalized.indexOf(right);
|
|
35567
|
+
if (leftHit < 0 || rightHit < 0) continue;
|
|
35568
|
+
const start = Math.min(leftHit, rightHit);
|
|
35569
|
+
const end = Math.max(leftHit + left.length, rightHit + right.length);
|
|
35570
|
+
if (end - start > 56) continue;
|
|
35571
|
+
const local = normalized.slice(start, end);
|
|
35572
|
+
if (/[+/]/u.test(local) && !containsNormalizedPhrase(local, "\u0438\u043B\u0438")) return true;
|
|
35573
|
+
}
|
|
35574
|
+
}
|
|
35575
|
+
return false;
|
|
35576
|
+
}
|
|
35577
|
+
function optionFamilyCompactComboAdjustment({
|
|
35578
|
+
question,
|
|
35579
|
+
answer,
|
|
35580
|
+
evidence
|
|
35581
|
+
}) {
|
|
35582
|
+
if (!comboQuestion(question)) return { adjustment: 0, evidence: null };
|
|
35583
|
+
const comboPhrases = compactComboPhrases(answer.text);
|
|
35584
|
+
const alternativeTokens = alternativeComboTokens(answer.text);
|
|
35585
|
+
for (const item of evidence) {
|
|
35586
|
+
if ((item.score ?? 0) < 5.5 || !item.text) continue;
|
|
35587
|
+
const normalizedEvidence = normalizeForSearch(item.text);
|
|
35588
|
+
if (comboPhrases.some((phrase) => normalizedEvidence.includes(phrase))) {
|
|
35589
|
+
return {
|
|
35590
|
+
adjustment: 6.8,
|
|
35591
|
+
evidence: {
|
|
35592
|
+
answerId: answer.id,
|
|
35593
|
+
page: item.page,
|
|
35594
|
+
text: item.text,
|
|
35595
|
+
score: Math.max(9.2, Math.min(14.5, item.score + 1.1)),
|
|
35596
|
+
kind: "option_family_compact_combo_match"
|
|
35597
|
+
}
|
|
35598
|
+
};
|
|
35599
|
+
}
|
|
35600
|
+
if (alternativeTokens.length >= 2 && evidenceHasCompactTokenPair(item.text, alternativeTokens)) {
|
|
35601
|
+
return {
|
|
35602
|
+
adjustment: -6.4,
|
|
35603
|
+
evidence: {
|
|
35604
|
+
answerId: answer.id,
|
|
35605
|
+
page: item.page,
|
|
35606
|
+
text: item.text,
|
|
35607
|
+
score: Math.max(7.2, Math.min(13, item.score)),
|
|
35608
|
+
kind: "option_family_compact_combo_mismatch"
|
|
35609
|
+
}
|
|
35610
|
+
};
|
|
35611
|
+
}
|
|
35612
|
+
}
|
|
35613
|
+
return { adjustment: 0, evidence: null };
|
|
35614
|
+
}
|
|
35270
35615
|
|
|
35271
35616
|
// src/predictor/scorers/direction.ts
|
|
35272
35617
|
var POLARITY_UP_CUES = ["\u043F\u043E\u0432\u044B\u0448", "\u0443\u0432\u0435\u043B\u0438\u0447", "\u0432\u043E\u0437\u0440\u0430\u0441\u0442\u0430", "\u0440\u043E\u0441\u0442", "\u0432\u044B\u0441\u043E\u043A", "\u0431\u043E\u043B\u0435\u0435", "\u0432\u044B\u0448\u0435"].map((item) => normalizeForSearch(item));
|
|
@@ -35378,6 +35723,117 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
35378
35723
|
if (bestMismatch && (!bestMatch || bestMismatch.score > bestMatch.score + 0.4)) return { support: null, adjustment: -4.8, evidence: bestMismatch };
|
|
35379
35724
|
return { support: null, adjustment: 0, evidence: null };
|
|
35380
35725
|
}
|
|
35726
|
+
var CLINICAL_COURSE_CUE_GROUPS = [
|
|
35727
|
+
{
|
|
35728
|
+
target: "\u043E\u0441\u0442\u0440",
|
|
35729
|
+
opposite: ["\u0445\u0440\u043E\u043D", "\u0445\u0440\u043E\u043D\u0438\u0447"]
|
|
35730
|
+
},
|
|
35731
|
+
{
|
|
35732
|
+
target: "\u0445\u0440\u043E\u043D",
|
|
35733
|
+
opposite: ["\u043E\u0441\u0442\u0440"]
|
|
35734
|
+
}
|
|
35735
|
+
].map((group) => ({
|
|
35736
|
+
target: normalizeForSearch(group.target),
|
|
35737
|
+
opposite: group.opposite.map((item) => normalizeForSearch(item))
|
|
35738
|
+
}));
|
|
35739
|
+
function clinicalCourseCue(question) {
|
|
35740
|
+
const tokens = tokenize(question);
|
|
35741
|
+
for (const group of CLINICAL_COURSE_CUE_GROUPS) {
|
|
35742
|
+
if (tokens.some((token) => token.startsWith(group.target))) return group;
|
|
35743
|
+
}
|
|
35744
|
+
return null;
|
|
35745
|
+
}
|
|
35746
|
+
function clinicalCourseRelationQuestion(question) {
|
|
35747
|
+
const normalized = normalizeForSearch(question);
|
|
35748
|
+
if (containsNormalizedPhrase(normalized, "\u0440\u0435\u043A\u043E\u043C\u0435\u043D\u0434") || containsNormalizedPhrase(normalized, "\u043D\u0430\u0437\u043D\u0430\u0447")) {
|
|
35749
|
+
return false;
|
|
35750
|
+
}
|
|
35751
|
+
return [
|
|
35752
|
+
"\u043F\u0440\u043E\u044F\u0432\u043B",
|
|
35753
|
+
"\u0445\u0430\u0440\u0430\u043A\u0442\u0435\u0440",
|
|
35754
|
+
"\u0442\u0438\u043F\u0438\u0447",
|
|
35755
|
+
"\u043F\u0440\u0438\u0437\u043D\u0430\u043A",
|
|
35756
|
+
"\u0441\u0438\u043C\u043F\u0442\u043E\u043C"
|
|
35757
|
+
].some((cue) => normalized.includes(normalizeForSearch(cue)));
|
|
35758
|
+
}
|
|
35759
|
+
var CLINICAL_COURSE_GENERIC_BINDING_TOKENS = new Set(
|
|
35760
|
+
[
|
|
35761
|
+
"\u0442\u0435\u0447\u0435\u043D\u0438\u0435",
|
|
35762
|
+
"\u0442\u0435\u0447\u0435\u043D\u0438\u044F",
|
|
35763
|
+
"\u0444\u043E\u0440\u043C\u0430",
|
|
35764
|
+
"\u0444\u043E\u0440\u043C\u044B",
|
|
35765
|
+
"\u0431\u043E\u043B\u0435\u0437\u043D\u044C",
|
|
35766
|
+
"\u0431\u043E\u043B\u0435\u0437\u043D\u0438",
|
|
35767
|
+
"\u0433\u0435\u043F\u0430\u0442\u0438\u0442",
|
|
35768
|
+
"\u0441\u0438\u043C\u043F\u0442\u043E\u043C",
|
|
35769
|
+
"\u043F\u0440\u0438\u0437\u043D\u0430\u043A",
|
|
35770
|
+
"\u043F\u0440\u043E\u044F\u0432\u043B\u0435\u043D\u0438\u0435",
|
|
35771
|
+
"\u043F\u0440\u043E\u044F\u0432\u043B\u044F\u0442\u044C"
|
|
35772
|
+
].flatMap((item) => tokenize(item))
|
|
35773
|
+
);
|
|
35774
|
+
function clinicalCourseBindingTokens(answerTokens, questionTokens) {
|
|
35775
|
+
const questionSet = new Set(questionTokens);
|
|
35776
|
+
return answerTokens.filter(
|
|
35777
|
+
(token) => token.length >= 4 && /[а-яё]/u.test(token) && !FOCUS_STOPWORDS.has(token) && !questionSet.has(token) && !CLINICAL_COURSE_GENERIC_BINDING_TOKENS.has(token)
|
|
35778
|
+
);
|
|
35779
|
+
}
|
|
35780
|
+
function nearestClinicalCourseCueBeforeAnswer(tokens, bindingTokens, cueGroup) {
|
|
35781
|
+
let best = null;
|
|
35782
|
+
if (!bindingTokens.length) return null;
|
|
35783
|
+
for (let index = 0; index < tokens.length; index += 1) {
|
|
35784
|
+
const token = tokens[index];
|
|
35785
|
+
if (!bindingTokens.some((answerToken) => token === answerToken || token.startsWith(answerToken) || answerToken.startsWith(token))) continue;
|
|
35786
|
+
const start = Math.max(0, index - 10);
|
|
35787
|
+
for (let cursor = index - 1; cursor >= start; cursor -= 1) {
|
|
35788
|
+
const beforeToken = tokens[cursor];
|
|
35789
|
+
const distance = index - cursor;
|
|
35790
|
+
let type = null;
|
|
35791
|
+
if (beforeToken.startsWith(cueGroup.target)) type = "target";
|
|
35792
|
+
else if (cueGroup.opposite.some((opposite2) => beforeToken.startsWith(opposite2))) type = "opposite";
|
|
35793
|
+
if (!type) continue;
|
|
35794
|
+
if (!best || distance < best.distance) best = { type, distance };
|
|
35795
|
+
break;
|
|
35796
|
+
}
|
|
35797
|
+
}
|
|
35798
|
+
return best;
|
|
35799
|
+
}
|
|
35800
|
+
function clinicalCourseCueAdjustment({ mode, pages, topQuestionPages, question, questionTokens, focusTokens, answer, answerTokens }) {
|
|
35801
|
+
if (mode !== "single") return { support: null, adjustment: 0, evidence: null };
|
|
35802
|
+
if (!clinicalCourseRelationQuestion(question)) return { support: null, adjustment: 0, evidence: null };
|
|
35803
|
+
const cueGroup = clinicalCourseCue(question);
|
|
35804
|
+
if (!cueGroup) return { support: null, adjustment: 0, evidence: null };
|
|
35805
|
+
const bindingTokens = clinicalCourseBindingTokens(answerTokens, questionTokens);
|
|
35806
|
+
if (!bindingTokens.length) return { support: null, adjustment: 0, evidence: null };
|
|
35807
|
+
const usefulFocus = focusTokens?.length ? focusTokens : questionTokens;
|
|
35808
|
+
let bestMatch = null;
|
|
35809
|
+
let bestMismatch = null;
|
|
35810
|
+
for (const page of pages) {
|
|
35811
|
+
const topPage = topQuestionPages?.has(page.page);
|
|
35812
|
+
const adjacentTopPage = topQuestionPages?.has(page.page - 1) || topQuestionPages?.has(page.page + 1);
|
|
35813
|
+
if (topQuestionPages?.size && !topPage && !adjacentTopPage) continue;
|
|
35814
|
+
for (const segment of cachedLineWindowSegments(page)) {
|
|
35815
|
+
const focusCoverage = coverage(usefulFocus, segment.tokens);
|
|
35816
|
+
if (focusCoverage < 0.12) continue;
|
|
35817
|
+
const binding = nearestClinicalCourseCueBeforeAnswer(segment.tokens, bindingTokens, cueGroup);
|
|
35818
|
+
if (!binding) continue;
|
|
35819
|
+
const answerHits = tokenHitCount(bindingTokens, segment.tokens);
|
|
35820
|
+
if (answerHits < Math.min(2, bindingTokens.length)) continue;
|
|
35821
|
+
const score = 9.2 + Math.min(0.5, focusCoverage) * 5 + Math.min(3, answerHits) * 0.7 + Math.max(0, 10 - binding.distance) * 0.12;
|
|
35822
|
+
const evidence = {
|
|
35823
|
+
answerId: answer.id,
|
|
35824
|
+
page: page.page,
|
|
35825
|
+
text: segment.text,
|
|
35826
|
+
score,
|
|
35827
|
+
kind: binding.type === "target" ? "clinical_course_cue_segment" : "clinical_course_cue_mismatch"
|
|
35828
|
+
};
|
|
35829
|
+
if (binding.type === "target") bestMatch = betterEvidence(bestMatch, evidence);
|
|
35830
|
+
else bestMismatch = betterEvidence(bestMismatch, evidence);
|
|
35831
|
+
}
|
|
35832
|
+
}
|
|
35833
|
+
if (bestMatch && (!bestMismatch || bestMatch.score >= bestMismatch.score - 0.6)) return { support: bestMatch, adjustment: 0, evidence: null };
|
|
35834
|
+
if (bestMismatch && (!bestMatch || bestMismatch.score > bestMatch.score + 0.6)) return { support: null, adjustment: -6.8, evidence: bestMismatch };
|
|
35835
|
+
return { support: null, adjustment: 0, evidence: null };
|
|
35836
|
+
}
|
|
35381
35837
|
var CONTRAST_CUE_GROUPS = [
|
|
35382
35838
|
{
|
|
35383
35839
|
answer: ["\u0432\u0435\u0440\u0445\u043D"],
|
|
@@ -36880,52 +37336,6 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
36880
37336
|
}
|
|
36881
37337
|
|
|
36882
37338
|
// src/predictor/selection.ts
|
|
36883
|
-
var STRUCTURAL_EVIDENCE_WEIGHTS = new Map(
|
|
36884
|
-
Object.entries({
|
|
36885
|
-
coordinate_table_row: 1.25,
|
|
36886
|
-
coordinate_table_group: 1.25,
|
|
36887
|
-
coordinate_table_group_inverse: 1.25,
|
|
36888
|
-
coordinate_table_multicell_row: 1.25,
|
|
36889
|
-
coordinate_table_membership: 1.15,
|
|
36890
|
-
parenthetical_group_segment: 1.05,
|
|
36891
|
-
preceding_question_label: 1.05,
|
|
36892
|
-
question_continuation_list: 1.05,
|
|
36893
|
-
exact_numeric_option_segment: 1.05,
|
|
36894
|
-
exact_hour_alias_segment: 1.05,
|
|
36895
|
-
short_medical_alias_segment: 0.9,
|
|
36896
|
-
visual_table_column: 1.2,
|
|
36897
|
-
exact_short_label_visual_row: 1.15,
|
|
36898
|
-
short_label_visual_row: 1.05,
|
|
36899
|
-
answer_ordinal_row: 1.05,
|
|
36900
|
-
fibrosis_stage_row: 1.2,
|
|
36901
|
-
gene_sentence_segment: 1.1,
|
|
36902
|
-
clinical_feature_segment: 1,
|
|
36903
|
-
mkb_class_exclusion_absent: 1,
|
|
36904
|
-
classification_code_segment: 1.15,
|
|
36905
|
-
label_number_proximity: 1,
|
|
36906
|
-
label_definition_segment: 1,
|
|
36907
|
-
row_label_segment: 0.95,
|
|
36908
|
-
bounded_list_segment: 0.95,
|
|
36909
|
-
ordinal_list_segment: 0.9,
|
|
36910
|
-
drug_dose_segment: 0.9,
|
|
36911
|
-
recommendation_item_segment: 0.85,
|
|
36912
|
-
explicit_recommendation_target_segment: 0.85,
|
|
36913
|
-
numeric_condition_less_than: 0.85,
|
|
36914
|
-
numeric_condition_more_than: 0.85,
|
|
36915
|
-
numeric_condition_equal: 0.85,
|
|
36916
|
-
conditioned_number_segment: 0.8,
|
|
36917
|
-
cloze_gap_local: 0.8
|
|
36918
|
-
})
|
|
36919
|
-
);
|
|
36920
|
-
var BROAD_EVIDENCE_KINDS = /* @__PURE__ */ new Set([
|
|
36921
|
-
"bm25_question_answer",
|
|
36922
|
-
"question_chunk_answer",
|
|
36923
|
-
"answer_chunk_question",
|
|
36924
|
-
"answer_window",
|
|
36925
|
-
"focused_answer_window",
|
|
36926
|
-
"shared_multi_segment"
|
|
36927
|
-
]);
|
|
36928
|
-
var NOISY_SHARED_EVIDENCE_KINDS = /* @__PURE__ */ new Set(["question_chunk_answer", "bm25_question_answer", "shared_multi_segment"]);
|
|
36929
37339
|
function calibrateScores(answerScores) {
|
|
36930
37340
|
const rawValues = answerScores.map((item) => item.raw);
|
|
36931
37341
|
const max = Math.max(...rawValues, 1e-4);
|
|
@@ -37026,7 +37436,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
37026
37436
|
bestScore = score;
|
|
37027
37437
|
bestKind = evidence.kind;
|
|
37028
37438
|
}
|
|
37029
|
-
const weight =
|
|
37439
|
+
const weight = SELECTION_STRUCTURAL_EVIDENCE_WEIGHTS.get(evidence.kind) ?? 0;
|
|
37030
37440
|
if (weight > 0) {
|
|
37031
37441
|
bestStructuralScore = Math.max(bestStructuralScore, score);
|
|
37032
37442
|
structuralWeight = Math.max(structuralWeight, weight);
|
|
@@ -38958,6 +39368,256 @@ ${nextPage.text}`;
|
|
|
38958
39368
|
}
|
|
38959
39369
|
return best;
|
|
38960
39370
|
}
|
|
39371
|
+
function definitionQuestionLike(question) {
|
|
39372
|
+
const normalized = normalizeForSearch(question);
|
|
39373
|
+
return questionDefinitionTerm(question) || containsNormalizedPhrase(normalized, "\u044D\u0442\u043E") || containsNormalizedPhrase(normalized, "\u043F\u043E\u043D\u0438\u043C\u0430") || containsNormalizedPhrase(normalized, "\u043D\u0430\u0437\u044B\u0432\u0430");
|
|
39374
|
+
}
|
|
39375
|
+
function definitionCueWindow(normalized) {
|
|
39376
|
+
return containsNormalizedPhrase(normalized, "\u044D\u0442\u043E") || containsNormalizedPhrase(normalized, "\u043F\u043E\u043D\u0438\u043C\u0430") || containsNormalizedPhrase(normalized, "\u043D\u0430\u0437\u044B\u0432\u0430") || /(?:^|\s)[a-z\u0430-\u044f]{4,}\s+[-\u2013\u2014]\s+/iu.test(normalized);
|
|
39377
|
+
}
|
|
39378
|
+
function definitionExactFragments(text) {
|
|
39379
|
+
const fragments = String(text ?? "").split(/(?<=[.!?;])\s+/u).map((item) => item.trim()).filter((item) => item.length >= 20);
|
|
39380
|
+
return fragments.length ? fragments : [String(text ?? "")];
|
|
39381
|
+
}
|
|
39382
|
+
var DEFINITION_TERM_GENERIC_TOKENS = new Set(
|
|
39383
|
+
[
|
|
39384
|
+
"\u043F\u043E\u0434",
|
|
39385
|
+
"\u043F\u043E\u043D\u0438\u043C\u0430\u044E\u0442",
|
|
39386
|
+
"\u043F\u043E\u043D\u0438\u043C\u0430\u0435\u0442\u0441\u044F",
|
|
39387
|
+
"\u044D\u0442\u043E",
|
|
39388
|
+
"\u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F",
|
|
39389
|
+
"\u043F\u0440\u0438\u0437\u043D\u0430\u043A"
|
|
39390
|
+
].flatMap((item) => uniqueTokens(item))
|
|
39391
|
+
);
|
|
39392
|
+
function primaryDefinitionTermToken(question) {
|
|
39393
|
+
const term = questionDefinitionTerm(question);
|
|
39394
|
+
const tokens = uniqueTokens(term ?? question).filter((token) => token.length >= 4 && !DEFINITION_TERM_GENERIC_TOKENS.has(token));
|
|
39395
|
+
return tokens[0] ?? "";
|
|
39396
|
+
}
|
|
39397
|
+
function editDistanceAtMostOne(left, right) {
|
|
39398
|
+
if (left === right) return true;
|
|
39399
|
+
if (Math.abs(left.length - right.length) > 1) return false;
|
|
39400
|
+
let edits = 0;
|
|
39401
|
+
let i = 0;
|
|
39402
|
+
let j = 0;
|
|
39403
|
+
while (i < left.length && j < right.length) {
|
|
39404
|
+
if (left[i] === right[j]) {
|
|
39405
|
+
i += 1;
|
|
39406
|
+
j += 1;
|
|
39407
|
+
continue;
|
|
39408
|
+
}
|
|
39409
|
+
edits += 1;
|
|
39410
|
+
if (edits > 1) return false;
|
|
39411
|
+
if (left.length > right.length) i += 1;
|
|
39412
|
+
else if (right.length > left.length) j += 1;
|
|
39413
|
+
else {
|
|
39414
|
+
i += 1;
|
|
39415
|
+
j += 1;
|
|
39416
|
+
}
|
|
39417
|
+
}
|
|
39418
|
+
return edits + (left.length - i) + (right.length - j) <= 1;
|
|
39419
|
+
}
|
|
39420
|
+
function definitionFragmentMatchesQuestionTerm(fragmentTokens, primaryTerm) {
|
|
39421
|
+
if (!primaryTerm) return true;
|
|
39422
|
+
const cueIndex = fragmentTokens.findIndex((token) => token === normalizeForSearch("\u044D\u0442\u043E"));
|
|
39423
|
+
const labelTokens = fragmentTokens.slice(0, cueIndex >= 0 ? cueIndex : Math.min(3, fragmentTokens.length));
|
|
39424
|
+
return labelTokens.some((token) => token.length >= 4 && editDistanceAtMostOne(token, primaryTerm));
|
|
39425
|
+
}
|
|
39426
|
+
function bestDefinitionExactAnswerSupport({ mode, pages, topQuestionPages, question, answer, answerTokens }) {
|
|
39427
|
+
if (mode !== "single" || !definitionQuestionLike(question)) return null;
|
|
39428
|
+
const answerPhrases = answerSearchPhrases(answer.text).slice(0, 12);
|
|
39429
|
+
const primaryTerm = primaryDefinitionTermToken(question);
|
|
39430
|
+
let best = null;
|
|
39431
|
+
for (const page of pages) {
|
|
39432
|
+
if (topQuestionPages?.size && !topQuestionPages.has(page.page) && !topQuestionPages.has(page.page - 1) && !topQuestionPages.has(page.page + 1)) {
|
|
39433
|
+
continue;
|
|
39434
|
+
}
|
|
39435
|
+
for (const source of cachedLineWindowSegments(page)) {
|
|
39436
|
+
for (const fragment of definitionExactFragments(source.text)) {
|
|
39437
|
+
const normalized = normalizeForSearch(fragment);
|
|
39438
|
+
if (!definitionCueWindow(normalized)) continue;
|
|
39439
|
+
const fragmentTokens = tokenizeNormalized(normalized);
|
|
39440
|
+
if (!definitionFragmentMatchesQuestionTerm(fragmentTokens, primaryTerm)) continue;
|
|
39441
|
+
const phraseHit = answerPhrases.some((phrase) => containsNormalizedPhrase(normalized, phrase));
|
|
39442
|
+
const answerCoverage = strictSoftCoverage(answerTokens, fragmentTokens);
|
|
39443
|
+
if (!phraseHit || answerCoverage < 0.72) continue;
|
|
39444
|
+
const score = 15.2 + answerCoverage * 6 + numberCoverage(answer.text, normalized) * 0.8;
|
|
39445
|
+
best = betterEvidence(best, {
|
|
39446
|
+
answerId: answer.id,
|
|
39447
|
+
page: page.page,
|
|
39448
|
+
text: fragment,
|
|
39449
|
+
score,
|
|
39450
|
+
kind: "definition_exact_answer_segment"
|
|
39451
|
+
});
|
|
39452
|
+
}
|
|
39453
|
+
}
|
|
39454
|
+
}
|
|
39455
|
+
return best;
|
|
39456
|
+
}
|
|
39457
|
+
var DEFINITION_COMPLETION_EVIDENCE = /* @__PURE__ */ new Set(["definition_exact_answer_segment", "term_definition_segment", "label_definition_segment"]);
|
|
39458
|
+
function definitionCompletionAdjustment({ mode, question, answer, answers, answerTokens }, evidence) {
|
|
39459
|
+
if (mode !== "single" || !definitionQuestionLike(question)) return { adjustment: 0, evidence: null };
|
|
39460
|
+
const definitionEvidence = evidence.find((item) => DEFINITION_COMPLETION_EVIDENCE.has(item.kind) && (item.score ?? 0) >= 18);
|
|
39461
|
+
if (!definitionEvidence) return { adjustment: 0, evidence: null };
|
|
39462
|
+
const answerNorm = normalizeForSearch(answer.text);
|
|
39463
|
+
if (answerTokens.length < 5 || answerNorm.length < 32) return { adjustment: 0, evidence: null };
|
|
39464
|
+
let contained = 0;
|
|
39465
|
+
for (const candidate of answers) {
|
|
39466
|
+
if (candidate.id === answer.id) continue;
|
|
39467
|
+
const candidateNorm = normalizeForSearch(candidate.text);
|
|
39468
|
+
if (candidateNorm.length < 18 || candidateNorm === answerNorm) continue;
|
|
39469
|
+
const candidateTokens = uniqueTokens(candidate.text);
|
|
39470
|
+
if (candidateTokens.length < 3 || candidateTokens.length >= answerTokens.length) continue;
|
|
39471
|
+
if (answerNorm.includes(candidateNorm)) contained += 1;
|
|
39472
|
+
}
|
|
39473
|
+
if (!contained) return { adjustment: 0, evidence: null };
|
|
39474
|
+
const adjustment = Math.min(5, contained * 2.4);
|
|
39475
|
+
return {
|
|
39476
|
+
adjustment,
|
|
39477
|
+
evidence: {
|
|
39478
|
+
answerId: answer.id,
|
|
39479
|
+
page: definitionEvidence.page,
|
|
39480
|
+
text: definitionEvidence.text,
|
|
39481
|
+
score: Math.max(8.5, Math.min(14.5, definitionEvidence.score)),
|
|
39482
|
+
kind: "definition_completion_specificity"
|
|
39483
|
+
}
|
|
39484
|
+
};
|
|
39485
|
+
}
|
|
39486
|
+
var FREQUENCY_POLARITY_HIGH_CUES = [
|
|
39487
|
+
"\u043D\u0430\u0438\u0431\u043E\u043B\u0435\u0435 \u0447\u0430\u0441\u0442",
|
|
39488
|
+
"\u0441\u0430\u043C\u043E\u0439 \u0447\u0430\u0441\u0442",
|
|
39489
|
+
"\u0441\u0430\u043C\u044B\u043C \u0447\u0430\u0441\u0442",
|
|
39490
|
+
"\u0447\u0430\u0441\u0442\u043E \u0432\u0441\u0442\u0440\u0435\u0447",
|
|
39491
|
+
"\u0447\u0430\u0449\u0435",
|
|
39492
|
+
"\u0432\u0435\u0434\u0443\u0449"
|
|
39493
|
+
];
|
|
39494
|
+
var FREQUENCY_POLARITY_LOW_CUES = [
|
|
39495
|
+
"\u0440\u0435\u0434\u043A",
|
|
39496
|
+
"\u0440\u0435\u0436\u0435"
|
|
39497
|
+
];
|
|
39498
|
+
var FREQUENCY_POLARITY_GENERIC_FOCUS = new Set(
|
|
39499
|
+
[
|
|
39500
|
+
"\u043D\u0430\u0438\u0431\u043E\u043B\u0435\u0435",
|
|
39501
|
+
"\u0447\u0430\u0441\u0442\u044B\u0439",
|
|
39502
|
+
"\u0447\u0430\u0441\u0442\u0430\u044F",
|
|
39503
|
+
"\u0447\u0430\u0441\u0442\u043E\u0439",
|
|
39504
|
+
"\u0447\u0430\u0441\u0442\u043E\u0435",
|
|
39505
|
+
"\u0440\u0435\u0434\u043A\u0438\u0439",
|
|
39506
|
+
"\u0440\u0435\u0434\u043A\u0430\u044F",
|
|
39507
|
+
"\u0440\u0435\u0434\u043A\u043E\u0439",
|
|
39508
|
+
"\u0444\u043E\u0440\u043C\u0430",
|
|
39509
|
+
"\u0444\u043E\u0440\u043C\u043E\u0439",
|
|
39510
|
+
"\u0432\u0430\u0440\u0438\u0430\u043D\u0442",
|
|
39511
|
+
"\u0432\u0430\u0440\u0438\u0430\u043D\u0442\u043E\u043C",
|
|
39512
|
+
"\u0440\u043E\u043B\u044C",
|
|
39513
|
+
"\u043E\u0442\u0432\u043E\u0434\u0438\u0442\u0441\u044F",
|
|
39514
|
+
"\u0432\u0441\u0442\u0440\u0435\u0447\u0430\u0435\u0442\u0441\u044F"
|
|
39515
|
+
].flatMap((item) => uniqueTokens(item))
|
|
39516
|
+
);
|
|
39517
|
+
function frequencyPolarity(normalized) {
|
|
39518
|
+
if (FREQUENCY_POLARITY_LOW_CUES.some((cue) => containsNormalizedPhrase(normalized, cue))) return "low";
|
|
39519
|
+
if (FREQUENCY_POLARITY_HIGH_CUES.some((cue) => containsNormalizedPhrase(normalized, cue))) return "high";
|
|
39520
|
+
return null;
|
|
39521
|
+
}
|
|
39522
|
+
function frequencyPolarityFocusTokens(focusTokens, answerTokens) {
|
|
39523
|
+
const answerSet = new Set(answerTokens ?? []);
|
|
39524
|
+
return (focusTokens ?? []).filter((token) => token.length >= 4 && !answerSet.has(token) && !FREQUENCY_POLARITY_GENERIC_FOCUS.has(token));
|
|
39525
|
+
}
|
|
39526
|
+
function containsPhraseOutsideParentheses(text, phrases) {
|
|
39527
|
+
const normalized = normalizeForSearch(String(text ?? "").replace(/\([^)]*\)/gu, " "));
|
|
39528
|
+
for (const phrase of phrases) {
|
|
39529
|
+
const normalizedPhrase = normalizeForSearch(phrase);
|
|
39530
|
+
if (!normalizedPhrase) continue;
|
|
39531
|
+
if (normalized.includes(normalizedPhrase)) return true;
|
|
39532
|
+
}
|
|
39533
|
+
return false;
|
|
39534
|
+
}
|
|
39535
|
+
function frequencyPolarityFragments(text) {
|
|
39536
|
+
const fragments = String(text ?? "").split(/(?<=[.!?;])\s+/u).map((item) => item.trim()).filter((item) => item.length >= 20);
|
|
39537
|
+
return fragments.length ? fragments : [String(text ?? "")];
|
|
39538
|
+
}
|
|
39539
|
+
function frequencyListItemLine(line) {
|
|
39540
|
+
return /^\s*(?:[•*\-]|\d+[.)]|[IVX]+[.)])\s+/iu.test(String(line ?? ""));
|
|
39541
|
+
}
|
|
39542
|
+
function frequencyPolarityListItems(pages, pageIndex, lineIndex) {
|
|
39543
|
+
const items = [];
|
|
39544
|
+
for (let offset = 0; offset <= 1; offset += 1) {
|
|
39545
|
+
const page = pages[pageIndex + offset];
|
|
39546
|
+
if (!page) continue;
|
|
39547
|
+
const start = offset === 0 ? lineIndex + 1 : 0;
|
|
39548
|
+
for (let index = start; index < (page.lines?.length ?? 0); index += 1) {
|
|
39549
|
+
const line = page.lines[index];
|
|
39550
|
+
if (!frequencyListItemLine(line)) {
|
|
39551
|
+
if (items.length) return items;
|
|
39552
|
+
continue;
|
|
39553
|
+
}
|
|
39554
|
+
items.push({ text: line, page: page.page });
|
|
39555
|
+
if (items.length >= 10) return items;
|
|
39556
|
+
}
|
|
39557
|
+
}
|
|
39558
|
+
return items;
|
|
39559
|
+
}
|
|
39560
|
+
function betterFrequencyListSupport(best, { pages, pageIndex, lineIndex, answer, answerPhrases, answerTokens, specificTokens, target }) {
|
|
39561
|
+
const page = pages[pageIndex];
|
|
39562
|
+
const heading = page.lines?.[lineIndex] ?? "";
|
|
39563
|
+
const headingNorm = normalizeForSearch(heading);
|
|
39564
|
+
if (frequencyPolarity(headingNorm) !== target) return best;
|
|
39565
|
+
const headingTokens = tokenizeNormalized(headingNorm);
|
|
39566
|
+
const headingFocusHits = tokenHitCount(specificTokens, headingTokens);
|
|
39567
|
+
if (specificTokens.length >= 2 && headingFocusHits <= 0) return best;
|
|
39568
|
+
for (const item of frequencyPolarityListItems(pages, pageIndex, lineIndex)) {
|
|
39569
|
+
if (!containsPhraseOutsideParentheses(item.text, answerPhrases)) continue;
|
|
39570
|
+
const itemTokens = tokenize(item.text);
|
|
39571
|
+
const answerCoverage = strictSoftCoverage(answerTokens, itemTokens);
|
|
39572
|
+
const score = 15.8 + answerCoverage * 4.4 + Math.min(2, headingFocusHits) * 1.2;
|
|
39573
|
+
best = betterEvidence(best, {
|
|
39574
|
+
answerId: answer.id,
|
|
39575
|
+
page: item.page,
|
|
39576
|
+
text: `${heading} ${item.text}`,
|
|
39577
|
+
score,
|
|
39578
|
+
kind: "frequency_polarity_list_item"
|
|
39579
|
+
});
|
|
39580
|
+
}
|
|
39581
|
+
return best;
|
|
39582
|
+
}
|
|
39583
|
+
function bestFrequencyPolaritySupport({ mode, pages, topQuestionPages, question, answer, answerTokens, focusTokens }) {
|
|
39584
|
+
if (mode !== "single") return null;
|
|
39585
|
+
const target = frequencyPolarity(normalizeForSearch(question));
|
|
39586
|
+
if (!target) return null;
|
|
39587
|
+
const answerPhrases = answerSearchPhrases(answer.text).slice(0, 16);
|
|
39588
|
+
const specificTokens = frequencyPolarityFocusTokens(focusTokens, answerTokens);
|
|
39589
|
+
let best = null;
|
|
39590
|
+
for (let pageIndex = 0; pageIndex < pages.length; pageIndex += 1) {
|
|
39591
|
+
const page = pages[pageIndex];
|
|
39592
|
+
if (topQuestionPages?.size && !topQuestionPages.has(page.page) && !topQuestionPages.has(page.page - 1) && !topQuestionPages.has(page.page + 1)) {
|
|
39593
|
+
continue;
|
|
39594
|
+
}
|
|
39595
|
+
for (let lineIndex = 0; lineIndex < (page.lines?.length ?? 0); lineIndex += 1) {
|
|
39596
|
+
best = betterFrequencyListSupport(best, { pages, pageIndex, lineIndex, answer, answerPhrases, answerTokens, specificTokens, target });
|
|
39597
|
+
}
|
|
39598
|
+
for (const segment of cachedLineWindowSegments(page)) {
|
|
39599
|
+
for (const fragment of frequencyPolarityFragments(segment.text)) {
|
|
39600
|
+
const normalized = normalizeForSearch(fragment);
|
|
39601
|
+
if (frequencyPolarity(normalized) !== target) continue;
|
|
39602
|
+
const phraseHit = containsPhraseOutsideParentheses(fragment, answerPhrases);
|
|
39603
|
+
if (!phraseHit) continue;
|
|
39604
|
+
const fragmentTokens = tokenizeNormalized(normalized);
|
|
39605
|
+
const answerCoverage = strictSoftCoverage(answerTokens, fragmentTokens);
|
|
39606
|
+
const focusHits = tokenHitCount(specificTokens, fragmentTokens);
|
|
39607
|
+
if (specificTokens.length >= 2 && focusHits <= 0) continue;
|
|
39608
|
+
const score = 12.2 + (phraseHit ? 2.8 : 0) + answerCoverage * 4.2 + Math.min(2, focusHits) * 1.1;
|
|
39609
|
+
best = betterEvidence(best, {
|
|
39610
|
+
answerId: answer.id,
|
|
39611
|
+
page: page.page,
|
|
39612
|
+
text: fragment,
|
|
39613
|
+
score,
|
|
39614
|
+
kind: "frequency_polarity_segment"
|
|
39615
|
+
});
|
|
39616
|
+
}
|
|
39617
|
+
}
|
|
39618
|
+
}
|
|
39619
|
+
return best;
|
|
39620
|
+
}
|
|
38961
39621
|
function negatedAnswerPrefixAdjustment({ mode, pages, question, answer, answerTokens }) {
|
|
38962
39622
|
if (mode !== "single" || answerTokens.length < 2) return { adjustment: 0, evidence: null };
|
|
38963
39623
|
const questionNorm = normalizeForSearch(question);
|
|
@@ -39997,6 +40657,7 @@ ${nextPage.text}`;
|
|
|
39997
40657
|
const chunk = bestChunkSupport(context);
|
|
39998
40658
|
const polarity = polarityAdjustment(context);
|
|
39999
40659
|
const temporal = temporalCueAdjustment(context);
|
|
40660
|
+
const clinicalCourseCue2 = clinicalCourseCueAdjustment(context);
|
|
40000
40661
|
const conditionPair = conditionPairAdjustment(context);
|
|
40001
40662
|
const riskCondition = riskConditionAdjustment(context);
|
|
40002
40663
|
const genericPopulation = genericPopulationConditionAdjustmentForMode(context);
|
|
@@ -40014,10 +40675,13 @@ ${nextPage.text}`;
|
|
|
40014
40675
|
const ageEligibility = ageEligibilityAdjustment(context);
|
|
40015
40676
|
const drugDose = bestDrugDoseSupport(context);
|
|
40016
40677
|
const termDefinition = bestTermDefinitionSupport(context);
|
|
40678
|
+
const definitionExactAnswer = bestDefinitionExactAnswerSupport(context);
|
|
40679
|
+
const frequencyPolarity2 = bestFrequencyPolaritySupport(context);
|
|
40017
40680
|
const negatedAnswerPrefix = negatedAnswerPrefixAdjustment(context);
|
|
40018
40681
|
const impossibilityOnly = impossibilityOnlyAdjustment(context);
|
|
40019
40682
|
const activeTherapyIndication = activeTherapyIndicationAdjustment(context);
|
|
40020
40683
|
const recommendationItem = bestRecommendationItemSupport(context);
|
|
40684
|
+
const recommendationBlock = bestRecommendationBlockSupport(context);
|
|
40021
40685
|
const explicitRecommendationTarget = explicitRecommendationTargetAdjustment(context);
|
|
40022
40686
|
const conditionedNumber = bestConditionedNumberSupport(context);
|
|
40023
40687
|
const numericCondition = bestNumericConditionSupport(context);
|
|
@@ -40051,7 +40715,7 @@ ${nextPage.text}`;
|
|
|
40051
40715
|
const focusedWeight = context.mode === "multi" ? 0.15 : 0.9;
|
|
40052
40716
|
const lineTokenWeight = context.mode === "single" ? 0.85 : 0;
|
|
40053
40717
|
const latinFuzzyWeight = context.mode === "multi" && polarity.evidence?.kind !== "polarity_mismatch" ? 1.15 : 0;
|
|
40054
|
-
let raw = (anchor?.score ?? 0) * 1.35 + (section?.score ?? 0) * 1.2 + (rowLabel?.score ?? 0) * 0.95 + (focused?.score ?? 0) * focusedWeight + (lineToken?.score ?? 0) * lineTokenWeight + (prefix?.score ?? 0) * 1.15 + (phrase?.score ?? 0) * phraseWeight + (precedingLabel?.score ?? 0) * 1.3 + (exactAnswer?.score ?? 0) * 1.08 + (chunk?.score ?? 0) * 1 + polarity.adjustment + (temporal.support?.score ?? 0) * 1 + temporal.adjustment + conditionPair.adjustment + riskCondition.adjustment + genericPopulation.adjustment + (classSubject?.score ?? 0) * 1.15 + (frequency?.score ?? 0) * 1.1 + negativeLocal.adjustment + (boundedList.support?.score ?? 0) * 1.15 + boundedList.adjustment + (ordinalList?.score ?? 0) * 1.15 + (typeOrdinal?.score ?? 0) * 1.15 + (indicationLabel?.score ?? 0) * 1.15 + (labelDefinition?.score ?? 0) * 1.15 + (recommendationPolarity.support?.score ?? 0) * 1.05 + recommendationPolarity.adjustment + (exactNumericOption?.score ?? 0) * 1.04 + (exactHourAlias?.score ?? 0) * 1.08 + ageEligibility.adjustment + (drugDose?.score ?? 0) * 1.15 + (termDefinition?.score ?? 0) * 1.15 + negatedAnswerPrefix.adjustment + impossibilityOnly.adjustment + activeTherapyIndication.adjustment + (recommendationItem?.score ?? 0) * 1.1 + (explicitRecommendationTarget.support?.score ?? 0) * 1.05 + explicitRecommendationTarget.adjustment + (conditionedNumber?.score ?? 0) * 1.1 + (numericCondition?.score ?? 0) * 1.05 + (countRelation?.score ?? 0) * 1.1 + (ageForm?.score ?? 0) * 1.15 + (fibrosisStage?.score ?? 0) * 1.15 + (conditionNumber?.score ?? 0) * 1.15 + (romanStage?.score ?? 0) * 1.15 + (answerOrdinalRow?.score ?? 0) * 1.15 + (clozeGap?.score ?? 0) * 1.12 + (visualTableColumn?.score ?? 0) * 1.18 + (coordinateTableRow?.score ?? 0) * 1.12 + (coordinateTableGroup?.score ?? 0) * 1.16 + (coordinateMultiCellRow?.score ?? 0) * 1.16 + (coordinateTableMembership?.score ?? 0) * 1.1 + (parentheticalGroup?.score ?? 0) * 1.16 + (questionContinuationList?.score ?? 0) * 1.1 + (shortMedicalAlias?.score ?? 0) * 0.35 + (latinFuzzy?.score ?? 0) * latinFuzzyWeight + (geneSentence?.score ?? 0) * 1.18 + (clinicalFeature.support?.score ?? 0) * 1.12 + clinicalFeature.adjustment + (mkbClassExclusion.support?.score ?? 0) * 1.12 + mkbClassExclusion.adjustment + (labelNumber?.score ?? 0) * 1.15 + (classificationCode?.score ?? 0) * 1.15 + (exactShortLabelRow?.score ?? 0) * 1.2 + (shortLabelRow?.score ?? 0) * 1.15 + (answerPhraseFound ? 0.35 : 0) + (numbers.length ? numberSpecificity(context.answer.text) * 0.35 : 0) + Math.min(0.35, answerTokens.length * 0.015);
|
|
40718
|
+
let raw = (anchor?.score ?? 0) * 1.35 + (section?.score ?? 0) * 1.2 + (rowLabel?.score ?? 0) * 0.95 + (focused?.score ?? 0) * focusedWeight + (lineToken?.score ?? 0) * lineTokenWeight + (prefix?.score ?? 0) * 1.15 + (phrase?.score ?? 0) * phraseWeight + (precedingLabel?.score ?? 0) * 1.3 + (exactAnswer?.score ?? 0) * 1.08 + (chunk?.score ?? 0) * 1 + polarity.adjustment + (temporal.support?.score ?? 0) * 1 + temporal.adjustment + (clinicalCourseCue2.support?.score ?? 0) * 1.05 + clinicalCourseCue2.adjustment + conditionPair.adjustment + riskCondition.adjustment + genericPopulation.adjustment + (classSubject?.score ?? 0) * 1.15 + (frequency?.score ?? 0) * 1.1 + negativeLocal.adjustment + (boundedList.support?.score ?? 0) * 1.15 + boundedList.adjustment + (ordinalList?.score ?? 0) * 1.15 + (typeOrdinal?.score ?? 0) * 1.15 + (indicationLabel?.score ?? 0) * 1.15 + (labelDefinition?.score ?? 0) * 1.15 + (recommendationPolarity.support?.score ?? 0) * 1.05 + recommendationPolarity.adjustment + (exactNumericOption?.score ?? 0) * 1.04 + (exactHourAlias?.score ?? 0) * 1.08 + ageEligibility.adjustment + (drugDose?.score ?? 0) * 1.15 + (termDefinition?.score ?? 0) * 1.15 + (definitionExactAnswer?.score ?? 0) * 1.12 + (frequencyPolarity2?.score ?? 0) * 1.08 + negatedAnswerPrefix.adjustment + impossibilityOnly.adjustment + activeTherapyIndication.adjustment + (recommendationItem?.score ?? 0) * 1.1 + (recommendationBlock?.score ?? 0) * 0.92 + (explicitRecommendationTarget.support?.score ?? 0) * 1.05 + explicitRecommendationTarget.adjustment + (conditionedNumber?.score ?? 0) * 1.1 + (numericCondition?.score ?? 0) * 1.05 + (countRelation?.score ?? 0) * 1.1 + (ageForm?.score ?? 0) * 1.15 + (fibrosisStage?.score ?? 0) * 1.15 + (conditionNumber?.score ?? 0) * 1.15 + (romanStage?.score ?? 0) * 1.15 + (answerOrdinalRow?.score ?? 0) * 1.15 + (clozeGap?.score ?? 0) * 1.12 + (visualTableColumn?.score ?? 0) * 1.18 + (coordinateTableRow?.score ?? 0) * 1.12 + (coordinateTableGroup?.score ?? 0) * 1.16 + (coordinateMultiCellRow?.score ?? 0) * 1.16 + (coordinateTableMembership?.score ?? 0) * 1.1 + (parentheticalGroup?.score ?? 0) * 1.16 + (questionContinuationList?.score ?? 0) * 1.1 + (shortMedicalAlias?.score ?? 0) * 0.35 + (latinFuzzy?.score ?? 0) * latinFuzzyWeight + (geneSentence?.score ?? 0) * 1.18 + (clinicalFeature.support?.score ?? 0) * 1.12 + clinicalFeature.adjustment + (mkbClassExclusion.support?.score ?? 0) * 1.12 + mkbClassExclusion.adjustment + (labelNumber?.score ?? 0) * 1.15 + (classificationCode?.score ?? 0) * 1.15 + (exactShortLabelRow?.score ?? 0) * 1.2 + (shortLabelRow?.score ?? 0) * 1.15 + (answerPhraseFound ? 0.35 : 0) + (numbers.length ? numberSpecificity(context.answer.text) * 0.35 : 0) + Math.min(0.35, answerTokens.length * 0.015);
|
|
40055
40719
|
if (context.intent.listLike && context.anchorSegments?.length && !anchor) {
|
|
40056
40720
|
raw *= 0.62;
|
|
40057
40721
|
}
|
|
@@ -40072,6 +40736,8 @@ ${nextPage.text}`;
|
|
|
40072
40736
|
polarity.evidence,
|
|
40073
40737
|
temporal.support,
|
|
40074
40738
|
temporal.evidence,
|
|
40739
|
+
clinicalCourseCue2.support,
|
|
40740
|
+
clinicalCourseCue2.evidence,
|
|
40075
40741
|
conditionPair.evidence,
|
|
40076
40742
|
riskCondition.evidence,
|
|
40077
40743
|
genericPopulation.evidence,
|
|
@@ -40091,10 +40757,13 @@ ${nextPage.text}`;
|
|
|
40091
40757
|
ageEligibility.evidence,
|
|
40092
40758
|
drugDose,
|
|
40093
40759
|
termDefinition,
|
|
40760
|
+
definitionExactAnswer,
|
|
40761
|
+
frequencyPolarity2,
|
|
40094
40762
|
negatedAnswerPrefix.evidence,
|
|
40095
40763
|
impossibilityOnly.evidence,
|
|
40096
40764
|
activeTherapyIndication.evidence,
|
|
40097
40765
|
recommendationItem,
|
|
40766
|
+
recommendationBlock,
|
|
40098
40767
|
explicitRecommendationTarget.support,
|
|
40099
40768
|
explicitRecommendationTarget.evidence,
|
|
40100
40769
|
conditionedNumber,
|
|
@@ -40125,9 +40794,22 @@ ${nextPage.text}`;
|
|
|
40125
40794
|
exactShortLabelRow,
|
|
40126
40795
|
shortLabelRow
|
|
40127
40796
|
].filter(Boolean);
|
|
40797
|
+
const definitionCompletion = definitionCompletionAdjustment(context, evidence);
|
|
40798
|
+
raw += definitionCompletion.adjustment;
|
|
40799
|
+
if (definitionCompletion.evidence) evidence.push(definitionCompletion.evidence);
|
|
40128
40800
|
const contrastCue = contrastCueMismatchAdjustment(context, evidence.sort((a, b) => b.score - a.score));
|
|
40129
40801
|
raw += contrastCue.adjustment;
|
|
40130
40802
|
if (contrastCue.evidence) evidence.push(contrastCue.evidence);
|
|
40803
|
+
if (context.config?.optionFamilyComparatorGuard) {
|
|
40804
|
+
const optionFamilyComparator = optionFamilyComparatorAdjustment({ answer: context.answer, answers: context.answers, evidence });
|
|
40805
|
+
raw += optionFamilyComparator.adjustment;
|
|
40806
|
+
if (optionFamilyComparator.evidence) evidence.push(optionFamilyComparator.evidence);
|
|
40807
|
+
}
|
|
40808
|
+
if (context.config?.optionFamilyCompactComboGuard) {
|
|
40809
|
+
const optionFamilyCompactCombo = optionFamilyCompactComboAdjustment({ question: context.question, answer: context.answer, evidence });
|
|
40810
|
+
raw += optionFamilyCompactCombo.adjustment;
|
|
40811
|
+
if (optionFamilyCompactCombo.evidence) evidence.push(optionFamilyCompactCombo.evidence);
|
|
40812
|
+
}
|
|
40131
40813
|
const excludedCondition = excludedConditionMismatchAdjustment(context, evidence.sort((a, b) => b.score - a.score));
|
|
40132
40814
|
raw += excludedCondition.adjustment;
|
|
40133
40815
|
if (excludedCondition.evidence) evidence.push(excludedCondition.evidence);
|
|
@@ -40143,7 +40825,8 @@ ${nextPage.text}`;
|
|
|
40143
40825
|
if (!answers.length) throw new Error("predict input requires answers");
|
|
40144
40826
|
const runtime = await getPdfRuntime(pdfInput, {
|
|
40145
40827
|
cacheKey: input.cacheKey ?? input.pdfPath ?? input.pdfUrl ?? input.url,
|
|
40146
|
-
pdfjsLib: options.pdfjsLib
|
|
40828
|
+
pdfjsLib: options.pdfjsLib,
|
|
40829
|
+
pdfVerbosity: options.pdfVerbosity
|
|
40147
40830
|
});
|
|
40148
40831
|
const question = String(input.question ?? "");
|
|
40149
40832
|
const questionTokens = uniqueTokens(question);
|
|
@@ -40231,41 +40914,6 @@ ${nextPage.text}`;
|
|
|
40231
40914
|
}
|
|
40232
40915
|
};
|
|
40233
40916
|
}
|
|
40234
|
-
var CONFIDENCE_STRUCTURAL_KINDS = /* @__PURE__ */ new Set([
|
|
40235
|
-
"coordinate_table_row",
|
|
40236
|
-
"coordinate_table_group",
|
|
40237
|
-
"coordinate_table_group_inverse",
|
|
40238
|
-
"coordinate_table_multicell_row",
|
|
40239
|
-
"coordinate_table_membership",
|
|
40240
|
-
"parenthetical_group_segment",
|
|
40241
|
-
"preceding_question_label",
|
|
40242
|
-
"question_continuation_list",
|
|
40243
|
-
"exact_numeric_option_segment",
|
|
40244
|
-
"exact_hour_alias_segment",
|
|
40245
|
-
"visual_table_column",
|
|
40246
|
-
"exact_short_label_visual_row",
|
|
40247
|
-
"short_label_visual_row",
|
|
40248
|
-
"answer_ordinal_row",
|
|
40249
|
-
"fibrosis_stage_row",
|
|
40250
|
-
"gene_sentence_segment",
|
|
40251
|
-
"clinical_feature_segment",
|
|
40252
|
-
"mkb_class_exclusion_absent",
|
|
40253
|
-
"classification_code_segment",
|
|
40254
|
-
"label_number_proximity",
|
|
40255
|
-
"label_definition_segment",
|
|
40256
|
-
"row_label_segment",
|
|
40257
|
-
"bounded_list_segment",
|
|
40258
|
-
"ordinal_list_segment",
|
|
40259
|
-
"drug_dose_segment",
|
|
40260
|
-
"recommendation_item_segment",
|
|
40261
|
-
"explicit_recommendation_target_segment",
|
|
40262
|
-
"numeric_condition_less_than",
|
|
40263
|
-
"numeric_condition_more_than",
|
|
40264
|
-
"numeric_condition_equal",
|
|
40265
|
-
"conditioned_number_segment",
|
|
40266
|
-
"cloze_gap_local"
|
|
40267
|
-
]);
|
|
40268
|
-
var CONFIDENCE_BROAD_KINDS = /* @__PURE__ */ new Set(["bm25_question_answer", "question_chunk_answer", "answer_chunk_question", "answer_window", "focused_answer_window", "shared_multi_segment"]);
|
|
40269
40917
|
function confidenceEvidenceSummary(item) {
|
|
40270
40918
|
let bestScore = 0;
|
|
40271
40919
|
let bestKind = "";
|
|
@@ -40277,8 +40925,8 @@ ${nextPage.text}`;
|
|
|
40277
40925
|
bestScore = score;
|
|
40278
40926
|
bestKind = String(evidence.kind ?? "");
|
|
40279
40927
|
}
|
|
40280
|
-
if (
|
|
40281
|
-
if (
|
|
40928
|
+
if (CONFIDENCE_STRUCTURAL_EVIDENCE_KINDS.has(evidence.kind)) structuralScore = Math.max(structuralScore, score);
|
|
40929
|
+
if (BROAD_EVIDENCE_KINDS.has(evidence.kind)) broadCount += 1;
|
|
40282
40930
|
}
|
|
40283
40931
|
return {
|
|
40284
40932
|
bestScore,
|
|
@@ -40387,7 +41035,7 @@ ${nextPage.text}`;
|
|
|
40387
41035
|
answers,
|
|
40388
41036
|
mode: options.type ?? options.mode ?? "single"
|
|
40389
41037
|
},
|
|
40390
|
-
{ pdfjsLib: options.pdfjsLib }
|
|
41038
|
+
{ pdfjsLib: options.pdfjsLib, pdfVerbosity: options.pdfVerbosity }
|
|
40391
41039
|
);
|
|
40392
41040
|
const selectedAnswers = output.selected.map((id) => answers.find((answer) => answer.id === id)).filter(Boolean);
|
|
40393
41041
|
return {
|