1
1
mirror of https://github.com/leon-ai/leon.git synced 2024-12-28 11:13:14 +03:00

refactor: stop crash on brain + new skills DB calls

This commit is contained in:
louistiti 2022-02-20 19:25:08 +08:00
parent 7977d55b81
commit 98a0382103
No known key found for this signature in database
GPG Key ID: 0A1C3B043E70C77D
16 changed files with 163 additions and 147 deletions

View File

@ -12,6 +12,7 @@ def main():
path.append('.')
intent_obj = utils.get_intent_obj()
skill = import_module('skills.' + intent_obj['domain'] + '.' + intent_obj['skill'] + '.src.actions.' + intent_obj['action'])
return getattr(skill, intent_obj['action'])(intent_obj['utterance'], intent_obj['entities'])

View File

@ -136,7 +136,7 @@
{
"type": "between",
"from": ["coche", "complète", "complete"],
"to": ["de", "de", "de"]
"to": ["de"]
}
]
},
@ -167,7 +167,7 @@
{
"type": "between",
"from": ["décoche", "decoche", "invalide", "remet"],
"to": ["de", "de", "de", "sur"]
"to": ["de", "sur"]
}
]
},

View File

@ -30,6 +30,7 @@ export default () => new Promise(async (resolve, reject) => {
nluManager.settings.log = false
nluManager.settings.trainByDomain = true
nlp.settings.forceNER = true // https://github.com/axa-group/nlp.js/blob/master/examples/17-ner-nlg/index.js
nlp.settings.calculateSentiment = true
nlp.settings.modelFileName = modelFileName
nlp.settings.threshold = 0.8

View File

@ -70,7 +70,9 @@ class Brain {
*/
static deleteIntentObjFile (intentObjectPath) {
try {
fs.unlinkSync(intentObjectPath)
if (fs.existsSync(intentObjectPath)) {
fs.unlinkSync(intentObjectPath)
}
} catch (e) {
log.error(`Failed to delete intent object file: ${e}`)
}
@ -234,6 +236,7 @@ class Brain {
Brain.deleteIntentObjFile(intentObjectPath)
log.title(`${skillFriendlyName} skill`)
log.error(data.toString())
const executionTimeEnd = Date.now()
const executionTime = executionTimeEnd - executionTimeStart

View File

@ -175,7 +175,10 @@ server.handleOnConnection = (socket) => {
log.info(`${data.client} emitted: ${data.value}`)
socket.emit('is-typing', true)
await nlu.process(data.value)
try {
await nlu.process(data.value)
} catch (e) { /* */ }
})
// Handle automatic speech recognition

View File

@ -3,19 +3,14 @@
* @nlpjs/core-loader can make use of file system
* https://github.com/axa-group/nlp.js/issues/766#issuecomment-750315909
*/
import { containerBootstrap } from '@nlpjs/core-loader'
import { Ner as NerManager } from '@nlpjs/ner'
import { BuiltinMicrosoft } from '@nlpjs/builtin-microsoft'
import fs from 'fs'
import log from '@/helpers/log'
import string from '@/helpers/string'
class Ner {
constructor () {
this.container = containerBootstrap()
this.container.register('extract-builtin-??', new BuiltinMicrosoft(), true)
this.ner = new NerManager({ container: this.container })
constructor (ner) {
this.ner = ner
log.title('NER')
log.success('New instance')
@ -86,16 +81,14 @@ class Ner {
if (condition.type === 'between') {
// e.g. list.addBetweenCondition('en', 'list', 'create a', 'list')
if (Array.isArray(condition.from) && Array.isArray(condition.to)) {
const { from, to } = condition
from.forEach((word, index) => {
this.ner[conditionMethod](lang, entity.name, word, to[index])
})
} else {
this.ner[conditionMethod](lang, entity.name, condition.from, condition.to)
}
this.ner[conditionMethod](lang, entity.name, condition.from, condition.to)
} else if (condition.type.indexOf('after') !== -1) {
const rule = {
type: 'afterLast',
words: condition.from,
options: { }
}
this.ner.addRule(lang, entity.name, 'trim', rule)
this.ner[conditionMethod](lang, entity.name, condition.from)
} else if (condition.type.indexOf('before') !== -1) {
this.ner[conditionMethod](lang, entity.name, condition.to)

View File

@ -1,5 +1,6 @@
import { containerBootstrap } from '@nlpjs/core-loader'
import { Nlp } from '@nlpjs/nlp'
import { BuiltinMicrosoft } from '@nlpjs/builtin-microsoft'
import { LangAll } from '@nlpjs/lang-all'
import request from 'superagent'
import fs from 'fs'
@ -17,7 +18,7 @@ class Nlu {
this.brain = brain
this.request = request
this.nlp = { }
this.ner = new Ner()
this.ner = { }
log.title('NLU')
log.success('New instance')
@ -37,6 +38,7 @@ class Nlu {
try {
const container = await containerBootstrap()
container.register('extract-builtin-??', new BuiltinMicrosoft(), true)
container.use(Nlp)
container.use(LangAll)
@ -45,8 +47,9 @@ class Nlu {
nluManager.settings.spellCheck = true
await this.nlp.load(nlpModel)
log.success('NLP model loaded')
this.ner = new Ner(this.nlp.ner)
resolve()
} catch (err) {
this.brain.talk(`${this.brain.wernicke('random_errors')}! ${this.brain.wernicke('errors', 'nlu', { '%error%': err.message })}.`)
@ -148,7 +151,7 @@ class Nlu {
}
log.title('NLU')
log.success('Intent found')
log.success(`Intent found: ${obj.classification.skill}.${obj.classification.action} (domain: ${obj.classification.domain})`)
try {
obj.entities = await this.ner.extractEntities(
@ -157,8 +160,9 @@ class Nlu {
obj
)
} catch (e) /* istanbul ignore next */ {
console.error(e)
log[e.type](e.obj.message)
if (log[e.type]) {
log[e.type](e.obj.message)
}
if (!opts.mute) {
this.brain.talk(`${this.brain.wernicke(e.code, '', e.data)}!`)
@ -177,7 +181,6 @@ class Nlu {
nluProcessingTime: processingTime - data?.executionTime // In ms, NLU processing time only
})
} catch (e) /* istanbul ignore next */ {
console.error(e)
log[e.type](e.obj.message)
if (!opts.mute) {

View File

@ -21,7 +21,7 @@
{
"type": "between",
"from": ["the", "a", "an", "my"],
"to": ["list", "list", "list", "list"]
"to": ["list"]
}
]
}
@ -59,7 +59,7 @@
{
"type": "between",
"from": ["the", "my"],
"to": ["list", "list"]
"to": ["list"]
}
]
}
@ -67,8 +67,12 @@
},
"rename_list": {
"utterance_samples": [
"Rename the x list to y",
"Rename my x list to y"
"Rename the shopping list to purchases",
"Rename my material list to purchases",
"Can you rename the food list into groceries?",
"Change the stuff list to food",
"Modify my reminder list to do not forget",
"Replace my food list by shopping"
],
"entities": [
{
@ -78,7 +82,7 @@
{
"type": "between",
"from": ["the", "my"],
"to": ["list", "list"]
"to": ["list"]
}
]
},
@ -87,8 +91,8 @@
"name": "new_list",
"conditions": [
{
"type": "after",
"from": "to"
"type": "after_last",
"from": ["to", "by", "with"]
}
]
}
@ -96,8 +100,12 @@
},
"delete_list": {
"utterance_samples": [
"Delete the x list",
"Delete my x list"
"Delete the shopping list",
"Delete my material list",
"Can you remove the food list?",
"Remove the stuff list",
"I don't want the reminder list anymore",
"Cancel my groceries list"
],
"entities": [
{
@ -107,7 +115,7 @@
{
"type": "between",
"from": ["the", "my"],
"to": ["list", "list"]
"to": ["list"]
}
]
}
@ -115,8 +123,10 @@
},
"add_todos": {
"utterance_samples": [
"Add x to the list x",
"Add x to my list x"
"Add potatoes to the shopping list",
"Add bananas to my groceries list",
"Append cleaning to the reminder list",
"Can you add meat to my food list?"
],
"entities": [
{
@ -125,8 +135,8 @@
"conditions": [
{
"type": "between",
"from": "add",
"to": "to"
"from": ["add", "append"],
"to": ["to"]
}
]
},
@ -137,7 +147,7 @@
{
"type": "between",
"from": ["the", "my"],
"to": ["list", "list"]
"to": ["list"]
}
]
}
@ -158,7 +168,7 @@
{
"type": "between",
"from": ["check", "complete", "tick"],
"to": ["from", "from", "from"]
"to": ["from"]
}
]
},
@ -169,7 +179,7 @@
{
"type": "between",
"from": ["the", "my"],
"to": ["list", "list"]
"to": ["list"]
}
]
}
@ -189,7 +199,7 @@
{
"type": "between",
"from": ["uncheck", "untick"],
"to": ["from", "from"]
"to": ["from"]
}
]
},
@ -200,7 +210,7 @@
{
"type": "between",
"from": ["the", "my"],
"to": ["list", "list"]
"to": ["list"]
}
]
}

View File

@ -4,22 +4,13 @@
from time import time
import utils
from ..lib.db import db_create_list
# Skill database
db = utils.db()['db']
# Todo lists table
db_lists = db.table('todo_lists')
# Query
Query = utils.db()['query']()
from ..lib import db
def add_todos(string, entities):
"""Add todos to a to-do list"""
# List name
listname = ''
list_name = ''
# Todos
todos = []
@ -27,13 +18,13 @@ def add_todos(string, entities):
# Find entities
for item in entities:
if item['entity'] == 'list':
listname = item['sourceText'].lower()
list_name = item['sourceText'].lower()
elif item['entity'] == 'todos':
# Split todos into array and trim start/end-whitespaces
todos = [chunk.strip() for chunk in item['sourceText'].lower().split(',')]
# Verify if a list name has been provided
if not listname:
if not list_name:
return utils.output('end', 'list_not_provided', utils.translate('list_not_provided'))
# Verify todos have been provided
@ -41,17 +32,17 @@ def add_todos(string, entities):
return utils.output('end', 'todos_not_provided', utils.translate('todos_not_provided'))
# Verify the list exists
if db_lists.count(Query.name == listname) == 0:
if db.has_list(list_name) == False:
# Create the new to-do list
db_create_list(listname)
db.create_list(list_name)
result = ''
for todo in todos:
# Add to-do to DB
db_create_todo(listname, todo)
db.create_todo(list_name, todo)
result += utils.translate('list_todo_element', { 'todo': todo })
return utils.output('end', 'todos_added', utils.translate('todos_added', {
'list': listname,
'list': list_name,
'result': result
}))

View File

@ -21,7 +21,7 @@ def complete_todos(string, entities):
"""Complete todos"""
# List name
listname = ''
list_name = ''
# Todos
todos = []
@ -29,13 +29,13 @@ def complete_todos(string, entities):
# Find entities
for item in entities:
if item['entity'] == 'list':
listname = item['sourceText'].lower()
list_name = item['sourceText'].lower()
elif item['entity'] == 'todos':
# Split todos into array and trim start/end-whitespaces
todos = [chunk.strip() for chunk in item['sourceText'].lower().split(',')]
# Verify if a list name has been provided
if not listname:
if not list_name:
return utils.output('end', 'list_not_provided', utils.translate('list_not_provided'))
# Verify todos have been provided
@ -43,23 +43,24 @@ def complete_todos(string, entities):
return utils.output('end', 'todos_not_provided', utils.translate('todos_not_provided'))
# Verify the list exists
if db_lists.count(Query.name == listname) == 0:
if db_lists.count(Query.name == list_name) == 0:
# Create the new to-do list
db_create_list(listname)
db_create_list(db_lists, {
'list_name': list_name
})
result = ''
for todo in todos:
for db_todo in db_todos.search(Query.list == listname):
for db_todo in db_todos.search(Query.list == list_name):
# Rough matching (e.g. 1kg of rice = rice)
if db_todo['name'].find(todo) != -1:
db_todos.update({
'is_completed': True,
'updated_at': timestamp
}, (Query.list == listname) & (Query.name == db_todo['name']))
'is_completed': True
}, (Query.list == list_name) & (Query.name == db_todo['name']))
result += utils.translate('list_completed_todo_element', { 'todo': db_todo['name'] })
return utils.output('end', 'todos_completed', utils.translate('todos_completed', {
'list': listname,
'list': list_name,
'result': result
}))

