Mejoras en cerebro

This commit is contained in:
2020-11-20 16:20:22 -03:00
parent d67ffbced2
commit 9be47df527
8 changed files with 81 additions and 47 deletions

17
TODO.md
View File

@ -1,26 +1,33 @@
# TODO # TODO
## 1. Main modulo ## Main modulo
1. Workers para 1. Workers para
1. [x] Revisar Email 1. [x] Revisar Email
1. [ ] Revisar WhatsApp 1. [ ] Revisar WhatsApp
1. [ ] Procesar Texto 1. [ ] Procesar Texto
## 2. Modulo de Revision de Email ## Modulo de Revision de Email
Para revisar si hay mails nuevos, validando que sea de las personas registradas. Para revisar si hay mails nuevos, validando que sea de las personas registradas.
Si no está registrada se avisa a administrador para saber que hacer. Si no está registrada se avisa a administrador para saber que hacer.
Limpieza de Inbox y Spam. Limpieza de Inbox y Spam.
- [x] Revisar lista de emails - [x] Revisar lista de emails
- [x] Revisar si fue revisado - [x] Revisar si fue revisado
- [x] Revisar si corresponde a un "Jefe" - [x] Revisar si corresponde a un "Jefe"
- [x] Confirmar con cerebro si es un comando
## 3. Modulo de WhatsApp ## Modulo de WhatsApp
Respuestas a mensajes. Respuestas a mensajes.
## 4. Modulo de Recordatorio ## AI para procesar textos
Spacy permite procesar texto
Hay que poder "educar" el modelo
Hay que poder agregar datos
Hay que poder agregar los correos y mensajes que no se conocen a listado "desconocido"
## Modulo de Recordatorio
Crear recordatorios y mandar correo o WhatsApp en el momento del recordatorio. Crear recordatorios y mandar correo o WhatsApp en el momento del recordatorio.
## 5. Modulo de Registro de Eventos ## Modulo de Registro de Eventos
Ir llevando un registro de eventos. Ir llevando un registro de eventos.
### Otros ### Otros

View File

@ -4,7 +4,7 @@
"port": 993, "port": 993,
"user": { "user": {
"name": "secretary@incoviba.cl", "name": "secretary@incoviba.cl",
"password": "quzshqzyfcnydevp" "password": "vgvjuwzwizktdpka"
}, },
"ssl": true "ssl": true
}, },
@ -13,7 +13,7 @@
"port": 495, "port": 495,
"user": { "user": {
"name": "secretary@incoviba.cl", "name": "secretary@incoviba.cl",
"password": "quzshqzyfcnydevp" "password": "vgvjuwzwizktdpka"
}, },
"ssl": true "ssl": true
}, },

View File

@ -1,15 +1,29 @@
import os import os
import spacy import spacy
from pprint import pprint from src.instrucciones import Instrucciones
class Brain: class Brain:
def __init__(self, data_folder): def __init__(self, data_folder):
self.folder = data_folder
self.filename = os.path.join(data_folder, 'brain.json') self.filename = os.path.join(data_folder, 'brain.json')
self.nlp = spacy.load('es_core_news_sm') self.nlp = None
self.load_nlp(data_folder)
def load_nlp(self, data_folder):
folder = os.path.join(data_folder, 'model')
self.nlp = spacy.load(folder)
def save_model(self):
folder = os.path.join(self.folder, 'model')
self.nlp.to_disk(folder)
def get_command(self, phrase): def get_command(self, phrase):
doc = self.nlp(phrase) doc = self.nlp(phrase)
verbs = [t for t in doc if t.pos_ == 'VERB'] command = max(doc.cats, key=doc.cats.get)
pprint(verbs) return command
return doc.ents[0]
def get_response(self, command, phrase):
doc = self.nlp(phrase)
return doc

15
src/brain/build_model.py Normal file
View File

