1
1
mirror of https://github.com/leon-ai/leon.git synced 2024-11-27 16:16:48 +03:00

feat: annotate entities on the fly + prepare for dialog skill type and cross-domains data

This commit is contained in:
louistiti 2022-02-22 22:31:06 +08:00
parent cf6340b3ca
commit 4107932d00
No known key found for this signature in database
GPG Key ID: 0A1C3B043E70C77D
17 changed files with 92 additions and 73 deletions

2
.gitignore vendored
View File

@ -25,6 +25,6 @@ packages/**/config/config.json
skills/**/src/config.json
packages/**/data/db/*.json
skills/**/memory/*.json
server/src/data/leon-model.nlp
core/data/leon-model.nlp
package.json.backup
.python-version

View File

@ -0,0 +1 @@
{"lang":"en","domain":"leon","skill":"random_number","action":"run","utterance":"Give me a random number","entities":[]}

View File

@ -1 +0,0 @@
{"lang":"en","package":"leon","module":"randomnumber","action":"run","utterance":"Give me a random number","entities":[]}

View File

@ -22,7 +22,7 @@ export default () => new Promise(async (resolve, reject) => {
const googleCloudPath = 'server/src/config/voice/google-cloud.json'
const watsonSttPath = 'server/src/config/voice/watson-stt.json'
const watsonTtsPath = 'server/src/config/voice/watson-tts.json'
const nlpModelPath = 'server/src/data/leon-model.nlp'
const nlpModelPath = 'core/data/leon-model.nlp'
const report = {
can_run: { title: 'Run', type: 'error', v: true },
can_run_module: { title: 'Run modules', type: 'error', v: true },

View File

@ -17,7 +17,7 @@ dotenv.config()
* npm run train [en or fr]
*/
export default () => new Promise(async (resolve, reject) => {
const modelFileName = 'server/src/data/leon-model.nlp'
const modelFileName = 'core/data/leon-model.nlp'
try {
const container = await containerBootstrap()
@ -58,19 +58,31 @@ export default () => new Promise(async (resolve, reject) => {
const nluFilePath = path.join(currentSkill.path, 'nlu', `${lang}.json`)
if (fs.existsSync(nluFilePath)) {
const { actions } = JSON.parse(fs.readFileSync(nluFilePath, 'utf8'))
const { actions, entities } = JSON.parse(fs.readFileSync(nluFilePath, 'utf8'))
const actionsKeys = Object.keys(actions)
for (let k = 0; k < actionsKeys.length; k += 1) {
const actionName = actionsKeys[k]
const actionObj = actions[actionName]
const { utterance_samples: utteranceSamples } = actionObj
const { utterance_samples: utteranceSamples, answers } = actionObj
nlp.assignDomain(lang, `${skillName}.${actionName}`, currentDomain.name)
for (let l = 0; l < utteranceSamples.length; l += 1) {
nlp.addDocument(lang, utteranceSamples[l], `${skillName}.${actionName}`)
}
// Train NLG if the skill has a dialog type
if (currentSkill.type === 'dialog') {
for (let l = 0; l < answers?.length; l += 1) {
nlp.addAnswer(lang, `${skillName}.${actionName}`, answers[l])
}
}
// Add entities annotations (@...)
if (entities) {
nlp.addEntities(entities, lang)
}
}
}
}

View File

@ -12,7 +12,7 @@ import domain from '@/helpers/domain'
class Brain {
constructor () {
this._lang = 'en'
this.broca = JSON.parse(fs.readFileSync(`${__dirname}/../data/${this._lang}.json`, 'utf8'))
this.broca = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'core/data', this._lang, 'answers.json'), 'utf8'))
this.process = { }
this.interOutput = { }
this.finalOutput = { }
@ -55,7 +55,7 @@ class Brain {
set lang (newLang) {
this._lang = newLang
// Update broca
this.broca = JSON.parse(fs.readFileSync(`${__dirname}/../data/${this._lang}.json`, 'utf8'))
this.broca = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'core/data', this._lang, 'answers.json'), 'utf8'))
if (process.env.LEON_TTS === 'true') {
this._tts.init(this._lang, () => {

View File

@ -285,7 +285,7 @@ server.init = async () => {
// Load NLP model
try {
await nlu.loadModel(join(__dirname, '../../data/leon-model.nlp'))
await nlu.loadModel(join(process.cwd(), 'core/data/leon-model.nlp'))
} catch (e) {
log[e.type](e.obj.message)
}

View File

@ -19,10 +19,11 @@ domain.getDomainsObj = async () => {
const skillPath = path.join(domainPath, skillFolders[i])
if (fs.statSync(skillPath).isDirectory()) {
const { name: skillName } = JSON.parse(fs.readFileSync(path.join(skillPath, 'skill.json'), 'utf8'))
const { name: skillName, type: skillType } = JSON.parse(fs.readFileSync(path.join(skillPath, 'skill.json'), 'utf8'))
skillObj[skillName] = {
name: skillFolders[i],
type: skillType,
path: skillPath
}
}

View File

@ -7,21 +7,20 @@
"Make me laugh",
"Do you have jokes to tell me?",
"I wanna laugh"
],
"answers": [
"My email password has been hacked. That's the third time I've had to rename the cat.",
"What does a baby computer call it's father? Data.",
"My New Year's resolution is 4K.",
"Any room is a panic room if you've lost your phone in it.",
"Why was the JavaScript developer sad? Because he didn't Node how to Express himself.",
"Why did the developer go broke? Because he used up all his cache.",
"There are 10 types of people in the world: those who understand binary, and those who don't.",
"Instagram is just Twitter for people who go outside.",
"Human: What do we want?! Computer: Natural language processing! Human: When do we want it?! Computer: When do we want what?",
"Is your name Wi-Fi? Because I'm feeling a connection."
]
}
},
"answers": {
"jokes": [
"My email password has been hacked. That's the third time I've had to rename the cat.",
"What does a baby computer call it's father? Data.",
"My New Year's resolution is 4K.",
"Any room is a panic room if you've lost your phone in it.",
"Why was the JavaScript developer sad? Because he didn't Node how to Express himself.",
"Why did the developer go broke? Because he used up all his cache.",
"There are 10 types of people in the world: those who understand binary, and those who don't.",
"Instagram is just Twitter for people who go outside.",
"Human: What do we want?! Computer: Natural language processing! Human: When do we want it?! Computer: When do we want what?",
"Is your name Wi-Fi? Because I'm feeling a connection."
]
}
"answers": { }
}

View File

@ -7,27 +7,26 @@
"Donne-moi une blague",
"Je veux rire",
"As-tu des blagues à raconter ?"
],
"answers": [
"Le mot de passe de ma boîte de réception a été piraté. C'est la troisième fois que je dois renommer le chat.",
"Combien de développeurs faut-t-il pour remplacer une ampoule grillée ? Aucun, c'est un problème hardware.",
"T'as pris quoi comme résolution pour cette nouvelle année ? La 4K.",
"Toute pièce est une salle de panique si vous avez perdu votre téléphone à l'intérieur.",
"C'est l'histoire d'un administrateur qui configure ses variables d'environnement, et là... PATH le chemin !",
"Tu sais pourquoi l'iPhone 6 se plie ? Parce que l'Apple Store.",
"Dans le monde, il y a 10 catégories de personnes : celles qui connaissent le binaire et celles qui ne le connaissent pas.",
"Instagram c'est en fait Twitter pour les gens qui sortent un peu.",
"Un humain demande : qu'est-ce que tu veux ?! Un ordinateur répond : du traitement automatique du langage naturel ! L'humain : quand le voulons-nous ?! L'ordinateur : quand le voulons quoi ?",
"Est-ce que votre nom est Wi-Fi ? Parce que je sens une connexion.",
"Quand quelqu'un de triste joue aux jeux vidéo pour oublier, on peut dire qu'il se console.",
"Quel Pokemon a une mitraillette ? Ratatatatatatatatata.",
"Les filles c'est comme les noms de domaine. Celles que j'aime sont déjà prises.",
"Que dit une mère à son fils geek quand le diner est servi ? Alt Tab !",
"Quelle est la meilleure heure pour écouter de la musique ? Deezer.",
"De nos jours, le zip ça devient rar..."
]
}
},
"answers": {
"jokes": [
"Le mot de passe de ma boîte de réception a été piraté. C'est la troisième fois que je dois renommer le chat.",
"Combien de développeurs faut-t-il pour remplacer une ampoule grillée ? Aucun, c'est un problème hardware.",
"T'as pris quoi comme résolution pour cette nouvelle année ? 4K.",
"Toute pièce est une salle de panique si vous avez perdu votre téléphone à l'intérieur.",
"C'est l'histoire d'un administrateur qui configure ses variables d'environnement, et là... PATH le chemin !",
"Tu sais pourquoi l'iPhone 6 se plie ? Parce que l'Apple Store.",
"Dans le monde, il y a 10 catégories de personnes : celles qui connaissent le binaire et celles qui ne le connaissent pas.",
"Instagram c'est en fait Twitter pour les gens qui sortent un peu.",
"Un humain demande : qu'est-ce que tu veux ?! Un ordinateur répond : du traitement automatique du langage naturel ! L'humain : quand le voulons-nous ?! L'ordinateur : quand le voulons quoi ?",
"Est-ce que votre nom est Wi-Fi ? Parce que je sens une connexion.",
"Quand quelqu'un de triste joue aux jeux vidéo pour oublier, on peut dire qu'il se console.",
"Quel Pokemon a une mitraillette ? Ratatatatatatatatata.",
"Les filles c'est comme les noms de domaine. Celles que j'aime sont déjà prises.",
"Que dit une mère à son fils geek quand le diner est servi ? Alt Tab !",
"Quelle est la meilleure heure pour écouter de la musique ? Deezer.",
"De nos jours, le zip ça devient rar..."
]
}
"answers": { }
}

