UNPKG

@cognigy/rest-api-client

Version:

Cognigy REST-Client

270 lines 11.2 kB
"use strict"; 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