View File

@ -4,19 +4,7 @@
from time import time
import utils
from ..lib.db import db_create_list
# Skill database
db = utils.db()['db']
# Todo lists table
db_lists = db.table('todo_lists')
# Query
Query = utils.db()['query']()
# Time stamp
timestamp = int(time())
from ..lib import db
def create_list(string, entities):
"""Create a to-do list"""
@ -34,12 +22,9 @@ def create_list(string, entities):
return utils.output('end', 'list_not_provided', utils.translate('list_not_provided'))
# Verify if list already exists or not
if db_lists.count(Query.name == list_name) > 0:
if db.has_list(list_name):
return utils.output('end', 'list_already_exists', utils.translate('list_already_exists', { 'list': list_name }))
db_create_list(db_lists, {
'list_name': list_name,
'timestamp': timestamp
})
db.create_list(list_name)
return utils.output('end', 'list_created', utils.translate('list_created', { 'list': list_name }))

View File

@ -4,59 +4,42 @@
from time import time
import utils
from ..lib.db import db_create_list
# Skill database
db = utils.db()['db']
# Todo lists table
db_lists = db.table('todo_lists')
# Todos of the module table
db_todos = db.table('todo_todos')
# Query
Query = utils.db()['query']()
from ..lib import db
def rename_list(string, entities):
"""Rename a to-do list"""
# Old list name
old_listname = ''
old_list_name = ''
# New list name
new_listname = ''
new_list_name = ''
# Find entities
for item in entities:
if item['entity'] == 'old_list':
old_listname = item['sourceText'].lower()
old_list_name = item['sourceText'].lower()
elif item['entity'] == 'new_list':
new_listname = item['sourceText'].lower()
new_list_name = item['sourceText'].lower()
# Verify if an old and new list name have been provided
if not old_listname or not new_listname:
if not old_list_name or not new_list_name:
return utils.output('end', 'new_or_old_list_not_provided', utils.translate('new_or_old_list_not_provided'))
# Verify if the old list exists
if db_lists.count(Query.name == old_listname) == 0:
return utils.output('end', 'list_does_not_exist', utils.translate('list_does_not_exist', { 'list': old_listname }))
if db.has_list(old_list_name) == False:
return utils.output('end', 'list_does_not_exist', utils.translate('list_does_not_exist', { 'list': old_list_name }))
# Verify if the new list name already exists
if db_lists.count(Query.name == new_listname) > 0:
return utils.output('end', 'list_already_exists', utils.translate('list_already_exists', { 'list': new_listname }))
if db.has_list(new_list_name):
return utils.output('end', 'list_already_exists', utils.translate('list_already_exists', { 'list': new_list_name }))
# Rename the to-do list
db_lists.update({
'name': new_listname,
'updated_at': int(time())
}, Query.name == old_listname)
db.update_list_name(old_list_name, new_list_name)
# Rename the list name of the todos
db_todos.update({
'list': new_listname,
'updated_at': int(time())
}, Query.list == old_listname)
db.update_todo_list_name(old_list_name, new_list_name)
return utils.output('end', 'list_renamed', utils.translate('list_renamed', {
'old_list': old_listname,
'new_list': new_listname
'old_list': old_list_name,
'new_list': new_list_name
}))