@ -0,0 +1,15 @@
import os
import spacy
from src.instrucciones import Instrucciones
def load_model(commands):
nlp = spacy.load('es_core_news_sm')
if 'textcat' not in nlp.pipe_names:
textcat = nlp.create_pipe('textcat')
nlp.add_pipe(textcat)
textcat.add_label('test')
for c in commands.instrucciones:
textcat.add_label(c.instruccion)
optimizer = nlp.begin_training()
return nlp

View File

@ -1,8 +1,9 @@
class Message: class Message:
def __init__(self, mtype, sender, datetime, text, original): def __init__(self, mtype, sender, datetime, text, original, subject):
self.type = mtype self.type = mtype
self.sender = sender self.sender = sender
self.datetime = datetime self.datetime = datetime
self.text = text self.text = text
self.checked = False self.checked = False
self.original = original self.original = original
self.subject = subject

View File

@ -95,9 +95,7 @@ class Email(Thread):
def run(self) -> None: def run(self) -> None:
self.start_workers() self.start_workers()
worker = Thread(target=exit_thread, args=(self.params['events']['stop'], self.params['logging'])) worker = Thread(target=exit_thread, args=(self.params['events']['stop'], self.params['logging']))
self.add_worker(worker)
worker.start() worker.start()
self.worker_status.append(True)
while not self.params['events']['stop'].is_set(): while not self.params['events']['stop'].is_set():
if not self.check_workers(): if not self.check_workers():
@ -106,3 +104,4 @@ class Email(Thread):
self.params['logging'].log('Waiting for workers', type(self)) self.params['logging'].log('Waiting for workers', type(self))
self.params['events']['log_stop'].set() self.params['events']['log_stop'].set()
self.join_workers() self.join_workers()
worker.join()

View File

@ -9,6 +9,7 @@ import email.utils
from src.communication import Message from src.communication import Message
import json import json
from src.functions import dump_queue from src.functions import dump_queue
from pprint import pprint
class Obtenedor(Worker): class Obtenedor(Worker):
@ -94,8 +95,9 @@ class Obtenedor(Worker):
if self.is_revisado(em.uid): if self.is_revisado(em.uid):
continue continue
sender = em.message['from'] sender = em.message['from']
text = ' '.join([em.message['subject'] + '.'] + self.build_message(em.message)) # text = ' '.join([em.message['subject'] + '.'] + self.build_message(em.message))
msg = Message('email', text=text, original=em, sender=sender, text = self.build_message(em.message)
msg = Message('email', text=text, original=em, sender=sender, subject=str(em.message['subject']),
datetime=email.utils.parsedate_to_datetime(em.message['Date'])) datetime=email.utils.parsedate_to_datetime(em.message['Date']))
self.queue.put(msg) self.queue.put(msg)
self.add_revisado(em.uid) self.add_revisado(em.uid)
@ -132,7 +134,7 @@ class Validador(Worker):
return self.bosses.is_boss(sender) return self.bosses.is_boss(sender)
def validar_instrucciones(self, message): def validar_instrucciones(self, message):
return self.instrucciones.is_valid(message.original.message['subject']) return self.instrucciones.is_valid(message.subject)
def validar(self, message): def validar(self, message):
if self.validar_bosses(message.sender): if self.validar_bosses(message.sender):
@ -245,7 +247,7 @@ class Borrador(Worker):
return return
for uid in self.borrar: for uid in self.borrar:
print(uid) print('Borrar ', uid)
# status, ids = imap.uid('store', uid, '+FLAGS', b'\\Deleted') # status, ids = imap.uid('store', uid, '+FLAGS', b'\\Deleted')
# if status != 'OK': # if status != 'OK':
# continue # continue
@ -281,6 +283,9 @@ class Procesador(Worker):
self.frec = configs.get('supervisor.wait') self.frec = configs.get('supervisor.wait')
self.brain = params['brain'] self.brain = params['brain']
def cleanup(self):
self.brain.save_model()
def run(self) -> None: def run(self) -> None:
self.start_turn() self.start_turn()
while not self.stop.is_set(): while not self.stop.is_set():
@ -288,6 +293,10 @@ class Procesador(Worker):
em = self.queue.get(timeout=self.frec) em = self.queue.get(timeout=self.frec)
except queue.Empty: except queue.Empty:
continue continue
command = self.brain.get_command(em.text) command = self.brain.get_command(em.subject)
pprint((em.subject, command))
for t in em.text:
contenido = self.brain.get_response(command, t)
self.cleanup()
self.end_turn() self.end_turn()

