Basic functionality

This commit is contained in:
Daniel Dayley 2023-04-10 23:40:51 -06:00
parent 0444be965b
commit 7f1e558780
5 changed files with 23 additions and 84 deletions

View File

@ -1,81 +0,0 @@
#!python3
import os
import sys
import yaml
import logging
import argparse
import persona
from typing import List
from dataclasses import dataclass
import datetime
import requests
import socketio
class LoggingFormatter(logging.Formatter):
def format(self, record):
module_max_width = 30
datefmt='%Y/%m/%d/ %H:%M:%S'
level = f'[{record.levelname}]'.ljust(9)
if 'log_module' not in dir(record) :
modname = str(record.module)+'.'+str(record.name)
else :
modname = record.log_module
modname = (f'{modname}'[:module_max_width-1] + ']').ljust(module_max_width)
final = "%-7s %s [%s %s" % (self.formatTime(record, self.datefmt), level, modname, record.getMessage())
return final
if __name__ == '__main__':
# Command-line client
# Define constants
config_template = {'bluebubbles_bot': {}}
# Gather Argument options
EXAMPLE_TEXT='Example:\n\tbluebubbles_bot -h'
parser = argparse.ArgumentParser(epilog=EXAMPLE_TEXT,formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('-H', '--hosts', action='append', default=None, help='Collects arguments in an array.')
parser.add_argument('-d', '--dry-run', action='store_true', help='Store the existence of a variable.')
parser.add_argument('-l', '--log', action='store', help='Specify a file to log to.')
parser.add_argument('-v', '--verbose', action='count', help='Include verbose information in the output. Add \'v\'s for more output.',default=0)
args = parser.parse_args()
log = logging.getLogger(__name__)
log = logging.LoggerAdapter(log,{'log_module':'bluebubbles_bot'})
# Configure logging
log_options = [logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG]
if not args.verbose :
args.verbose = 0
if args.verbose > 3 :
args.verbose = 3
if args.log :
logging.basicConfig(level=log_options[args.verbose],filename=args.log)
logging.getLogger().addHandler(logging.StreamHandler(sys.stderr))
else :
logging.basicConfig(level=log_options[args.verbose])
logging.getLogger().handlers[0].setFormatter(LoggingFormatter())
logging.propagate=True
# Check for missing environment variables
for required_var in ['BB_SERVER_URL','BB_SERVER_PASSWORD'] :
if required_var not in os.environ.keys() :
log.error(f'Missing required ENV variable {required_var}')
exit(1)
# Create persona instance
test = persona.Persona()
# Test Message
message = persona.Message(text="Hello",sender_identifier="Daniel",chat_identifier=None,attachments=[],timestamp=datetime.datetime.now(), recipients=[], identifier=None)
responses = test.receive_message(message)
for response in responses :
log.warning('Bot responded with:')
log.warning(response.text)
# Create socket connection
sio = socketio.Client()
try :
sio.connect(os.environ['BB_SERVER_URL'])
log.info('Connected to server.')
except socketio.exceptions.ConnectionError as e:
log.error(str(e))

View File

@ -36,6 +36,7 @@ class Message :
timestamp: datetime.datetime
recipients: List[String]
identifier: str
meta: dict
class PersonaBaseSkill() :

View File

@ -1,11 +1,25 @@
from __future__ import annotations
import os
import inspect
import logging
import importlib
from typing import List
from dataclasses import dataclass
import datetime
class LoggingFormatter(logging.Formatter):
def format(self, record):
module_max_width = 30
datefmt='%Y/%m/%d/ %H:%M:%S'
level = f'[{record.levelname}]'.ljust(9)
if 'log_module' not in dir(record) :
modname = str(record.module)+'.'+str(record.name)
else :
modname = record.log_module
modname = (f'{modname}'[:module_max_width-1] + ']').ljust(module_max_width)
final = "%-7s %s [%s %s" % (self.formatTime(record, self.datefmt), level, modname, record.getMessage())
return final
class Persona :
"""A class that represents state data for the chatbot. This is the personality for the bot.
Personas load skills that allow them to execute different commands. The personas can receive
@ -18,6 +32,10 @@ class Persona :
skill_class = 'PersonaSkill'
ready_skills = {}
def __init__(self) :
# Enable logging
self.log = logging.getLogger(__name__)
self.log = logging.LoggerAdapter(self.log,{'log_module':'persona'})
logging.getLogger().handlers[0].setFormatter(LoggingFormatter())
# Load skills
available_skills = self.search_skills(directory='/'.join(os.path.realpath(__file__).split('/')[:-2]) + '/persona' + '/skills')
self.use_skills([x for x in available_skills.values()])
@ -97,5 +115,6 @@ class Persona :
should_respond = skill.match_intent(message)
if should_respond :
response = skill.respond(message=message)
self.log.info(f'Responding to \'{message.text}\' with \'{response.text}\'')
generated_messages.append(response)
return generated_messages

View File

@ -19,4 +19,4 @@ class PersonaSkill(PersonaBaseSkill) :
"""Respond to a message by generating another message."""
response_options = ['Hello!','Howdy!','Hello there!','What\'s up!','Hi there!']
response_text = random.choice(response_options)
return persona.Message(text=response_text,sender_identifier=message.sender_identifier,chat_identifier=message.chat_identifier,attachments=[],timestamp=datetime.datetime.now(), recipients=[message.sender_identifier], identifier=None)
return persona.Message(text=response_text,sender_identifier=message.sender_identifier,chat_identifier=message.chat_identifier,attachments=[],timestamp=datetime.datetime.now(), recipients=[message.sender_identifier], identifier=None, meta={})

View File

@ -54,8 +54,8 @@ setup(name='bluebubbles_bot',
description='A chatbot for a local BlueBlubbles server.',
packages=find_packages(exclude=['tests']),
package_data={"": ['skills/*.py']},
install_requires=['pyyaml','datetime','python-socketio[asyncio_client]','requests','websocket-client'],
scripts=['bin/bluebubbles_bot'],
install_requires=['pyyaml','datetime','requests','fastapi[all]'],
scripts=['bin/bluebubbles_bot.py'],
long_description=open('README.md').read(),
zip_safe=True
)