АДРЕСНЫЙ РЕЖИМ - стабилизация LLM fallback якорей и периода
This commit is contained in:
@@ -103,6 +103,46 @@ const BANK_OPERATIONS_BY_COUNTERPARTY_HINTS = [
|
||||
"поступлен",
|
||||
"движени"
|
||||
];
|
||||
const DOCUMENTS_BY_CONTRACT_HINTS = [
|
||||
"documents by contract",
|
||||
"docs by contract",
|
||||
"show documents by contract",
|
||||
"list documents by contract",
|
||||
"документы по договору",
|
||||
"доки по договору",
|
||||
"док по договору",
|
||||
"документы договор",
|
||||
"договор"
|
||||
];
|
||||
const BANK_OPERATIONS_BY_CONTRACT_HINTS = [
|
||||
"bank operations by contract",
|
||||
"bank payments by contract",
|
||||
"payment orders by contract",
|
||||
"transactions by contract",
|
||||
"bank ops by contract",
|
||||
"банковские операции по договору",
|
||||
"платежи по договору",
|
||||
"выписка по договору"
|
||||
];
|
||||
|
||||
const BANK_OPERATION_CORE_HINTS = [
|
||||
"банков",
|
||||
"выписк",
|
||||
"платеж",
|
||||
"платёж",
|
||||
"оплат",
|
||||
"списан",
|
||||
"поступлен",
|
||||
"движени",
|
||||
"транзак",
|
||||
"bank",
|
||||
"payment",
|
||||
"payments",
|
||||
"transaction",
|
||||
"transactions",
|
||||
"statement",
|
||||
"wire"
|
||||
];
|
||||
|
||||
function hasAny(text: string, patterns: string[]): boolean {
|
||||
return patterns.some((item) => text.includes(item));
|
||||
@@ -198,6 +238,72 @@ function hasPartyAnchorMention(text: string): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
function hasContractAnchorMention(text: string): boolean {
|
||||
return (
|
||||
text.includes("договор") ||
|
||||
text.includes("дог.") ||
|
||||
text.includes("contract") ||
|
||||
text.includes("dogovor")
|
||||
);
|
||||
}
|
||||
|
||||
function hasContractNumberLikeToken(text: string): boolean {
|
||||
if (/(?:^|[\s([{])(?:№|#|n)\s*[a-zа-яё0-9][a-zа-яё0-9./_-]{1,}(?=$|[\s,.;:!?)\]}])/iu.test(text)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const rawTokens = text
|
||||
.split(/[\s,;:!?()[\]{}"«»]+/u)
|
||||
.map((token) => token.replace(/^[^\p{L}\p{N}#№]+|[^\p{L}\p{N}./_-]+$/gu, "").trim())
|
||||
.filter((token) => token.length > 0);
|
||||
|
||||
for (const rawToken of rawTokens) {
|
||||
const token = String(rawToken ?? "").trim();
|
||||
if (!/^\d{1,6}[./_-]\d{1,6}(?:[./_-]\d{1,6})?$/u.test(token)) {
|
||||
continue;
|
||||
}
|
||||
if (!token) {
|
||||
continue;
|
||||
}
|
||||
const parts = token.split(/[./_-]+/u).map((part) => Number(part));
|
||||
if (!parts.every((part) => Number.isFinite(part))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (parts.length === 2) {
|
||||
const [a, b] = parts;
|
||||
const yearFirst = a >= 1900 && a <= 2099 && b >= 1 && b <= 12;
|
||||
const yearSecond = b >= 1900 && b <= 2099 && a >= 1 && a <= 12;
|
||||
if (yearFirst || yearSecond) {
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (parts.length === 3) {
|
||||
const [a, b, c] = parts;
|
||||
const ymd = a >= 1900 && a <= 2099 && b >= 1 && b <= 12 && c >= 1 && c <= 31;
|
||||
const dmy = c >= 1900 && c <= 2099 && a >= 1 && a <= 31 && b >= 1 && b <= 12;
|
||||
if (ymd || dmy) {
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function hasContractAnchorSignal(text: string): boolean {
|
||||
if (hasContractAnchorMention(text)) {
|
||||
return true;
|
||||
}
|
||||
// Allow short forms like "15/24" for follow-up prompts if document/bank signal exists.
|
||||
return hasContractNumberLikeToken(text) && hasDocsOrBankSignal(text);
|
||||
}
|
||||
|
||||
function hasLooseByAnchorMention(text: string): boolean {
|
||||
const match = text.match(/(?:^|\s)по\s+([a-zа-яё][a-zа-яё0-9._-]{1,})(?=[\s,.;:!?)]|$)/iu);
|
||||
if (!match) {
|
||||
@@ -260,6 +366,20 @@ function hasDocsOrBankSignal(text: string): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
function hasBankOperationSignal(text: string): boolean {
|
||||
return hasAny(text, BANK_OPERATION_CORE_HINTS) || hasAny(text, BANK_OPERATIONS_BY_COUNTERPARTY_HINTS) || hasAny(text, BANK_OPERATIONS_BY_CONTRACT_HINTS);
|
||||
}
|
||||
|
||||
function hasDocumentSignal(text: string): boolean {
|
||||
return (
|
||||
text.includes("док") ||
|
||||
text.includes("доки") ||
|
||||
text.includes("документ") ||
|
||||
text.includes("docs") ||
|
||||
text.includes("documents")
|
||||
);
|
||||
}
|
||||
|
||||
function hasHeuristicCounterpartyAnchor(text: string): boolean {
|
||||
if (!hasDocsOrBankSignal(text)) {
|
||||
return false;
|
||||
@@ -329,6 +449,28 @@ export function resolveAddressIntent(userMessage: string): AddressIntentResoluti
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
hasContractAnchorSignal(text) &&
|
||||
hasBankOperationSignal(text)
|
||||
) {
|
||||
return {
|
||||
intent: "bank_operations_by_contract",
|
||||
confidence: "medium",
|
||||
reasons: ["bank_ops_by_contract_signal_detected"]
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
hasContractAnchorSignal(text) &&
|
||||
(hasAny(text, DOCUMENTS_BY_CONTRACT_HINTS) || hasDocumentSignal(text))
|
||||
) {
|
||||
return {
|
||||
intent: "list_documents_by_contract",
|
||||
confidence: "medium",
|
||||
reasons: ["documents_by_contract_signal_detected"]
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
hasAny(text, BANK_OPERATIONS_BY_COUNTERPARTY_HINTS) &&
|
||||
(hasPartyAnchorMention(text) || hasLooseByAnchorMention(text) || hasHeuristicCounterpartyAnchor(text))
|
||||
|
||||
Reference in New Issue
Block a user