Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed some things and changed the discord module to disnake #30

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 49 additions & 28 deletions cathy/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import aiml
from datetime import datetime, timedelta
import discord
import disnake
import os
import pkg_resources
import logging
Expand All @@ -16,12 +16,12 @@ class Cathy:

STARTUP_FILE = "std-startup.xml"
SQL_SCHEMA = [
'CREATE TABLE IF NOT EXISTS chat_log (time, server_name, user_id, message, response)',
'CREATE TABLE IF NOT EXISTS users (id, name, first_seen)',
'CREATE TABLE IF NOT EXISTS servers (id, name, first_seen)',
"CREATE TABLE IF NOT EXISTS chat_log (time, server_name, user_id, message, response)",
"CREATE TABLE IF NOT EXISTS users (id, name, first_seen)",
"CREATE TABLE IF NOT EXISTS servers (id, name, first_seen)",
]

def exit_handler(signal_received, frame):
def exit_handler(self, signal_received, frame):
logging.info(f"[*] Signal received ({signal_received})....Exiting.")
exit()

Expand Down Expand Up @@ -49,7 +49,7 @@ def __init__(self, channel_name, bot_token, database):
self.db = sqlite3.connect(self.database)
self.cursor = self.db.cursor()
self.setup_database_schema()
logging.info('[+] Database initialized')
logging.info("[+] Database initialized")

# Load AIML kernel
logging.info("[*] Initializing AIML kernel...")
Expand All @@ -61,7 +61,7 @@ def __init__(self, channel_name, bot_token, database):

# Set up Discord
logging.info("[*] Initializing Discord bot...")
self.discord_bot = discord.AutoShardedClient()
self.discord_bot = disnake.AutoShardedClient()
self.setup_discord_events()
logging.info("[+] Done initializing Discord bot.")
logging.info("[+] Exiting __init__ function.")
Expand All @@ -73,7 +73,9 @@ def setup_database_schema(self):

def setup_aiml(self):
initial_dir = os.getcwd()
os.chdir(pkg_resources.resource_filename(__name__, '')) # Change directories to load AIML files properly
os.chdir(
pkg_resources.resource_filename(__name__, "")
) # Change directories to load AIML files properly
startup_filename = pkg_resources.resource_filename(__name__, self.STARTUP_FILE)
self.aiml_kernel.setBotPredicate("name", "Cathy")
self.aiml_kernel.learn(startup_filename)
Expand All @@ -88,12 +90,13 @@ async def reset(self, message):
now = datetime.now()
if datetime.now() - self.last_reset_time > timedelta(hours=1):
self.last_reset_time = now
await message.channel.send('Resetting my brain...')
await message.channel.send("Resetting my brain...")
self.aiml_kernel.resetBrain()
self.setup_aiml()
else:
await message.channel.send(
f'Sorry, I can only reset once per hour and I was last reset on {self.last_reset_time} UTC')
f"Sorry, I can only reset once per hour and I was last reset on {self.last_reset_time} UTC"
)

