@botmock/export
Advanced tools
Comparing version 0.15.0 to 0.16.0
@@ -8,27 +8,9 @@ "use strict"; | ||
}; | ||
var _multiChannelProjectName, _getResources, _convertToCombinedResourceStructure; | ||
var _multiChannelProjectName, _getResources, _convertToCombinedResourceStructure, _generateMissingIntents; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const uuid_1 = require("uuid"); | ||
const client_1 = require("@botmock/client"); | ||
const uuid_1 = require("uuid"); | ||
class BaseExporter { | ||
constructor(config) { | ||
this.config = config; | ||
this.replaceEntityCharacters = (input, left = "{", right = "}") => { | ||
const processedInput = input.split(""); | ||
let numCaptured = 0; | ||
let i = 0; | ||
for (const char of processedInput) { | ||
if (char === "%") { | ||
if (numCaptured % 2 === 0) { | ||
processedInput[i] = left; | ||
} | ||
else { | ||
processedInput[i] = right; | ||
} | ||
numCaptured += 1; | ||
} | ||
i += 1; | ||
} | ||
return processedInput.join(""); | ||
}; | ||
_multiChannelProjectName.set(this, "multi-channel"); | ||
@@ -55,7 +37,12 @@ _getResources.set(this, async (projectReference) => { | ||
board: { | ||
board: Object.assign(Object.assign({}, resources.board.board), { messages: resources.board.board.messages.map((message) => { | ||
board: Object.assign(Object.assign({}, resources.board.board), { messages: resources.board.board.messages | ||
.map((message) => { | ||
return Object.assign(Object.assign({}, message), { payload: resources.project.locales.reduce((acc, locale) => { | ||
var _a; | ||
const unconnectedNextMessageIds = (_a = message.next_message_ids) === null || _a === void 0 ? void 0 : _a.filter(next => !next.intent.value).map(next => next.message_id); | ||
const unconnectedMessages = unconnectedNextMessageIds === null || unconnectedNextMessageIds === void 0 ? void 0 : unconnectedNextMessageIds.map(id => resources.board.board.messages.find(message => message.message_id === id)); | ||
const unconnectedPayloads = unconnectedMessages === null || unconnectedMessages === void 0 ? void 0 : unconnectedMessages.map(message => message === null || message === void 0 ? void 0 : message.payload); | ||
return Object.assign(Object.assign({}, acc), { [locale]: { | ||
[resources.project.platform]: { | ||
blocks: [message.payload], | ||
blocks: [message.payload, ...(unconnectedPayloads !== null && unconnectedPayloads !== void 0 ? unconnectedPayloads : [])], | ||
} | ||
@@ -69,2 +56,69 @@ } }); | ||
}); | ||
this.replaceEntityCharacters = (input, left = "{", right = "}") => { | ||
const processedInput = input.split(""); | ||
let numCaptured = 0; | ||
let i = 0; | ||
for (const char of processedInput) { | ||
if (char === "%") { | ||
if (numCaptured % 2 === 0) { | ||
processedInput[i] = left; | ||
} | ||
else { | ||
processedInput[i] = right; | ||
} | ||
numCaptured += 1; | ||
} | ||
i += 1; | ||
} | ||
return processedInput.join(""); | ||
}; | ||
_generateMissingIntents.set(this, (resources) => { | ||
const rootMessages = resources.board.board.root_messages; | ||
const isMissingIntentFromRoot = !resources.board.board.messages | ||
.flatMap(message => ({ | ||
source: message.message_id, | ||
hasIntentOnConnector: message.next_message_ids.some(next => !!next.intent.value) | ||
})) | ||
.some(obj => rootMessages.includes(obj.source) && obj.hasIntentOnConnector); | ||
if (!isMissingIntentFromRoot) { | ||
return resources; | ||
} | ||
const generatedIntentId = `${uuid_1.v4()}_generated`; | ||
const generatedIntent = { | ||
id: generatedIntentId, | ||
name: generatedIntentId, | ||
utterances: { | ||
en: [ | ||
{ text: "hello", variables: [] } | ||
] | ||
}, | ||
created_at: { | ||
date: new Date().toISOString(), | ||
timezone_type: 3, | ||
timezone: "UTC" | ||
}, | ||
updated_at: { | ||
date: new Date().toISOString(), | ||
timezone_type: 3, | ||
timezone: "UTC" | ||
}, | ||
slots: [], | ||
}; | ||
return Object.assign(Object.assign({}, resources), { intents: resources.intents.concat(generatedIntent), board: Object.assign(Object.assign({}, resources.board), { board: { | ||
messages: resources.board.board.messages.map(message => { | ||
if (message.is_root) { | ||
return Object.assign(Object.assign({}, message), { next_message_ids: message.next_message_ids.map((next, i) => { | ||
if (i === 0) { | ||
return Object.assign(Object.assign({}, next), { intent: { | ||
value: generatedIntentId, | ||
label: generatedIntentId, | ||
} }); | ||
} | ||
return next; | ||
}) }); | ||
} | ||
return message; | ||
}), | ||
} }) }); | ||
}); | ||
this.client = new client_1.Client({ token: config.token }); | ||
@@ -80,2 +134,3 @@ } | ||
resources = __classPrivateFieldGet(this, _convertToCombinedResourceStructure).call(this, resources); | ||
resources = __classPrivateFieldGet(this, _generateMissingIntents).call(this, resources); | ||
for (const transform of this.dataTransformations.entries()) { | ||
@@ -104,3 +159,3 @@ const [directoryPath, transformFn] = transform; | ||
exports.default = BaseExporter; | ||
_multiChannelProjectName = new WeakMap(), _getResources = new WeakMap(), _convertToCombinedResourceStructure = new WeakMap(); | ||
_multiChannelProjectName = new WeakMap(), _getResources = new WeakMap(), _convertToCombinedResourceStructure = new WeakMap(), _generateMissingIntents = new WeakMap(); | ||
//# sourceMappingURL=index.js.map |
@@ -8,3 +8,3 @@ import BaseExporter from '../base-exporter'; | ||
} | ||
export declare class DialogflowExporter<D> extends BaseExporter<D> { | ||
export declare class DialogflowExporter extends BaseExporter { | ||
#private; | ||
@@ -11,0 +11,0 @@ protected generateInputContexts(responseBlockId: string): IterableIterator<string | void>; |
@@ -18,6 +18,5 @@ "use strict"; | ||
}; | ||
var _intents, _blocks, _shouldUseFollowupIntents, _entityMap, _typesForPlatform, _createIntentName, _mapResponsesToMessages, _replaceVariableCharacterInText, _mapBlockToEntity, _mapBlockToIntent, _intentsTransformation, _entitiesTransformation, _rootTransformation; | ||
var _shouldUseFollowupIntents, _intents, _blocks, _entityMap, _typesForPlatform, _createIntentName, _mapResponsesToMessages, _replaceVariableCharacterInText, _mapBlockToEntity, _mapBlockToIntent, _intentsTransformation, _entitiesTransformation, _rootTransformation; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.DialogflowExporter = void 0; | ||
const assert_1 = require("assert"); | ||
const uuid_1 = require("uuid"); | ||
@@ -35,8 +34,7 @@ const base_exporter_1 = __importDefault(require("../base-exporter")); | ||
super(...arguments); | ||
_shouldUseFollowupIntents.set(this, void 0); | ||
_intents.set(this, void 0); | ||
_blocks.set(this, void 0); | ||
_shouldUseFollowupIntents.set(this, void 0); | ||
_entityMap.set(this, new Map([ | ||
[types_1.Botmock.SystemEntity.ANY, types_1.Dialogflow.SystemEntity.ANY], | ||
[types_1.Botmock.SystemEntity.ANY, types_1.Dialogflow.SystemEntity.AGE], | ||
[types_1.Botmock.SystemEntity.COUNTRY, types_1.Dialogflow.SystemEntity.GEO_COUNTRY], | ||
@@ -70,2 +68,5 @@ [types_1.Botmock.SystemEntity.CITY, types_1.Dialogflow.SystemEntity.GEO_CITY], | ||
[types_1.Botmock.Component.text, types_1.Dialogflow.DataTypes.TEXT], | ||
[types_1.Botmock.Component.generic, types_1.Dialogflow.DataTypes.CARD], | ||
[types_1.Botmock.Component.button, types_1.Dialogflow.DataTypes.BUTTONS], | ||
[types_1.Botmock.Component.quick_replies, types_1.Dialogflow.DataTypes.BUTTONS], | ||
]) | ||
@@ -96,7 +97,9 @@ ], | ||
var _a; | ||
const intentConnnectedToBlock = __classPrivateFieldGet(this, _blocks).flatMap(block => block.next_message_ids) | ||
const intentConnnectedToMessage = __classPrivateFieldGet(this, _blocks).flatMap(block => block.next_message_ids) | ||
.find(next => next.message_id === botmockMessage.message_id); | ||
assert_1.notStrictEqual(intentConnnectedToBlock, undefined); | ||
const id = intentConnnectedToBlock === null || intentConnnectedToBlock === void 0 ? void 0 : intentConnnectedToBlock.intent.value; | ||
const name = (_a = __classPrivateFieldGet(this, _intents).find(intent => intent.id === id)) === null || _a === void 0 ? void 0 : _a.name; | ||
const intentId = intentConnnectedToMessage === null || intentConnnectedToMessage === void 0 ? void 0 : intentConnnectedToMessage.intent.value; | ||
let name = (_a = __classPrivateFieldGet(this, _intents).find(intent => intent.id === intentId)) === null || _a === void 0 ? void 0 : _a.name; | ||
if (name === null || name === void 0 ? void 0 : name.endsWith("_generated")) { | ||
name = "Default Welcome Intent"; | ||
} | ||
return name; | ||
@@ -115,3 +118,2 @@ }); | ||
} | ||
assert_1.notStrictEqual(typeof responses, "string"); | ||
const messagesContainedInLang = Object | ||
@@ -125,5 +127,4 @@ .entries(responses) | ||
const relevantTypesForPlatform = __classPrivateFieldGet(this, _typesForPlatform).get(types_1.Platform[platform]); | ||
assert_1.notStrictEqual(relevantTypesForPlatform, undefined); | ||
const messagesContainedInResponse = blocks.map(block => { | ||
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m; | ||
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; | ||
const type = (_a = relevantTypesForPlatform === null || relevantTypesForPlatform === void 0 ? void 0 : relevantTypesForPlatform.get(types_1.Botmock.Component[block.component_type])) !== null && _a !== void 0 ? _a : types_1.Dialogflow.DataTypes.CUSTOM; | ||
@@ -136,9 +137,2 @@ const object = { | ||
}; | ||
assert_1.notStrictEqual(lang, undefined); | ||
try { | ||
assert_1.notStrictEqual(type, types_1.Dialogflow.DataTypes.RCS_CARD); | ||
} | ||
catch (_o) { | ||
console.warn(`${type} unimplemented`); | ||
} | ||
switch (type) { | ||
@@ -156,5 +150,5 @@ case types_1.Dialogflow.DataTypes.TEXT: | ||
case types_1.Dialogflow.DataTypes.BUTTONS: | ||
object.replies = (_c = block.quick_replies) === null || _c === void 0 ? void 0 : _c.map(quick => quick.title); | ||
object.replies = (_c = block.quick_replies) === null || _c === void 0 ? void 0 : _c.map(quick => quick.title.slice(0, 19)); | ||
if (!object.replies) { | ||
object.replies = (_d = block.buttons) === null || _d === void 0 ? void 0 : _d.map(button => button.title); | ||
object.replies = (_d = block.buttons) === null || _d === void 0 ? void 0 : _d.map(button => button.title.slice(0, 19)); | ||
} | ||
@@ -166,4 +160,3 @@ break; | ||
case types_1.Dialogflow.DataTypes.CARD: | ||
assert_1.strictEqual((_e = block.elements) === null || _e === void 0 ? void 0 : _e.length, 1); | ||
const [cardElement] = (_f = block.elements) !== null && _f !== void 0 ? _f : []; | ||
const [cardElement] = (_e = block.elements) !== null && _e !== void 0 ? _e : []; | ||
object.title = cardElement.title; | ||
@@ -180,3 +173,3 @@ object.subtitle = cardElement.subtitle; | ||
object.cardWidth = "SMALL"; | ||
object.cardContents = ((_g = block.elements) !== null && _g !== void 0 ? _g : []).map(element => ({ | ||
object.cardContents = ((_f = block.elements) !== null && _f !== void 0 ? _f : []).map(element => ({ | ||
title: element.title, | ||
@@ -204,4 +197,3 @@ description: element.subtitle, | ||
case types_1.Dialogflow.DataTypes.BASIC_CARD: | ||
assert_1.strictEqual((_h = block.elements) === null || _h === void 0 ? void 0 : _h.length, 1); | ||
const [basicCardElement] = (_j = block.elements) !== null && _j !== void 0 ? _j : []; | ||
const [basicCardElement] = (_g = block.elements) !== null && _g !== void 0 ? _g : []; | ||
object.title = basicCardElement.title; | ||
@@ -223,7 +215,7 @@ object.subtitle = basicCardElement.subtitle; | ||
case types_1.Dialogflow.DataTypes.SUGGESTION_CHIPS: | ||
object.suggestions = (_k = block.quick_replies) === null || _k === void 0 ? void 0 : _k.map(quickReply => ({ | ||
object.suggestions = (_h = block.quick_replies) === null || _h === void 0 ? void 0 : _h.map(quickReply => ({ | ||
title: quickReply.title, | ||
})); | ||
if (!object.suggestions) { | ||
object.suggestions = (_l = block.buttons) === null || _l === void 0 ? void 0 : _l.map(button => ({ | ||
object.suggestions = (_j = block.buttons) === null || _j === void 0 ? void 0 : _j.map(button => ({ | ||
title: button.title, | ||
@@ -234,3 +226,3 @@ })); | ||
case types_1.Dialogflow.DataTypes.LIST_CARD: | ||
object.items = (_m = block.elements) === null || _m === void 0 ? void 0 : _m.map(element => ({ | ||
object.items = (_k = block.elements) === null || _k === void 0 ? void 0 : _k.map(element => ({ | ||
optionInfo: { | ||
@@ -294,3 +286,3 @@ key: uuid_1.v4(), | ||
_mapBlockToIntent.set(this, (block) => { | ||
var _a, _b, _c, _d, _e; | ||
var _a, _b, _c, _d; | ||
const events = []; | ||
@@ -301,3 +293,3 @@ const parentBlock = __classPrivateFieldGet(this, _blocks).find(projectBlocks => projectBlocks.next_message_ids.map(next => next.message_id).includes(block.message_id)); | ||
} | ||
const name = (_a = __classPrivateFieldGet(this, _createIntentName).call(this, block)) !== null && _a !== void 0 ? _a : "Default Welcome Intent"; | ||
const name = __classPrivateFieldGet(this, _createIntentName).call(this, block); | ||
const generatedInputContexts = this.generateInputContexts(block.message_id); | ||
@@ -318,3 +310,2 @@ let contexts = []; | ||
if (!block.is_root && __classPrivateFieldGet(this, _shouldUseFollowupIntents)) { | ||
assert_1.notStrictEqual(contexts.length, 0); | ||
rootParentId = contexts[0]; | ||
@@ -324,3 +315,47 @@ parentId = contexts.slice(-1)[0]; | ||
} | ||
const [intentConnectedToBlock] = __classPrivateFieldGet(this, _intents).filter(intent => name.includes(intent.name)); | ||
if (!name) { | ||
return { | ||
filenames: [], | ||
data: [] | ||
}; | ||
} | ||
const [intentConnectedToBlock] = __classPrivateFieldGet(this, _blocks).flatMap(b => b.next_message_ids | ||
.filter(next => !!next.intent.value && next.message_id === block.message_id) | ||
.map(next => { | ||
const intentId = next.intent.value; | ||
return __classPrivateFieldGet(this, _intents).find(intent => intent.id === intentId); | ||
})); | ||
const outputContextOfIntentSettingThisInputContext = []; | ||
const outputContext = [ | ||
!(parentBlock === null || parentBlock === void 0 ? void 0 : parentBlock.is_root) | ||
? undefined | ||
: { | ||
name: "welcome", | ||
parameters: {}, | ||
lifespan: 5, | ||
}, | ||
...outputContextOfIntentSettingThisInputContext, | ||
...block.next_message_ids | ||
.reduce((acc, next) => { | ||
var _a, _b; | ||
const immediatelyConnectedBlock = __classPrivateFieldGet(this, _blocks).find(block => block.message_id === next.message_id); | ||
const nextOfNext = (_a = __classPrivateFieldGet(this, _blocks).find(block => block.message_id === next.message_id)) === null || _a === void 0 ? void 0 : _a.next_message_ids; | ||
const distantlyConnectedBlocksCreatingIntents = (_b = nextOfNext === null || nextOfNext === void 0 ? void 0 : nextOfNext.filter(next => !!next.intent.value).map(next => __classPrivateFieldGet(this, _blocks).find(block => block.message_id === next.message_id))) !== null && _b !== void 0 ? _b : []; | ||
return [ | ||
...acc, | ||
...distantlyConnectedBlocksCreatingIntents.map(block => { | ||
return { | ||
name: __classPrivateFieldGet(this, _createIntentName).call(this, block), | ||
parameters: {}, | ||
lifespan: 5, | ||
}; | ||
}), | ||
{ | ||
name: __classPrivateFieldGet(this, _createIntentName).call(this, immediatelyConnectedBlock), | ||
parameters: {}, | ||
lifespan: 5, | ||
} | ||
]; | ||
}, []) | ||
].filter(context => typeof context !== "undefined"); | ||
return { | ||
@@ -338,40 +373,26 @@ filenames: [`${name}.json`, `${name}_usersays_en.json`], | ||
resetContexts: false, | ||
action: "input.welcome", | ||
affectedContexts: [ | ||
!(parentBlock === null || parentBlock === void 0 ? void 0 : parentBlock.is_root) | ||
? undefined | ||
: { | ||
name: "welcome", | ||
parameters: {}, | ||
lifespan: 5, | ||
}, | ||
...block.next_message_ids.map(next => { | ||
const connectedResponseBlock = __classPrivateFieldGet(this, _blocks).find(block => block.message_id === next.message_id); | ||
assert_1.notStrictEqual(connectedResponseBlock, undefined); | ||
action: name, | ||
affectedContexts: outputContext, | ||
parameters: Object | ||
.values((_a = intentConnectedToBlock === null || intentConnectedToBlock === void 0 ? void 0 : intentConnectedToBlock.utterances) !== null && _a !== void 0 ? _a : {}) | ||
.reduce((uniqueEntities, utterances) => { | ||
const entitiesInUtterances = utterances.flatMap(utterance => utterance.variables.map(variable => { | ||
return { | ||
name: __classPrivateFieldGet(this, _createIntentName).call(this, connectedResponseBlock), | ||
parameters: {}, | ||
lifespan: 5, | ||
id: variable.id, | ||
required: false, | ||
dataType: __classPrivateFieldGet(this, _entityMap).get(variable.entity), | ||
name: variable.name.replace(/\%/g, ""), | ||
value: `$${variable.default_value}`, | ||
promptMessages: [], | ||
noMatchPromptMessages: [], | ||
outputDialogContexts: [], | ||
isList: false, | ||
}; | ||
}) | ||
].filter(context => typeof context !== "undefined"), | ||
parameters: Object | ||
.values((_b = intentConnectedToBlock === null || intentConnectedToBlock === void 0 ? void 0 : intentConnectedToBlock.utterances) !== null && _b !== void 0 ? _b : {}) | ||
.reduce((uniqueEntities, utterances) => { | ||
const entitiesInUtterances = utterances.flatMap(utterance => utterance.variables.map(variable => ({ | ||
id: variable.id, | ||
required: false, | ||
dataType: __classPrivateFieldGet(this, _entityMap).get(variable.entity), | ||
name: variable.name.replace(/\%/g, ""), | ||
value: `$${variable.default_value}`, | ||
promptMessages: [], | ||
noMatchPromptMessages: [], | ||
outputDialogContexts: [], | ||
isList: false, | ||
}))); | ||
return uniqueEntities.concat(entitiesInUtterances.filter(entity => !uniqueEntities.map(unique => unique.name).includes(entity.name))); | ||
})); | ||
return uniqueEntities | ||
.concat(entitiesInUtterances.filter(entity => !uniqueEntities.map(unique => unique.name).includes(entity.name))); | ||
}, []), | ||
messages: __classPrivateFieldGet(this, _mapResponsesToMessages).call(this, (_c = block.payload) !== null && _c !== void 0 ? _c : {}), | ||
messages: __classPrivateFieldGet(this, _mapResponsesToMessages).call(this, (_b = block.payload) !== null && _b !== void 0 ? _b : {}), | ||
defaultResponsePlatforms: Object | ||
.keys((_d = block.payload) !== null && _d !== void 0 ? _d : {}) | ||
.keys((_c = block.payload) !== null && _c !== void 0 ? _c : {}) | ||
.flatMap(lang => { | ||
@@ -403,3 +424,3 @@ let platformNames = []; | ||
Object | ||
.values((_e = intentConnectedToBlock === null || intentConnectedToBlock === void 0 ? void 0 : intentConnectedToBlock.utterances) !== null && _e !== void 0 ? _e : {}) | ||
.values((_d = intentConnectedToBlock === null || intentConnectedToBlock === void 0 ? void 0 : intentConnectedToBlock.utterances) !== null && _d !== void 0 ? _d : {}) | ||
.reduce((acc, utterances) => { | ||
@@ -409,3 +430,26 @@ return [ | ||
...utterances.map(utterance => { | ||
const data = [{ text: __classPrivateFieldGet(this, _replaceVariableCharacterInText).call(this, utterance.text), userDefined: false }]; | ||
const replacedText = __classPrivateFieldGet(this, _replaceVariableCharacterInText).call(this, utterance.text); | ||
const data = []; | ||
for (const word of replacedText.split(" ")) { | ||
if (word.startsWith("$")) { | ||
data.push({ | ||
text: word, | ||
userDefined: false, | ||
alias: word.slice(1), | ||
meta: __classPrivateFieldGet(this, _entityMap).get(utterance.variables[0].entity), | ||
}); | ||
} | ||
else { | ||
const lastElement = data[data.length - 1]; | ||
if ((lastElement === null || lastElement === void 0 ? void 0 : lastElement.alias) || !lastElement) { | ||
data.push({ | ||
text: `${word} `, | ||
userDefined: false, | ||
}); | ||
} | ||
else { | ||
data[data.length - 1].text += word; | ||
} | ||
} | ||
} | ||
return { | ||
@@ -419,18 +463,5 @@ id: uuid_1.v4(), | ||
}; | ||
}) | ||
}), | ||
]; | ||
}, [ | ||
{ | ||
"id": uuid_1.v4(), | ||
"data": [ | ||
{ | ||
"text": "hi", | ||
"userDefined": false | ||
} | ||
], | ||
"isTemplate": false, | ||
"count": 0, | ||
"updated": 0 | ||
} | ||
]) | ||
}, []) | ||
] | ||
@@ -440,5 +471,10 @@ }; | ||
_intentsTransformation.set(this, (resources) => { | ||
__classPrivateFieldSet(this, _intents, resources.intents); | ||
__classPrivateFieldSet(this, _blocks, resources.board.board.messages); | ||
__classPrivateFieldSet(this, _intents, resources.intents); | ||
return __classPrivateFieldGet(this, _blocks).filter((block) => !block.is_root).map(__classPrivateFieldGet(this, _mapBlockToIntent)); | ||
return __classPrivateFieldGet(this, _blocks).filter(block => !block.is_root) | ||
.filter(block => { | ||
const nextMessages = __classPrivateFieldGet(this, _blocks).flatMap(b => b.next_message_ids.filter(next => !!next.intent.value)); | ||
return nextMessages.some(next => next.message_id === block.message_id); | ||
}) | ||
.map(__classPrivateFieldGet(this, _mapBlockToIntent)); | ||
}); | ||
@@ -525,7 +561,10 @@ _entitiesTransformation.set(this, (resources) => { | ||
const fullBlock = __classPrivateFieldGet(this, _blocks).find(block => block.message_id === blockId); | ||
const pathBackwardsIsDeterministic = Object.is(fullBlock === null || fullBlock === void 0 ? void 0 : fullBlock.previous_message_ids.length, 1); | ||
if (pathBackwardsIsDeterministic) { | ||
const isUnambiguousBackwardPath = Object.is(fullBlock === null || fullBlock === void 0 ? void 0 : fullBlock.previous_message_ids.length, 1); | ||
if (isUnambiguousBackwardPath) { | ||
const parentBlock = __classPrivateFieldGet(this, _blocks).find(block => block.message_id === (fullBlock === null || fullBlock === void 0 ? void 0 : fullBlock.previous_message_ids[0].message_id)); | ||
if (parentBlock === null || parentBlock === void 0 ? void 0 : parentBlock.is_root) { | ||
break; | ||
} | ||
blockId = parentBlock === null || parentBlock === void 0 ? void 0 : parentBlock.message_id; | ||
const name = __classPrivateFieldGet(this, _createIntentName).call(this, fullBlock); | ||
const name = __classPrivateFieldGet(this, _createIntentName).call(this, parentBlock); | ||
const suffix = __classPrivateFieldGet(this, _shouldUseFollowupIntents) ? "-followup" : ""; | ||
@@ -541,3 +580,3 @@ yield `${name}${suffix}`; | ||
exports.DialogflowExporter = DialogflowExporter; | ||
_intents = new WeakMap(), _blocks = new WeakMap(), _shouldUseFollowupIntents = new WeakMap(), _entityMap = new WeakMap(), _typesForPlatform = new WeakMap(), _createIntentName = new WeakMap(), _mapResponsesToMessages = new WeakMap(), _replaceVariableCharacterInText = new WeakMap(), _mapBlockToEntity = new WeakMap(), _mapBlockToIntent = new WeakMap(), _intentsTransformation = new WeakMap(), _entitiesTransformation = new WeakMap(), _rootTransformation = new WeakMap(); | ||
_shouldUseFollowupIntents = new WeakMap(), _intents = new WeakMap(), _blocks = new WeakMap(), _entityMap = new WeakMap(), _typesForPlatform = new WeakMap(), _createIntentName = new WeakMap(), _mapResponsesToMessages = new WeakMap(), _replaceVariableCharacterInText = new WeakMap(), _mapBlockToEntity = new WeakMap(), _mapBlockToIntent = new WeakMap(), _intentsTransformation = new WeakMap(), _entitiesTransformation = new WeakMap(), _rootTransformation = new WeakMap(); | ||
//# sourceMappingURL=index.js.map |
@@ -43,3 +43,3 @@ "use strict"; | ||
} | ||
const nodeName = (_b = blocks.find(block => block.message_id === idOfBlockConnectedToIntent)) === null || _b === void 0 ? void 0 : _b.node_name; | ||
const nodeName = (_b = blocks.find(block => block.message_id === idOfBlockConnectedToIntent)) === null || _b === void 0 ? void 0 : _b.message_id; | ||
return Object.assign(Object.assign({}, intentList), { [intent.name]: [`utter_${nodeName === null || nodeName === void 0 ? void 0 : nodeName.toLowerCase().replace(/\s/g, "_")}`] }); | ||
@@ -46,0 +46,0 @@ }, {}) |
@@ -120,5 +120,2 @@ import { JSONResponse } from "@botmock/client"; | ||
}; | ||
enum Lang { | ||
en = "en" | ||
} | ||
export interface Slot { | ||
@@ -133,3 +130,3 @@ id: string; | ||
name: string; | ||
utterances: KeyDependent<Utterance[], Lang>; | ||
utterances: KeyDependent<Utterance[], string>; | ||
created_at: DateObj; | ||
@@ -190,18 +187,19 @@ updated_at: DateObj; | ||
} | ||
export interface Next { | ||
message_id: string; | ||
action: { | ||
type: string; | ||
title: string; | ||
payload: string; | ||
}; | ||
intent: { | ||
label: string; | ||
value: string; | ||
}; | ||
conditional: boolean; | ||
} | ||
export interface Message { | ||
message_id: string; | ||
message_type: string; | ||
next_message_ids: { | ||
message_id: string; | ||
action: { | ||
type: string; | ||
title: string; | ||
payload: string; | ||
}; | ||
intent: { | ||
label: string; | ||
value: string; | ||
}; | ||
conditional: boolean; | ||
}[]; | ||
next_message_ids: Next[]; | ||
previous_message_ids: { | ||
@@ -208,0 +206,0 @@ message_id: string; |
@@ -75,6 +75,2 @@ "use strict"; | ||
})(SystemEntity = Botmock.SystemEntity || (Botmock.SystemEntity = {})); | ||
let Lang; | ||
(function (Lang) { | ||
Lang["en"] = "en"; | ||
})(Lang || (Lang = {})); | ||
let Component; | ||
@@ -81,0 +77,0 @@ (function (Component) { |
{ | ||
"name": "@botmock/export", | ||
"version": "0.15.0", | ||
"version": "0.16.0", | ||
"description": "", | ||
@@ -52,4 +52,4 @@ "contributors": [ | ||
"pascal-case": "3.1.1", | ||
"ts-jest": "26.1.2" | ||
"ts-jest": "26.1.3" | ||
} | ||
} |
@@ -0,1 +1,2 @@ | ||
import { v4 } from "uuid"; | ||
import { Client, Resource, JSONResponse } from "@botmock/client"; | ||
@@ -13,3 +14,2 @@ import { | ||
} from "../types"; | ||
import { v4 } from "uuid"; | ||
@@ -25,19 +25,2 @@ export interface ExportReference { | ||
} | ||
protected replaceEntityCharacters = (input: string, left: string = "{", right: string = "}"): string => { | ||
const processedInput = input.split(""); | ||
let numCaptured = 0; | ||
let i = 0; | ||
for (const char of processedInput) { | ||
if (char === "%") { | ||
if (numCaptured % 2 === 0) { | ||
processedInput[i] = left; | ||
} else { | ||
processedInput[i] = right; | ||
} | ||
numCaptured += 1; | ||
} | ||
i += 1; | ||
} | ||
return processedInput.join(""); | ||
}; | ||
#multiChannelProjectName = "multi-channel"; | ||
@@ -58,3 +41,3 @@ #getResources = async (projectReference: ExportReference["projectReference"]) => { | ||
* Transforms uncombined project resources into combined project resources. | ||
* @param resources Resources from original project. | ||
* @param {Resources} resources Resources object containing project data | ||
*/ | ||
@@ -65,3 +48,2 @@ #convertToCombinedResourceStructure = (resources: Resources): Resources => { | ||
} | ||
const conversion = Object.assign(resources, { | ||
@@ -71,3 +53,3 @@ intents: resources.intents.map((intent: Botmock.Intent) => { | ||
...intent, | ||
utterances: resources.project.locales.reduce((acc, locale) => { | ||
utterances: (resources.project.locales as string[]).reduce((acc, locale) => { | ||
return { | ||
@@ -83,17 +65,21 @@ ...acc, | ||
...resources.board.board, | ||
messages: resources.board.board.messages.map((message: Partial<Botmock.Message>) => { | ||
return { | ||
...message, | ||
payload: resources.project.locales.reduce((acc, locale) => { | ||
return { | ||
...acc, | ||
[locale]: { | ||
[resources.project.platform]: { | ||
blocks: [message.payload], | ||
messages: resources.board.board.messages | ||
.map((message: Partial<Botmock.Message>) => { | ||
return { | ||
...message, | ||
payload: (resources.project.locales as string[]).reduce((acc, locale) => { | ||
const unconnectedNextMessageIds = message.next_message_ids?.filter(next => !next.intent.value).map(next => next.message_id); | ||
const unconnectedMessages = unconnectedNextMessageIds?.map(id => (resources.board.board.messages as Botmock.Message[]).find(message => message.message_id === id)); | ||
const unconnectedPayloads = unconnectedMessages?.map(message => message?.payload); | ||
return { | ||
...acc, | ||
[locale]: { | ||
[resources.project.platform]: { | ||
blocks: [message.payload, ...(unconnectedPayloads ?? [])], | ||
} | ||
} | ||
} | ||
}; | ||
}, {}), | ||
}; | ||
}) | ||
}; | ||
}, {}), | ||
}; | ||
}) | ||
}, | ||
@@ -105,2 +91,95 @@ } | ||
/** | ||
* Replaces default "%" occurances with a left and right character sequence. | ||
* @param input Original string | ||
* @param left String to pad on the left side | ||
* @param right String to pad on the right side | ||
*/ | ||
protected replaceEntityCharacters = (input: string, left: string = "{", right: string = "}"): string => { | ||
const processedInput = input.split(""); | ||
let numCaptured = 0; | ||
let i = 0; | ||
for (const char of processedInput) { | ||
if (char === "%") { | ||
if (numCaptured % 2 === 0) { | ||
processedInput[i] = left; | ||
} else { | ||
processedInput[i] = right; | ||
} | ||
numCaptured += 1; | ||
} | ||
i += 1; | ||
} | ||
return processedInput.join(""); | ||
}; | ||
/** | ||
* Generates intent data if missing between root node and any connected message. | ||
* @param {Resources} resources Resources from the project | ||
*/ | ||
#generateMissingIntents = (resources: Resources): Resources => { | ||
const rootMessages = resources.board.board.root_messages; | ||
// determine if the board is missing an intent between the root node and any connected node | ||
// by iterating over next messages where the source is a root node | ||
const isMissingIntentFromRoot = !(resources.board.board.messages as Botmock.Message[]) | ||
.flatMap(message => ({ | ||
source: message.message_id, | ||
hasIntentOnConnector: message.next_message_ids.some(next => !!next.intent.value) | ||
})) | ||
.some(obj => rootMessages.includes(obj.source) && obj.hasIntentOnConnector); | ||
if (!isMissingIntentFromRoot) { | ||
return resources; | ||
} | ||
const generatedIntentId = `${v4()}_generated`; | ||
const generatedIntent: Botmock.Intent = { | ||
id: generatedIntentId, | ||
name: generatedIntentId, | ||
utterances: { | ||
en: [ | ||
{ text: "hello", variables: [] } | ||
] | ||
} as Botmock.Intent["utterances"], | ||
created_at: { | ||
date: new Date().toISOString(), | ||
timezone_type: 3, | ||
timezone: "UTC" | ||
}, | ||
updated_at: { | ||
date: new Date().toISOString(), | ||
timezone_type: 3, | ||
timezone: "UTC" | ||
}, | ||
slots: [], | ||
}; | ||
return { | ||
...resources, | ||
intents: resources.intents.concat(generatedIntent), | ||
board: { | ||
...resources.board, | ||
board: { | ||
messages: (resources.board.board.messages as Botmock.Message[]).map(message => { | ||
if (message.is_root) { | ||
return { | ||
...message, | ||
// add the generated intent in the case of the first next message | ||
next_message_ids: message.next_message_ids.map((next, i) => { | ||
if (i === 0) { | ||
return { | ||
...next, | ||
intent: { | ||
value: generatedIntentId, | ||
label: generatedIntentId, | ||
} | ||
}; | ||
} | ||
return next; | ||
}) | ||
}; | ||
} | ||
return message; | ||
}), | ||
} | ||
} | ||
}; | ||
}; | ||
/** | ||
* Abstract property for setting {@link dataTransformations} for specific directory paths. | ||
@@ -120,3 +199,3 @@ * | ||
* This means combining the results of all transforms over the project resources into a single object. | ||
* @param reference Reference to a specific project. | ||
* @param {ExportReference} reference Reference to a specific project | ||
* | ||
@@ -133,3 +212,2 @@ * @example | ||
} | ||
const data = {} as ObjectData<LowLevelAsset<any>, D>; | ||
@@ -140,2 +218,3 @@ | ||
resources = this.#convertToCombinedResourceStructure(resources); | ||
resources = this.#generateMissingIntents(resources); | ||
@@ -145,2 +224,4 @@ for (const transform of this.dataTransformations.entries()) { | ||
let transformation!: Promise<DataTransformation<any>> | DataTransformation<any>; | ||
// if this is a promise, resolve it | ||
if (typeof (transformFn as any).then === "function") { | ||
@@ -147,0 +228,0 @@ transformation = await transformFn(resources); |
@@ -1,2 +0,1 @@ | ||
import { notStrictEqual, strictEqual } from "assert"; | ||
import { v4 } from "uuid"; | ||
@@ -18,9 +17,9 @@ import BaseExporter from '../base-exporter'; | ||
export class DialogflowExporter<D> extends BaseExporter<D> { | ||
export class DialogflowExporter extends BaseExporter { | ||
#shouldUseFollowupIntents!: boolean; | ||
#intents!: Botmock.Intent[]; | ||
#blocks!: Botmock.Message[]; | ||
#shouldUseFollowupIntents!: boolean; | ||
// #contextMap = new Map<string, string[]>([]); | ||
#entityMap = new Map([ | ||
[Botmock.SystemEntity.ANY, Dialogflow.SystemEntity.ANY], | ||
[Botmock.SystemEntity.ANY, Dialogflow.SystemEntity.AGE], | ||
[Botmock.SystemEntity.COUNTRY, Dialogflow.SystemEntity.GEO_COUNTRY], | ||
@@ -54,2 +53,5 @@ [Botmock.SystemEntity.CITY, Dialogflow.SystemEntity.GEO_CITY], | ||
[Botmock.Component.text, Dialogflow.DataTypes.TEXT], | ||
[Botmock.Component.generic, Dialogflow.DataTypes.CARD], | ||
[Botmock.Component.button, Dialogflow.DataTypes.BUTTONS], | ||
[Botmock.Component.quick_replies, Dialogflow.DataTypes.BUTTONS], | ||
]) | ||
@@ -79,19 +81,20 @@ ], | ||
/** | ||
* Creates intent name from response block | ||
* | ||
* @param botmockMessage {@link Botmock.Message} Response block | ||
* Creates intent name from response block. | ||
* @param {Botmock.Message} botmockMessage Response block | ||
* @returns Name of connected intent | ||
*/ | ||
#createIntentName = (botmockMessage: Botmock.Message): string => { | ||
const intentConnnectedToBlock = this.#blocks | ||
const intentConnnectedToMessage = this.#blocks | ||
.flatMap(block => block.next_message_ids) | ||
.find(next => next.message_id === botmockMessage.message_id); | ||
notStrictEqual(intentConnnectedToBlock, undefined); | ||
const id = intentConnnectedToBlock?.intent.value; | ||
const name = this.#intents.find(intent => intent.id === id)?.name; | ||
const intentId = intentConnnectedToMessage?.intent.value; | ||
let name = this.#intents.find(intent => intent.id === intentId)?.name; | ||
if (name?.endsWith("_generated")) { | ||
name = "Default Welcome Intent"; | ||
} | ||
return name as string; | ||
}; | ||
/** | ||
* Yields name of intent connected to response block id until impossible | ||
* | ||
* Yields name of intent connected to response block id until impossible. | ||
* @param responseBlockId Initial response block id | ||
@@ -101,11 +104,15 @@ */ | ||
let blockId: string | void = responseBlockId; | ||
while (blockId) { | ||
const fullBlock = this.#blocks.find(block => block.message_id === blockId); | ||
const pathBackwardsIsDeterministic = Object.is(fullBlock?.previous_message_ids.length, 1); | ||
if (pathBackwardsIsDeterministic) { | ||
const parentBlock = this.#blocks.find(block => | ||
block.message_id === fullBlock?.previous_message_ids[0].message_id | ||
); | ||
const isUnambiguousBackwardPath = Object.is(fullBlock?.previous_message_ids.length, 1); | ||
if (isUnambiguousBackwardPath) { | ||
const parentBlock = this.#blocks.find(block => block.message_id === fullBlock?.previous_message_ids[0].message_id); | ||
if (parentBlock?.is_root) { | ||
break; | ||
} | ||
blockId = parentBlock?.message_id as string; | ||
const name = this.#createIntentName(fullBlock as Botmock.Message); | ||
const name = this.#createIntentName(parentBlock as Botmock.Message); | ||
const suffix = this.#shouldUseFollowupIntents ? "-followup" : ""; | ||
@@ -119,5 +126,4 @@ yield `${name}${suffix}`; | ||
/** | ||
* Maps nested responses to flat messages array | ||
* | ||
* @param blocks {@link Botmock.Responses} Responses per platform per language | ||
* Maps nested responses to flat messages array. | ||
* @param {Botmock.Responses} blocks Responses per platform per language | ||
*/ | ||
@@ -134,3 +140,2 @@ #mapResponsesToMessages = (responseData: Botmock.Responses): Dialogflow.Message[] => { | ||
} | ||
notStrictEqual(typeof responses, "string"); | ||
const messagesContainedInLang = Object | ||
@@ -143,10 +148,5 @@ .entries(responses) | ||
} | ||
const relevantTypesForPlatform = this.#typesForPlatform.get( | ||
Platform[platform] | ||
); | ||
notStrictEqual(relevantTypesForPlatform, undefined); | ||
const relevantTypesForPlatform = this.#typesForPlatform.get(Platform[platform]); | ||
const messagesContainedInResponse = blocks.map(block => { | ||
const type: Dialogflow.MessageType = relevantTypesForPlatform?.get( | ||
Botmock.Component[block.component_type] | ||
) ?? Dialogflow.DataTypes.CUSTOM; | ||
const type: Dialogflow.MessageType = relevantTypesForPlatform?.get(Botmock.Component[block.component_type]) ?? Dialogflow.DataTypes.CUSTOM; | ||
const object = { | ||
@@ -158,8 +158,2 @@ type, | ||
} as unknown as Dialogflow.Message; | ||
notStrictEqual(lang, undefined); | ||
try { | ||
notStrictEqual(type, Dialogflow.DataTypes.RCS_CARD); | ||
} catch { | ||
console.warn(`${type} unimplemented`); | ||
} | ||
switch (type) { | ||
@@ -177,5 +171,5 @@ case Dialogflow.DataTypes.TEXT: | ||
case Dialogflow.DataTypes.BUTTONS: | ||
object.replies = block.quick_replies?.map(quick => quick.title) as []; | ||
object.replies = block.quick_replies?.map(quick => quick.title.slice(0, 19)) as []; | ||
if (!object.replies) { | ||
object.replies = block.buttons?.map(button => button.title) as []; | ||
object.replies = block.buttons?.map(button => button.title.slice(0, 19)) as []; | ||
} | ||
@@ -187,3 +181,2 @@ break; | ||
case Dialogflow.DataTypes.CARD: | ||
strictEqual(block.elements?.length, 1); | ||
const [cardElement] = block.elements ?? []; | ||
@@ -224,3 +217,2 @@ object.title = cardElement.title; | ||
case Dialogflow.DataTypes.BASIC_CARD: | ||
strictEqual(block.elements?.length, 1); | ||
const [basicCardElement] = block.elements ?? []; | ||
@@ -287,2 +279,3 @@ object.title = basicCardElement.title; | ||
const matches = text.match(alphanumericRegexp); | ||
if (Object.is(matches, null)) { | ||
@@ -292,2 +285,3 @@ return text; | ||
let replacedText = text; | ||
for (const match of matches as string[]) { | ||
@@ -321,6 +315,6 @@ const variableNameInsideMatch = match.substr(1, match.length - 2); | ||
}; | ||
/** | ||
* Maps single botmock block to single dialogflow intent. | ||
* @param block {@link Botmock.Message} | ||
*/ | ||
/** | ||
* Maps single botmock message to single dialogflow intent. | ||
* @param {Botmock.Message} block Message object | ||
*/ | ||
#mapBlockToIntent = (block: Botmock.Message) => { | ||
@@ -331,9 +325,12 @@ const events: object[] = []; | ||
); | ||
if (typeof parentBlock !== "undefined" && parentBlock.is_root) { | ||
events.push({ name: Dialogflow.Event.WELCOME }); | ||
} | ||
const name = this.#createIntentName(block) ?? "Default Welcome Intent"; | ||
const name = this.#createIntentName(block); | ||
const generatedInputContexts = this.generateInputContexts(block.message_id); | ||
let contexts: string[] = []; | ||
let generatorState: IteratorResult<any>; | ||
while (generatorState = generatedInputContexts.next()) { | ||
@@ -349,4 +346,4 @@ const { value, done } = generatorState; | ||
let rootParentId: string | undefined; | ||
if (!block.is_root && this.#shouldUseFollowupIntents) { | ||
notStrictEqual(contexts.length, 0); | ||
rootParentId = contexts[0]; | ||
@@ -356,5 +353,53 @@ parentId = contexts.slice(-1)[0]; | ||
} | ||
const [intentConnectedToBlock] = this.#intents.filter(intent => | ||
name.includes(intent.name) | ||
); | ||
if (!name) { | ||
return { | ||
filenames: [], | ||
data: [] | ||
}; | ||
} | ||
const [intentConnectedToBlock] = this.#blocks | ||
.flatMap(b => | ||
b.next_message_ids | ||
.filter(next => !!next.intent.value && next.message_id === block.message_id) | ||
.map(next => { | ||
const intentId = next.intent.value; | ||
return this.#intents.find(intent => intent.id === intentId); | ||
}) | ||
); | ||
const outputContextOfIntentSettingThisInputContext = []; | ||
const outputContext = [ | ||
!parentBlock?.is_root | ||
? undefined | ||
: { | ||
name: "welcome", | ||
parameters: {}, | ||
lifespan: 5, | ||
}, | ||
...outputContextOfIntentSettingThisInputContext, | ||
...block.next_message_ids | ||
.reduce((acc: {}[], next) => { | ||
const immediatelyConnectedBlock = this.#blocks.find(block => block.message_id === next.message_id); | ||
const nextOfNext = this.#blocks.find(block => block.message_id === next.message_id)?.next_message_ids; | ||
const distantlyConnectedBlocksCreatingIntents = nextOfNext?.filter(next => !!next.intent.value) | ||
.map(next => this.#blocks.find(block => block.message_id === next.message_id)) ?? []; | ||
return [ | ||
...acc, | ||
...distantlyConnectedBlocksCreatingIntents.map(block => { | ||
return { | ||
name: this.#createIntentName(block as Botmock.Message), | ||
parameters: {}, | ||
lifespan: 5, | ||
}; | ||
}), | ||
{ | ||
name: this.#createIntentName(immediatelyConnectedBlock as Botmock.Message), | ||
parameters: {}, | ||
lifespan: 5, | ||
} | ||
]; | ||
}, []) | ||
].filter(context => typeof context !== "undefined"); | ||
return { | ||
@@ -372,23 +417,4 @@ filenames: [`${name}.json`, `${name}_usersays_en.json`], | ||
resetContexts: false, | ||
action: "input.welcome", | ||
affectedContexts: [ | ||
!parentBlock?.is_root | ||
? undefined | ||
: { | ||
name: "welcome", | ||
parameters: {}, | ||
lifespan: 5, | ||
}, | ||
...block.next_message_ids.map(next => { | ||
const connectedResponseBlock = this.#blocks.find(block => | ||
block.message_id === next.message_id | ||
); | ||
notStrictEqual(connectedResponseBlock, undefined); | ||
return { | ||
name: this.#createIntentName(connectedResponseBlock as Botmock.Message), | ||
parameters: {}, | ||
lifespan: 5, | ||
}; | ||
}) | ||
].filter(context => typeof context !== "undefined"), | ||
action: name, | ||
affectedContexts: outputContext, | ||
parameters: Object | ||
@@ -398,19 +424,20 @@ .values(intentConnectedToBlock?.utterances ?? {}) | ||
const entitiesInUtterances = utterances.flatMap(utterance => | ||
utterance.variables.map(variable => ({ | ||
id: variable.id, | ||
required: false, | ||
dataType: this.#entityMap.get(variable.entity as Botmock.SystemEntity), | ||
name: variable.name.replace(/\%/g, ""), | ||
value: `$${variable.default_value}`, | ||
promptMessages: [], | ||
noMatchPromptMessages: [], | ||
outputDialogContexts: [], | ||
isList: false, | ||
})) | ||
utterance.variables.map(variable => { | ||
return { | ||
id: variable.id, | ||
required: false, | ||
dataType: this.#entityMap.get(variable.entity as Botmock.SystemEntity), | ||
name: variable.name.replace(/\%/g, ""), | ||
value: `$${variable.default_value}`, | ||
promptMessages: [], | ||
noMatchPromptMessages: [], | ||
outputDialogContexts: [], | ||
isList: false, | ||
}; | ||
}) | ||
); | ||
return uniqueEntities.concat( | ||
entitiesInUtterances.filter(entity => | ||
return uniqueEntities | ||
.concat(entitiesInUtterances.filter(entity => | ||
!uniqueEntities.map(unique => unique.name).includes(entity.name) | ||
) as unknown as Dialogflow.Parameter[] | ||
); | ||
) as unknown as Dialogflow.Parameter[]); | ||
}, []), | ||
@@ -450,3 +477,28 @@ messages: this.#mapResponsesToMessages(block.payload ?? {}), | ||
...utterances.map(utterance => { | ||
const data = [{ text: this.#replaceVariableCharacterInText(utterance.text), userDefined: false }]; | ||
type Utterance = { text: string; userDefined: boolean; alias?: string; meta?: string; }[]; | ||
const replacedText = this.#replaceVariableCharacterInText(utterance.text); | ||
const data: Utterance = []; | ||
for (const word of replacedText.split(" ")) { | ||
if (word.startsWith("$")) { | ||
data.push({ | ||
text: word, | ||
userDefined: false, | ||
alias: word.slice(1), | ||
meta: this.#entityMap.get(utterance.variables[0].entity as Botmock.SystemEntity), | ||
}); | ||
} else { | ||
const lastElement = data[data.length - 1]; | ||
if (lastElement?.alias || !lastElement) { | ||
data.push({ | ||
text: `${word} `, | ||
userDefined: false, | ||
}); | ||
} else { | ||
data[data.length - 1].text += word; | ||
} | ||
} | ||
} | ||
return { | ||
@@ -460,18 +512,5 @@ id: v4(), | ||
}; | ||
}) | ||
}), | ||
]; | ||
}, [ | ||
{ | ||
"id": v4(), | ||
"data": [ | ||
{ | ||
"text": "hi", | ||
"userDefined": false | ||
} | ||
], | ||
"isTemplate": false, | ||
"count": 0, | ||
"updated": 0 | ||
} | ||
]) | ||
}, []) | ||
] | ||
@@ -481,5 +520,11 @@ }; | ||
#intentsTransformation = (resources: Resources): DataTransformation => { | ||
this.#intents = resources.intents; | ||
this.#blocks = resources.board.board.messages; | ||
this.#intents = resources.intents; | ||
return this.#blocks.filter((block: Botmock.Message) => !block.is_root).map(this.#mapBlockToIntent); | ||
return this.#blocks | ||
.filter(block => !block.is_root) | ||
.filter(block => { | ||
const nextMessages = this.#blocks.flatMap(b => b.next_message_ids.filter(next => !!next.intent.value)); | ||
return nextMessages.some(next => next.message_id === block.message_id); | ||
}) | ||
.map(this.#mapBlockToIntent); | ||
}; | ||
@@ -486,0 +531,0 @@ #entitiesTransformation = (resources: Resources): DataTransformation => { |
@@ -33,3 +33,3 @@ import Exporter from '../base-exporter'; | ||
} | ||
const nodeName = blocks.find(block => block.message_id === idOfBlockConnectedToIntent)?.node_name; | ||
const nodeName = blocks.find(block => block.message_id === idOfBlockConnectedToIntent)?.message_id; | ||
return { | ||
@@ -36,0 +36,0 @@ ...intentList, |
@@ -78,2 +78,3 @@ import { JSONResponse } from "@botmock/client"; | ||
debug?: boolean; | ||
// fallbackPlatformName?: Platform, | ||
} | ||
@@ -145,5 +146,2 @@ | ||
}; | ||
enum Lang { | ||
en = "en", | ||
} | ||
export interface Slot { | ||
@@ -158,3 +156,3 @@ id: string; | ||
name: string; | ||
utterances: KeyDependent<Utterance[], Lang>; | ||
utterances: KeyDependent<Utterance[], string>; | ||
created_at: DateObj; | ||
@@ -212,15 +210,16 @@ updated_at: DateObj; | ||
} | ||
export interface Next { | ||
message_id: string; | ||
action: { | ||
type: string; | ||
title: string; | ||
payload: string; | ||
}; | ||
intent: { label: string; value: string; }; | ||
conditional: boolean; | ||
} | ||
export interface Message { | ||
message_id: string; | ||
message_type: string; | ||
next_message_ids: { | ||
message_id: string; | ||
action: { | ||
type: string; | ||
title: string; | ||
payload: string; | ||
}; | ||
intent: { label: string; value: string; }; | ||
conditional: boolean; | ||
}[]; | ||
next_message_ids: Next[]; | ||
previous_message_ids: { | ||
@@ -227,0 +226,0 @@ message_id: string; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
345803
6974