Post-F: защитить VAT follow-up от stale period carryover

This commit is contained in:
dctouch 2026-04-24 00:14:50 +03:00
parent da8b328d98
commit d7d6be18ff
2 changed files with 22 additions and 5 deletions

View File

@ -15,6 +15,7 @@ const addressQueryShapeClassifier_1 = require("../addressQueryShapeClassifier");
const addressIntentResolver_1 = require("../addressIntentResolver"); const addressIntentResolver_1 = require("../addressIntentResolver");
const addressFilterExtractor_1 = require("../addressFilterExtractor"); const addressFilterExtractor_1 = require("../addressFilterExtractor");
const inventoryLifecycleCueHelpers_1 = require("../inventoryLifecycleCueHelpers"); const inventoryLifecycleCueHelpers_1 = require("../inventoryLifecycleCueHelpers");
const addressTextRepair_1 = require("../addressTextRepair");
const assistantOrganizationMatcher_1 = require("../assistantOrganizationMatcher"); const assistantOrganizationMatcher_1 = require("../assistantOrganizationMatcher");
const semanticHintOverlay_1 = require("./semanticHintOverlay"); const semanticHintOverlay_1 = require("./semanticHintOverlay");
function hasExplicitPeriodWindow(filters) { function hasExplicitPeriodWindow(filters) {
@ -28,6 +29,11 @@ function toNonEmptyString(value) {
const normalized = String(value).trim(); const normalized = String(value).trim();
return normalized.length > 0 ? normalized : null; return normalized.length > 0 ? normalized : null;
} }
function textWithRepairedVariant(text) {
const source = String(text ?? "");
const repaired = (0, addressTextRepair_1.repairAddressMojibakeText)(source);
return repaired && repaired !== source ? `${source} ${repaired}` : source;
}
function hasAllTimeHint(text) { function hasAllTimeHint(text) {
const normalized = String(text ?? ""); const normalized = String(text ?? "");
return /(?:за\s+вс[её]\s+время|за\s+весь\s+период|за\s+весь\s+срок|за\s+всю\s+истори(?:ю|и)|за\s+любой\s+период|за\s+любой\s+срок|for\s+all\s+time|all\s+time|for\s+entire\s+period|entire\s+period|for\s+any\s+period|any\s+period|for\s+full\s+history|full\s+history)/iu.test(normalized); return /(?:за\s+вс[её]\s+время|за\s+весь\s+период|за\s+весь\s+срок|за\s+всю\s+истори(?:ю|и)|за\s+любой\s+период|за\s+любой\s+срок|for\s+all\s+time|all\s+time|for\s+entire\s+period|entire\s+period|for\s+any\s+period|any\s+period|for\s+full\s+history|full\s+history)/iu.test(normalized);
@ -45,13 +51,13 @@ function hasExplicitPeriodLiteral(text) {
return /(?:^|[^\d*×xх])((?:19|20)\d{2}(?:[./-](?:0?[1-9]|1[0-2]))?)(?=$|[^\d*×xх])/iu.test(String(text ?? "")); return /(?:^|[^\d*×xх])((?:19|20)\d{2}(?:[./-](?:0?[1-9]|1[0-2]))?)(?=$|[^\d*×xх])/iu.test(String(text ?? ""));
} }
function hasExplicitCurrentDateHint(text) { function hasExplicitCurrentDateHint(text) {
return /(?:на\s+текущ(?:ую|ая|ий|ее|ей|ем|его)\s+дат(?:у|а|е|ой|ою)|на\s+сегодняшн(?:юю|ий|ей|ем|его)\s+дат(?:у|а|е|ой|ою)|на\s+сегодня|сегодня|на\s+текущ(?:ий|ую)\s+момент|today|as\s+of\s+today|current\s+date|as\s+of\s+current\s+date)/iu.test(String(text ?? "")); return /(?:на\s+текущ(?:ую|ая|ий|ее|ей|ем|его)\s+дат(?:у|а|е|ой|ою)|на\s+сегодняшн(?:юю|ий|ей|ем|его)\s+дат(?:у|а|е|ой|ою)|на\s+сегодня|сегодня|на\s+текущ(?:ий|ую)\s+момент|today|as\s+of\s+today|current\s+date|as\s+of\s+current\s+date)/iu.test(textWithRepairedVariant(String(text ?? "")));
} }
function hasOpenItemsHint(text) { function hasOpenItemsHint(text) {
return /(?:open\s+items|unclosed\s+items|хвост|висят|незакрыт|не\s+закрыт|открыт|долг|задолж|позиц)/iu.test(String(text ?? "")); return /(?:open\s+items|unclosed\s+items|хвост|висят|незакрыт|не\s+закрыт|открыт|долг|задолж|позиц)/iu.test(String(text ?? ""));
} }
function hasVatCue(text) { function hasVatCue(text) {
return /(?:^|[\s,.;:!?()\-])(?:ндс|vat)(?=$|[\s,.;:!?()\-])/iu.test(String(text ?? "")); return /(?:^|[\s,.;:!?()\-])(?:ндс[а-яё]*|vat)(?=$|[\s,.;:!?()\-])/iu.test(textWithRepairedVariant(String(text ?? "")));
} }
function hasVatForecastCue(text) { function hasVatForecastCue(text) {
return /(?:прогноз|forecast|прикин|оцен|план)/iu.test(String(text ?? "")); return /(?:прогноз|forecast|прикин|оцен|план)/iu.test(String(text ?? ""));
@ -1059,6 +1065,7 @@ function mergeFollowupFilters(current, intent, userMessage, followupContext) {
previousHasPeriod && previousHasPeriod &&
hasFollowupSignal && hasFollowupSignal &&
!hasExplicitPeriodInMessage && !hasExplicitPeriodInMessage &&
!hasExplicitCurrentDateInMessage &&
!inventoryLifecycleHistoryIntent && !inventoryLifecycleHistoryIntent &&
!vatRelativeMonthFollowup && !vatRelativeMonthFollowup &&
!shouldSuppressGenericPeriodCarryover) { !shouldSuppressGenericPeriodCarryover) {

View File

@ -1,4 +1,4 @@
import type { import type {
AddressFilterSet, AddressFilterSet,
AddressIntent, AddressIntent,
AddressIntentResolution, AddressIntentResolution,
@ -21,6 +21,7 @@ import {
hasInventorySaleCue, hasInventorySaleCue,
hasInventorySupplierCue hasInventorySupplierCue
} from "../inventoryLifecycleCueHelpers"; } from "../inventoryLifecycleCueHelpers";
import { repairAddressMojibakeText } from "../addressTextRepair";
import { normalizeOrganizationScopeSearchText, organizationsLikelySameEntity } from "../assistantOrganizationMatcher"; import { normalizeOrganizationScopeSearchText, organizationsLikelySameEntity } from "../assistantOrganizationMatcher";
import { applyAddressLlmSemanticHintsToExtraction } from "./semanticHintOverlay"; import { applyAddressLlmSemanticHintsToExtraction } from "./semanticHintOverlay";
import type { AddressLlmSemanticHints } from "../../types/addressQuery"; import type { AddressLlmSemanticHints } from "../../types/addressQuery";
@ -88,6 +89,12 @@ function toNonEmptyString(value: unknown): string | null {
return normalized.length > 0 ? normalized : null; return normalized.length > 0 ? normalized : null;
} }
function textWithRepairedVariant(text: string): string {
const source = String(text ?? "");
const repaired = repairAddressMojibakeText(source);
return repaired && repaired !== source ? `${source} ${repaired}` : source;
}
function hasAllTimeHint(text: string): boolean { function hasAllTimeHint(text: string): boolean {
const normalized = String(text ?? ""); const normalized = String(text ?? "");
return /(?:за\s+вс[её]\s+время|за\s+весь\s+период|за\s+весь\s+срок|за\s+всю\s+истори(?:ю|и)|за\s+любой\s+период|за\s+любой\s+срок|for\s+all\s+time|all\s+time|for\s+entire\s+period|entire\s+period|for\s+any\s+period|any\s+period|for\s+full\s+history|full\s+history)/iu.test( return /(?:за\s+вс[её]\s+время|за\s+весь\s+период|за\s+весь\s+срок|за\s+всю\s+истори(?:ю|и)|за\s+любой\s+период|за\s+любой\s+срок|for\s+all\s+time|all\s+time|for\s+entire\s+period|entire\s+period|for\s+any\s+period|any\s+period|for\s+full\s+history|full\s+history)/iu.test(
@ -117,7 +124,7 @@ function hasExplicitPeriodLiteral(text: string): boolean {
function hasExplicitCurrentDateHint(text: string): boolean { function hasExplicitCurrentDateHint(text: string): boolean {
return /(?:на\s+текущ(?:ую|ая|ий|ее|ей|ем|его)\s+дат(?:у|а|е|ой|ою)|на\s+сегодняшн(?:юю|ий|ей|ем|его)\s+дат(?:у|а|е|ой|ою)|на\s+сегодня|сегодня|на\s+текущ(?:ий|ую)\s+момент|today|as\s+of\s+today|current\s+date|as\s+of\s+current\s+date)/iu.test( return /(?:на\s+текущ(?:ую|ая|ий|ее|ей|ем|его)\s+дат(?:у|а|е|ой|ою)|на\s+сегодняшн(?:юю|ий|ей|ем|его)\s+дат(?:у|а|е|ой|ою)|на\s+сегодня|сегодня|на\s+текущ(?:ий|ую)\s+момент|today|as\s+of\s+today|current\s+date|as\s+of\s+current\s+date)/iu.test(
String(text ?? "") textWithRepairedVariant(String(text ?? ""))
); );
} }
@ -126,7 +133,9 @@ function hasOpenItemsHint(text: string): boolean {
} }
function hasVatCue(text: string): boolean { function hasVatCue(text: string): boolean {
return /(?:^|[\s,.;:!?()\-])(?:ндс|vat)(?=$|[\s,.;:!?()\-])/iu.test(String(text ?? "")); return /(?:^|[\s,.;:!?()\-])(?:ндс[а-яё]*|vat)(?=$|[\s,.;:!?()\-])/iu.test(
textWithRepairedVariant(String(text ?? ""))
);
} }
function hasVatForecastCue(text: string): boolean { function hasVatForecastCue(text: string): boolean {
@ -1327,6 +1336,7 @@ function mergeFollowupFilters(
previousHasPeriod && previousHasPeriod &&
hasFollowupSignal && hasFollowupSignal &&
!hasExplicitPeriodInMessage && !hasExplicitPeriodInMessage &&
!hasExplicitCurrentDateInMessage &&
!inventoryLifecycleHistoryIntent && !inventoryLifecycleHistoryIntent &&
!vatRelativeMonthFollowup && !vatRelativeMonthFollowup &&
!shouldSuppressGenericPeriodCarryover !shouldSuppressGenericPeriodCarryover