Закрепить selected-object закупки в 1С ассистенте
This commit is contained in:
@@ -126,7 +126,7 @@ function hasSelectedObjectInventoryPurchaseDocumentsSignal(text: string): boolea
|
||||
const value = String(text ?? "");
|
||||
if (
|
||||
hasSelectedObjectInventoryCue(value) &&
|
||||
/(?:по\s+каким\s+документам\s+(?:это|его|этот\s+товар|эту\s+позицию)?\s*купили|по\s+каким\s+документам\s+(?:был\s+)?куплен|какими\s+документами\s+(?:это|его|этот\s+товар|эту\s+позицию)?\s*купили|какими\s+документами\s+(?:был\s+)?куплен|покажи\s+документы\s+по\s+(?:этой\s+позиции|этому\s+товару|ней|нему)|документы\s+по\s+(?:этой\s+позиции|этому\s+товару|ней|нему)|purchase\s+documents|documents\s+of\s+purchase|through\s+which\s+documents)/iu.test(
|
||||
/(?:по\s+каким\s+документам\s+(?:это|его|этот\s+товар|эту\s+позицию)?\s*купили|по\s+каким\s+документам\s+(?:был\s+)?куплен|какими\s+документами\s+(?:это|его|этот\s+товар|эту\s+позицию)?\s*купили|какими\s+документами\s+(?:был\s+)?куплен|каким\s+документом\s+подтвержден[ао]?\s+закупк|какой\s+документ\s+подтвержда[её]т\s+закупк|документ[а-яё]*\s+подтвержд[а-яё]*\s+закупк|закупк[а-яё]*\s+подтвержден[а-яё]*\s+документ|покажи\s+документы\s+по\s+(?:этой\s+позиции|этому\s+товару|ней|нему)|документы\s+по\s+(?:этой\s+позиции|этому\s+товару|ней|нему)|purchase\s+documents|documents\s+of\s+purchase|through\s+which\s+documents)/iu.test(
|
||||
value
|
||||
)
|
||||
) {
|
||||
|
||||
@@ -721,6 +721,14 @@ function shouldRestoreInventoryRootFrame(
|
||||
}
|
||||
|
||||
function hasSelectedObjectInventorySignal(text: string): boolean {
|
||||
const repairedSelectedObjectText = textWithRepairedVariant(String(text ?? ""));
|
||||
if (
|
||||
/(?:по\s+выбранному\s+объекту|по\s+этой\s+позиции|по\s+этому\s+товару|по\s+ней|по\s+нему|по\s+ним|for\s+selected\s+object|selected\s+object)/iu.test(
|
||||
repairedSelectedObjectText
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
/(?:по\s+выбранному\s+объекту|по\s+этой\s+позиции|по\s+этому\s+товару|по\s+ней|по\s+нему|по\s+ним|for\s+selected\s+object|selected\s+object)/iu.test(
|
||||
String(text ?? "")
|
||||
@@ -762,8 +770,11 @@ export function hasInventorySupplierFollowupCue(text: string): boolean {
|
||||
}
|
||||
|
||||
export function hasInventoryPurchaseDocumentsFollowupCue(text: string): boolean {
|
||||
const value = String(text ?? "");
|
||||
const value = textWithRepairedVariant(String(text ?? ""));
|
||||
return (
|
||||
/(?:по\s+каким\s+документам\s+(?:это|его|ее|её|этот\s+товар|эту\s+позицию)\s+купили|по\s+каким\s+документам\s+(?:был\s+)?куплен|какими\s+документами\s+(?:это|его|этот\s+товар|эту\s+позицию)\s+купили|какими\s+документами\s+(?:был\s+)?куплен|каким\s+документом\s+(?:это|его|ее|её|она|он|этот\s+товар|эта\s+позиция|эту\s+позицию)?\s*(?:подтвержден[оа]?|подтверждена\s+закупка|доказан[оа]?|закрыт[оа]?)|закупк[аи]\s+подтвержден[аы]?\s+документ|покажи\s+документы\s+по\s+(?:этой\s+позиции|этому\s+товару|ней|нему)|документы\s+по\s+(?:этой\s+позиции|этому\s+товару|ней|нему))/iu.test(
|
||||
value
|
||||
) ||
|
||||
/(?:по\s+каким\s+документам\s+(?:это|его|этот\s+товар|эту\s+позицию)\s+купили|по\s+каким\s+документам\s+(?:был\s+)?куплен|какими\s+документами\s+(?:это|его|этот\s+товар|эту\s+позицию)\s+купили|какими\s+документами\s+(?:был\s+)?куплен|каким\s+документом\s+(?:это|его|её|ее|она|он|этот\s+товар|эта\s+позиция|эту\s+позицию)?\s*(?:подтвержден[оа]?|доказан[оа]?|закрыт[оа]?)|покажи\s+документы\s+по\s+(?:этой\s+позиции|этому\s+товару|ней|нему)|документы\s+по\s+(?:этой\s+позиции|этому\s+товару|ней|нему)|purchase\s+documents|documents\s+of\s+purchase|through\s+which\s+documents)/iu.test(
|
||||
value
|
||||
) ||
|
||||
@@ -875,10 +886,17 @@ export function hasInventoryMarginRankingFollowupCue(text: string): boolean {
|
||||
}
|
||||
|
||||
export function hasAddressFollowupContextSignal(text: string): boolean {
|
||||
const normalized = String(text ?? "").trim();
|
||||
const normalized = textWithRepairedVariant(String(text ?? "")).trim();
|
||||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
/(?:по\s+выбранному\s+объекту|по\s+этой\s+позиции|по\s+этому\s+товару|по\s+ней|по\s+нему|по\s+ним|for\s+selected\s+object|selected\s+object)/iu.test(
|
||||
normalized
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
if (hasInventoryMarginRankingFollowupCue(normalized)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -134,6 +134,10 @@ function inventoryPartyListOrUnknown(parties: string[]): string {
|
||||
return parties.length > 0 ? parties.slice(0, 4).join("; ") : "не выделен отдельным полем";
|
||||
}
|
||||
|
||||
function omitAmountFromInventoryTraceEvidence(lines: string[]): string[] {
|
||||
return lines.map((line) => String(line ?? "").replace(/\s+\|\s+сумма:\s+[^|]+(?=\s+\||$)/gu, ""));
|
||||
}
|
||||
|
||||
function normalizeInventoryReplyEntityToken(value: string | null | undefined): string | null {
|
||||
const normalized = String(value ?? "")
|
||||
.trim()
|
||||
@@ -535,7 +539,7 @@ export function composeInventoryReply(
|
||||
appendInventorySection(
|
||||
lines,
|
||||
"Опорные документы:",
|
||||
deps.formatInventoryTraceRows(purchaseRows, INVENTORY_TRACE_EVIDENCE_ROW_LIMIT)
|
||||
omitAmountFromInventoryTraceEvidence(deps.formatInventoryTraceRows(purchaseRows, INVENTORY_TRACE_EVIDENCE_ROW_LIMIT))
|
||||
);
|
||||
if (purchaseRows.length > INVENTORY_TRACE_EVIDENCE_ROW_LIMIT) {
|
||||
lines.push(
|
||||
|
||||
@@ -3255,6 +3255,11 @@ function hasPredecomposeExplicitDrilldownSignal(text) {
|
||||
return ADDRESS_DOCS_SIGNAL_PATTERN.test(source) || ADDRESS_BANK_SIGNAL_PATTERN.test(source) || ADDRESS_CONTRACT_SIGNAL_PATTERN.test(source);
|
||||
}
|
||||
function hasSelectedObjectInventoryFollowupSignalForPredecompose(text) {
|
||||
const source = String(text ?? "");
|
||||
const repaired = repairAddressMojibake(source);
|
||||
if (/(?:по\s+выбранному\s+объекту|по\s+этой\s+позиции|по\s+этому\s+товару|selected\s+object)/iu.test(`${source} ${repaired}`)) {
|
||||
return true;
|
||||
}
|
||||
return /(?:по\s+выбранному\s+объекту|по\s+этой\s+позиции|по\s+этому\s+товару|selected\s+object)/iu.test(String(text ?? ""));
|
||||
}
|
||||
function isInventorySelectedObjectFollowupIntent(intent) {
|
||||
@@ -3540,6 +3545,33 @@ async function runAddressLlmPreDecompose(normalizerService, payload, userMessage
|
||||
}, userMessage);
|
||||
}
|
||||
const candidateAnchorQuality = evaluateAddressAnchorQuality(candidate);
|
||||
const candidateHasSemanticSelectedObjectScope =
|
||||
candidateMeta?.semanticHints?.selected_object_scope_detected === true ||
|
||||
candidateMeta?.semanticHints?.scope_target_kind === "selected_object";
|
||||
const candidateTextForSelectedObjectCounterpartyDegradation = compactWhitespace(repairAddressMojibake(String(candidate ?? "")).toLowerCase());
|
||||
const candidateUsesSelectedObjectAsCounterpartyAnchor =
|
||||
/(?:^|\s)по\s+контрагент\p{L}*\s+(?:выбран\p{L}*|selected(?:\s+object)?|object|объект\p{L}*)/iu.test(candidateTextForSelectedObjectCounterpartyDegradation) ||
|
||||
/(?:^|\s)counterparty\s+(?:selected(?:\s+object)?|object)/iu.test(candidateTextForSelectedObjectCounterpartyDegradation);
|
||||
const candidateTurnsSelectedObjectIntoCounterparty =
|
||||
sourceHasSelectedObjectInventoryFollowup &&
|
||||
(candidateInjectsGenericDocsIntent || candidateUsesSelectedObjectAsCounterpartyAnchor) &&
|
||||
(candidateHasSemanticSelectedObjectScope || candidateUsesSelectedObjectAsCounterpartyAnchor) &&
|
||||
(candidateAnchorQuality.anchorType === "counterparty" || candidateUsesSelectedObjectAsCounterpartyAnchor) &&
|
||||
(candidateAnchorQuality.quality < 2 || candidateUsesSelectedObjectAsCounterpartyAnchor);
|
||||
if (candidateTurnsSelectedObjectIntoCounterparty) {
|
||||
return attachAddressPredecomposeContract({
|
||||
...baseMeta,
|
||||
attempted: true,
|
||||
applied: false,
|
||||
traceId: normalized?.trace_id ?? null,
|
||||
llmCanonicalCandidateDetected: true,
|
||||
effectiveMessage: userMessage,
|
||||
reason: "normalized_fragment_rejected_selected_object_counterparty_degradation",
|
||||
fallbackRuleHit: null,
|
||||
sanitizedUserMessage,
|
||||
semanticHints: candidateMeta?.semanticHints ?? null
|
||||
}, userMessage);
|
||||
}
|
||||
const sameIntentForAnchorSafety = sourceAnchorQuality.intent !== "unknown" && sourceAnchorQuality.intent === candidateAnchorQuality.intent;
|
||||
const sourceSelectedObjectItemAnchorValue = toNonEmptyString((0, addressFilterExtractor_1.extractSelectedObjectQuotedValue)(userMessage)) ??
|
||||
toNonEmptyString((0, addressFilterExtractor_1.extractSelectedObjectQuotedValue)(repairedSourceMessage || userMessage));
|
||||
|
||||
@@ -195,6 +195,24 @@ export function createAssistantTransitionPolicy(deps) {
|
||||
if (samples.length === 0) {
|
||||
return null;
|
||||
}
|
||||
if (
|
||||
samples.some((sample) =>
|
||||
/(?:где\s+(?:мы\s+)?взял|откуда\s+(?:мы\s+)?взял|у\s+кого\s+купил|кто\s+постав|поставщик|источник\s+поступл|от\s+кого\s+поступ)/iu.test(
|
||||
sample
|
||||
)
|
||||
)
|
||||
) {
|
||||
return "inventory_purchase_provenance_for_item";
|
||||
}
|
||||
if (
|
||||
samples.some((sample) =>
|
||||
/(?:документ|накладн|счет|счёт|акт|поступл|подтвержден|подтверждена\s+закупка|закупк[аи]\s+подтвержден)/iu.test(
|
||||
sample
|
||||
)
|
||||
)
|
||||
) {
|
||||
return "inventory_purchase_documents_for_item";
|
||||
}
|
||||
if (
|
||||
suggestedIntents.includes("bank_operations_by_counterparty") &&
|
||||
samples.some((sample) => hasBankOperationsPivotCue(sample) || hasReadableBankOperationsPivotCue(sample))
|
||||
@@ -233,6 +251,13 @@ export function createAssistantTransitionPolicy(deps) {
|
||||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
/(?:по\s+выбранному\s+объекту|по\s+выбранной\s+позиции|по\s+этой\s+позиции|по\s+этому\s+товару|selected\s+object)/iu.test(
|
||||
normalized
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return /(?:по\s+выбранному\s+объекту|по\s+выбранной\s+позиции|по\s+этой\s+позиции|по\s+этому\s+товару|selected\s+object)/iu.test(
|
||||
normalized
|
||||
);
|
||||
@@ -240,6 +265,12 @@ export function createAssistantTransitionPolicy(deps) {
|
||||
|
||||
function extractSelectedObjectLabel(text) {
|
||||
const repaired = deps.repairAddressMojibake(String(text ?? ""));
|
||||
const unicodeQuotedMatch = repaired.match(
|
||||
/(?:по\s+выбранному\s+объекту|по\s+выбранной\s+позиции)\s*[:,-]?\s*[«"]([^"»]+?)["»]/iu
|
||||
);
|
||||
if (unicodeQuotedMatch?.[1]) {
|
||||
return deps.toNonEmptyString(unicodeQuotedMatch[1]);
|
||||
}
|
||||
const quotedMatch = repaired.match(
|
||||
/(?:по\s+выбранному\s+объекту|по\s+выбранной\s+позиции)\s*[:,-]?\s*[«"]([^"»]+?)["»]/iu
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user