View File

@ -52,8 +52,7 @@ def uncheck_todos(string, entities):
# Rough matching (e.g. 1kg of rice = rice)
if db_todo['name'].find(todo) != -1:
db_todos.update({
'is_completed': False,
'updated_at': timestamp
'is_completed': False
}, (Query.list == listname) & (Query.name == db_todo['name']))
result += utils.translate('list_todo_element', { 'todo': db_todo['name'] })

View File

@ -4,24 +4,13 @@
from time import time
import utils
from ..lib.db import db_create_list
# Skill database
db = utils.db()['db']
# Todo lists table
db_lists = db.table('todo_lists')
# Todos of the module table
db_todos = db.table('todo_todos')
# Query
Query = utils.db()['query']()
from ..lib import db
def view_lists(string, entities):
"""View to-do lists"""
# Lists number
lists_nb = len(db_lists)
lists_nb = db.count_lists()
# Verify if a list exists
if lists_nb == 0:
@ -29,10 +18,10 @@ def view_lists(string, entities):
result = ''
# Fill end-result
for list_element in db_lists:
for list_element in db.get_lists():
result += utils.translate('list_list_element', {
'list': list_element['name'],
'todos_nb': db_todos.count(Query.list == list_element['name'])
'todos_nb': db.count_todos( list_element['name'])
})
return utils.output('end', 'lists_listed', utils.translate('lists_listed', {

View File

@ -1,19 +1,73 @@
def db_create_list(db_lists, data):
from time import time
import utils
# Skill database
db = utils.db()['db']
# Todo lists table
db_lists = db.table('todo_lists')
# Todos of the module table
db_todos = db.table('todo_todos')
# Query
Query = utils.db()['query']()
# Time stamp
timestamp = int(time())
def create_list(list_name):
"""Create list in DB"""
db_lists.insert({
'name': data['list_name'],
'created_at': data['timestamp'],
'updated_at': data['timestamp']
'name': list_name,
'created_at': timestamp,
'updated_at': timestamp
})
def db_create_todo(db_todos, data):
def get_lists():
"""Get lists"""
return db_lists
def update_list_name(old_list_name, new_list_name):
"""Update list name in DB"""
db_lists.update({
'name': new_list_name,
'updated_at': timestamp
}, Query.name == old_list_name)
def count_lists():
"""Count number of lists"""
return len(db_lists)
def has_list(list_name):
"""Check if the list already exist"""
return db_lists.count(Query.name == list_name) > 0
def create_todo(list_name, todo_name):
"""Create to-todo in list DB table"""
db_todos.insert({
'list': data['list_name'],
'name': data['todo_name'],
'list': list_name,
'name': todo_name,
'is_completed': False,
'created_at': data['timestamp'],
'updated_at': data['timestamp']
'created_at': timestamp,
'updated_at': timestamp
})
def update_todo_list_name(old_list_name, new_list_name):
"""Update todo list name in DB"""
db_lists.update({
'list': new_list_name,
'updated_at': timestamp
}, Query.name == old_list_name)
def count_todos(list_name):
"""Count number of todos within a list"""
return db_todos.count(Query.list == list_name)