"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.resolveAddressIntent = resolveAddressIntent; const RECEIVABLES_STRONG = [ "кто должен нам", "нам должны", "who owes us", "receivable", "receivables", "debtor", "debtors", "дебитор", "дебиторск" ]; const PAYABLES_STRONG = [ "кому должны мы", "мы должны", "who we owe", "payable", "payables", "creditor", "creditors", "кредитор", "кредиторск" ]; const ACCOUNT_BALANCE_HINTS = [ "account balance", "balance by account", "saldo", "остаток по счет", "сальдо по счет", "по счету" ]; const DOCUMENTS_FORMING_BALANCE_HINTS = [ "documents forming balance", "documents form balance", "balance documents", "documents for balance", "which documents form balance", "из чего состоит остаток", "какие документы формируют остаток", "раскрой остаток по документам", "документы под остатком" ]; const OPEN_CONTRACTS_HINTS = [ "open contracts", "unclosed contracts", "незакрыт", "не закрыт", "открыт", "договор" ]; const OPEN_ITEMS_HINTS = [ "open items", "unclosed items", "хвост", "висят", "незакрыт", "открыт", "позици" ]; const DOCUMENTS_BY_COUNTERPARTY_HINTS = [ "documents by counterparty", "docs by counterparty", "documents by company", "documents by supplier", "documents by customer", "documents by client", "documents by partner", "show documents by counterparty", "list documents by counterparty", "документы по", "доступные документы", "список документов", "документ", "доки", "доки по", "док по", "по контрагент" ]; const BANK_OPERATIONS_BY_COUNTERPARTY_HINTS = [ "bank operations by counterparty", "bank payments by counterparty", "payment orders by counterparty", "bank operations by company", "bank operations by supplier", "bank operations by customer", "show bank operations by counterparty", "bank ops", "transactions by counterparty", "банков", "выписк", "платеж", "платёж", "оплат", "списан", "поступлен", "движени" ]; function hasAny(text, patterns) { return patterns.some((item) => text.includes(item)); } function hasDocumentsFormingBalanceSignal(text) { if (hasAny(text, DOCUMENTS_FORMING_BALANCE_HINTS)) { return true; } const hasDocLexeme = text.includes("документ") || text.includes("доки"); const hasFormingLexeme = text.includes("формир"); const hasBalanceLexeme = text.includes("остат"); const hasAccountLexeme = text.includes("счет") || text.includes("счёт") || hasAccountNumberAnchor(text); if (hasDocLexeme && hasFormingLexeme && hasBalanceLexeme && hasAccountLexeme) { return true; } return hasBalanceLexeme && hasAccountLexeme && text.includes("из чего состоит"); } function isLikelyCounterpartyToken(rawToken) { const token = String(rawToken ?? "").trim().toLowerCase(); if (!token || token.length < 2) { return false; } if (/^\d+$/.test(token)) { return false; } if (/^(?:19|20)\d{2}$/.test(token)) { return false; } const stopWords = new Set([ "за", "с", "по", "на", "и", "или", "док", "доки", "доки?", "документ", "документы", "документов", "банк", "банковские", "операции", "платежи", "платеж", "платёж", "контрагент", "контрагенту", "контрагента", "компания", "компании", "организация", "организации", "год", "года", "г", "плс", "pls", "пж", "пжлст", "пожалуйста", "бля", "блять", "епт", "ёпт", "епта", "нах", "нахуй" ]); return !stopWords.has(token); } function hasPartyAnchorMention(text) { return (text.includes("контраг") || text.includes("контра") || text.includes("counterparty") || text.includes("компан") || text.includes("company") || text.includes("организац") || text.includes("supplier") || text.includes("vendor") || text.includes("customer") || text.includes("client") || text.includes("partner") || text.includes("поставщик") || text.includes("клиент") || text.includes("покупател") || text.includes("партнер")); } function hasLooseByAnchorMention(text) { const match = text.match(/(?:^|\s)по\s+([a-zа-яё][a-zа-яё0-9._-]{1,})(?=[\s,.;:!?)]|$)/iu); if (!match) { return false; } const token = String(match[1] ?? "").toLowerCase(); if (!token) { return false; } const stopWords = new Set([ "контрагенту", "контрагента", "контре", "компании", "компанию", "организации", "организацию", "поставщику", "поставщика", "клиенту", "клиента", "покупателю", "покупателя", "партнеру", "партнера", "договору", "договора", "счету", "счёту", "дате", "периоду", "период", "документам", "докам" ]); return !stopWords.has(token); } function hasImplicitCounterpartyAnchorAroundDocs(text) { const beforeDocsMatch = text.match(/(?:^|\s)([a-zа-яё][a-zа-яё0-9._-]{1,})\s+(?:док(?:и|ум(?:ент(?:ы|ов|ам|а)?)?)|docs?|documents?)(?=[\s,.;:!?)]|$)/iu); if (beforeDocsMatch && isLikelyCounterpartyToken(String(beforeDocsMatch[1] ?? ""))) { return true; } const afterDocsMatch = text.match(/(?:док(?:и|ум(?:ент(?:ы|ов|ам|а)?)?)|docs?|documents?)\s+(?:по\s+)?([a-zа-яё][a-zа-яё0-9._-]{1,})(?=[\s,.;:!?)]|$)/iu); if (afterDocsMatch && isLikelyCounterpartyToken(String(afterDocsMatch[1] ?? ""))) { return true; } return false; } function hasDocsOrBankSignal(text) { return /(?:док(?:и|умент|ументы|ументов)|docs?|documents?|банк|выписк|платеж|платёж|оплат|transactions?|bank\s+ops|bank\s+operations?)/iu.test(text); } function hasHeuristicCounterpartyAnchor(text) { if (!hasDocsOrBankSignal(text)) { return false; } const tokens = String(text ?? "") .split(/[^a-zа-яё0-9._-]+/iu) .map((item) => item.trim()) .filter((item) => item.length > 0); for (const token of tokens) { const lowered = token.toLowerCase(); if (!isLikelyCounterpartyToken(lowered)) { continue; } if (/^\d{2}$/.test(lowered) || /^\d{4}$/.test(lowered)) { continue; } if (/(?:^за$|^for$|^from$|^to$|^по$|^с$|^год$|^года$|^г$|^year$)/iu.test(lowered)) { continue; } return true; } return false; } function hasGenericAddressLookupSignal(text) { return (/\bесть\b/iu.test(text) || /\bпокажи\b/iu.test(text) || /\bвыведи\b/iu.test(text) || /\bкакие\b/iu.test(text) || /\bчто(?:-|\s)?то\b/iu.test(text) || /за\s+любой\s+период/iu.test(text) || /за\s+вс[её]\s+время/iu.test(text) || /for\s+all\s+time/iu.test(text) || /all\s+time/iu.test(text)); } function hasAccountNumberAnchor(text) { return /(?:account|сч[её]т|счет)\D{0,12}\d{2}(?:[.,]\d{1,2})?/i.test(text); } function resolveAddressIntent(userMessage) { const text = String(userMessage ?? "").trim().toLowerCase(); if (hasAny(text, RECEIVABLES_STRONG)) { return { intent: "list_receivables_counterparties", confidence: "high", reasons: ["receivables_signal_detected"] }; } if (hasAny(text, PAYABLES_STRONG)) { return { intent: "list_payables_counterparties", confidence: "high", reasons: ["payables_signal_detected"] }; } if (hasDocumentsFormingBalanceSignal(text) && (hasAccountNumberAnchor(text) || text.includes("счет"))) { return { intent: "documents_forming_balance", confidence: "high", reasons: ["documents_forming_balance_signal_detected"] }; } if (hasAny(text, BANK_OPERATIONS_BY_COUNTERPARTY_HINTS) && (hasPartyAnchorMention(text) || hasLooseByAnchorMention(text) || hasHeuristicCounterpartyAnchor(text))) { return { intent: "bank_operations_by_counterparty", confidence: "medium", reasons: ["bank_ops_by_counterparty_signal_detected"] }; } if (hasAny(text, DOCUMENTS_BY_COUNTERPARTY_HINTS) && (hasPartyAnchorMention(text) || hasLooseByAnchorMention(text) || hasImplicitCounterpartyAnchorAroundDocs(text) || hasHeuristicCounterpartyAnchor(text))) { return { intent: "list_documents_by_counterparty", confidence: "medium", reasons: ["documents_by_counterparty_signal_detected"] }; } if (hasAny(text, ACCOUNT_BALANCE_HINTS) || hasAccountNumberAnchor(text)) { return { intent: "account_balance_snapshot", confidence: "high", reasons: ["account_balance_signal_detected"] }; } if (hasLooseByAnchorMention(text) && hasGenericAddressLookupSignal(text)) { return { intent: "list_documents_by_counterparty", confidence: "low", reasons: ["generic_lookup_with_loose_anchor_fallback"] }; } if (hasAny(text, OPEN_ITEMS_HINTS) && (text.includes("контраг") || text.includes("договор") || text.includes("counterparty") || text.includes("contract"))) { return { intent: "open_items_by_counterparty_or_contract", confidence: "medium", reasons: ["open_items_signal_detected"] }; } if (hasAny(text, OPEN_CONTRACTS_HINTS) && (text.includes("договор") || text.includes("contract"))) { return { intent: "list_open_contracts", confidence: "medium", reasons: ["open_contract_signal_detected"] }; } return { intent: "unknown", confidence: "low", reasons: ["intent_not_supported_in_v1"] }; }