View File

@ -10,14 +10,15 @@ class Command:
class Commands: class Commands:
def __init__(self, data_folder): def __init__(self, data_folder):
self.filename = os.path.join(data_folder, 'commands.json') self.filename = os.path.join(data_folder, 'commands.json')
data = []
try:
with open(self.filename, 'r') as f:
data = json.load(f)
except FileNotFoundError:
pass
self.commands = [] self.commands = []
self.load_commands(self.filename)
def load_commands(self, filename):
data = []
if os.path.isfile(filename):
with open(filename, 'r') as f:
data = json.load(f)
for c in data: for c in data:
cmd = Command() cmd = Command()
cmd.command = c cmd.command = c
@ -36,7 +37,6 @@ class Commands:
class Instruccion: class Instruccion:
def __init__(self): def __init__(self):
self.instruccion = '' self.instruccion = ''
self.aliases = []
self.command = None self.command = None
self.params = {} self.params = {}
@ -44,22 +44,20 @@ class Instruccion:
class Instrucciones: class Instrucciones:
def __init__(self, data_folder): def __init__(self, data_folder):
self.filename = os.path.join(data_folder, 'instrucciones.json') self.filename = os.path.join(data_folder, 'instrucciones.json')
data = []
try:
with open(self.filename, 'r') as f:
data = json.load(f)
except FileNotFoundError:
pass
self.commands = Commands(data_folder) self.commands = Commands(data_folder)
self.instrucciones = [] self.instrucciones = []
self.load_instrucciones(self.filename)
self.idx = 0
def load_instrucciones(self, filename):
data = []
if os.path.isfile(filename):
with open(filename, 'r') as f:
data = json.load(f)
for d in data: for d in data:
i = Instruccion() i = Instruccion()
i.instruccion = d['name'] i.instruccion = d['name']
if 'aliases' in d:
for a in d['aliases']:
i.aliases.append(a)
if 'params' in d: if 'params' in d:
for param, val in d['params'].items(): for param, val in d['params'].items():
i.params[param] = val i.params[param] = val
@ -73,8 +71,6 @@ class Instrucciones:
for i, ins in enumerate(self.instrucciones): for i, ins in enumerate(self.instrucciones):
if instruccion == ins.instruccion: if instruccion == ins.instruccion:
return i return i
if instruccion in ins.aliases:
return i
def find(self, instruccion): def find(self, instruccion):
if not self.is_valid(instruccion): if not self.is_valid(instruccion):
@ -85,23 +81,16 @@ class Instrucciones:
for i in self.instrucciones: for i in self.instrucciones:
if instruccion == i.instruccion: if instruccion == i.instruccion:
return True return True
if instruccion in i.aliases:
return True
return False return False
def add(self, instruccion, aliases: list = None): def add(self, instruccion, aliases: list = None):
if self.is_valid(instruccion): if self.is_valid(instruccion):
if aliases is not None:
i = self.get(instruccion)
self.instrucciones[i].aliases = aliases
return return
ins = Instruccion() ins = Instruccion()
ins.instruccion = instruccion ins.instruccion = instruccion
if aliases is not None:
ins.aliases = aliases
self.instrucciones.append(ins) self.instrucciones.append(ins)
def save(self): def save(self):
data = [{'instruccion': i.instruccion, 'aliases': i.aliases} for i in self.instrucciones] data = [{'instruccion': i.instruccion, 'params': i.params.items()} for i in self.instrucciones]
with open(self.filename, 'w') as f: with open(self.filename, 'w') as f:
json.dump(data, f, indent=4) json.dump(data, f, indent=4)