1
1
mirror of https://github.com/leon-ai/leon.git synced 2024-12-25 17:54:43 +03:00

feat(server): introduce basic concept of action loop

This commit is contained in:
louistiti 2022-05-04 22:52:05 +08:00
parent 7a9db1363d
commit c5b3840082
No known key found for this signature in database
GPG Key ID: 7ECA3DD523793FE6
4 changed files with 68 additions and 31 deletions

View File

@ -9,6 +9,7 @@ const defaultActiveContext = {
currentEntities: [],
entities: [],
slots: { },
isInActionLoop: false,
nextAction: null,
originalUtterance: null,
activatedAt: 0
@ -50,6 +51,7 @@ class Conversation {
set activeContext (contextObj) {
const {
slots,
isInActionLoop,
nluDataFilePath,
actionName,
lang,
@ -81,6 +83,7 @@ class Conversation {
currentEntities: [],
entities: [],
slots: { },
isInActionLoop,
nextAction,
originalUtterance: contextObj.originalUtterance,
activatedAt: Date.now()
@ -112,6 +115,7 @@ class Conversation {
currentEntities: entities,
entities,
slots: { },
isInActionLoop,
nextAction: null,
originalUtterance: contextObj.originalUtterance,
activatedAt: Date.now()

View File

@ -92,7 +92,7 @@ class Nlu {
* TODO: split this method into several methods
*/
process (utterance, opts) {
console.log('this.conv.activeContext', this.conv.activeContext)
console.log('process() start this.conv.activeContext', this.conv.activeContext)
const processingTimeStart = Date.now()
return new Promise(async (resolve, reject) => {
@ -133,34 +133,66 @@ class Nlu {
})
}
// TODO: make difference between context that needs slots and the ones who does not
// TODO: this case is only for slots context
// TODO: an action requiring slots must always have a next_action
console.log('THIS.CONV', this.conv.activeContext)
// Pre NLU processing according to the active context if there is one
if (this.conv.hasActiveContext()) {
const processedData = await this.slotFill(utterance, opts)
console.log('processedData (slot filled over)', processedData)
if (processedData && Object.keys(processedData).length > 0) {
processedData.nextAction = 'guess'
// Set new context with the next action if there is one
if (processedData.nextAction) {
this.conv.activeContext = {
lang: this.brain.lang,
slots: { },
originalUtterance: processedData.utterance,
nluDataFilePath: processedData.nluDataFilePath,
actionName: processedData.nextAction,
domain: processedData.classification.domain,
intent: `${processedData.classification.skill}.${processedData.nextAction}`,
entities: []
// When the active context is in an action loop, then directly trigger the action
if (this.conv.activeContext.isInActionLoop) {
const { domain, intent } = this.conv.activeContext
const [skillName, actionName] = intent.split('.')
const nluDataFilePath = join(process.cwd(), 'skills', domain, skillName, `nlu/${this.brain.lang}.json`)
this.nluResultObj = {
...this.nluResultObj,
slots: this.conv.activeContext.slots,
utterance,
nluDataFilePath,
classification: {
domain,
skill: skillName,
action: actionName,
confidence: 1
}
console.log('NEW ACTIVE CONTEXT', this.conv.activeContext)
}
this.nluResultObj.entities = await this.ner.extractEntities(
this.brain.lang,
nluDataFilePath,
this.nluResultObj
)
const processedData = await this.brain.execute(this.nluResultObj, { mute: opts.mute })
return resolve(processedData)
}
return resolve(processedData)
// TODO: make difference between context that needs slots and the ones who does not
// TODO: this case is only for slots context
// TODO: an action requiring slots must always have a next_action
console.log('THIS.CONV', this.conv.activeContext)
// When the active context has slots filled
if (Object.keys(this.conv.activeContext.slots).length > 0) {
const processedData = await this.slotFill(utterance, opts)
console.log('processedData (slot filled over)', processedData)
if (processedData && Object.keys(processedData).length > 0) {
processedData.nextAction = 'guess'
// Set new context with the next action if there is one
if (processedData.nextAction) {
this.conv.activeContext = {
lang: this.brain.lang,
slots: { },
isInActionLoop: true, // TODO: dynamic value according to the skill output
originalUtterance: processedData.utterance,
nluDataFilePath: processedData.nluDataFilePath,
actionName: processedData.nextAction,
domain: processedData.classification.domain,
intent: `${processedData.classification.skill}.${processedData.nextAction}`,
entities: []
}
console.log('NEW ACTIVE CONTEXT', this.conv.activeContext)
}
}
return resolve(processedData)
}
}
const result = await this.nlp.process(utterance)
@ -302,8 +334,8 @@ class Nlu {
}
}
const shouldLoop = await this.routeSlotFilling(intent)
if (shouldLoop) {
const shouldSlotLoop = await this.routeSlotFilling(intent)
if (shouldSlotLoop) {
return resolve({ })
}

View File

@ -4,7 +4,9 @@
"skill": "is_it_down",
"action": "run",
"utterance": "Check if github.com, mozilla.org and twitter.com are up",
"entities": [
"slots": {},
"entities": [],
"current_entities": [
{
"sourceText": "github.com",
"utteranceText": "github.com",

View File

@ -11,6 +11,7 @@ def guess(params):
nb_to_guess = 42 # TODO: pick up from DB
# Find entities
# TODO: if no number entity found, then break the action loop
for item in params['entities']:
if item['entity'] == 'number':
given_nb = item['resolution']['value']
@ -18,8 +19,6 @@ def guess(params):
if given_nb == nb_to_guess:
return utils.output('end', 'guessed', '....CONGRATS....')
if nb_to_guess < given_nb:
# TODO: enable loop
return utils.output('end', 'smaller', utils.translate('smaller')
return utils.output('end', 'smaller', utils.translate('smaller'))
if nb_to_guess > given_nb:
# TODO: enable loop
return utils.output('end', 'bigger', utils.translate('bigger')
return utils.output('end', 'bigger', utils.translate('bigger'))