Post-F: укрепить Unicode arbitration address-интентов

This commit is contained in:
dctouch 2026-04-24 13:43:34 +03:00
parent 5a9b30bcdb
commit f5409bbcbc
2 changed files with 965 additions and 1 deletions

View File

@ -1551,6 +1551,279 @@ function repairLikelyUtf8Mojibake(text) {
return raw;
}
}
function unicodeBridgeResolution(intent, confidence, reason) {
return { intent, confidence, reasons: [reason] };
}
function resolveUnicodeAddressIntentBridge(text) {
const normalized = String(text ?? "").trim().toLowerCase();
if (!normalized) {
return null;
}
const hasAccountAnchor = /(?:\b(?:60|62|76)(?:[.,]\d{2})?\b|сч(?:е|ё)т(?:а|у|ом|е|ов)?|account)/iu.test(normalized);
const hasDocumentCue = /(?:док(?:умент(?:ы|ов|а|ам|ами|ах)?|и|ам|ами|ах|ов|а)?|docs?|documents?)/iu.test(normalized);
const hasBankCue = /(?:банк|банковск|плат[её]ж|оплат|транзакц|51|bank|payment|transaction)/iu.test(normalized);
const hasContractCue = /(?:договор|дог(?:\s|$)|контракт|contract|dogovor)/iu.test(normalized);
const hasSpecificContractCue = /(?:\b\d{1,4}\/\d{1,4}\b|этому\s+же\s+договор)/iu.test(normalized);
const hasCounterpartyCue = /(?:контрагент|компани|организац|клиент|покупател|заказчик|поставщик|свк|альфа|жуковк|альтернатива|counterpart|company|supplier|customer|client|buyer)/iu.test(normalized);
const byAnchorMatch = normalized.match(/(?:^|[\s,.;:!?])(?:по|для)\s+([\p{L}\d._-]{2,})/iu);
const byAnchorToken = String(byAnchorMatch?.[1] ?? "").toLowerCase();
const hasLooseCounterpartyByAnchor = !!byAnchorToken &&
!new Set([
"количеству",
"документам",
"докам",
"договору",
"договорам",
"счету",
"счёту",
"остатку",
"операциям",
"оплате",
"платежам",
"сальдо",
"дате",
"периоду",
"складу",
"товару",
"этому",
"этой",
"нему",
"ней"
]).has(byAnchorToken);
const hasMoneyCue = /(?:деньг|денег|выручк|доход|оборот|заработ|прин[её]с|чек|ликвидн|revenue|turnover|money)/iu.test(normalized);
const hasRankingCue = /(?:топ|ранк|сам(?:ый|ая|ое|ые)|больше\s+всего|наибольш|крупн|жирн|max|top|rank)/iu.test(normalized);
if (/(?:за\s+какие\s+годы|диапазон\s+лет|покрыт(?:ие|ый)\s+период|какой\s+год.*актив|какой\s+месяц.*актив|год.*пассив|месяц.*пассив|минимальн.*док|минимальн.*операц|месяц[\s-]*пик|profile\s+period|top\s*year|top\s*month)/iu.test(normalized)) {
return unicodeBridgeResolution("period_coverage_profile", "high", "unicode_period_coverage_bridge_signal_detected");
}
if (/(?:тип(?:ы|ов)?\s+док|док(?:умент|ов).*?(?:чаще|редк|больше\s+всего|меньше\s+всего|крутит)|раздел(?:ы|ов)?\s+уч[её]та|сводк.*тип.*док|document\s+type|account\s+section)/iu.test(normalized)) {
return unicodeBridgeResolution("document_type_and_account_section_profile", "high", "unicode_document_type_profile_bridge_signal_detected");
}
if (hasAccountAnchor &&
hasDocumentCue &&
/(?:формирующ.*остат|раскрой\s+остат|остат.*по\s+документ|по\s+докам.*(?:60|62|76)|(?:60|62|76)(?:[.,]\d{2})?.*(?:по\s+докам|по\s+документ))/iu.test(normalized)) {
return unicodeBridgeResolution("documents_forming_balance", "high", "unicode_documents_forming_balance_bridge_signal_detected");
}
if (/(?:договор[а-я]*.*(?:все|список).*по\s+[\p{L}\d]|(?:покажи|показать).*договор[а-я]*.*по\s+[\p{L}\d])/iu.test(normalized)) {
return unicodeBridgeResolution("list_contracts_by_counterparty", "high", "unicode_contracts_by_counterparty_bridge_signal_detected");
}
if (/(?:проконтрол|акты\s+без\s+приход|без\s+приходок|засорять\s+бухгалтер)/iu.test(normalized)) {
return unicodeBridgeResolution("unknown", "low", "unsupported_supplier_control_signal_detected");
}
if (/(?:кроме\s+этого\s+документ.*(?:есть\s+еще\s+что|есть\s+ещ[её]\s+что|что[-\s]?то))/iu.test(normalized)) {
return unicodeBridgeResolution("list_documents_by_counterparty", "medium", "generic_document_followup_with_previous_counterparty");
}
if (/(?:плат[её]ж|оплат|отгрузк|документ|аванс|взаиморасчет|закрыт)/iu.test(normalized) &&
/(?:без\s+(?:закрыт|документ|оплат)|нет\s+(?:документ|оплат)|не\s+закрыт|оплат[а-я]*\s+нет|документ[а-я]*\s+есть|требует\s+ручн)/iu.test(normalized)) {
return unicodeBridgeResolution("list_open_contracts", "high", "unicode_open_contract_gap_bridge_signal_detected");
}
if (/(?:долгожител|долго\s+долж|задолженн(?:ост|остям).*(?:давн|долго)|не\s+плат|не\s+оплат|не\s+оплачен|неоплачен|просроч|сроки\s+давно\s+прошл|слишком\s+длинн.*оплат)/iu.test(normalized) &&
/(?:покупател|клиент|заказ|отгрузк|товар|услуг|задолженн|сальдо|не\s+плат|не\s+оплат|не\s+оплачен|неоплачен|просроч)/iu.test(normalized)) {
return unicodeBridgeResolution("list_receivables_counterparties", "high", "receivables_debt_lifecycle_signal_detected");
}
const inventoryBridgeIntent = (0, addressInventoryIntentSignals_1.resolveInventoryAddressIntent)(normalized);
if (inventoryBridgeIntent) {
if (inventoryBridgeIntent.intent === "inventory_aging_by_purchase_date") {
return { ...inventoryBridgeIntent, confidence: "high" };
}
return inventoryBridgeIntent;
}
if (/(?:поставщик|vendor|supplier)/iu.test(normalized) &&
/(?:хвост|задержк|проблем|систематическ)/iu.test(normalized)) {
return unicodeBridgeResolution("list_payables_counterparties", "high", "supplier_tail_risk_signal_detected");
}
if (hasBankCue && (hasCounterpartyCue || hasLooseCounterpartyByAnchor) && !hasContractCue) {
return unicodeBridgeResolution("bank_operations_by_counterparty", "high", "unicode_bank_ops_by_counterparty_bridge_signal_detected");
}
if (/(?:есть\s+что[-\s]?то|что[-\s]?то)/iu.test(normalized) &&
(hasLooseCounterpartyByAnchor || /по\s+(?:ней|нему|этой|этому)/iu.test(normalized))) {
return unicodeBridgeResolution("list_documents_by_counterparty", "medium", "generic_lookup_with_loose_anchor_fallback");
}
if (hasDocumentCue &&
(hasLooseCounterpartyByAnchor || hasCounterpartyCue || /по\s+(?:ней|нему|этой|этому)/iu.test(normalized)) &&
!hasContractCue &&
!/(?:купил|куплен|закуп|товар|позици|номенклатур)/iu.test(normalized)) {
return unicodeBridgeResolution("list_documents_by_counterparty", "medium", "unicode_documents_by_counterparty_bridge_signal_detected");
}
if (/(?:долгожител|долго\s+долж|задолженн(?:ост|остям).*(?:давн|долго)|не\s+плат|не\s+оплат|не\s+оплачен|неоплачен|просроч|сроки\s+давно\s+прошл|слишком\s+длинн.*оплат)/iu.test(normalized) &&
/(?:покупател|клиент|заказ|отгрузк|товар|услуг|задолженн|сальдо|не\s+плат|не\s+оплат|не\s+оплачен|неоплачен|просроч)/iu.test(normalized)) {
return unicodeBridgeResolution("list_receivables_counterparties", "high", "receivables_debt_lifecycle_signal_detected");
}
if (/\b41(?:[.,]\d{2})?\b/iu.test(normalized) && /(?:товар|склад|остат|состоит|номенклатур)/iu.test(normalized)) {
return unicodeBridgeResolution("inventory_on_hand_as_of_date", "high", "unicode_inventory_on_hand_bridge_signal_detected");
}
if (/(?:год.*(?:док|операц).*(?:актив|пик|жив|много|движов)|год.*движов.*(?:док|операц)|(?:док|операц).*год.*(?:актив|пик|жив|много|движов)|месяц[\s-]*пик)/iu.test(normalized)) {
return unicodeBridgeResolution("period_coverage_profile", "high", "unicode_period_coverage_bridge_signal_detected");
}
if (!hasContractCue &&
/(?:скольк|скока).*(?:деньг|денег|выручк|доход|оборот)|(?:деньг|денег|выручк|доход|оборот).*(?:прин[её]с|зан[её]с|плат)/iu.test(normalized)) {
return unicodeBridgeResolution("customer_revenue_and_payments", "high", "unicode_customer_revenue_bridge_signal_detected");
}
if (!hasContractCue &&
/(?:кто|какие|выведи|покажи|список|самые)/iu.test(normalized) &&
/(?:список\s+(?:заказчик|клиент|покупател).*за\s+\d{2,4}\s*год|актив.*отвал|ровно\s+один\s+раз|один\s+раз.*пропал|стар(?:ые|ые)?\s+по\s+сотруднич|сотрудничеству\s+кто)/iu.test(normalized)) {
return unicodeBridgeResolution("counterparty_activity_lifecycle", "high", "unicode_counterparty_lifecycle_bridge_signal_detected");
}
if (!hasContractCue &&
/(?:кто|какие|выведи|покажи|список|разбей|раздели|самые)/iu.test(normalized) &&
/(?:заказчик|клиент|покупател|поставщик|контрагент|зак(?!рыт))/iu.test(normalized) &&
/(?:работал|работают|актив|все\s+время|вообще|регулярн|эпизодич|частот|давно\s+не\s+использ|операционн|разов|один\s+раз|пропал|отвал|сотруднич)/iu.test(normalized)) {
return unicodeBridgeResolution("counterparty_activity_lifecycle", "high", "unicode_counterparty_lifecycle_bridge_signal_detected");
}
if (/(?:поставщик|vendor|supplier|кому\s+(?:ушло|платили|заплатили)|выплат|исходящ|списан|сгрузил)/iu.test(normalized) &&
!/(?:аванс.*(?:не\s+)?закрыт|закрыт.*аванс)/iu.test(normalized) &&
(hasMoneyCue || hasRankingCue || /плат[её]ж|оплат|выплат|outflow|payout|хвост|задержк|проблем/iu.test(normalized))) {
return unicodeBridgeResolution(/(?:хвост|задержк|проблем)/iu.test(normalized) ? "list_payables_counterparties" : "supplier_payouts_profile", "high", /(?:хвост|задержк|проблем)/iu.test(normalized)
? "supplier_tail_risk_signal_detected"
: "unicode_supplier_payouts_bridge_signal_detected");
}
if (!hasContractCue &&
(/(?:клиент|покупател|заказчик|контрагент|альтернатива|свк)/iu.test(normalized) || hasRankingCue) &&
(hasMoneyCue || /поступлен|приход|входящ|сделк|бюджет|inflow/iu.test(normalized))) {
return unicodeBridgeResolution("customer_revenue_and_payments", "high", "unicode_customer_revenue_bridge_signal_detected");
}
if (!hasContractCue &&
/(?:кто.*(?:деньг|денег|доход|выручк).*(?:прин[её]с|зан[её]с|плат)|(?:жирн|ликвидн).*контрагент.*(?:деньг|денег))/iu.test(normalized)) {
return unicodeBridgeResolution("customer_revenue_and_payments", "high", "unicode_customer_revenue_bridge_signal_detected");
}
if (/(?:общие\s+обороты|общая\s+выручк|оборот.*за\s+все\s+время|выручк.*за\s+все\s+время)/iu.test(normalized)) {
return unicodeBridgeResolution("customer_revenue_and_payments", "high", "unicode_customer_revenue_bridge_signal_detected");
}
if (/(?:открыт(?:ые|ая|ый)?\s+задолж|открыт(?:ые|ая|ый)?\s+позици|позици.*по\s+договор|open\s+items?)/iu.test(normalized) &&
(hasContractCue || hasCounterpartyCue || hasAccountAnchor || /покупател|клиент/iu.test(normalized))) {
return unicodeBridgeResolution("open_items_by_counterparty_or_contract", "high", "unicode_open_items_bridge_signal_detected");
}
if (hasContractCue &&
/(?:нескольк(?:ими|о)?\s+договор|контрагент.*нескольк.*договор|какие\s+из\s+договор.*актив)/iu.test(normalized)) {
return unicodeBridgeResolution("contract_usage_and_value", "high", "unicode_contract_usage_value_bridge_signal_detected");
}
if (hasContractCue && (hasMoneyCue || hasRankingCue || /оборот|бюджет|сумм|стоим|value|amount/iu.test(normalized))) {
return unicodeBridgeResolution("contract_usage_and_value", "high", "unicode_contract_usage_value_bridge_signal_detected");
}
if (/(?:сальдо.*(?:расход|не\s+совпад)|расход.*сальдо|акт(?:ом|ах)?\s+сверк|плат[её]ж[и]?,?\s+но\s+нет\s+док|документ(?:ы)?\s+есть,?\s+а\s+оплат\s+нет|(?:оплат|плат[её]ж|отгрузк|закрыти[ея]\s+счет)[\p{L}\s,]*\s+без\s+(?:закрыт|документ|подтвержд)|аванс.*давно\s+не\s+закрыт)/iu.test(normalized)) {
return unicodeBridgeResolution("list_open_contracts", "high", "unicode_open_contracts_list_bridge_signal_detected");
}
if (/(?:долгожител|долго\s+долж|задолженн(?:ост|остям).*(?:давн|долго)|не\s+плат|не\s+оплат|не\s+оплачен|неоплачен|просроч|сроки\s+давно\s+прошл|слишком\s+длинн.*оплат)/iu.test(normalized) &&
/(?:покупател|клиент|заказ|отгрузк|товар|услуг|задолженн|сальдо|не\s+плат|не\s+оплат|не\s+оплачен|неоплачен|просроч)/iu.test(normalized)) {
return unicodeBridgeResolution("list_receivables_counterparties", "high", "receivables_debt_lifecycle_signal_detected");
}
if (/(?:сальдо.*(?:расход|не\s+совпад)|расход.*сальдо|акт(?:ом|ах)?\s+сверк|плат[её]ж[и]?,?\s+но\s+нет\s+док|документ(?:ы)?\s+есть,?\s+а\s+оплат\s+нет|(?:оплат|плат[её]ж|отгрузк|закрыти[ея]\s+счет)[\p{L}\s,]*\s+без\s+(?:закрыт|документ|подтвержд)|аванс.*давно\s+не\s+закрыт)/iu.test(normalized)) {
return unicodeBridgeResolution("list_open_contracts", "high", "unicode_open_contracts_list_bridge_signal_detected");
}
if (/(?:открыт(?:ые|ая|ый)?\s+позици|позици.*по\s+договор|open\s+items?)/iu.test(normalized) &&
(hasContractCue || hasCounterpartyCue || hasAccountAnchor)) {
return unicodeBridgeResolution("open_items_by_counterparty_or_contract", "high", "unicode_open_items_bridge_signal_detected");
}
if (hasAccountAnchor &&
hasDocumentCue &&
/(?:формир|под\s+остат|раскр(?:ой|ыть|ывай)|остат(?:ок|ком)?\s+по\s+док|documents?\s+forming|docs?\s+forming)/iu.test(normalized)) {
return unicodeBridgeResolution("documents_forming_balance", "high", "unicode_documents_forming_balance_bridge_signal_detected");
}
if (hasContractCue && hasSpecificContractCue && hasBankCue) {
return unicodeBridgeResolution("bank_operations_by_contract", "high", "unicode_bank_ops_by_contract_bridge_signal_detected");
}
if (hasContractCue && hasSpecificContractCue && hasDocumentCue) {
return unicodeBridgeResolution("list_documents_by_contract", "high", "unicode_documents_by_contract_bridge_signal_detected");
}
if (hasAccountAnchor &&
!hasDocumentCue &&
/(?:баланс|остат(?:ок)?|сальдо|что\s+на\s+сч(?:е|ё)те|по\s+сч(?:е|ё)ту|скольк|скока|account\s+balance|balance\s+account|as\s+of)/iu.test(normalized)) {
return unicodeBridgeResolution("account_balance_snapshot", "high", "unicode_account_balance_bridge_signal_detected");
}
if (/(?:ндс|vat)/iu.test(normalized)) {
const hasVatDebtCue = /(?:долг|должн|подтвержд)/iu.test(normalized);
if (/(?:прогноз|прикин|план)/iu.test(normalized) ||
(!hasVatDebtCue && /(?:надо|нужно)\s+(?:заплат|оплат|уплат)/iu.test(normalized))) {
return unicodeBridgeResolution("vat_payable_forecast", "high", "forecast_tax_signal_detected");
}
if (/(?:долг|подтвержд|скольк|скока|надо|нужно|заплат|уплат|оплат)/iu.test(normalized)) {
return unicodeBridgeResolution(/(?:налогов|бюджет|декларац|квартал|\b[1-4]\s*кв)/iu.test(normalized)
? "vat_liability_confirmed_for_tax_period"
: "vat_payable_confirmed_as_of_date", "high", "vat_payable_confirmed_signal_detected");
}
}
if (/(?:незакрыт|открыт).*договор/iu.test(normalized) &&
!/(?:долг|задолж|хвост|висит|расчет|расчёт)/iu.test(normalized)) {
return unicodeBridgeResolution("open_contracts_confirmed_as_of_date", "high", "unicode_open_contracts_snapshot_bridge_signal_detected");
}
if (/(?:долг|задолж|хвост|висит|открыт(?:ые|ая|ый)?\s+задолж|open\s+items?)/iu.test(normalized) &&
(hasContractCue || hasCounterpartyCue || hasAccountAnchor || /покупател|клиент/iu.test(normalized))) {
return unicodeBridgeResolution("open_items_by_counterparty_or_contract", "high", "unicode_open_items_bridge_signal_detected");
}
if (hasContractCue &&
/(?:без\s+(?:закрыт|оплат|плат[её]ж|док)|не\s+закрыт|аванс|отгрузк|плат[её]ж.*без|док.*без|расхожд|mismatch)/iu.test(normalized)) {
return unicodeBridgeResolution("list_open_contracts", "high", "unicode_open_contracts_list_bridge_signal_detected");
}
if (hasContractCue &&
/(?:скольк.*(?:всего\s+)?договор|договор.*(?:заведен|использовал|реально\s+использ)|сколько\s+из\s+них)/iu.test(normalized)) {
return unicodeBridgeResolution("contract_usage_overview", "high", "unicode_contract_usage_overview_bridge_signal_detected");
}
if (hasContractCue &&
/(?:нескольк(?:ими|о)?\s+договор|контрагент.*нескольк.*договор|какие\s+из\s+договор.*актив)/iu.test(normalized)) {
return unicodeBridgeResolution("contract_usage_and_value", "high", "unicode_contract_usage_value_bridge_signal_detected");
}
if (hasContractCue &&
/(?:все|покажи|показать|какие|список|list|show)/iu.test(normalized) &&
!hasSpecificContractCue &&
!hasDocumentCue &&
!hasBankCue &&
(hasCounterpartyCue || hasLooseCounterpartyByAnchor)) {
return unicodeBridgeResolution("list_contracts_by_counterparty", "high", "unicode_contracts_by_counterparty_bridge_signal_detected");
}
if (hasContractCue && !hasSpecificContractCue && !hasDocumentCue && !hasBankCue && hasCounterpartyCue) {
return unicodeBridgeResolution("list_contracts_by_counterparty", "high", "unicode_contracts_by_counterparty_bridge_signal_detected");
}
if (hasBankCue && (hasCounterpartyCue || hasLooseCounterpartyByAnchor) && !hasContractCue) {
return unicodeBridgeResolution("bank_operations_by_counterparty", "high", "unicode_bank_ops_by_counterparty_bridge_signal_detected");
}
if (hasDocumentCue && (hasCounterpartyCue || hasLooseCounterpartyByAnchor) && !hasContractCue && !hasAccountAnchor) {
return unicodeBridgeResolution("list_documents_by_counterparty", "high", "unicode_documents_by_counterparty_bridge_signal_detected");
}
if (/(?:за\s+какие\s+годы|диапазон\s+лет|покрыт(?:ие|ый)\s+период|какой\s+год.*актив|какой\s+месяц.*актив|год.*пассив|месяц.*пассив|минимальн.*док|минимальн.*операц|profile\s+period|top\s*year|top\s*month)/iu.test(normalized)) {
return unicodeBridgeResolution("period_coverage_profile", "high", "unicode_period_coverage_bridge_signal_detected");
}
if (/(?:тип(?:ы|ов)?\s+док|документ.*(?:чаще|редк|больше\s+всего|меньше\s+всего)|раздел(?:ы|ов)?\s+уч[её]та|сводк.*тип.*док|document\s+type|account\s+section)/iu.test(normalized)) {
return unicodeBridgeResolution("document_type_and_account_section_profile", "high", "unicode_document_type_profile_bridge_signal_detected");
}
if (/(?:скольк|скока|число|количеств|разбей|раздели|сформируй\s+сводк)/iu.test(normalized) &&
/(?:контрагент|поставщик|клиент|покупател|заказчик|рол)/iu.test(normalized) &&
!/(?:активн|давно|нов(?:ые|ых)|однораз|уш[её]л|исчез|регулярн|эпизодич|частот|разов|churn|lifecycle)/iu.test(normalized)) {
return unicodeBridgeResolution("counterparty_population_and_roles", "high", "unicode_counterparty_population_bridge_signal_detected");
}
if (/(?:скок|скока|сколько)\s+(?:клиент|покупател|заказчик)/iu.test(normalized)) {
return unicodeBridgeResolution("counterparty_population_and_roles", "high", "unicode_counterparty_population_bridge_signal_detected");
}
if (/(?:активн(?:ые|ость)?\s+(?:клиент|покупател|поставщик|контрагент)|все\s+время|однораз|давно\s+(?:не\s+)?(?:покупал|платил|актив)|уш[её]л|исчез|нов(?:ые|ых)\s+(?:клиент|контрагент)|регулярн|разов(?:ый|ые)|stale\s+supplier|churn|lifecycle)/iu.test(normalized)) {
return unicodeBridgeResolution("counterparty_activity_lifecycle", "high", "unicode_counterparty_lifecycle_bridge_signal_detected");
}
if (hasContractCue && /(?:давно\s+не\s+использ|не\s+использ|stale|inactive)/iu.test(normalized)) {
return unicodeBridgeResolution("contract_usage_overview", "high", "unicode_contract_usage_overview_bridge_signal_detected");
}
if (hasContractCue && (hasMoneyCue || hasRankingCue || /оборот|бюджет|сумм|стоим|value|amount/iu.test(normalized))) {
return unicodeBridgeResolution("contract_usage_and_value", "high", "unicode_contract_usage_value_bridge_signal_detected");
}
if (/(?:поставщик|vendor|supplier|кому\s+(?:ушло|платили|заплатили)|выплат|исходящ|списан|сгрузил)/iu.test(normalized) &&
(hasMoneyCue || hasRankingCue || /плат[её]ж|оплат|выплат|outflow|payout/iu.test(normalized))) {
return unicodeBridgeResolution("supplier_payouts_profile", "high", "unicode_supplier_payouts_bridge_signal_detected");
}
if ((/(?:клиент|покупател|заказчик|контрагент|альтернатива|свк)/iu.test(normalized) || hasRankingCue) &&
(hasMoneyCue || /поступлен|приход|входящ|inflow/iu.test(normalized))) {
return unicodeBridgeResolution("customer_revenue_and_payments", "high", "unicode_customer_revenue_bridge_signal_detected");
}
if (/(?:к[оа]му\s+мы\s+должны|мы\s+должны\s+к[оа]му|кредитор|payables?)/iu.test(normalized)) {
return unicodeBridgeResolution("payables_confirmed_as_of_date", "high", "payables_debt_lifecycle_signal_detected");
}
if (/(?:кто\s+нам\s+должен|нам\s+должны|дебитор|receivables?)/iu.test(normalized)) {
return unicodeBridgeResolution("receivables_confirmed_as_of_date", "high", "unicode_receivables_snapshot_bridge_signal_detected");
}
if (/(?:покупател|клиент).*(?:не\s+плат|просроч|долго\s+долж|долг.*давн)|(?:долг|задолж).*(?:покупател|клиент)/iu.test(normalized)) {
return unicodeBridgeResolution("list_receivables_counterparties", "high", "unicode_receivables_list_bridge_signal_detected");
}
if (/(?:что|че|чё|какие|покажи|показать|список).*(?:склад|остат|товар)|(?:склад|остат).*(?:сейчас|лежит|есть|на\s+дату|на\s+конец|what|show|list)/iu.test(normalized) &&
!/(?:поставщик|продаж|реализ|цепоч|документал|давно|стар(?:ые|ый|ым|ых)|закуп)/iu.test(normalized)) {
return unicodeBridgeResolution("inventory_on_hand_as_of_date", "high", "unicode_inventory_on_hand_bridge_signal_detected");
}
return null;
}
function resolveAddressIntent(userMessage) {
const text = String(userMessage ?? "").trim().toLowerCase();
const repairedText = repairLikelyUtf8Mojibake(text).trim().toLowerCase();
@ -1559,6 +1832,10 @@ function resolveAddressIntent(userMessage) {
.replace(/(^|[^\p{L}0-9_])\u043d\u0430\u043c\u0441(?=$|[^\p{L}0-9_])/giu, "$1\u043d\u0430\u043c")
.replace(/(^|[^\p{L}0-9_])\u043a\u0430\u043a\u0438\u0435\u043a(?=$|[^\p{L}0-9_])/giu, "$1\u043a\u0430\u043a\u0438\u0435");
const currentTurnBridgeText = turnNoiseNormalizedBridgeText !== bridgeText ? `${bridgeText} ${turnNoiseNormalizedBridgeText}` : bridgeText;
const unicodeAddressIntent = resolveUnicodeAddressIntentBridge(currentTurnBridgeText);
if (unicodeAddressIntent) {
return unicodeAddressIntent;
}
const hasLooseVatPayableBridge = /(?:\u043d\u0434\u0441|vat)/iu.test(text) &&
/(?:\u043a\u0430\u043a\u043e\u0439\s+\u043d\u0434\u0441\s+(?:(?:\u043d\u0430\u043c|(?:\u043c\u044b\s+)?\u0434\u043e\u043b\u0436\u043d\u044b)\s+)?(?:\u043d\u0430\u0434\u043e|\u043d\u0443\u0436\u043d\u043e|\u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e)|(?:\u043d\u0430\u043c|\u043c\u044b\s+)?\u043d\u0430\u0434\u043e\s+(?:\u0437\u0430\u043f\u043b\u0430\u0442\u0438\u0442\u044c|\u0441\u0433\u0440\u0443\u0437\u0438\u0442\u044c)|(?:\u043d\u0430\u043c|\u043c\u044b\s+)?\u043d\u0443\u0436\u043d\u043e\s+(?:\u0437\u0430\u043f\u043b\u0430\u0442\u0438\u0442\u044c|\u0441\u0433\u0440\u0443\u0437\u0438\u0442\u044c)|\u043c\u044b\s+\u0434\u043e\u043b\u0436\u043d\u044b\s+(?:\u0437\u0430\u043f\u043b\u0430\u0442\u0438\u0442\u044c|\u0441\u0433\u0440\u0443\u0437\u0438\u0442\u044c)|\u043d\u0434\u0441\s+\u043a\s+\u0443\u043f\u043b\u0430\u0442\u0435)/iu.test(text) &&
/(?:\u0437\u0430\s+(?:\d{4}|(?:\u044f\u043d\u0432\u0430\u0440|\u0444\u0435\u0432\u0440\u0430\u043b|\u043c\u0430\u0440\u0442|\u0430\u043f\u0440\u0435\u043b|\u043c\u0430[\u0439\u044f]|\u0438\u044e\u043d|\u0438\u044e\u043b|\u0430\u0432\u0433\u0443\u0441\u0442|\u0441\u0435\u043d\u0442\u044f\u0431\u0440|\u043e\u043a\u0442\u044f\u0431\u0440|\u043d\u043e\u044f\u0431\u0440|\u0434\u0435\u043a\u0430\u0431\u0440)\S*(?:\s+(?:19|20)\d{2})?)|\u043d\u0430\s+(?:\u044f\u043d\u0432\u0430\u0440|\u0444\u0435\u0432\u0440\u0430\u043b|\u043c\u0430\u0440\u0442|\u0430\u043f\u0440\u0435\u043b|\u043c\u0430[\u0439\u044f]|\u0438\u044e\u043d|\u0438\u044e\u043b|\u0430\u0432\u0433\u0443\u0441\u0442|\u0441\u0435\u043d\u0442\u044f\u0431\u0440|\u043e\u043a\u0442\u044f\u0431\u0440|\u043d\u043e\u044f\u0431\u0440|\u0434\u0435\u043a\u0430\u0431\u0440)\S*(?:\s+(?:19|20)\d{2})?|\u0432\s+(?:\u044f\u043d\u0432\u0430\u0440|\u0444\u0435\u0432\u0440\u0430\u043b|\u043c\u0430\u0440\u0442|\u0430\u043f\u0440\u0435\u043b|\u043c\u0430[\u0439\u044f]|\u0438\u044e\u043d|\u0438\u044e\u043b|\u0430\u0432\u0433\u0443\u0441\u0442|\u0441\u0435\u043d\u0442\u044f\u0431\u0440|\u043e\u043a\u0442\u044f\u0431\u0440|\u043d\u043e\u044f\u0431\u0440|\u0434\u0435\u043a\u0430\u0431\u0440)\S*(?:\s+(?:19|20)\d{2})?|\b[1-4]\s*(?:\u043a\u0432\u0430\u0440\u0442\u0430\u043b|\u043a\u0432\.?)\b)/iu.test(text);

View File

@ -1,4 +1,4 @@
import type { AddressIntentResolution } from "../types/addressQuery";
import type { AddressIntent, AddressIntentResolution } from "../types/addressQuery";
import { resolveCounterpartyAddressIntent } from "./addressCounterpartyIntentSignals";
import { resolveInventoryAddressIntent } from "./addressInventoryIntentSignals";
import {
@ -1946,6 +1946,688 @@ function repairLikelyUtf8Mojibake(text: string): string {
}
}
function unicodeBridgeResolution(
intent: AddressIntent,
confidence: AddressIntentResolution["confidence"],
reason: string
): AddressIntentResolution {
return { intent, confidence, reasons: [reason] };
}
function resolveUnicodeAddressIntentBridge(text: string): AddressIntentResolution | null {
const normalized = String(text ?? "").trim().toLowerCase();
if (!normalized) {
return null;
}
const hasAccountAnchor = /(?:\b(?:60|62|76)(?:[.,]\d{2})?\b|сч(?:е|ё)т(?:а|у|ом|е|ов)?|account)/iu.test(
normalized
);
const hasDocumentCue = /(?:док(?:умент(?:ы|ов|а|ам|ами|ах)?|и|ам|ами|ах|ов|а)?|docs?|documents?)/iu.test(
normalized
);
const hasBankCue = /(?:банк|банковск|плат[её]ж|оплат|транзакц|51|bank|payment|transaction)/iu.test(normalized);
const hasContractCue = /(?:договор|дог(?:\s|$)|контракт|contract|dogovor)/iu.test(normalized);
const hasSpecificContractCue = /(?:\b\d{1,4}\/\d{1,4}\b|этому\s+же\s+договор)/iu.test(normalized);
const hasCounterpartyCue =
/(?:контрагент|компани|организац|клиент|покупател|заказчик|поставщик|свк|альфа|жуковк|альтернатива|counterpart|company|supplier|customer|client|buyer)/iu.test(
normalized
);
const byAnchorMatch = normalized.match(/(?:^|[\s,.;:!?])(?:по|для)\s+([\p{L}\d._-]{2,})/iu);
const byAnchorToken = String(byAnchorMatch?.[1] ?? "").toLowerCase();
const hasLooseCounterpartyByAnchor =
!!byAnchorToken &&
!new Set([
"количеству",
"документам",
"докам",
"договору",
"договорам",
"счету",
"счёту",
"остатку",
"операциям",
"оплате",
"платежам",
"сальдо",
"дате",
"периоду",
"складу",
"товару",
"этому",
"этой",
"нему",
"ней"
]).has(byAnchorToken);
const hasMoneyCue = /(?:деньг|денег|выручк|доход|оборот|заработ|прин[её]с|чек|ликвидн|revenue|turnover|money)/iu.test(
normalized
);
const hasRankingCue = /(?:топ|ранк|сам(?:ый|ая|ое|ые)|больше\s+всего|наибольш|крупн|жирн|max|top|rank)/iu.test(
normalized
);
if (
/(?:за\s+какие\s+годы|диапазон\s+лет|покрыт(?:ие|ый)\s+период|какой\s+год.*актив|какой\s+месяц.*актив|год.*пассив|месяц.*пассив|минимальн.*док|минимальн.*операц|месяц[\s-]*пик|profile\s+period|top\s*year|top\s*month)/iu.test(
normalized
)
) {
return unicodeBridgeResolution(
"period_coverage_profile",
"high",
"unicode_period_coverage_bridge_signal_detected"
);
}
if (
/(?:тип(?:ы|ов)?\s+док|док(?:умент|ов).*?(?:чаще|редк|больше\s+всего|меньше\s+всего|крутит)|раздел(?:ы|ов)?\s+уч[её]та|сводк.*тип.*док|document\s+type|account\s+section)/iu.test(
normalized
)
) {
return unicodeBridgeResolution(
"document_type_and_account_section_profile",
"high",
"unicode_document_type_profile_bridge_signal_detected"
);
}
if (
hasAccountAnchor &&
hasDocumentCue &&
/(?:формирующ.*остат|раскрой\s+остат|остат.*по\s+документ|по\s+докам.*(?:60|62|76)|(?:60|62|76)(?:[.,]\d{2})?.*(?:по\s+докам|по\s+документ))/iu.test(normalized)
) {
return unicodeBridgeResolution(
"documents_forming_balance",
"high",
"unicode_documents_forming_balance_bridge_signal_detected"
);
}
if (/(?:договор[а-я]*.*(?:все|список).*по\s+[\p{L}\d]|(?:покажи|показать).*договор[а-я]*.*по\s+[\p{L}\d])/iu.test(normalized)) {
return unicodeBridgeResolution(
"list_contracts_by_counterparty",
"high",
"unicode_contracts_by_counterparty_bridge_signal_detected"
);
}
if (/(?:проконтрол|акты\s+без\s+приход|без\s+приходок|засорять\s+бухгалтер)/iu.test(normalized)) {
return unicodeBridgeResolution("unknown", "low", "unsupported_supplier_control_signal_detected");
}
if (/(?:кроме\s+этого\s+документ.*(?:есть\s+еще\s+что|есть\s+ещ[её]\s+что|что[-\s]?то))/iu.test(normalized)) {
return unicodeBridgeResolution(
"list_documents_by_counterparty",
"medium",
"generic_document_followup_with_previous_counterparty"
);
}
if (
/(?:плат[её]ж|оплат|отгрузк|документ|аванс|взаиморасчет|закрыт)/iu.test(normalized) &&
/(?:без\s+(?:закрыт|документ|оплат)|нет\s+(?:документ|оплат)|не\s+закрыт|оплат[а-я]*\s+нет|документ[а-я]*\s+есть|требует\s+ручн)/iu.test(normalized)
) {
return unicodeBridgeResolution(
"list_open_contracts",
"high",
"unicode_open_contract_gap_bridge_signal_detected"
);
}
if (
/(?:долгожител|долго\s+долж|задолженн(?:ост|остям).*(?:давн|долго)|не\s+плат|не\s+оплат|не\s+оплачен|неоплачен|просроч|сроки\s+давно\s+прошл|слишком\s+длинн.*оплат)/iu.test(
normalized
) &&
/(?:покупател|клиент|заказ|отгрузк|товар|услуг|задолженн|сальдо|не\s+плат|не\s+оплат|не\s+оплачен|неоплачен|просроч)/iu.test(
normalized
)
) {
return unicodeBridgeResolution(
"list_receivables_counterparties",
"high",
"receivables_debt_lifecycle_signal_detected"
);
}
const inventoryBridgeIntent = resolveInventoryAddressIntent(normalized);
if (inventoryBridgeIntent) {
if (inventoryBridgeIntent.intent === "inventory_aging_by_purchase_date") {
return { ...inventoryBridgeIntent, confidence: "high" };
}
return inventoryBridgeIntent;
}
if (
/(?:поставщик|vendor|supplier)/iu.test(normalized) &&
/(?:хвост|задержк|проблем|систематическ)/iu.test(normalized)
) {
return unicodeBridgeResolution(
"list_payables_counterparties",
"high",
"supplier_tail_risk_signal_detected"
);
}
if (hasBankCue && (hasCounterpartyCue || hasLooseCounterpartyByAnchor) && !hasContractCue) {
return unicodeBridgeResolution(
"bank_operations_by_counterparty",
"high",
"unicode_bank_ops_by_counterparty_bridge_signal_detected"
);
}
if (
/(?:есть\s+что[-\s]?то|что[-\s]?то)/iu.test(normalized) &&
(hasLooseCounterpartyByAnchor || /по\s+(?:ней|нему|этой|этому)/iu.test(normalized))
) {
return unicodeBridgeResolution(
"list_documents_by_counterparty",
"medium",
"generic_lookup_with_loose_anchor_fallback"
);
}
if (
hasDocumentCue &&
(hasLooseCounterpartyByAnchor || hasCounterpartyCue || /по\s+(?:ней|нему|этой|этому)/iu.test(normalized)) &&
!hasContractCue &&
!/(?:купил|куплен|закуп|товар|позици|номенклатур)/iu.test(normalized)
) {
return unicodeBridgeResolution(
"list_documents_by_counterparty",
"medium",
"unicode_documents_by_counterparty_bridge_signal_detected"
);
}
if (
/(?:долгожител|долго\s+долж|задолженн(?:ост|остям).*(?:давн|долго)|не\s+плат|не\s+оплат|не\s+оплачен|неоплачен|просроч|сроки\s+давно\s+прошл|слишком\s+длинн.*оплат)/iu.test(
normalized
) &&
/(?:покупател|клиент|заказ|отгрузк|товар|услуг|задолженн|сальдо|не\s+плат|не\s+оплат|не\s+оплачен|неоплачен|просроч)/iu.test(
normalized
)
) {
return unicodeBridgeResolution(
"list_receivables_counterparties",
"high",
"receivables_debt_lifecycle_signal_detected"
);
}
if (/\b41(?:[.,]\d{2})?\b/iu.test(normalized) && /(?:товар|склад|остат|состоит|номенклатур)/iu.test(normalized)) {
return unicodeBridgeResolution(
"inventory_on_hand_as_of_date",
"high",
"unicode_inventory_on_hand_bridge_signal_detected"
);
}
if (
/(?:год.*(?:док|операц).*(?:актив|пик|жив|много|движов)|год.*движов.*(?:док|операц)|(?:док|операц).*год.*(?:актив|пик|жив|много|движов)|месяц[\s-]*пик)/iu.test(
normalized
)
) {
return unicodeBridgeResolution(
"period_coverage_profile",
"high",
"unicode_period_coverage_bridge_signal_detected"
);
}
if (
!hasContractCue &&
/(?:скольк|скока).*(?:деньг|денег|выручк|доход|оборот)|(?:деньг|денег|выручк|доход|оборот).*(?:прин[её]с|зан[её]с|плат)/iu.test(normalized)
) {
return unicodeBridgeResolution(
"customer_revenue_and_payments",
"high",
"unicode_customer_revenue_bridge_signal_detected"
);
}
if (
!hasContractCue &&
/(?:кто|какие|выведи|покажи|список|самые)/iu.test(normalized) &&
/(?:список\s+(?:заказчик|клиент|покупател).*за\s+\d{2,4}\s*год|актив.*отвал|ровно\s+один\s+раз|один\s+раз.*пропал|стар(?:ые|ые)?\s+по\s+сотруднич|сотрудничеству\s+кто)/iu.test(normalized)
) {
return unicodeBridgeResolution(
"counterparty_activity_lifecycle",
"high",
"unicode_counterparty_lifecycle_bridge_signal_detected"
);
}
if (
!hasContractCue &&
/(?:кто|какие|выведи|покажи|список|разбей|раздели|самые)/iu.test(normalized) &&
/(?:заказчик|клиент|покупател|поставщик|контрагент|зак(?!рыт))/iu.test(normalized) &&
/(?:работал|работают|актив|все\s+время|вообще|регулярн|эпизодич|частот|давно\s+не\s+использ|операционн|разов|один\s+раз|пропал|отвал|сотруднич)/iu.test(normalized)
) {
return unicodeBridgeResolution(
"counterparty_activity_lifecycle",
"high",
"unicode_counterparty_lifecycle_bridge_signal_detected"
);
}
if (
/(?:поставщик|vendor|supplier|кому\s+(?:ушло|платили|заплатили)|выплат|исходящ|списан|сгрузил)/iu.test(normalized) &&
!/(?:аванс.*(?:не\s+)?закрыт|закрыт.*аванс)/iu.test(normalized) &&
(hasMoneyCue || hasRankingCue || /плат[её]ж|оплат|выплат|outflow|payout|хвост|задержк|проблем/iu.test(normalized))
) {
return unicodeBridgeResolution(
/(?:хвост|задержк|проблем)/iu.test(normalized) ? "list_payables_counterparties" : "supplier_payouts_profile",
"high",
/(?:хвост|задержк|проблем)/iu.test(normalized)
? "supplier_tail_risk_signal_detected"
: "unicode_supplier_payouts_bridge_signal_detected"
);
}
if (
!hasContractCue &&
(/(?:клиент|покупател|заказчик|контрагент|альтернатива|свк)/iu.test(normalized) || hasRankingCue) &&
(hasMoneyCue || /поступлен|приход|входящ|сделк|бюджет|inflow/iu.test(normalized))
) {
return unicodeBridgeResolution(
"customer_revenue_and_payments",
"high",
"unicode_customer_revenue_bridge_signal_detected"
);
}
if (
!hasContractCue &&
/(?:кто.*(?:деньг|денег|доход|выручк).*(?:прин[её]с|зан[её]с|плат)|(?:жирн|ликвидн).*контрагент.*(?:деньг|денег))/iu.test(
normalized
)
) {
return unicodeBridgeResolution(
"customer_revenue_and_payments",
"high",
"unicode_customer_revenue_bridge_signal_detected"
);
}
if (
/(?:общие\s+обороты|общая\s+выручк|оборот.*за\s+все\s+время|выручк.*за\s+все\s+время)/iu.test(normalized)
) {
return unicodeBridgeResolution(
"customer_revenue_and_payments",
"high",
"unicode_customer_revenue_bridge_signal_detected"
);
}
if (
/(?:открыт(?:ые|ая|ый)?\s+задолж|открыт(?:ые|ая|ый)?\s+позици|позици.*по\s+договор|open\s+items?)/iu.test(
normalized
) &&
(hasContractCue || hasCounterpartyCue || hasAccountAnchor || /покупател|клиент/iu.test(normalized))
) {
return unicodeBridgeResolution(
"open_items_by_counterparty_or_contract",
"high",
"unicode_open_items_bridge_signal_detected"
);
}
if (
hasContractCue &&
/(?:нескольк(?:ими|о)?\s+договор|контрагент.*нескольк.*договор|какие\s+из\s+договор.*актив)/iu.test(
normalized
)
) {
return unicodeBridgeResolution(
"contract_usage_and_value",
"high",
"unicode_contract_usage_value_bridge_signal_detected"
);
}
if (hasContractCue && (hasMoneyCue || hasRankingCue || /оборот|бюджет|сумм|стоим|value|amount/iu.test(normalized))) {
return unicodeBridgeResolution(
"contract_usage_and_value",
"high",
"unicode_contract_usage_value_bridge_signal_detected"
);
}
if (
/(?:сальдо.*(?:расход|не\s+совпад)|расход.*сальдо|акт(?:ом|ах)?\s+сверк|плат[её]ж[и]?,?\s+но\s+нет\s+док|документ(?:ы)?\s+есть,?\s+а\s+оплат\s+нет|(?:оплат|плат[её]ж|отгрузк|закрыти[ея]\s+счет)[\p{L}\s,]*\s+без\s+(?:закрыт|документ|подтвержд)|аванс.*давно\s+не\s+закрыт)/iu.test(
normalized
)
) {
return unicodeBridgeResolution("list_open_contracts", "high", "unicode_open_contracts_list_bridge_signal_detected");
}
if (
/(?:долгожител|долго\s+долж|задолженн(?:ост|остям).*(?:давн|долго)|не\s+плат|не\s+оплат|не\s+оплачен|неоплачен|просроч|сроки\s+давно\s+прошл|слишком\s+длинн.*оплат)/iu.test(
normalized
) &&
/(?:покупател|клиент|заказ|отгрузк|товар|услуг|задолженн|сальдо|не\s+плат|не\s+оплат|не\s+оплачен|неоплачен|просроч)/iu.test(
normalized
)
) {
return unicodeBridgeResolution(
"list_receivables_counterparties",
"high",
"receivables_debt_lifecycle_signal_detected"
);
}
if (
/(?:сальдо.*(?:расход|не\s+совпад)|расход.*сальдо|акт(?:ом|ах)?\s+сверк|плат[её]ж[и]?,?\s+но\s+нет\s+док|документ(?:ы)?\s+есть,?\s+а\s+оплат\s+нет|(?:оплат|плат[её]ж|отгрузк|закрыти[ея]\s+счет)[\p{L}\s,]*\s+без\s+(?:закрыт|документ|подтвержд)|аванс.*давно\s+не\s+закрыт)/iu.test(
normalized
)
) {
return unicodeBridgeResolution("list_open_contracts", "high", "unicode_open_contracts_list_bridge_signal_detected");
}
if (
/(?:открыт(?:ые|ая|ый)?\s+позици|позици.*по\s+договор|open\s+items?)/iu.test(normalized) &&
(hasContractCue || hasCounterpartyCue || hasAccountAnchor)
) {
return unicodeBridgeResolution(
"open_items_by_counterparty_or_contract",
"high",
"unicode_open_items_bridge_signal_detected"
);
}
if (
hasAccountAnchor &&
hasDocumentCue &&
/(?:формир|под\s+остат|раскр(?:ой|ыть|ывай)|остат(?:ок|ком)?\s+по\s+док|documents?\s+forming|docs?\s+forming)/iu.test(
normalized
)
) {
return unicodeBridgeResolution(
"documents_forming_balance",
"high",
"unicode_documents_forming_balance_bridge_signal_detected"
);
}
if (hasContractCue && hasSpecificContractCue && hasBankCue) {
return unicodeBridgeResolution(
"bank_operations_by_contract",
"high",
"unicode_bank_ops_by_contract_bridge_signal_detected"
);
}
if (hasContractCue && hasSpecificContractCue && hasDocumentCue) {
return unicodeBridgeResolution(
"list_documents_by_contract",
"high",
"unicode_documents_by_contract_bridge_signal_detected"
);
}
if (
hasAccountAnchor &&
!hasDocumentCue &&
/(?:баланс|остат(?:ок)?|сальдо|что\s+на\s+сч(?:е|ё)те|по\s+сч(?:е|ё)ту|скольк|скока|account\s+balance|balance\s+account|as\s+of)/iu.test(
normalized
)
) {
return unicodeBridgeResolution("account_balance_snapshot", "high", "unicode_account_balance_bridge_signal_detected");
}
if (/(?:ндс|vat)/iu.test(normalized)) {
const hasVatDebtCue = /(?:долг|должн|подтвержд)/iu.test(normalized);
if (
/(?:прогноз|прикин|план)/iu.test(normalized) ||
(!hasVatDebtCue && /(?:надо|нужно)\s+(?:заплат|оплат|уплат)/iu.test(normalized))
) {
return unicodeBridgeResolution("vat_payable_forecast", "high", "forecast_tax_signal_detected");
}
if (/(?:долг|подтвержд|скольк|скока|надо|нужно|заплат|уплат|оплат)/iu.test(normalized)) {
return unicodeBridgeResolution(
/(?:налогов|бюджет|декларац|квартал|\b[1-4]\s*кв)/iu.test(normalized)
? "vat_liability_confirmed_for_tax_period"
: "vat_payable_confirmed_as_of_date",
"high",
"vat_payable_confirmed_signal_detected"
);
}
}
if (
/(?:незакрыт|открыт).*договор/iu.test(normalized) &&
!/(?:долг|задолж|хвост|висит|расчет|расчёт)/iu.test(normalized)
) {
return unicodeBridgeResolution(
"open_contracts_confirmed_as_of_date",
"high",
"unicode_open_contracts_snapshot_bridge_signal_detected"
);
}
if (
/(?:долг|задолж|хвост|висит|открыт(?:ые|ая|ый)?\s+задолж|open\s+items?)/iu.test(normalized) &&
(hasContractCue || hasCounterpartyCue || hasAccountAnchor || /покупател|клиент/iu.test(normalized))
) {
return unicodeBridgeResolution(
"open_items_by_counterparty_or_contract",
"high",
"unicode_open_items_bridge_signal_detected"
);
}
if (
hasContractCue &&
/(?:без\s+(?:закрыт|оплат|плат[её]ж|док)|не\s+закрыт|аванс|отгрузк|плат[её]ж.*без|док.*без|расхожд|mismatch)/iu.test(
normalized
)
) {
return unicodeBridgeResolution("list_open_contracts", "high", "unicode_open_contracts_list_bridge_signal_detected");
}
if (
hasContractCue &&
/(?:скольк.*(?:всего\s+)?договор|договор.*(?:заведен|использовал|реально\s+использ)|сколько\s+из\s+них)/iu.test(
normalized
)
) {
return unicodeBridgeResolution(
"contract_usage_overview",
"high",
"unicode_contract_usage_overview_bridge_signal_detected"
);
}
if (
hasContractCue &&
/(?:нескольк(?:ими|о)?\s+договор|контрагент.*нескольк.*договор|какие\s+из\s+договор.*актив)/iu.test(
normalized
)
) {
return unicodeBridgeResolution(
"contract_usage_and_value",
"high",
"unicode_contract_usage_value_bridge_signal_detected"
);
}
if (
hasContractCue &&
/(?:все|покажи|показать|какие|список|list|show)/iu.test(normalized) &&
!hasSpecificContractCue &&
!hasDocumentCue &&
!hasBankCue &&
(hasCounterpartyCue || hasLooseCounterpartyByAnchor)
) {
return unicodeBridgeResolution(
"list_contracts_by_counterparty",
"high",
"unicode_contracts_by_counterparty_bridge_signal_detected"
);
}
if (hasContractCue && !hasSpecificContractCue && !hasDocumentCue && !hasBankCue && hasCounterpartyCue) {
return unicodeBridgeResolution(
"list_contracts_by_counterparty",
"high",
"unicode_contracts_by_counterparty_bridge_signal_detected"
);
}
if (hasBankCue && (hasCounterpartyCue || hasLooseCounterpartyByAnchor) && !hasContractCue) {
return unicodeBridgeResolution(
"bank_operations_by_counterparty",
"high",
"unicode_bank_ops_by_counterparty_bridge_signal_detected"
);
}
if (hasDocumentCue && (hasCounterpartyCue || hasLooseCounterpartyByAnchor) && !hasContractCue && !hasAccountAnchor) {
return unicodeBridgeResolution(
"list_documents_by_counterparty",
"high",
"unicode_documents_by_counterparty_bridge_signal_detected"
);
}
if (
/(?:за\s+какие\s+годы|диапазон\s+лет|покрыт(?:ие|ый)\s+период|какой\s+год.*актив|какой\s+месяц.*актив|год.*пассив|месяц.*пассив|минимальн.*док|минимальн.*операц|profile\s+period|top\s*year|top\s*month)/iu.test(
normalized
)
) {
return unicodeBridgeResolution(
"period_coverage_profile",
"high",
"unicode_period_coverage_bridge_signal_detected"
);
}
if (
/(?:тип(?:ы|ов)?\s+док|документ.*(?:чаще|редк|больше\s+всего|меньше\s+всего)|раздел(?:ы|ов)?\s+уч[её]та|сводк.*тип.*док|document\s+type|account\s+section)/iu.test(
normalized
)
) {
return unicodeBridgeResolution(
"document_type_and_account_section_profile",
"high",
"unicode_document_type_profile_bridge_signal_detected"
);
}
if (
/(?:скольк|скока|число|количеств|разбей|раздели|сформируй\s+сводк)/iu.test(normalized) &&
/(?:контрагент|поставщик|клиент|покупател|заказчик|рол)/iu.test(normalized) &&
!/(?:активн|давно|нов(?:ые|ых)|однораз|уш[её]л|исчез|регулярн|эпизодич|частот|разов|churn|lifecycle)/iu.test(normalized)
) {
return unicodeBridgeResolution(
"counterparty_population_and_roles",
"high",
"unicode_counterparty_population_bridge_signal_detected"
);
}
if (/(?:скок|скока|сколько)\s+(?:клиент|покупател|заказчик)/iu.test(normalized)) {
return unicodeBridgeResolution(
"counterparty_population_and_roles",
"high",
"unicode_counterparty_population_bridge_signal_detected"
);
}
if (
/(?:активн(?:ые|ость)?\s+(?:клиент|покупател|поставщик|контрагент)|все\s+время|однораз|давно\s+(?:не\s+)?(?:покупал|платил|актив)|уш[её]л|исчез|нов(?:ые|ых)\s+(?:клиент|контрагент)|регулярн|разов(?:ый|ые)|stale\s+supplier|churn|lifecycle)/iu.test(
normalized
)
) {
return unicodeBridgeResolution(
"counterparty_activity_lifecycle",
"high",
"unicode_counterparty_lifecycle_bridge_signal_detected"
);
}
if (hasContractCue && /(?:давно\s+не\s+использ|не\s+использ|stale|inactive)/iu.test(normalized)) {
return unicodeBridgeResolution(
"contract_usage_overview",
"high",
"unicode_contract_usage_overview_bridge_signal_detected"
);
}
if (hasContractCue && (hasMoneyCue || hasRankingCue || /оборот|бюджет|сумм|стоим|value|amount/iu.test(normalized))) {
return unicodeBridgeResolution(
"contract_usage_and_value",
"high",
"unicode_contract_usage_value_bridge_signal_detected"
);
}
if (
/(?:поставщик|vendor|supplier|кому\s+(?:ушло|платили|заплатили)|выплат|исходящ|списан|сгрузил)/iu.test(normalized) &&
(hasMoneyCue || hasRankingCue || /плат[её]ж|оплат|выплат|outflow|payout/iu.test(normalized))
) {
return unicodeBridgeResolution(
"supplier_payouts_profile",
"high",
"unicode_supplier_payouts_bridge_signal_detected"
);
}
if (
(/(?:клиент|покупател|заказчик|контрагент|альтернатива|свк)/iu.test(normalized) || hasRankingCue) &&
(hasMoneyCue || /поступлен|приход|входящ|inflow/iu.test(normalized))
) {
return unicodeBridgeResolution(
"customer_revenue_and_payments",
"high",
"unicode_customer_revenue_bridge_signal_detected"
);
}
if (/(?:к[оа]му\s+мы\s+должны|мы\s+должны\s+к[оа]му|кредитор|payables?)/iu.test(normalized)) {
return unicodeBridgeResolution(
"payables_confirmed_as_of_date",
"high",
"payables_debt_lifecycle_signal_detected"
);
}
if (/(?:кто\s+нам\s+должен|нам\s+должны|дебитор|receivables?)/iu.test(normalized)) {
return unicodeBridgeResolution(
"receivables_confirmed_as_of_date",
"high",
"unicode_receivables_snapshot_bridge_signal_detected"
);
}
if (
/(?:покупател|клиент).*(?:не\s+плат|просроч|долго\s+долж|долг.*давн)|(?:долг|задолж).*(?:покупател|клиент)/iu.test(
normalized
)
) {
return unicodeBridgeResolution(
"list_receivables_counterparties",
"high",
"unicode_receivables_list_bridge_signal_detected"
);
}
if (
/(?:что|че|чё|какие|покажи|показать|список).*(?:склад|остат|товар)|(?:склад|остат).*(?:сейчас|лежит|есть|на\s+дату|на\s+конец|what|show|list)/iu.test(
normalized
) &&
!/(?:поставщик|продаж|реализ|цепоч|документал|давно|стар(?:ые|ый|ым|ых)|закуп)/iu.test(normalized)
) {
return unicodeBridgeResolution(
"inventory_on_hand_as_of_date",
"high",
"unicode_inventory_on_hand_bridge_signal_detected"
);
}
return null;
}
export function resolveAddressIntent(userMessage: string): AddressIntentResolution {
const text = String(userMessage ?? "").trim().toLowerCase();
const repairedText = repairLikelyUtf8Mojibake(text).trim().toLowerCase();
@ -1956,6 +2638,11 @@ export function resolveAddressIntent(userMessage: string): AddressIntentResoluti
const currentTurnBridgeText =
turnNoiseNormalizedBridgeText !== bridgeText ? `${bridgeText} ${turnNoiseNormalizedBridgeText}` : bridgeText;
const unicodeAddressIntent = resolveUnicodeAddressIntentBridge(currentTurnBridgeText);
if (unicodeAddressIntent) {
return unicodeAddressIntent;
}
const hasLooseVatPayableBridge =
/(?:\u043d\u0434\u0441|vat)/iu.test(text) &&
/(?:\u043a\u0430\u043a\u043e\u0439\s+\u043d\u0434\u0441\s+(?:(?:\u043d\u0430\u043c|(?:\u043c\u044b\s+)?\u0434\u043e\u043b\u0436\u043d\u044b)\s+)?(?:\u043d\u0430\u0434\u043e|\u043d\u0443\u0436\u043d\u043e|\u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e)|(?:\u043d\u0430\u043c|\u043c\u044b\s+)?\u043d\u0430\u0434\u043e\s+(?:\u0437\u0430\u043f\u043b\u0430\u0442\u0438\u0442\u044c|\u0441\u0433\u0440\u0443\u0437\u0438\u0442\u044c)|(?:\u043d\u0430\u043c|\u043c\u044b\s+)?\u043d\u0443\u0436\u043d\u043e\s+(?:\u0437\u0430\u043f\u043b\u0430\u0442\u0438\u0442\u044c|\u0441\u0433\u0440\u0443\u0437\u0438\u0442\u044c)|\u043c\u044b\s+\u0434\u043e\u043b\u0436\u043d\u044b\s+(?:\u0437\u0430\u043f\u043b\u0430\u0442\u0438\u0442\u044c|\u0441\u0433\u0440\u0443\u0437\u0438\u0442\u044c)|\u043d\u0434\u0441\s+\u043a\s+\u0443\u043f\u043b\u0430\u0442\u0435)/iu.test(