@cognigy/rest-api-client
Version:
Cognigy REST-Client
270 lines • 11.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.filterConversationEntries = exports.GENERATIVE_SLOT_FILLER = void 0;
/* Custom modules */
const createNodeDescriptor_1 = require("../../../createNodeDescriptor");
const prompt_1 = require("./prompt");
const logger_1 = require("../../../../helper/logger");
const message_1 = require("../../message");
exports.GENERATIVE_SLOT_FILLER = (0, createNodeDescriptor_1.createNodeDescriptor)({
type: "generativeSlotFiller",
defaultLabel: "Generative Slot Filler",
summary: "UI__NODE_EDITOR__NLU__GENERATIVE_SLOT_FILLER__SUMMARY__DEFAULT",
dependencies: {
children: ["generativeSlotFillerFallback", "generativeSlotFillerSuccess"],
},
fields: [
{
key: "slotsConfig",
type: "json",
label: "UI__NODE_EDITOR__NLU__GENERATIVE_SLOT_FILLER__FIELDS__SLOT_CONFIG__DEFAULT_LABEL",
},
{
key: "amountOfLastUserInputs",
type: "slider",
label: "UI__NODE_EDITOR__NLU__GENERATIVE_SLOT_FILLER__FIELDS__AMOUNT_OF_LAST_USERS_INPUTS__LABEL",
params: {
min: 1,
max: 10,
step: 1,
},
defaultValue: 5
},
{
key: "maxQuestions",
label: "UI__NODE_EDITOR__NLU__GENERATIVE_MAX_QUESTIONS__DEFAULT_LABEL",
type: "slider",
defaultValue: 5,
params: {
min: 0,
max: 10,
step: 1
},
},
{
key: "temperature",
label: "UI__NODE_EDITOR__NLU__GENERATIVE_TEMPERATURE__DEFAULT_LABEL",
type: "slider",
description: "UI__NODE_EDITOR__NLU__GENERATIVE_SLIDER__DEFAULT_LABEL",
defaultValue: 1,
params: {
min: 0,
max: 1,
step: 0.1
},
},
{
key: "timeout",
label: "UI__NODE_EDITOR__NLU__GENERATIVE_TIMEOUT__DEFAULT_LABEL",
defaultValue: 6000,
type: "number",
description: "UI__NODE_EDITOR__NLU__GENERATIVE_TIMEOUT__DESCRIPTION",
},
{
key: "storeLocation",
type: "select",
label: "UI__NODE_EDITOR__NLU__GENERATIVE_STORE_LOCATION__DEFAULT_LABEL",
defaultValue: "context",
params: {
options: [
{
label: "UI__NODE_EDITOR__NLU__GENERATIVE_STORE_LOCATION__OPTIONS__INPUT__LABEL",
value: "input"
},
{
label: "UI__NODE_EDITOR__NLU__GENERATIVE_STORE_LOCATION__OPTIONS__CONTEXT__LABEL",
value: "context"
}
],
required: true
},
},
{
key: "inputKey",
type: "cognigyText",
label: "UI__NODE_EDITOR__NLU__GENERATIVE_INPUT_KEY__DEFAULT_LABEL",
defaultValue: "generativeSlotFiller",
condition: {
key: "storeLocation",
value: "input",
}
},
{
key: "contextKey",
type: "cognigyText",
label: "UI__NODE_EDITOR__NLU__GENERATIVE_CONTEXT_KEY__DEFAULT_LABEL",
defaultValue: "generativeSlotFiller",
condition: {
key: "storeLocation",
value: "context",
}
},
],
sections: [
{
key: "advanced",
label: "UI__NODE_EDITOR__NLU__GENERATIVE_SLOT_FILLER__SECTIONS__ADVANCED__DEFAULT_LABEL",
defaultCollapsed: true,
fields: [
"temperature",
"timeout",
]
},
{
key: "storage",
label: "UI__NODE_EDITOR__NLU__GENERATIVE_SLOT_FILLER__SECTIONS__STORAGE__DEFAULT_LABEL",
defaultCollapsed: true,
fields: [
"storeLocation",
"inputKey",
"contextKey",
]
}
],
form: [
{ type: "field", key: "slotsConfig" },
{ type: "field", key: "amountOfLastUserInputs" },
{ type: "field", key: "maxQuestions" },
{ type: "section", key: "advanced" },
{ type: "section", key: "storage" },
],
appearance: {},
tags: ["ai", "nlu"],
function: async ({ cognigy, config, childConfigs, nodeId, organisationId }) => {
var _a;
const { api, lastConversationEntries } = cognigy;
const { slotsConfig, amountOfLastUserInputs, maxQuestions, temperature, storeLocation, contextKey, inputKey, timeout, } = config;
const fallBackChild = childConfigs.find(child => child.type === "generativeSlotFillerFallback");
if ((slotsConfig === null || slotsConfig === void 0 ? void 0 : slotsConfig.length) < 1 || (lastConversationEntries === null || lastConversationEntries === void 0 ? void 0 : lastConversationEntries.length) < 1) {
api.setNextNode(fallBackChild.id);
return;
}
try {
// the filled slots that were found in the previous execution
const filledSlots = storeLocation === "context" ? cognigy.context[contextKey] : cognigy.input[inputKey];
const slots = [...slotsConfig];
if (filledSlots) {
for (const filledSlot of Object.keys(filledSlots)) {
const slot = slots.find(slot => slot.tag === filledSlot);
slot.value = filledSlots[filledSlot];
// remove the validation, so that the slot is not validated again
delete slot.validation;
}
}
const questionCountKey = `generativeSlotFiller_${nodeId}_questionCount`;
const questionCount = api.getSystemContext(questionCountKey) || 0;
// for questions, we only use the last user input
const extractionEntries = questionCount > 0 ? (0, exports.filterConversationEntries)(lastConversationEntries, 1) : (0, exports.filterConversationEntries)(lastConversationEntries, amountOfLastUserInputs);
const extractEntitiesprompt = (0, prompt_1.createExtractionPrompt)(slots, extractionEntries);
const data = {
prompt: extractEntitiesprompt,
temperature,
timeoutInMs: timeout,
useCase: "slotExtraction",
};
// TODO: Create a new useCase for this feature and use it here instead
const response = await api.runGenerativeAIPrompt(data, "gptConversation");
const parsed = JSON.parse(response);
const slotsWithLexiconValidations = [];
slots.forEach(slot => {
if (parsed[slot.tag]) {
if (slot.validation && slot.validation.type === "slot") {
slotsWithLexiconValidations.push(slot);
}
slot.value = parsed[slot.tag];
}
});
for (const slot of slotsWithLexiconValidations) {
const nlu = await api.executeCognigyNLU(parsed[slot.tag], null, "TODO", {
parseIntents: false,
});
if ((_a = nlu === null || nlu === void 0 ? void 0 : nlu.slots) === null || _a === void 0 ? void 0 : _a[slot.validation.value]) {
slot.invalid = false;
}
else {
slot.invalid = true;
}
}
;
let complete = true;
let allValid = true;
const missingSlots = [];
const invalidSlots = [];
const foundSlots = [];
for (const slot of slots) {
if (!slot.optional && !slot.value) {
missingSlots.push(slot);
}
else if (slot.invalid) {
invalidSlots.push(slot);
}
else if (slot.value && !slot.invalid) {
foundSlots.push(slot);
}
}
const slotResult = {};
foundSlots.forEach(slot => {
slotResult[slot.tag] = slot.value;
});
if (storeLocation === "context") {
cognigy.context[contextKey] = slotResult;
}
else {
cognigy.input[contextKey] = slotResult;
}
if (missingSlots.length > 0) {
complete = false;
}
if (invalidSlots.length > 0) {
allValid = false;
}
if (complete && allValid) {
const childNode = childConfigs.find(child => child.type === "generativeSlotFillerSuccess");
api.setNextNode(childNode.id);
return;
}
if (questionCount >= maxQuestions && !(complete && allValid)) {
const childNode = childConfigs.find(child => child.type === "generativeSlotFillerFallback");
api.setNextNode(childNode.id);
return;
}
if (questionCount < maxQuestions && !(complete && allValid)) {
api.setSystemContext(questionCountKey, questionCount + 1);
const prompt = allValid ? (0, prompt_1.createQuestionPrompt)(foundSlots, missingSlots, extractionEntries) : (0, prompt_1.createInvalidAnswerPrompt)(invalidSlots, extractionEntries);
const data = {
prompt,
temperature,
timeoutInMs: timeout,
useCase: "slotExtractionQuestion",
};
// TODO: Create a new useCase for this feature and use it here instead
const question = await api.runGenerativeAIPrompt(data, "gptConversation");
await message_1.SAY.function({ cognigy, childConfigs: [], nodeId, organisationId, config: { say: { type: "text", text: [question] } } });
api.stopExecution();
api.setNextNode(nodeId);
return;
}
}
catch (error) {
api.setNextNode(fallBackChild.id);
logger_1.default.log("error", { traceId: cognigy.input.traceId }, `Error in generativeSlotFiller: ${error.message}`);
}
}
});
const filterConversationEntries = (lastConversationEntries, amountOfLastUserInputs) => {
let addedUserInputsCount = 0;
let lastEntries = [];
// lastUserInputs is ordered newest -> oldest
for (const entry of lastConversationEntries) {
if (entry.source === "user" && addedUserInputsCount >= amountOfLastUserInputs) {
break;
}
lastEntries.push(entry);
if (entry.source === "user") {
addedUserInputsCount++;
}
}
return lastEntries;
};
exports.filterConversationEntries = filterConversationEntries;
//# sourceMappingURL=generativeSlotFiller.js.map