View File

@ -1,6 +1,7 @@
{
"name": "Joke",
"bridge": "python",
"type": "dialog",
"bridge": null,
"version": "1.0.0",
"description": "Leon says some jokes.",
"author": {

View File

@ -2,17 +2,23 @@
"actions": {
"run": {
"utterance_samples": [
"Do you have something to say about Alexa?",
"Tell me about the personal assistant Alexa",
"Tell me about the personal assistant Cortana",
"Do you have something to say about Cortana?",
"Tell me about the personal assistant Siri",
"Do you have something to say about Siri?",
"Tell me about the personal assistant Google Assistant",
"Do you have something to say about Google Assistant?"
"Do you have something to say about @partnerAssistant?",
"Tell me about the personal assistant @partnerAssistant",
"I want to know more about @partnerAssistant",
"Tell me something related to @partnerAssistant"
]
}
},
"entities": {
"partnerAssistant": {
"options": {
"Alexa": ["alexa"],
"Cortana": ["cortana"],
"Siri": ["siri"],
"Google Assistant": ["google assistant"]
}
}
},
"answers": {
"alexa": [
"Alexa is very kind and Amazon is teaching it many things. It was born in November 2014.",

View File

@ -2,17 +2,23 @@
"actions": {
"run": {
"utterance_samples": [
"Connais-tu quelque chose sur Alexa ?",
"Dis-moi quelque chose sur l'assistant personnel Alexa",
"Connais-tu quelque chose sur Cortana ?",
"Dis-moi quelque chose sur l'assistant personnel Cortana",
"Connais-tu quelque chose sur Siri ?",
"Dis-moi quelque chose sur l'assistant personnel Siri",
"Connais-tu quelque chose sur le Google Assistant ?",
"Dis-moi quelque chose sur l'assistant personnel Google Assistant"
"Connais-tu quelque chose sur @partnerAssistant ?",
"Dis-moi quelque chose sur l'assistant personnel @partnerAssistant",
"Dis-moi quelque chose à propos de @partnerAssistant",
"Je veux en savoir plus au sujet de @partnerAssistant"
]
}
},
"entities": {
"partnerAssistant": {
"options": {
"Alexa": ["alexa"],
"Cortana": ["cortana"],
"Siri": ["siri"],
"Google Assistant": ["google assistant"]
}
}
},
"answers": {
"alexa": [
"Alexa est très sympa et Amazon lui enseigne pleins de choses. Elle est née en novembre 2014.",

View File

@ -6,17 +6,12 @@ import utils
def run(string, entities):
"""Leon tells you about other personal assistants"""
string = string.lower()
partner = ''
assistants = [
'alexa',
'cortana',
'siri',
'google assistant'
]
for assistant in assistants:
if string.find(assistant) != -1:
return utils.output('end', 'success', utils.translate(assistant.replace(' ', '_')))
# Find entities
for item in entities:
if item['entity'] == 'partnerAssistant':
partner = item['option'].lower()
return utils.output('end', 'success', utils.translate(partner.replace(' ', '_')))
return utils.output('end', 'unknown', utils.translate('unknown'))

View File

@ -1,6 +1,6 @@
import moment from 'moment-timezone'
import utterance_samples from '@/data/en.json' // eslint-disable-line camelcase
import utterance_samples from '../../core/data/en/answers.json' // eslint-disable-line camelcase
jest.setTimeout(60000)