sparkytron3000/sparkytron3000.py

1748 lines
70 KiB
Python
Raw Normal View History

2023-07-09 00:57:11 -07:00
import discord
2023-07-10 10:38:28 -07:00
from discord.ext import commands, tasks
2023-07-09 00:57:11 -07:00
from discord.utils import get
import shutil
import json
import random
import time
import os
import io
import base64
import asyncio
import sys
import subprocess
import math
from PIL import Image, PngImagePlugin
from dotenv import load_dotenv
import matplotlib.pyplot as plt
import aiohttp
import aioftp
import asyncssh
2023-07-09 00:57:11 -07:00
2023-07-13 01:10:28 -07:00
#Stable Diffusion
#Set this env variable to http://host:port or "disabled"
2023-07-13 01:10:28 -07:00
#os.getenv('stablediffusion_url')
2023-07-09 00:57:11 -07:00
#env vars START
load_dotenv()
imgflip_username = os.getenv('imgflip_username')
imgflip_password = os.getenv('imgflip_password')
discord_token = os.getenv('discord_token')
ftp_server = os.getenv('ftp_server')
ftp_username = os.getenv('ftp_username')
ftp_password = os.getenv('ftp_password')
ftp_public_html = os.getenv('ftp_public_html')
#env vars END
#discord stuff START
intents = discord.Intents.default()
intents.message_content = True
bot = commands.Bot(command_prefix='!', intents=intents)
#discord stuff END
@bot.command(
description="Moderate",
help="This currently tool works by replacing the filename on the ftp server with a black image. The description will remain the same and may need to be altered.",
brief="Moderation Tools"
)
2023-07-12 15:10:02 -07:00
async def moderate(ctx, filename):
await upload_sftp("blank_image.png", (os.getenv('ftp_public_html') + 'ai-images/'), filename)
output = "Image " + filename + " replaced"
await ctx.send(output)
2023-07-12 15:10:02 -07:00
2023-07-09 00:57:11 -07:00
async def upload_ftp(local_filename, server_folder, server_filename):
2023-07-09 18:02:15 -07:00
client = aioftp.Client()
await client.connect(ftp_server)
await client.login(ftp_username, ftp_password)
await client.change_directory(server_folder)
await client.upload(local_filename, server_folder+server_filename, write_into=True)
await client.quit()
async def upload_sftp(local_filename, server_folder, server_filename):
remotepath = server_folder + server_filename
async with asyncssh.connect(ftp_server, username=ftp_username, password=ftp_password) as conn:
async with conn.start_sftp_client() as sftp:
await sftp.put(local_filename, remotepath=remotepath)
2023-07-09 18:02:15 -07:00
2023-07-11 17:04:28 -07:00
async def handle_error(error):
print(error)
current_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
2023-07-16 16:35:40 -07:00
log_line = current_time + ': ' + str(error) + '\n'
2023-07-11 17:04:28 -07:00
with open("databases/error_log.txt", 'a') as f:
f.write(log_line)
return error
2023-07-09 00:57:11 -07:00
async def upload_ftp_ai_images(filename, prompt):
2023-07-09 16:06:45 -07:00
html_file = "phixxy.com/ai-images/index.html"
2023-07-09 00:57:11 -07:00
html_insert = '''<!--REPLACE THIS COMMENT-->
<div>
<img src="<!--filename-->" loading="lazy">
2023-07-09 00:57:11 -07:00
<p class="image-description"><!--description--></p>
</div>'''
img_list = []
server_folder = (os.getenv('ftp_public_html') + 'ai-images/')
new_filename = str(time.time_ns()) + ".png"
await upload_sftp(filename, server_folder, new_filename)
2023-12-27 22:05:14 -08:00
print("Uploaded", new_filename)
2023-07-09 18:02:15 -07:00
with open(html_file, 'r') as f:
html_data = f.read()
html_insert = html_insert.replace("<!--filename-->", new_filename)
2023-07-09 18:02:15 -07:00
html_insert = html_insert.replace("<!--description-->", prompt)
html_data = html_data.replace("<!--REPLACE THIS COMMENT-->", html_insert)
with open(html_file, "w") as f:
f.writelines(html_data)
await upload_sftp(html_file, server_folder, "index.html")
2023-07-09 00:57:11 -07:00
def create_channel_config(filepath):
config_dict = {
"personality":"average",
"channel_topic":"casual",
"chat_enabled":False,
"commands_enabled":True,
"chat_history_len":5,
"look_at_images":False,
"react_to_msgs":False,
"ftp_enabled":False
}
with open(filepath,"w") as f:
json.dump(config_dict,f)
print("Wrote config variables to file.")
async def get_channel_config(channel_id):
2023-07-09 16:06:45 -07:00
filepath = "channels/config/{0}.json".format(str(channel_id))
2023-07-09 00:57:11 -07:00
if not os.path.exists(filepath):
create_channel_config(filepath)
with open(filepath, "r") as f:
config_dict = json.loads(f.readline())
return config_dict
async def answer_question(topic, model="gpt-3.5-turbo"):
headers = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {os.getenv("openai.api_key")}',
}
data = {
"model": model,
"messages": [{"role": "user", "content": topic}]
}
url = "https://api.openai.com/v1/chat/completions"
try:
async with bot.http_session.post(url, headers=headers, json=data) as resp:
response_data = await resp.json()
response = response_data['choices'][0]['message']['content']
return response
2023-07-09 00:57:11 -07:00
except Exception as error:
2023-07-11 17:04:28 -07:00
return await handle_error(error)
2023-07-09 00:57:11 -07:00
def extract_key_value_pairs(input_str):
output_str = input_str
key_value_pairs = {}
tokens = input_str.split(', ')
for token in tokens:
if '=' in token:
key, value = token.split('=')
key_value_pairs[key] = value
output_str = output_str.replace(token+', ', '') # Remove the key-value pair from the output string
return key_value_pairs, output_str
def my_open_img_file(path):
img = Image.open(path)
w, h = img.size
encoded = ""
with io.BytesIO() as output:
img.save(output, format="PNG")
contents = output.getvalue()
encoded = str(base64.b64encode(contents), encoding='utf-8')
img.close()
return encoded
async def look_at(ctx, look=False):
metadata = ""
if look:
2023-07-13 01:10:28 -07:00
url = os.getenv('stablediffusion_url')
2023-07-13 01:24:27 -07:00
if url == "disabled":
return
for attachment in ctx.attachments:
if attachment.url.endswith(('.jpg', '.png')):
print("image seen")
async with bot.http_session.get(attachment.url) as response:
imageName = "tmp/" + str(len(os.listdir('tmp/'))) + '.png'
2023-07-17 17:36:06 -07:00
with open(imageName, 'wb') as out_file:
print('Saving image: ' + imageName)
while True:
chunk = await response.content.read(1024)
if not chunk:
break
out_file.write(chunk)
img_link = my_open_img_file(imageName)
try:
payload = {"image": img_link}
async with bot.http_session.post(f'{url}/sdapi/v1/interrogate', json=payload) as response:
data = await response.json()
description = data.get("caption")
description = description.split(',')[0]
metadata += f"<image:{description}>\n"
except aiohttp.ClientError as error:
await handle_error(error)
return "ERROR: CLIP may not be running. Could not look at image."
2023-07-09 00:57:11 -07:00
return metadata
def edit_channel_config(channel_id, key, value):
2023-07-09 16:06:45 -07:00
config_file = "channels/config/" + str(channel_id) + ".json"
2023-07-09 00:57:11 -07:00
with open(config_file, 'r') as f:
config_data = json.load(f)
config_data[key] = value
with open(config_file, "w") as f:
json.dump(config_data, f)
async def react_to_msg(ctx, react):
def is_emoji(string):
if len(string) == 1:
# Range of Unicode codepoints for emojis
2023-08-19 12:40:46 -07:00
if 0x1F300 <= ord(string) <= 0x1F6FF:
return True
return False
2023-07-25 17:20:14 -07:00
if react:
2023-07-09 00:57:11 -07:00
if not random.randint(0,10) and ctx.author.id != 1097302679836971038:
system_msg = "Send only an emoji as a discord reaction to the following chat message"
message = ctx.content[0]
2023-07-09 00:57:11 -07:00
headers = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {os.getenv("openai.api_key")}',
}
data = {
"model": "gpt-3.5-turbo",
"messages": [{"role": "system", "content": system_msg}, {"role": "user", "content": message}]
2023-07-09 00:57:11 -07:00
}
url = "https://api.openai.com/v1/chat/completions"
2023-07-09 00:57:11 -07:00
try:
async with bot.http_session.post(url, headers=headers, json=data) as resp:
response_data = await resp.json()
reaction = response_data['choices'][0]['message']['content'].strip()
if is_emoji(reaction):
await ctx.add_reaction(reaction)
else:
await ctx.add_reaction("😓")
2023-07-09 00:57:11 -07:00
except Exception as error:
print("Some error happened while trying to react to a message")
2023-07-11 17:04:28 -07:00
await handle_error(error)
2023-07-09 00:57:11 -07:00
async def log_chat_and_get_history(ctx, logfile, channel_vars):
metadata = await look_at(ctx, channel_vars["look_at_images"])
log_line = metadata
log_line += ctx.content
log_line = ctx.author.name + ": " + log_line +"\n"
chat_history = ""
print("Logging: " + log_line, end="")
with open(logfile, "a", encoding="utf-8") as f:
f.write(log_line)
with open(logfile, "r", encoding="utf-8") as f:
for line in (f.readlines() [-int(channel_vars["chat_history_len"]):]):
chat_history += line
return chat_history
async def chat_response(ctx, channel_vars, chat_history_string):
async with ctx.channel.typing():
await asyncio.sleep(1)
prompt = f"You are a {channel_vars['personality']} chat bot named Sparkytron 3000 created by @phixxy.com. Your personality should be {channel_vars['personality']}. You are currently in a {channel_vars['channel_topic']} chatroom. The message history is: {chat_history_string}"
headers = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {os.getenv("openai.api_key")}',
}
data = {
"model": "gpt-3.5-turbo",
"messages": [{"role": "user", "content": prompt}]
}
url = "https://api.openai.com/v1/chat/completions"
2023-07-17 23:06:04 -07:00
try:
async with bot.http_session.post(url, headers=headers, json=data) as resp:
response_data = await resp.json()
response = response_data['choices'][0]['message']['content']
if "Sparkytron 3000:" in response[0:17]:
response = response.replace("Sparkytron 3000:", "")
max_len = 1999
if len(response) > max_len:
messages=[response[y-max_len:y] for y in range(max_len, len(response)+max_len,max_len)]
else:
messages=[response]
for message in messages:
await ctx.channel.send(message)
2023-07-09 00:57:11 -07:00
except Exception as error:
2023-07-11 17:04:28 -07:00
await handle_error(error)
2023-07-09 00:57:11 -07:00
2023-07-09 01:57:35 -07:00
async def folder_setup():
folder_names = ["tmp", "channels", "users", "channels/config", "channels/logs", "databases", "databases/currency", "databases/currency/players"]
2023-07-09 01:57:35 -07:00
for folder_name in folder_names:
if not os.path.exists(folder_name):
os.mkdir(folder_name)
2023-07-09 16:06:45 -07:00
async def delete_all_files(path):
for filename in os.listdir(path):
if os.path.isdir(path+filename):
shutil.rmtree(path+filename)
elif os.path.isfile(path+filename):
os.remove(path+filename)
2023-07-10 17:44:15 -07:00
async def delete_derp_files(server_folder):
async with asyncssh.connect(ftp_server, username=ftp_username, password=ftp_password) as conn:
async with conn.start_sftp_client() as sftp:
for filename in (await sftp.listdir(server_folder)):
2023-12-28 17:05:26 -08:00
if filename == '.' or filename == '..' or filename == 'style.css' or filename == 'myScript.js':
pass
else:
try:
print("Deleting", filename)
await sftp.remove(server_folder+filename)
except:
print("Couldn't delete", filename)
2023-07-10 10:38:28 -07:00
2023-07-10 17:44:15 -07:00
@tasks.loop(seconds=1) # Run the task every second
2023-07-10 10:38:28 -07:00
async def task_loop():
current_time = time.localtime()
2023-07-10 17:44:15 -07:00
#Run daily tasks
2023-07-11 11:54:40 -07:00
if current_time.tm_hour == 17 and current_time.tm_min == 0 and current_time.tm_sec == 0:
2023-07-10 17:44:15 -07:00
bot_stuff = bot.get_channel(544408659174883328)
2023-07-10 17:08:39 -07:00
output = 'The following tasks failed:\n```'
2023-07-10 11:23:05 -07:00
failed_tasks = []
await bot_stuff.send("<@242018983241318410> The current time is 5pm. Running daily tasks!")
2023-07-10 10:38:28 -07:00
try:
await generate_blog(bot_stuff)
2023-07-10 10:38:28 -07:00
except Exception as error:
2023-07-11 17:04:28 -07:00
await handle_error(error)
2023-07-10 17:08:39 -07:00
failed_tasks.append("Blogpost")
2023-07-10 11:23:05 -07:00
try:
await delete_all_files("tmp/")
except Exception as error:
2023-07-11 17:04:28 -07:00
await handle_error(error)
2023-07-10 17:08:39 -07:00
failed_tasks.append("Delete tmp/")
try:
await delete_derp_files("/home/debian/websites/derp.phixxy.com/files/")
except Exception as error:
await handle_error(error)
failed_tasks.append("Delete derp files")
2023-07-10 11:23:05 -07:00
if failed_tasks != []:
for failed_task in failed_tasks:
2023-07-10 17:08:39 -07:00
output += failed_task + '\n'
output += '```'
await bot_stuff.send(output)
2023-07-10 11:23:05 -07:00
else:
await bot_stuff.send("All daily tasks successfully ran!")
async def create_session():
2023-07-25 17:13:23 -07:00
return aiohttp.ClientSession()
async def close_session(http_session):
await http_session.close()
@bot.event
async def on_connect():
bot.http_session = await create_session()
@bot.event
async def on_resumed():
bot.http_session = await create_session()
@bot.event
async def on_disconnect():
await close_session(bot.http_session)
2023-07-09 00:57:11 -07:00
@bot.event
async def on_ready():
print('We have logged in as {0.user}'.format(bot))
#stuff to do if first run
2023-07-09 01:57:35 -07:00
await folder_setup()
2023-07-09 16:06:45 -07:00
await delete_all_files("tmp/")
2023-07-10 10:38:28 -07:00
task_loop.start()
2023-07-10 17:44:15 -07:00
@bot.command(
description="Update",
help="This will update sparkytron to the most recent version on github. Only privileged users can run this command! Usage: !update",
2023-07-17 11:36:34 -07:00
brief="Runs git pull",
hidden=True
)
2023-07-10 17:44:15 -07:00
async def update(ctx):
if ctx.author.id == 242018983241318410:
2023-07-10 18:04:46 -07:00
output = subprocess.run(["git","pull"],capture_output=True)
if output.stderr:
await ctx.send("Update Attempted")
2023-07-10 18:04:46 -07:00
await ctx.send(output.stderr.decode('utf-8'))
else:
await ctx.send(output.stdout.decode('utf-8'))
2023-07-10 17:44:15 -07:00
else:
await ctx.send("You don't have permission to do this.")
2023-07-09 00:57:11 -07:00
@bot.command(
description="Currency",
help="Server currency. You can run !currency claim to get started!", #This needs an overhaul
brief="Server currency tools"
)
2023-07-09 00:57:11 -07:00
async def currency(ctx, arg1=None, arg2=None, arg3=None, arg4=None):
def read_db(filepath):
with open(filepath,"r") as fileobj:
db_content = json.load(fileobj)
#print(db_content,type(db_content))
return db_content
def save_to_db(filepath,db_content):
with open(filepath,"w") as fileobj:
json.dump(db_content,fileobj,indent=4)
def add_currency(filepath,amount):
player_db = read_db(filepath)
player_db["currency"] += amount
save_to_db(filepath,player_db)
return player_db
def calc_level_from_xp(xp):
level = min(100,math.floor(0.262615*xp**0.3220627))
return level
def add_xp(filepath,player_db,time_spent):
activity = player_db["status"]["current_activity"]
starting_xp = player_db["skills"][activity]["xp"]
starting_level = player_db["skills"][activity]["level"]
if activity == "mining":
equipment_level = player_db["equipment"]["pickaxe"]["level"]
xp_gained = (time_spent) * equipment_level # SKILL LEVEL of XP / SEC
player_db["skills"][activity]["xp"] += xp_gained
new_xp = starting_xp + xp_gained
new_level = calc_level_from_xp(new_xp) #calculate with curve here
player_db["skills"][activity]["level"] = new_level
levels_gained = new_level - starting_level
summary = "" #summary should include xp gained, levels gained (only if any were gained), current level (or new level)
summary += "You gained {} {} xp!".format(xp_gained, activity)
if levels_gained > 0: #if levels gained > 0, then include levels gained in summary
summary += "\nYou gained {} {} level(s)! You are now level {}.".format(levels_gained, activity, new_level)
save_to_db(filepath, player_db)
return player_db,summary
def add_resources(filepath,player_db,time_spent):
mining_resources = {
"sapphire": {
"value": 100,
"amount": 0
},
"emerald": {
"value": 250,
"amount": 0
},
"ruby": {
"value": 1000,
"amount": 0
},
"diamond": {
"value": 3000,
"amount": 0
}
}
if player_db["status"]["current_activity"] == "mining":
pick_power = player_db["equipment"]["pickaxe"]["power"]
pick_level = player_db["equipment"]["pickaxe"]["level"]
mining_level = player_db["skills"]["mining"]["level"]
numerator = pick_power + pick_level + mining_level
denominator = 1000
items_gained = []
time_summary = time.strftime("%H:%M:%S", time.gmtime(time_spent))
for second in range(0,time_spent):
roll = random.randint(0,denominator)
if roll <= numerator: #get a resource
roll2 = random.randint(0,100)
if roll2 <= 50:
mining_resources["sapphire"]["amount"] += 1
elif roll2 <=80:
mining_resources["emerald"]["amount"] += 1
elif roll2 <= 95:
mining_resources["ruby"]["amount"] += 1
else:
mining_resources["diamond"]["amount"] += 1
for item in mining_resources:
mined_amount = mining_resources[item]["amount"]
if item in player_db["items"]:
player_db["items"][item]["amount"] += mined_amount
items_gained.append(item.title())
items_gained.append(mined_amount)
else:
player_db["items"][item] = mining_resources[item]
items_gained.append(item.title())
items_gained.append(mined_amount)
save_to_db(filepath, player_db)
summary = "You spent {} mining. You mined {} x{}, {} x{}, {} x{}, and {} x{}.".format(time_summary, *items_gained)
return player_db,summary
async def transfer_currency(filepath, player_db, player_id, amount):
try:
amount = int(amount)
player2_filepath = "currency/players/" + str(player_id) + ".json"
player2_db = read_db(player2_filepath)
if player_db["currency"] >= amount:
add_currency(filepath, -amount)
add_currency(player2_filepath,amount)
await ctx.send("Sent " + str(amount) + " sparks to " + str(player_id))
except FileNotFoundError:
await ctx.send("They don't seem to be playing the game.")
async def show_levels(player_db):
output = ''
for skill in player_db["skills"]:
output += skill + ': ' + str(player_db["skills"][skill]["level"]) + '\n'
await ctx.send(output)
async def show_currency(player_db):
output = 'Sparks: ' + str(player_db["currency"])
await ctx.send(output)
async def show_items(player_db):
output = ''
for item in player_db["items"]:
output += item + ': ' + str(player_db["items"][item]["amount"]) + '\n'
await ctx.send(output)
async def stop_activity(filepath,player_db):
if player_db["status"]["current_activity"] == "idle":
await ctx.send("You are currently idle. There is no activity to stop.")
else:
time_spent = int(time.time() - player_db["status"]["start_time"]) #integer in seconds
player_db, xp_summary = add_xp(filepath,player_db,time_spent)
player_db, resources_summary = add_resources(filepath,player_db,time_spent)
await ctx.send(xp_summary)
await ctx.send(resources_summary)
player_db["status"]["current_activity"] = "idle"
save_to_db(filepath,player_db)
async def claim(filepath, player_db):
if time.time() - player_db["status"]["last_claimed"] >= 86400:
player_db = add_currency(filepath, 100)
player_db["status"]["last_claimed"] = time.time()
save_to_db(filepath,player_db)
await ctx.send("You claimed 100 sparks!")
else:
await ctx.send("Sorry, you already claimed your sparks today.")
async def mine(filepath, player_db):
if player_db["status"]["current_activity"] == "idle":
player_db["status"]["current_activity"] = "mining"
player_db["status"]["start_time"] = time.time()
save_to_db(filepath, player_db)
await ctx.send("You start mining.")
elif player_db["status"]["current_activity"] == "mining":
await ctx.send("You are already mining!")
else:
await ctx.send("You must stop " + player_db["status"]["current_activity"] + " before you start mining!")
async def gamble(filepath, player_db):
pass
working_dir = "databases/currency/"
2023-07-09 00:57:11 -07:00
players_dir = "players/"
sender_id = str(ctx.author.id)
default_db = read_db("{0}{1}default.json".format(working_dir, players_dir))
filepath = '{0}{1}{2}.json'.format(working_dir, players_dir, sender_id)
try:
player_db = read_db(filepath)
except FileNotFoundError:
save_to_db(filepath,default_db)
player_db = read_db(filepath)
if arg1 == "claim":
await claim(filepath, player_db)
player_db = read_db(filepath)
elif arg1 == "stop":
await stop_activity(filepath, player_db)
player_db = read_db(filepath)
elif arg1 == "mine":
await mine(filepath, player_db)
player_db = read_db(filepath)
elif arg1 == "levels":
await show_levels(player_db)
elif arg1 == "items":
await show_items(player_db)
elif (arg1 == "send" or arg1 == "give") and arg2 and arg3:
await transfer_currency(filepath, player_db, arg2, arg3)
player_db = read_db(filepath)
else:
await show_currency(player_db)
@bot.command(
description="Meme",
help="Generates a meme based on input. Usage: !meme (topic)",
brief="Generate a meme"
)
2023-07-09 00:57:11 -07:00
async def meme(ctx):
2023-07-09 01:57:35 -07:00
async def update_meme_webpage(filename):
server_folder = (os.getenv('ftp_public_html') + 'ai-memes/')
new_file_name = str(time.time_ns()) + ".png"
await upload_sftp(filename, server_folder, new_file_name)
print("Uploaded", new_file_name)
with open("phixxy.com/ai-memes/index.html", 'r') as f:
html_data = f.read()
html_insert = '<!--ADD IMG HERE-->\n <img src="' + new_file_name + '" loading="lazy">'
html_data = html_data.replace('<!--ADD IMG HERE-->',html_insert)
with open("phixxy.com/ai-memes/index.html", "w") as f:
f.writelines(html_data)
await upload_sftp("phixxy.com/ai-memes/index.html", server_folder, "index.html")
2023-07-09 00:57:11 -07:00
2023-07-09 00:57:11 -07:00
async def generate_random_meme(topic):
async with bot.http_session.get('https://api.imgflip.com/get_memes') as resp:
response_data = await resp.json()
response = response_data['data']['memes']
2023-07-17 16:46:51 -07:00
memepics = [{'name':image['name'],'url':image['url'],'id':image['id']} for image in response]
2023-07-09 00:57:11 -07:00
2023-07-17 16:46:51 -07:00
#Pick a meme format
memenumber = random.randint(1,99)
meme_name = response[memenumber-1]['name']
panel_count = response[memenumber-1]['box_count']
print("panel_count ",panel_count)
panel_text = await answer_question("Create text for a meme. The meme is " + meme_name + ". It has " + str(panel_count) + " panels. Only create one meme. Do not use emojis or hashtags! Use the topic: " + topic + ". Use the output format (DO NOT USE EXTRA NEWLINES AND DO NOT DESCRIBE THE PICTURE IN YOUR OUTPUT): \n1: [panel 1 text]\n2: [panel 2 text]")
2023-07-09 00:57:11 -07:00
id = memenumber
2024-01-04 09:21:49 -08:00
imgflip_username = os.getenv('imgflip_username')
imgflip_password = os.getenv('imgflip_password')
2023-07-09 00:57:11 -07:00
params = {
2024-01-04 09:21:49 -08:00
'username':imgflip_username,
'password':imgflip_password,
2023-07-17 16:46:51 -07:00
'template_id':memepics[id-1]['id']
2023-07-09 00:57:11 -07:00
}
2023-07-17 16:46:51 -07:00
boxes = []
text = panel_text.split('\n')
for x in range(len(text)):
if text[x].strip() != "":
item = text[x][3:]
if len(params)-3 < panel_count:
dictionary = {"text":item, "color": "#ffffff", "outline_color": "#000000"}
boxes.append(dictionary)
for i, box in enumerate(boxes):
params[f"boxes[{i}][text]"] = box["text"]
params[f"boxes[{i}][color]"] = box["color"]
params[f"boxes[{i}][outline_color]"] = box["outline_color"]
URL = 'https://api.imgflip.com/caption_image'
2023-07-09 00:57:11 -07:00
try:
async with bot.http_session.post(URL, params=params) as resp:
response = await resp.json()
2023-07-09 00:57:11 -07:00
print(f"Generated Meme = {response['success']}\nImage Link = {response['data']['url']}\nPage Link = {response['data']['page_url']}")
image_link = response['data']['url']
2023-07-11 17:04:28 -07:00
except Exception as error:
await handle_error(error)
2023-07-09 00:57:11 -07:00
try:
2023-07-25 17:22:03 -07:00
#------------------------------------Saving Image Using Aiohttp---------------------------------#
2023-07-09 00:57:11 -07:00
filename = memepics[id-1]['name']
async with bot.http_session.get(image_link) as response:
folder = "tmp/"
filename = folder + topic + str(len(os.listdir(folder))) + ".jpg"
with open(filename, "wb") as file:
while True:
chunk = await response.content.read(1024) # Read the response in chunks
if not chunk:
break
file.write(chunk)
2023-07-11 17:04:28 -07:00
except Exception as error:
await handle_error(error)
2023-07-09 00:57:11 -07:00
print("Something's Wrong with the urllib So try again")
return image_link, filename
try:
topic = ctx.message.content.split(" ", maxsplit=1)[1]
link, filepath = await generate_random_meme(topic)
channel_vars = await get_channel_config(ctx.channel.id)
try:
if channel_vars["ftp_enabled"]:
2023-07-09 01:57:35 -07:00
await update_meme_webpage(filepath)
2023-07-09 00:57:11 -07:00
except Exception as error:
print("COULDN'T UPLOAD TO FTP!")
2023-07-11 17:04:28 -07:00
await handle_error(error)
2023-07-09 00:57:11 -07:00
await ctx.send(link)
except Exception as error:
2023-07-11 17:04:28 -07:00
await handle_error(error)
2023-07-09 00:57:11 -07:00
await ctx.send('Something went wrong try again. Usage: !meme (topic)')
2023-07-25 17:35:43 -07:00
@bot.command(
description="Errors",
help="Shows the last errors that were logged.",
brief="Display Errors"
)
async def errors(ctx, amount="5"):
output = ""
amount = int(amount)
try:
with open("databases/error_log.txt", 'r') as f:
for line in (f.readlines() [-amount:]):
output += line
await ctx.send(output)
except Exception as error:
await handle_error(error)
@bot.command(
description="RSGP",
help="Uses probably outdated information to calculate how much rsgp is worth in usd. Usage: !rsgp (amount)",
brief="Runescape gold to usd"
)
2023-07-09 00:57:11 -07:00
async def rsgp(ctx, amount):
2023-07-19 23:04:05 -07:00
output = ""
cost_per_bil = 25.50 #1b rsgp to usd
cost_per_bil_os = 210
gold_per_bond = 70000000
gold_per_bond_os = 7000000
cost_per_bond = 8 #dollars usd
bondcost = (int(amount)/gold_per_bond) * cost_per_bond
rwtcost = (int(amount) * cost_per_bil / 1000000000)
dollar_gp = (int(amount)*1000000000)/cost_per_bil
osbondcost = (int(amount)/gold_per_bond_os) * cost_per_bond
osrwtcost = (int(amount) * cost_per_bil_os / 1000000000)
osdollar_gp = (int(amount)*1000000000)/cost_per_bil_os
2023-07-19 23:16:20 -07:00
output += str(amount) + ' rs3 gp would cost: $' + str(round(rwtcost,2)) + " (RWT)\n"
output += str(amount) + ' osrs gp would cost: $' + str(round(osrwtcost,2)) + " (RWT)\n"
2023-07-19 23:16:20 -07:00
output += str(amount) + ' rs3 gp would cost: $' + str(round(bondcost,2)) + " (Bonds)\n"
output += str(amount) + ' osrs gp would cost: $' + str(round(osbondcost,2)) + " (Bonds)\n"
2023-07-19 23:16:20 -07:00
output += str(amount) + ' dollars spent on rs3 gp would be: ' + str(round(dollar_gp,2)) + " (RS3 GP)\n"
output += str(amount) + ' dollars spent on osrs gp would be: ' + str(round(osdollar_gp,2)) + " (OSRS GP)\n"
2023-07-09 00:57:11 -07:00
await ctx.send(output)
2023-07-10 17:17:28 -07:00
@bot.command(
description="Blog",
help="Adds your topic to the list of possible future blog topics. Usage: !suggest_blog (topic)",
brief="Suggest a blog topic"
)
async def blog(ctx, *args):
2023-07-10 17:17:28 -07:00
message = ' '.join(args)
if '\n' in message:
await ctx.send("Send only one topic at a time.")
return
else:
blogpost_file = "databases/blog_topics.txt"
with open(blogpost_file, 'a') as f:
2023-07-17 23:47:00 -07:00
f.writelines(message+'\n')
await ctx.send("Saved suggestion!")
@bot.command(
description="Negative Prompt",
help="Changes the negative prompt for imagine across all channels",
brief="Change the negative prompt for imagine"
)
async def negative_prompt(ctx, *args):
message = ' '.join(args)
2023-09-18 23:48:27 -07:00
if not message:
message = "easynegative, badhandv4, verybadimagenegative_v1.3"
neg_prompt_file = "databases/negative_prompt.txt"
with open(neg_prompt_file, 'w') as f:
f.writelines(message)
await ctx.send("Changed negative prompt to " + message)
2023-07-09 00:57:11 -07:00
2023-07-17 23:33:58 -07:00
@bot.command()
async def generate_blog(ctx):
2023-07-09 00:57:11 -07:00
start_time = time.time()
2023-07-10 17:08:39 -07:00
topic = ''
2023-07-09 16:30:06 -07:00
filename = "phixxy.com/ai-blog/index.html"
2023-07-09 00:57:11 -07:00
with open(filename, 'r', encoding="utf-8") as f:
html_data = f.read()
current_time = time.time()
current_struct_time = time.localtime(current_time)
date = time.strftime("%B %d, %Y", current_struct_time)
if date in html_data:
await ctx.send("I already wrote a blog post today!")
return
2023-07-10 17:08:39 -07:00
blogpost_file = "databases/blog_topics.txt"
#blog_subscribers = ["276197608735637505","242018983241318410"]
2023-07-10 17:08:39 -07:00
if os.path.isfile(blogpost_file):
with open(blogpost_file, 'r') as f:
blogpost_topics = f.read()
2023-07-11 11:54:40 -07:00
f.seek(0)
topic = f.readline()
2023-07-13 22:23:17 -07:00
blogpost_topics = blogpost_topics.replace(topic, '')
with open(blogpost_file, 'w') as f:
2023-07-10 17:08:39 -07:00
f.write(blogpost_topics)
if topic != '':
await ctx.send("Writing blogpost")
else:
await ctx.send("No topic given for blogpost, generating one.")
2023-07-12 02:55:31 -07:00
topic = await answer_question("Give me one topic for an absurd blogpost.")
2023-07-09 00:57:11 -07:00
post_div = '''<!--replace this with a post-->
<div class="post">
<h2 class="post-title"><!--POST_TITLE--></h2>
<p class="post-date"><!--POST_DATE--></p>
<div class="post-content">
<!--POST_CONTENT-->
</div>
</div>'''
title_prompt = 'generate an absurd essay title about ' + topic
title = await answer_question(title_prompt, model="gpt-3.5-turbo")
prompt = 'Write a satirical essay with a serious tone titled: "' + title + '". Do not label parts of the essay.'
content = await answer_question(prompt, model="gpt-4")
if title in content[:len(title)]:
content = content.replace(title, '', 1)
content = f"<p>{content}</p>"
content = content.replace('\n\n', "</p><p>")
content = content.replace("<p></p>", '')
post_div = post_div.replace("<!--POST_TITLE-->", title)
post_div = post_div.replace("<!--POST_DATE-->", date)
post_div = post_div.replace("<!--POST_CONTENT-->", content)
html_data = html_data.replace("<!--replace this with a post-->", post_div)
with open(filename, 'w', encoding="utf-8") as f:
f.write(html_data)
await upload_sftp(filename, (os.getenv('ftp_public_html') + 'ai-blog/'), "index.html")
2023-07-09 00:57:11 -07:00
run_time = time.time() - start_time
print("It took " + str(run_time) + " seconds to generate the blog post!")
2023-12-27 22:58:58 -08:00
output = "Blog Updated! (" + str(run_time) + " seconds) https://ai.phixxy.com/ai-blog"
#output += '\nNotifying subscribers: '
#for subscriber in blog_subscribers:
# output += '<@' + subscriber + '> '
2023-07-10 10:38:28 -07:00
await ctx.send(output)
2023-07-09 00:57:11 -07:00
@bot.command(
description="Question",
help="Ask a raw chatgpt question. Usage: !question (question)",
brief="Get an answer"
)
2023-07-09 00:57:11 -07:00
async def question(ctx):
question = ctx.message.content.split(" ", maxsplit=1)[1]
answer = await answer_question(question)
chunks = [answer[i:i+1999] for i in range(0, len(answer), 1999)]
for chunk in chunks:
await ctx.send(chunk)
@bot.command(
description="Question GPT4",
help="Ask GPT4 a question. Usage: !question_gpt4 (question)",
brief="Get an answer"
)
2023-07-09 00:57:11 -07:00
async def question_gpt4(ctx):
question = ctx.message.content.split(" ", maxsplit=1)[1]
answer = await answer_question(question, "gpt-4-vision-preview")
chunks = [answer[i:i+1999] for i in range(0, len(answer), 1999)]
for chunk in chunks:
await ctx.send(chunk)
@bot.command(
description="Image GPT4",
help="Ask GPT4 a question about an image. Usage: !question_gpt4 (link) (question)",
brief="Get an answer"
)
async def looker(ctx):
image_link = ctx.message.content.split(" ", maxsplit=2)[1]
question = ctx.message.content.split(" ", maxsplit=2)[2]
headers = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {os.getenv("openai.api_key")}',
}
data = {
"model": "gpt-4-vision-preview",
"messages": [{"role": "user", "content": [{"type": "text", "text": question},{"type": "image_url","image_url": {"url": image_link}}]}],
"max_tokens": 500
}
url = "https://api.openai.com/v1/chat/completions"
try:
async with bot.http_session.post(url, headers=headers, json=data) as resp:
response_data = await resp.json()
print(response_data)
answer = response_data['choices'][0]['message']['content']
except Exception as error:
return await handle_error(error)
2023-07-09 00:57:11 -07:00
chunks = [answer[i:i+1999] for i in range(0, len(answer), 1999)]
for chunk in chunks:
await ctx.send(chunk)
@bot.command(
description="Highscores",
help="Shows a bar graph of users in this channel and how many messages they have sent.",
brief="Display chat highscores"
)
2023-07-09 00:57:11 -07:00
async def highscores(ctx, limit=0):
filename = str(ctx.channel.id) + ".log"
2023-07-09 16:06:45 -07:00
with open("channels/logs/" + filename, 'r', encoding="utf-8") as logfile:
2023-07-09 00:57:11 -07:00
data = logfile.readlines()
logfile.close()
def is_username(user):
for character in user:
if character.isupper():
return False
if not (character.isalpha() or character.isdigit() or character == '.' or character == '_'):
return False
return True
user_message_counts = {}
for line in data:
try:
user = line[0:line.find(':')]
if is_username(user):
if user not in user_message_counts and user != "" and len(user) <= 32:
user_message_counts[user] = 1
else:
user_message_counts[user] += 1
2023-07-11 17:04:28 -07:00
except Exception as error:
await handle_error(error)
2023-07-09 00:57:11 -07:00
def remove_dict_keys_if_less_than_x(dictionary,x):
for key in dictionary:
if dictionary[key] <= x:
dictionary.pop(key)
return remove_dict_keys_if_less_than_x(dictionary,x)
return dictionary
print(user_message_counts)
remove_dict_keys_if_less_than_x(user_message_counts,limit)
keys = list(user_message_counts.keys())
values = list(user_message_counts.values())
fig, ax = plt.subplots()
bar_container = ax.barh(keys, values)
ax.set_xlabel("Message Count")
ax.set_ylabel("Username")
ax.set_title("Messages Sent in " + ctx.channel.name)
ax.bar_label(bar_container, label_type='center')
plt.savefig(str(ctx.channel.id) + '_hiscores.png', dpi=1000, bbox_inches="tight")
with open(str(ctx.channel.id) + '_hiscores.png', "rb") as fh:
f = discord.File(fh, filename=str(ctx.channel.id) + '_hiscores.png')
await ctx.send(file=f)
@bot.command(
description="Highscores Server",
help="Shows a bar graph of users across all servers I am in and how many messages they have sent.",
brief="Display chat highscores"
)
2023-07-09 00:57:11 -07:00
async def highscores_server(ctx, limit=0):
user_message_counts = {}
data = []
2023-07-09 16:06:45 -07:00
for filename in os.listdir("channels/logs/"):
with open("channels/logs/" + filename, 'r', encoding="utf-8") as logfile:
2023-07-09 00:57:11 -07:00
data += logfile.readlines()
logfile.close()
def is_username(user):
for character in user:
if character.isupper():
return False
if not (character.isalpha() or character.isdigit() or character == '.' or character == '_'):
return False
return True
user_message_counts = {}
for line in data:
try:
user = line[0:line.find(':')]
if is_username(user):
if user not in user_message_counts and user != "" and len(user) <= 32:
user_message_counts[user] = 1
else:
user_message_counts[user] += 1
2023-07-11 17:04:28 -07:00
except Exception as error:
await handle_error(error)
2023-07-09 00:57:11 -07:00
def remove_dict_keys_if_less_than_x(dictionary,x):
for key in dictionary:
if dictionary[key] <= x:
dictionary.pop(key)
return remove_dict_keys_if_less_than_x(dictionary,x)
return dictionary
print(user_message_counts)
print("printed")
user_message_counts = remove_dict_keys_if_less_than_x(user_message_counts,limit)
keys = list(user_message_counts.keys())
values = list(user_message_counts.values())
fig, ax = plt.subplots()
bar_container = ax.barh(keys, values)
ax.set_xlabel("Message Count")
ax.set_ylabel("Username")
ax.set_title("Messages Sent in all channels I can see")
ax.bar_label(bar_container, label_type='center')
plt.savefig(str(ctx.channel.id) + '_hiscores.png', dpi=1000, bbox_inches="tight")
with open(str(ctx.channel.id) + '_hiscores.png', "rb") as fh:
f = discord.File(fh, filename=str(ctx.channel.id) + '_hiscores.png')
await ctx.send(file=f)
@bot.command(
description="Website",
help="Generates a website using gpt 3.5. Usage: !website (topic)",
brief="Generate a website"
)
2023-07-09 00:57:11 -07:00
async def website(ctx):
async def delete_local_pngs(local_folder):
for filename in os.listdir(local_folder):
if ".png" in filename:
os.remove(local_folder + filename)
2023-12-27 22:58:58 -08:00
async def delete_ftp_pngs(server_folder):
async with asyncssh.connect(ftp_server, username=ftp_username, password=ftp_password) as conn:
async with conn.start_sftp_client() as sftp:
for filename in (await sftp.listdir(server_folder)):
2023-12-27 23:10:14 -08:00
if '.png' in filename:
try:
print("Deleting", filename)
await sftp.remove(server_folder+filename)
except:
print("Couldn't delete", filename)
async def extract_image_tags(code):
count = code.count("<img")
tags = []
for x in range(0,count):
index1 = code.find("<img")
index2 = code[index1:].find(">") + index1 + 1
img_tag = code[index1:index2]
tags.append(img_tag)
code = code[index2:]
return tags
async def extract_image_alt_text(tags):
alt_texts = []
for tag in tags:
index1 = tag.find("alt") + 5
index2 = tag[index1:].find("\"") + index1
alt_text = tag[index1:index2]
alt_texts.append(alt_text)
return alt_texts
async def generate_images(local_folder, image_list):
2023-07-13 01:10:28 -07:00
url = os.getenv('stablediffusion_url')
2023-07-13 01:24:27 -07:00
if url == "disabled":
return
file_list = []
for image in image_list:
filename = image.replace(" ", "").lower() + ".png"
payload = {"prompt": image, "steps": 25}
response = await bot.http_session.post(url=f'{url}/sdapi/v1/txt2img', json=payload)
r = await response.json()
for i in r['images']:
image = Image.open(io.BytesIO(base64.b64decode(i.split(",", 1)[0])))
png_payload = {"image": "data:image/png;base64," + i}
response2 = await bot.http_session.post(url=f'{url}/sdapi/v1/png-info', json=png_payload)
pnginfo = PngImagePlugin.PngInfo()
json_response = await response2.json()
pnginfo.add_text("parameters", json_response.get("info"))
image.save(local_folder + filename, pnginfo=pnginfo)
file_list.append(filename)
return file_list
async def add_image_filenames(code, file_list):
for filename in file_list:
code = code.replace("src=\"\"", "src=\""+ filename + "\"", 1)
return code
async def upload_html_and_imgs(local_folder, server_folder):
for filename in os.listdir(local_folder):
if ".png" in filename:
await upload_sftp(local_folder + filename, (os.getenv('ftp_public_html') + 'ai-webpage/'), filename)
#explicitly upload html files last!
for filename in os.listdir(local_folder):
if ".html" in filename:
await upload_sftp(local_folder + filename, (os.getenv('ftp_public_html') + 'ai-webpage/'), filename)
server_folder = ftp_public_html + 'ai-webpage/'
server_archive_folder = ftp_public_html + "webpage-archive/"
local_archive_folder = "websites/"
2023-07-09 16:06:45 -07:00
local_folder = "tmp/webpage/"
working_file = local_folder + "index.html"
2023-07-09 16:06:45 -07:00
if not os.path.exists(local_folder):
os.mkdir(local_folder)
2023-07-09 00:57:11 -07:00
try:
2023-12-27 22:58:58 -08:00
await ctx.send("Please wait, this will take a long time! You will be able to view the website here: https://ai.phixxy.com/ai-webpage/")
with open(working_file, "w") as f:
2023-07-09 00:57:11 -07:00
f.write("<!DOCTYPE html><html><head><script>setTimeout(function(){location.reload();}, 10000);</script><title>Generating Website</title><style>body {font-size: 24px;text-align: center;margin-top: 100px;}</style></head><body><p>This webpage is currently being generated. The page will refresh once it is complete. Please be patient.</p></body></html>")
await upload_sftp(working_file, server_folder, "index.html")
2023-07-09 00:57:11 -07:00
topic = ctx.message.content.split(" ", maxsplit=1)[1]
prompt = "Generate a webpage using html and inline css. The webpage topic should be " + topic + ". Feel free to add image tags with alt text. Leave the image source blank. The images will be added later."
code = await answer_question(prompt)
await delete_local_pngs(local_folder)
await delete_ftp_pngs(server_folder)
tags = await extract_image_tags(code)
alt_texts = await extract_image_alt_text(tags)
file_list = await generate_images(local_folder, alt_texts)
code = await add_image_filenames(code, file_list)
with open(working_file, 'w') as f:
f.write(code)
f.close()
await upload_html_and_imgs(local_folder, server_folder)
2023-12-27 22:58:58 -08:00
await ctx.send("Finished https://ai.phixxy.com/ai-webpage/")
except Exception as error:
2023-07-11 17:04:28 -07:00
await handle_error(error)
2023-07-09 00:57:11 -07:00
await ctx.send("Failed, Try again.")
@bot.command(
description="Feature",
help="Suggest a feature. Usage: !feature (feature)",
brief="Suggest a feature"
)
2023-07-09 00:57:11 -07:00
async def feature(ctx):
try:
feature = ctx.message.content.split(" ", maxsplit=1)[1]
with open("features.txt",'a') as f:
f.writelines('\n' + feature)
await ctx.send("Added " + feature)
except Exception as error:
2023-07-11 17:04:28 -07:00
await handle_error(error)
2023-07-09 00:57:11 -07:00
with open("features.txt",'r') as f:
features = f.read()
await ctx.send(features)
@bot.command(
description="Draw",
help="Generates a picture using stable diffusion and gpt 3.5. It generates a list of 10 random artistic words and feeds them into stable diffusion. Usage: !draw (amount of pictures)",
brief="Generate a random image"
)
async def draw(ctx):
2023-07-13 01:10:28 -07:00
url = os.getenv('stablediffusion_url')
2023-07-13 01:24:27 -07:00
if url == "disabled":
return
2023-07-09 00:57:11 -07:00
try:
if " " in ctx.message.content:
amount = ctx.message.content.split(" ", maxsplit=1)[1]
if int(amount) > 4:
await ctx.send("No, that's too many.")
return
else:
amount = 1
await ctx.send("Please be patient this may take some time!")
2023-07-18 11:10:08 -07:00
choice1 = "Give me 11 keywords I can use to generate art using AI. They should all be related to one piece of art. Please only respond with the keywords and no other text. Be sure to use keywords that really describe what the art portrays. Keywords should be comma separated with no other text!"
2023-07-19 22:52:03 -07:00
choice2 = "Describe a creative scene, use only one sentence"
2023-07-18 11:10:08 -07:00
choice3 = "Give me comma seperated keywords describing an imaginary piece of art. Only return the keywords and no other text."
2023-07-20 19:37:38 -07:00
choice4 = "Describe a unique character and an environment in one sentence"
choice5 = "Describe a nonhuman character and an environment in one sentence"
prompt = random.choice([choice1,choice2,choice3,choice4,choice5])
2023-07-13 23:39:51 -07:00
prompt = await answer_question(prompt)
2023-07-18 11:10:08 -07:00
if random.randint(0,9):
prompt = prompt.replace("abstract, ", "")
2023-07-09 00:57:11 -07:00
prompt = prompt.replace("AI, ", "")
if "." in prompt:
prompt = prompt.replace(".",",")
prompt = prompt + " masterpiece, studio quality"
else:
prompt = prompt + ", masterpiece, studio quality"
2023-07-18 22:31:38 -07:00
negative_prompt = "easynegative verybadimagenegative_v1.3"
2023-07-09 00:57:11 -07:00
payload = {"prompt": prompt,"steps": 25, "negative_prompt": negative_prompt,"batch_size": amount}
try:
async with bot.http_session.post(url=f'{url}/sdapi/v1/txt2img', json=payload) as resp:
r = await resp.json()
2023-07-09 00:57:11 -07:00
for i in r['images']:
image = Image.open(io.BytesIO(base64.b64decode(i.split(",",1)[0])))
png_payload = {"image": "data:image/png;base64," + i}
async with bot.http_session.post(url=f'{url}/sdapi/v1/png-info', json=png_payload) as resp2:
response2 = await resp2.json()
2023-07-09 00:57:11 -07:00
pnginfo = PngImagePlugin.PngInfo()
2023-07-13 23:30:15 -07:00
pnginfo.add_text("parameters", response2.get("info"))
2023-07-13 01:20:41 -07:00
my_filename = "tmp/" + str(len(os.listdir("tmp/"))) + ".png"
2023-07-09 00:57:11 -07:00
image.save(my_filename, pnginfo=pnginfo)
channel_vars = await get_channel_config(ctx.channel.id)
if channel_vars["ftp_enabled"]:
await upload_ftp_ai_images(my_filename, prompt)
with open(my_filename, "rb") as fh:
f = discord.File(fh, filename=my_filename)
await ctx.send(file=f)
await ctx.send(prompt)
except Exception as error:
2023-07-11 17:04:28 -07:00
await handle_error(error)
2023-07-09 00:57:11 -07:00
await ctx.send("My image generation service may not be running.")
except Exception as error:
2023-07-11 17:04:28 -07:00
await handle_error(error)
2023-07-09 00:57:11 -07:00
await ctx.send('Did you mean to use !imagine?. Usage: !draw (number)')
@bot.command(
description="Chat",
help="Enable or disable bot chat in this channel. Usage !chat (enable|disable)",
brief="Enable or disable bot chat"
)
2023-07-09 00:57:11 -07:00
async def chat(ctx, message):
if "enable" in message:
edit_channel_config(ctx.channel.id, "chat_enabled", True)
await ctx.send("Chat Enabled")
elif "disable" in message:
edit_channel_config(ctx.channel.id, "chat_enabled", False)
await ctx.send("Chat Disabled")
else:
await ctx.send("Usage: !chat (enable|disable)")
@bot.command(
description="Reactions",
help="Enable or disable bot reactions in this channel. Usage !reactions (enable|disable)",
brief="Enable or disable bot reactions"
)
2023-07-09 00:57:11 -07:00
async def reactions(ctx, message):
if "enable" in message:
edit_channel_config(ctx.channel.id, "react_to_msgs", True)
await ctx.send("Reactions Enabled")
elif "disable" in message:
edit_channel_config(ctx.channel.id, "react_to_msgs", False)
await ctx.send("Reactions Disabled")
else:
await ctx.send("Usage: !reactions (enable|disable)")
@bot.command(
description="View Images",
help="Enable or disable bot viewing images in this channel. Usage !viewimages (enable|disable)",
brief="Enable or disable bot viewing images"
)
2023-07-09 00:57:11 -07:00
async def viewimages(ctx, message):
if "enable" in message:
edit_channel_config(ctx.channel.id, "look_at_images", True)
await ctx.send("Viewing Enabled")
elif "disable" in message:
edit_channel_config(ctx.channel.id, "look_at_images", False)
await ctx.send("Viewing Disabled")
else:
await ctx.send("Usage: !viewimages (enable|disable)")
@bot.command(
description="Commands",
help="Enable or disable bot commands in this channel. Usage !enable_commands (enable|disable)",
brief="Enable or disable bot commands"
)
2023-07-09 16:30:06 -07:00
async def enable_commands(ctx, message):
if "disable" in message or "false" in message:
2023-07-09 00:57:11 -07:00
edit_channel_config(ctx.channel.id, "commands_enabled", False)
await ctx.send("Commands Disabled")
else:
2023-07-09 16:30:06 -07:00
edit_channel_config(ctx.channel.id, "commands_enabled", True)
await ctx.send("Commands Enabled")
2023-07-09 00:57:11 -07:00
@bot.command(
description="Topic",
help="Set the channel topic for the bot. Usage: !topic (topic)",
brief="Set channel topic"
)
2023-07-09 00:57:11 -07:00
async def topic(ctx, channel_topic):
edit_channel_config(ctx.channel.id, "channel_topic", channel_topic)
await ctx.send("Topic changed to " + channel_topic)
'''@bot.command(
description="Python",
help="Run some python code. Imports are disabled but random is imported for you. Usage !python (codeblock)",
brief="Run some python code"
)
2023-07-09 00:57:11 -07:00
async def python(ctx):
try:
code = ctx.message.content
print(code.find("```"),code.rfind("```"))
code = code[code.find("```")+3:code.rfind("```")] #Finds the code in codeblocks
if "import" in code:
await ctx.send("Imports not allowed")
return 0
if "```" in code:
code = code.replace("```", "")
code = "import random\nimport math\n" + code
if len(code) == 0:
await ctx.send('Please provide some code to run')
else:
2023-07-09 16:06:45 -07:00
folder_path = "tmp/python_temp_scripts/"
2023-07-09 00:57:11 -07:00
if not os.path.exists(folder_path):
os.makedirs(folder_path)
2023-07-09 16:06:45 -07:00
unique_num = str(len(os.listdir(folder_path)))
filename = f"{folder_path}{unique_num}.py"
2023-07-09 00:57:11 -07:00
with open(filename, "w") as f:
f.write(code)
try:
try:
response = subprocess.run(["python", filename], timeout=10, capture_output=True, check=True)
except subprocess.TimeoutExpired:
await ctx.send("Code took too long to run!")
return 0
print("response", response.stdout.decode('utf-8'))
if response.stdout.decode('utf-8') == "":
await ctx.send("No Output")
return 0
await ctx.send(response.stdout.decode('utf-8'))
except subprocess.CalledProcessError as error:
await ctx.send(error.stderr.decode('utf-8'))
except Exception as error:
2023-07-11 17:04:28 -07:00
await handle_error(error)
await ctx.send("Usage: !python (codeblock)")'''
2023-07-09 00:57:11 -07:00
@bot.command(
description="FTP",
help="Enable or disable bot FTP to phixxy.com in this channel. Usage !ftp (enable|disable)",
brief="Enable or disable uploading to web"
)
2023-07-09 00:57:11 -07:00
async def ftp(ctx, message):
if "enable" in message:
edit_channel_config(ctx.channel.id, "ftp_enabled", True)
await ctx.send("FTP Enabled")
elif "disable" in message:
edit_channel_config(ctx.channel.id, "ftp_enabled", False)
await ctx.send("FTP Disabled")
else:
await ctx.send("Usage: !ftp (enable|disable)")
@bot.command(
description="Personality",
help="Set the personality of the bot. Usage: !personality (personality)",
brief="Set the personality"
)
2023-07-09 00:57:11 -07:00
async def personality(ctx):
personality_type = ctx.message.content.split(" ", maxsplit=1)[1]
edit_channel_config(ctx.channel.id, "personality", personality_type)
await ctx.send("Personality changed to " + personality_type)
2023-11-01 10:00:17 -07:00
2024-01-03 08:44:00 -08:00
'''@bot.command(
2023-11-01 10:00:17 -07:00
description="Secret Santa Register",
help="Register for secret santa!",
brief="Register for secret santa!"
)
async def ss_register(ctx):
try:
email = ctx.message.content.split(" ", maxsplit=1)[1]
print(ctx.author.name, email)
with open("santa.txt", 'a') as f:
f.writelines(ctx.author.name + ';' + email + ',')
await ctx.send(ctx.author.name + " registered for secret santa!")
except:
2024-01-03 08:44:00 -08:00
await ctx.send("Usage: !ss_register (email address)")'''
2023-07-09 00:57:11 -07:00
@bot.command(
description="Change Model",
help="Choose from a list of stable diffusion models.",
brief="Change stable diffusion model"
)
2023-07-09 00:57:11 -07:00
async def change_model(ctx, model_choice='0'):
2023-07-13 17:29:40 -07:00
model_choices = {
'1': ("deliberate_v2.safetensors [9aba26abdf]", "DeliberateV2"),
2023-07-18 04:07:13 -07:00
'2': ("flat2DAnimerge_v30.safetensors [5dd56bfa12]", "Flat2D"),
'3': ("Anything-V3.0.ckpt [8712e20a5d]", "AnythingV3"),
2023-07-24 03:07:48 -07:00
'4': ("aZovyaPhotoreal_v2.safetensors [dde3b17c05]", "PhotorealV2"),
2023-07-24 03:20:19 -07:00
'5': ("Pixel_Art_V1_PublicPrompts.ckpt [0f02127697]", "Pixel Art"),
'6': ("mistoonAnime_v20.safetensors [c35e1054c0]", "Mistoon AnimeV2")
2023-07-13 17:29:40 -07:00
}
2023-07-13 01:10:28 -07:00
url = os.getenv('stablediffusion_url')
2023-07-13 01:24:27 -07:00
if url == "disabled":
2023-07-13 17:29:40 -07:00
await ctx.send("This command is currently disabled")
2023-07-13 01:24:27 -07:00
return
2023-07-09 00:57:11 -07:00
async with bot.http_session.get(url=f'{url}/sdapi/v1/options') as response:
config_json = await response.json()
2023-07-13 17:29:40 -07:00
current_model = config_json["sd_model_checkpoint"]
output = 'Current Model: ' + current_model + '\n'
if model_choice in model_choices:
model_id, model_name = model_choices[model_choice]
if current_model != model_id:
payload = {"sd_model_checkpoint": model_id}
async with bot.http_session.post(url=f'{url}/sdapi/v1/options', json=payload) as response:
output = "Changed model to: " + model_name
await ctx.send(output)
return
2023-07-09 00:57:11 -07:00
else:
2023-07-13 17:29:40 -07:00
await ctx.send(f"Already set to use {model_name}")
2023-07-09 00:57:11 -07:00
return
else:
2024-01-04 09:43:48 -08:00
output = '\n'.join([f"{choice}: {name}" for choice, name in model_choices.items()])
2023-07-09 00:57:11 -07:00
await ctx.send(output)
2023-10-05 00:57:26 -07:00
@bot.command(
description="Lora",
help="List the stable diffusion loras.",
brief="List the stable diffusion loras"
)
async def lora(ctx):
lora_choices = {
'0': ("Lora Name", "Trigger Words"),
'1': ("<lora:rebecca:1>", "rebecca (cyberpunk)"),
'2': ("<lora:lucy:1>", "lucy (cyberpunk)"),
'3': ("<lora:dirty:1>", "dirty"),
'4': ("<lora:starcraft:1>", "c0nst3llation")
}
output = ""
lora_options = '\n'.join([f"{choice}: {name}" for choice, name in lora_choices.items()])
output += lora_options
await ctx.send(output)
@bot.command(
description="Imagine",
help="Generate an image using stable diffusion. You can add keyword arguments to your prompt and they will be treated as stable diffusion options. Usage !imagine (topic)",
brief="Generate an image"
)
2023-07-09 00:57:11 -07:00
async def imagine(ctx):
2023-07-13 01:10:28 -07:00
url = os.getenv('stablediffusion_url')
2023-07-13 01:24:27 -07:00
if url == "disabled":
await ctx.send("Command is currently disabled.")
return
else:
url=f"{url}/sdapi/v1/txt2img"
2023-07-09 00:57:11 -07:00
prompt = ctx.message.content.split(" ", maxsplit=1)[1]
key_value_pairs, prompt = extract_key_value_pairs(prompt)
#negative_prompt = ""
neg_prompt_file = "databases/negative_prompt.txt"
with open(neg_prompt_file, 'r') as f:
negative_prompt = f.readline()
2023-07-09 00:57:11 -07:00
await ctx.send("Please be patient this may take some time! Generating: " + prompt + ".")
payload = {
"prompt": prompt,
"steps": 25,
"negative_prompt": negative_prompt
}
headers = {
'Content-Type': 'application/json'
}
payload.update(key_value_pairs)
2023-07-09 00:57:11 -07:00
try:
async with bot.http_session.post(url, headers=headers, json=payload) as resp:
r = await resp.json()
2023-07-11 17:04:28 -07:00
except Exception as error:
2023-07-16 16:40:49 -07:00
await ctx.send("My image generation service may not be running.")
2023-07-11 17:04:28 -07:00
await handle_error(error)
for i in r['images']:
if not os.path.isdir("users/" + str(ctx.author.id)):
os.makedirs("users/" + str(ctx.author.id))
image = Image.open(io.BytesIO(base64.b64decode(i.split(",", 1)[0])))
png_payload = {"image": "data:image/png;base64," + i}
try:
async with bot.http_session.post(url, json=png_payload) as resp:
response2 = await resp.json()
except Exception as error:
2023-07-16 16:40:49 -07:00
await ctx.send("My image generation service may not be running.")
await handle_error(error)
2023-07-13 17:29:40 -07:00
pnginfo = PngImagePlugin.PngInfo()
pnginfo.add_text("parameters", response2.get("info"))
my_filename = "users/" + str(ctx.author.id) + '/' + str(len(os.listdir("users/" + str(ctx.author.id) + '/'))) + ".png"
image.save(my_filename, pnginfo=pnginfo)
channel_vars = await get_channel_config(ctx.channel.id)
with open(my_filename, "rb") as fh:
f = discord.File(fh, filename=my_filename)
2023-12-27 22:05:14 -08:00
await ctx.send(file=f)
2023-12-27 22:05:14 -08:00
if channel_vars["ftp_enabled"]:
await upload_ftp_ai_images(my_filename, prompt)
2023-07-09 00:57:11 -07:00
@bot.command(
description="Describe",
help="Get better understanding of what the bot \"sees\" when you post an image! (Runs it through CLIP) Usage !describe (image link)",
brief="Describe image"
)
2023-07-09 00:57:11 -07:00
async def describe(ctx):
2023-07-13 01:10:28 -07:00
url = os.getenv('stablediffusion_url')
2023-07-13 01:24:27 -07:00
if url == "disabled":
await ctx.send("Command is currently disabled")
return
else:
url=f"{url}/sdapi/v1/interrogate"
2023-07-09 00:57:11 -07:00
try:
if ctx.message.content.startswith("!describe "):
file_url = ctx.message.content.split(" ", maxsplit=1)[1]
elif ctx.message.attachments:
file_url = ctx.message.attachments[0].url
else:
print("No image linked or attached.")
return
2023-07-11 17:04:28 -07:00
except Exception as error:
await handle_error(error)
2023-07-09 00:57:11 -07:00
print("Couldn't find image.")
return
2023-07-17 23:06:04 -07:00
async with bot.http_session.get(file_url) as response:
imageName = "tmp/" + str(len(os.listdir("tmp/"))) + ".png"
with open(imageName, 'wb') as out_file:
print(f"Saving image: {imageName}")
while True:
chunk = await response.content.read(1024)
if not chunk:
break
out_file.write(chunk)
2023-07-09 00:57:11 -07:00
img_link = my_open_img_file(imageName)
2023-07-09 18:02:15 -07:00
try:
payload = {"image": img_link}
async with bot.http_session.post(url, json=payload) as response:
r = await response.json()
print(r)
await ctx.send(r.get("caption"))
2023-07-11 17:04:28 -07:00
except Exception as error:
await handle_error(error)
2023-07-09 18:02:15 -07:00
await ctx.send("My image generation service may not be running.")
2023-07-09 00:57:11 -07:00
@bot.command(
description="Reimagine",
help="Reimagine an image as something else. One example is reimagining a picture as anime. This command can be hard to use. \nUsage: !reimagine (image link) (topic)\nExample: !reimagine (image link) anime",
brief="Reimagine an image"
)
2023-07-09 00:57:11 -07:00
async def reimagine(ctx):
2023-07-13 01:10:28 -07:00
url = os.getenv('stablediffusion_url')
2023-07-13 01:24:27 -07:00
if url == "disabled":
await ctx.send("Command is currently disabled")
return
try:
if ctx.message.attachments:
file_url = ctx.message.attachments[0].url
prompt = ctx.message.content.split(" ", maxsplit=1)[1]
elif ctx.message.content.startswith("!reimagine "):
file_url = ctx.message.content.split(" ", maxsplit=2)[1]
prompt = ctx.message.content.split(" ", maxsplit=2)[2]
else:
print("No image linked or attached.")
return
except Exception as error:
await handle_error(error)
print("Couldn't find image.")
return
2023-07-13 17:29:40 -07:00
2023-07-09 00:57:11 -07:00
key_value_pairs, prompt = extract_key_value_pairs(prompt)
2023-07-13 17:29:40 -07:00
2023-07-16 16:40:49 -07:00
try:
async with bot.http_session.get(file_url) as response:
imageName = "tmp/" + str(len(os.listdir("tmp/"))) + ".png"
with open(imageName, 'wb') as out_file:
print(f"Saving image: {imageName}")
while True:
chunk = await response.content.read(1024)
if not chunk:
break
out_file.write(chunk)
2023-07-16 16:40:49 -07:00
except Exception as error:
await ctx.send("My image generation service may not be running.")
await handle_error(error)
2023-07-09 00:57:11 -07:00
img_link = my_open_img_file(imageName)
2023-07-13 17:29:40 -07:00
2023-07-09 00:57:11 -07:00
#negative_prompt = ""
2023-07-13 17:29:40 -07:00
negative_prompt = "badhandsv4, worst quality, lowres, EasyNegative, hermaphrodite, cropped, not in the frame, additional faces, jpeg large artifacts, jpeg small artifacts, ugly, tiling, poorly drawn hands, poorly drawn feet, poorly drawn face, out of frame, extra limbs, disfigured, deformed, body out of frame, blurry, bad anatomy, blurred, watermark, grainy, signature, cut off, draft, not finished drawing, unfinished image, bad eyes, doll, 3d, cartoon, (bad eyes:1.2), (worst quality:1.2), (low quality:1.2), bad-image-v2-39000, (bad_prompt_version2:0.8), nude, badhandv4 By bad artist -neg easynegative ng_deepnegative_v1_75t verybadimagenegative_v1.3, (Worst Quality, Low Quality:1.4), Poorly Made Bad 3D, Lousy Bad Realistic, nsfw,(worst quality, low quality:1.4), (lip, nose, tooth, rouge, lipstick, eyeshadow:1.4), ( jpeg artifacts:1.4), (depth of field, bokeh, blurry, film grain, chromatic aberration, lens flare:1.0), (1boy, abs, muscular, rib:1.0), greyscale, monochrome, dusty sunbeams, trembling, motion lines, motion blur, emphasis lines, text, title, logo, signature, child, childlike, young, easynegative, (bad-hands-5:0.8), plain background, monochrome, poorly drawn face, poorly drawn hands, watermark, censored, (mutated hands and fingers), ugly, worst quality, low quality,, nsfw,(worst quality, low quality:1.4), (lip, nose, tooth, rouge, lipstick, eyeshadow:1.4), ( jpeg artifacts:1.4), (depth of field, bokeh, blurry, film grain, chromatic aberration, lens flare:1.0), (1boy, abs, muscular, rib:1.0), greyscale, monochrome, dusty sunbeams, trembling, motion lines, motion blur, emphasis lines, text, title, logo, signature, child, childlike, young"
2023-07-09 00:57:11 -07:00
await ctx.send("Please be patient this may take some time! Generating: " + prompt + ".")
2023-07-13 17:29:40 -07:00
payload = {"init_images": [img_link], "prompt": prompt, "steps": 40, "negative_prompt": negative_prompt, "denoising_strength": 0.5}
payload.update(key_value_pairs)
2023-07-13 17:29:40 -07:00
2023-07-16 16:40:49 -07:00
try:
async with bot.http_session.post(url=f'{url}/sdapi/v1/img2img', json=payload) as response:
data = await response.json()
for i in data['images']:
if not os.path.isdir("tmp/reimagined/"+ str(ctx.author.id)):
os.makedirs("tmp/reimagined/"+ str(ctx.author.id))
image = Image.open(io.BytesIO(base64.b64decode(i.split(",",1)[0])))
png_payload = {"image": "data:image/png;base64," + i}
async with bot.http_session.post(url=f'{url}/sdapi/v1/png-info', json=png_payload) as resp2:
response2 = await resp2.json()
pnginfo = PngImagePlugin.PngInfo()
pnginfo.add_text("parameters", response2.get("info"))
my_filename = "tmp/" + str(len(os.listdir("tmp/"))) + ".png"
image.save(my_filename, pnginfo=pnginfo)
with open(my_filename, "rb") as fh:
f = discord.File(fh, filename=my_filename)
await ctx.send(file=f)
2023-07-16 16:40:49 -07:00
except Exception as error:
await ctx.send("My image generation service may not be running.")
await handle_error(error)
2023-07-09 00:57:11 -07:00
@bot.command(
description="Poll",
help='Create a poll with up to 9 options. Usage: !poll "Put question here" "option 1" "option 2"',
brief="Enable or disable bot reactions"
)
2023-07-09 00:57:11 -07:00
async def poll(ctx, question, *options: str):
if len(options) > 9:
await ctx.send("Error: You cannot have more than 9 options")
return
embed = discord.Embed(title=question, colour=discord.Colour(0x283593))
for i, option in enumerate(options):
embed.add_field(name=f"Option {i+1}", value=option, inline=False)
message = await ctx.send(embed=embed)
numbers = {0: "\u0030\ufe0f\u20e3", 1: "\u0031\ufe0f\u20e3", 2: "\u0032\ufe0f\u20e3", 3: "\u0033\ufe0f\u20e3", 4: "\u0034\ufe0f\u20e3", 5: "\u0035\ufe0f\u20e3", 6: "\u0036\ufe0f\u20e3", 7: "\u0037\ufe0f\u20e3", 8: "\u0038\ufe0f\u20e3", 9: "\u0039\ufe0f\u20e3"}
for i in range(len(options)):
await message.add_reaction(numbers.get(i+1))
@bot.command(
description="Roll",
help="Rolls dice mostly for Dungeons and Dragons type games. Usage: !roll 3d6+2",
brief="Simulate rolling dice"
)
2023-07-09 00:57:11 -07:00
async def roll(ctx, dice_string):
dice_parts = dice_string.split('d')
num_dice = int(dice_parts[0])
if '+' in dice_parts[1]:
die_parts = dice_parts[1].split('+')
die_size = int(die_parts[0])
modifier = int(die_parts[1])
elif '-' in dice_parts[1]:
die_parts = dice_parts[1].split('-')
die_size = int(die_parts[0])
modifier = -int(die_parts[1])
else:
die_size = int(dice_parts[1])
modifier = 0
rolls = [random.randint(1, die_size) for i in range(num_dice)]
dice_str = ' + '.join([str(roll) for roll in rolls])
total = sum(rolls) + modifier
await ctx.send(f'{dice_str} + {modifier} = {total}' if modifier != 0 else f'{dice_str} = {total}')
@bot.command(
description="Pokedex",
help="Get information on pokemon",
brief="Pokedex",
hidden=False
)
async def pdex(ctx, pokemon):
url = "https://pokeapi.co/api/v2/pokemon/" + pokemon
dex_url = "https://pokeapi.co/api/v2/pokemon-species/" + pokemon
async with bot.http_session.get(url) as resp:
data = await resp.json()
name = data['name']
height = data['height']
weight = data['weight']
type1 = data['types'][0]['type']['name']
try:
type2 = data['types'][1]['type']['name']
except:
type2 = "None"
sprite = data["sprites"]["front_default"]
message = name + ' ' + str(height) + ' ' + str(weight) + ' ' + type1 + ' ' + type2 + ' ' + sprite
await ctx.send(message)
@bot.command(
description="Kill",
help="Kills the bot in event of an emergency. Only special users can do this! Usage: !kill",
2023-07-17 11:36:34 -07:00
brief="Kill the bot",
hidden=True
)
async def kill(ctx):
"Kills the bot"
2023-07-09 00:57:11 -07:00
if ctx.author.id == 242018983241318410:
exit()
else:
await ctx.channel.send("You don't have permission to do that.")
@bot.command(
description="Reset",
help="Resets the bot in event of an emergency. Only special users can do this! Usage: !reset",
2023-07-17 11:36:34 -07:00
brief="Reset the bot",
hidden=True
)
2023-07-09 00:57:11 -07:00
async def reset(ctx):
if ctx.author.id == 242018983241318410:
python = sys.executable
os.execl(python, python, *sys.argv)
else:
await ctx.channel.send("You don't have permission to do that.")
@bot.event
async def on_reaction_add(reaction, user):
if not random.randint(0,9):
message = reaction.message
emoji = reaction.emoji
await message.add_reaction(emoji)
2023-07-09 00:57:11 -07:00
@bot.event
async def on_message(ctx):
2024-01-03 08:44:00 -08:00
#log stuff
2023-07-09 16:06:45 -07:00
logfile = "channels/logs/{0}.log".format(str(ctx.channel.id))
2023-07-09 00:57:11 -07:00
channel_vars = await get_channel_config(ctx.channel.id)
chat_history_string = await log_chat_and_get_history(ctx, logfile, channel_vars)
2024-01-03 08:44:00 -08:00
#handle non-text channels (dms, etc)
if ctx.channel.type.value != 0 and ctx.author.id != 242018983241318410:
#This used to notify the user it cannot respond in this channel, but that spammed threads
return
2024-01-03 08:44:00 -08:00
await react_to_msg(ctx, channel_vars["react_to_msgs"]) #emoji reactions
2023-07-09 00:57:11 -07:00
if channel_vars["commands_enabled"] or (ctx.author.id == 242018983241318410 and ctx.content[0] == "!"):
await bot.process_commands(ctx)
if not channel_vars["commands_enabled"]:
await ctx.channel.send("This command only ran because you set it to allow to run even when commands are disabled")
if channel_vars["chat_enabled"] and not ctx.author.bot:
if ctx.content and ctx.content[0] != "!":
await chat_response(ctx, channel_vars, chat_history_string)
elif not ctx.content:
await chat_response(ctx, channel_vars, chat_history_string)
bot.run(discord_token)