АДРЕСНЫЙ РЕЖИМ - локальная подель на декомпозе
This commit is contained in:
@@ -67,9 +67,20 @@ const OPEN_ITEMS_HINTS = [
|
||||
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",
|
||||
"документы по",
|
||||
"доступные документы",
|
||||
"список документов",
|
||||
"документ",
|
||||
"доки",
|
||||
"доки по",
|
||||
"док по",
|
||||
"по контрагент"
|
||||
];
|
||||
|
||||
@@ -77,16 +88,202 @@ 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: string, patterns: string[]): boolean {
|
||||
return patterns.some((item) => text.includes(item));
|
||||
}
|
||||
|
||||
function isLikelyCounterpartyToken(rawToken: string): boolean {
|
||||
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: string): boolean {
|
||||
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: string): boolean {
|
||||
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: string): boolean {
|
||||
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: string): boolean {
|
||||
return /(?:док(?:и|умент|ументы|ументов)|docs?|documents?|банк|выписк|платеж|платёж|оплат|transactions?|bank\s+ops|bank\s+operations?)/iu.test(
|
||||
text
|
||||
);
|
||||
}
|
||||
|
||||
function hasHeuristicCounterpartyAnchor(text: string): boolean {
|
||||
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: string): boolean {
|
||||
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: string): boolean {
|
||||
return /(?:account|сч[её]т|счет)\D{0,12}\d{2}(?:[.,]\d{1,2})?/i.test(text);
|
||||
}
|
||||
@@ -128,7 +325,7 @@ export function resolveAddressIntent(userMessage: string): AddressIntentResoluti
|
||||
|
||||
if (
|
||||
hasAny(text, BANK_OPERATIONS_BY_COUNTERPARTY_HINTS) &&
|
||||
(text.includes("контраг") || text.includes("counterparty"))
|
||||
(hasPartyAnchorMention(text) || hasLooseByAnchorMention(text) || hasHeuristicCounterpartyAnchor(text))
|
||||
) {
|
||||
return {
|
||||
intent: "bank_operations_by_counterparty",
|
||||
@@ -139,7 +336,10 @@ export function resolveAddressIntent(userMessage: string): AddressIntentResoluti
|
||||
|
||||
if (
|
||||
hasAny(text, DOCUMENTS_BY_COUNTERPARTY_HINTS) &&
|
||||
(text.includes("контраг") || text.includes("counterparty"))
|
||||
(hasPartyAnchorMention(text) ||
|
||||
hasLooseByAnchorMention(text) ||
|
||||
hasImplicitCounterpartyAnchorAroundDocs(text) ||
|
||||
hasHeuristicCounterpartyAnchor(text))
|
||||
) {
|
||||
return {
|
||||
intent: "list_documents_by_counterparty",
|
||||
@@ -148,6 +348,14 @@ export function resolveAddressIntent(userMessage: string): AddressIntentResoluti
|
||||
};
|
||||
}
|
||||
|
||||
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",
|
||||
|
||||
Reference in New Issue
Block a user