def setup_discord_events(self):
"""
Expand All @@ -110,7 +113,9 @@ async def on_ready():

@self.discord_bot.event
async def on_message(message):
sessionID = message.author.id # Change to message.guild.id if you want it to be for guilds
sessionID = (
message.author.id
) # Change to message.guild.id if you want it to be for guilds
self.message_count += 1

if message.author.bot or str(message.channel) != self.channel_name:
Expand All @@ -120,32 +125,39 @@ async def on_message(message):
logging.error("[-] Empty message received.")
return

if message.content.startswith('!reset'):
if message.content.startswith("!reset"):
await self.reset(message)
return
if message.content.lower() == "client info":
await message.channel.send(self.aiml_kernel.getSessionData(sessionID))

# Clean out the message to prevent issues
text = message.content
for ch in ['/', "'", ".", "\\", "(", ")", '"', '\n', '@', '<', '>']:
text = text.replace(ch, '')
for ch in ["/", "'", ".", "\\", "(", ")", '"', "\n", "@", "<", ">"]:
text = text.replace(ch, "")

try:
aiml_response = self.aiml_kernel.respond(text, sessionID=sessionID)
aiml_response = aiml_response.replace("://", "")
aiml_response = aiml_response.replace("@", "") # Prevent tagging and links
aiml_response = "`@%s`: %s" % (message.author.name, aiml_response) # Remove unicode to prevent errors

if len(aiml_response) > 1800: # Protect against discord message limit of 2000 chars
aiml_response = aiml_response.replace(
"@", ""
) # Prevent tagging and links
aiml_response = "`@%s`: %s" % (
message.author.name,
aiml_response,
) # Remove unicode to prevent errors

if (
len(aiml_response) > 1800
): # Protect against discord message limit of 2000 chars
aiml_response = aiml_response[0:1800]

now = datetime.now()
self.insert_chat_log(now, message, aiml_response)

await message.channel.send(aiml_response)

except discord.HTTPException as e:
except disnake.HTTPException as e:
logging.error("[-] Discord HTTP Error: %s" % e)
except Exception as e:
logging.error("[-] General Error: %s" % e)
Expand All @@ -156,22 +168,31 @@ def run(self):
logging.info("[*] Bot finished running.")

def insert_chat_log(self, now, message, aiml_response):
self.cursor.execute('INSERT INTO chat_log VALUES (?, ?, ?, ?, ?)',
(now.isoformat(), message.guild.id, message.author.id,
str(message.content), aiml_response))
self.cursor.execute(
"INSERT INTO chat_log VALUES (?, ?, ?, ?, ?)",
(
now.isoformat(),
message.guild.id,
message.author.id,
str(message.content),
aiml_response,
),
)

# Add user if necessary
self.cursor.execute('SELECT id FROM users WHERE id=?', (message.author.id,))
self.cursor.execute("SELECT id FROM users WHERE id=?", (message.author.id,))
if not self.cursor.fetchone():
self.cursor.execute(
'INSERT INTO users VALUES (?, ?, ?)',
(message.author.id, message.author.name, datetime.now().isoformat()))
"INSERT INTO users VALUES (?, ?, ?)",
(message.author.id, message.author.name, datetime.now().isoformat()),
)

# Add server if necessary
self.cursor.execute('SELECT id FROM servers WHERE id=?', (message.guild.id,))
self.cursor.execute("SELECT id FROM servers WHERE id=?", (message.guild.id,))
if not self.cursor.fetchone():
self.cursor.execute(
'INSERT INTO servers VALUES (?, ?, ?)',
(message.guild.id, message.guild.name, datetime.now().isoformat()))
"INSERT INTO servers VALUES (?, ?, ?)",
(message.guild.id, message.guild.name, datetime.now().isoformat()),
)

self.db.commit()
32 changes: 17 additions & 15 deletions cathy/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,32 @@ def print_usage():
print(" cathy")
print("DISCORD_TOKEN, DATABASE, DISCORD_CHANNEL should be environment variables.")
print("They can be placed in a `.env` file.")
print("These can also be input if they are not present in the env file.")
print("The database will be created if it does not exist.")
print("For more info, visit: http://cathy-docs.rtfd.io/")


def main(): # If called by entrypoint
if '--help' in argv or '-h' in argv:
if "--help" in argv or "-h" in argv:
print_usage()
exit()

load_dotenv()

errors = []
if not environ.get('DISCORD_TOKEN'):
errors.append('No DISCORD_TOKEN found in environment variables.')
if not environ.get('DISCORD_CHANNEL'):
errors.append('No DISCORD_CHANNEL found in environment variables.')
if not environ.get('DATABASE'):
errors.append('No DATABASE found in environment variables.')
if errors:
for error in errors:
print(f"Error: {error}")
exit(1)

bot = Cathy(environ['DISCORD_CHANNEL'], environ['DISCORD_TOKEN'], environ['DATABASE'])
token = environ.get("DISCORD_TOKEN")
channel = environ.get("DISCORD_CHANNEL")
db = environ.get("DATABASE")

if not token:
token = input("Input your token: ")
environ["DISCORD_TOKEN"] = token
if not channel:
channel = input("Input the channel: ")
environ["DISCORD_CHANNEL"] = channel
if not db:
db = input("Input the DB: ")
environ["DATABASE"] = db

bot = Cathy(environ["DISCORD_CHANNEL"], environ["DISCORD_TOKEN"], environ["DATABASE"])
bot.run()


Expand Down
15 changes: 2 additions & 13 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,8 @@
},
zip_safe=False,
install_requires=[
'aiohttp==3.6.2',
'async-timeout==3.0.1',
'attrs==19.3.0',
'certifi==2019.11.28',
'chardet==3.0.4',
'discord.py==1.3.1',
'idna==2.9',
'multidict==4.7.5',
'python-aiml==0.9.3',
'requests==2.23.0',
'urllib3==1.25.8',
'websockets==8.1',
'yarl==1.4.2',
'disnake==2.4.0',
'python-aiml',
'python-dotenv',
],
python_requires='>=3.7',
Expand Down
2 changes: 2 additions & 0 deletions start.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
python -m pip install .
python -m cathy