import discord from discord.ext import commands from discord.utils import get import shutil import json import requests import openai import random import time import os import io import base64 import asyncio import nacl import sys import subprocess import math from PIL import Image, PngImagePlugin from dotenv import load_dotenv from ftplib import FTP import threading import matplotlib.pyplot as plt import aiohttp #config STABLE_DIFFUSION_URL = "http://127.0.0.1:7861" #env vars START load_dotenv() imgflip_username = os.getenv('imgflip_username') imgflip_password = os.getenv('imgflip_password') openai.api_key = os.getenv('openai.api_key') discord_token = os.getenv('discord_token') eleven_labs_api_key = os.getenv('eleven_labs_api_key') ftp_server = os.getenv('ftp_server') ftp_username = os.getenv('ftp_username') ftp_password = os.getenv('ftp_password') ftp_ai_images = os.getenv('ftp_ai_images') ftp_ai_memes = os.getenv('ftp_ai_memes') ftp_ai_webpage = os.getenv('ftp_ai_webpage') 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 async def upload_ftp(local_filename, server_folder, server_filename): with FTP(ftp_server) as ftp: ftp.login(ftp_username, ftp_password) ftp.cwd(ftp_public_html) ftp.cwd(server_folder) server_filename = server_filename ftp.storbinary("STOR " + server_filename, open(local_filename, "rb")) async def upload_ftp_ai_images(filename, prompt): html_file = "phixxy.com/ai-images.html" html_insert = '''
AI generated memes using chatgpt and imgflip
{content}
" content = content.replace('\n\n', "") content = content.replace("
", '') post_div = post_div.replace("", title) post_div = post_div.replace("", date) post_div = post_div.replace("", content) html_data = html_data.replace("", post_div) with open(filename, 'w', encoding="utf-8") as f: f.write(html_data) await upload_ftp(filename, "ai-blog", "index.html") run_time = time.time() - start_time print("It took " + str(run_time) + " seconds to generate the blog post!") await ctx.send("Blog Updated! https://phixxy.com/ai-blog") @bot.command() 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() async def question_gpt4(ctx): question = ctx.message.content.split(" ", maxsplit=1)[1] answer = await answer_question(question, "gpt-4") chunks = [answer[i:i+1999] for i in range(0, len(answer), 1999)] for chunk in chunks: await ctx.send(chunk) @bot.command() async def save_website(ctx): try: folder_name = ctx.message.content.split(" ", maxsplit=1)[1] try: os.makedirs("websites/" + folder_name) except FileExistsError: await ctx.send(folder_name + " already exists. Choose a new name.") return 0 for filename in os.listdir("webpage/"): if ".png" in filename or ".html" in filename: shutil.copyfile("webpage/" + filename, "websites/"+folder_name+"/"+filename) await ctx.send("Website Archived!") except Exception as error: print(error) await ctx.send("Usage !save_website (filename)") @bot.command() async def highscores(ctx, limit=0): filename = str(ctx.channel.id) + ".log" with open("logs/" + filename, 'r', encoding="utf-8") as logfile: 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 except: pass 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() async def highscores_server(ctx, limit=0): user_message_counts = {} data = [] for filename in os.listdir("logs/"): with open("logs/" + filename, 'r', encoding="utf-8") as logfile: 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 except: pass 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() async def website_experimental(ctx): def website_gen(topic): response = subprocess.run(["python", "Web_Gen/website_gen.py", topic], capture_output=True, check=True) try: if ctx.author.id == 242018983241318410 or ctx.author.id == 179064694844293120: await ctx.send("Please wait, this will take a long time! (Potentially hours) You will be able to view the website here: https://phixxy.com/ai-website/") topic = ctx.message.content.split(" ", maxsplit=1)[1] website_gen_thread = threading.Thread(target=website_gen, args=[topic], daemon=True) website_gen_thread.start() else: await ctx.send("Ask for permission if you want to use this command.") except: await ctx.send("Something went wrong, try again.") @bot.command() 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) async def delete_ftp_pngs(server_folder): with FTP(ftp_server) as ftp: ftp.login(ftp_username, ftp_password) ftp.cwd(server_folder) file_list = ftp.nlst() for filename in file_list: if ".png" in filename: print("Deleting", filename) ftp.delete(filename) async def extract_image_tags(code): count = code.count("This is a list of saved websites that AI generated.
This webpage is currently being generated. The page will refresh once it is complete. Please be patient.
") await upload_ftp(working_file, server_folder, "index.html") 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) await upload_archived_website(server_archive_folder, local_archive_folder) await generate_website_archive_html(server_archive_folder) await ctx.send("Finished https://phixxy.com/ai-webpage/") except openai.error.APIConnectionError as error: print(error) await ctx.send("Failed, Try again.") @bot.command() 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: print(error) with open("features.txt",'r') as f: features = f.read() await ctx.send(features) @bot.command() async def draw(ctx): 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!") prompt = "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!" completion = openai.ChatCompletion.create(model="gpt-3.5-turbo",messages=[{"role": "user", "content": prompt}]) prompt = completion.choices[0].message.content prompt = prompt.split('\n', maxsplit=1)[0] prompt = prompt.replace("AI, ", "") if "." in prompt: prompt = prompt.replace(".",",") prompt = prompt + " masterpiece, studio quality" else: prompt = prompt + ", masterpiece, studio quality" negative_prompt = "" url = STABLE_DIFFUSION_URL payload = {"prompt": prompt,"steps": 25, "negative_prompt": negative_prompt,"batch_size": amount} try: response = requests.post(url=f'{url}/sdapi/v1/txt2img', json=payload) r = 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 = requests.post(url=f'{url}/sdapi/v1/png-info', json=png_payload) pnginfo = PngImagePlugin.PngInfo() pnginfo.add_text("parameters", response2.json().get("info")) my_filename = "ai_art/draw/" + prompt + str(random.randint(0,10000000)) + ".png" 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: print(error) await ctx.send("My image generation service may not be running.") except Exception as error: print(error) await ctx.send('Did you mean to use !imagine?. Usage: !draw (number)') @bot.command() 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() 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() async def memorylength(ctx, chat_history_len): if chat_history_len.isdigit(): edit_channel_config(ctx.channel.id, "chat_history_len", chat_history_len) await ctx.send("Memory changed to " + chat_history_len) else: await ctx.send("Memory unchanged, must be int.") @bot.command() 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() async def commandz(ctx, message): if "enable" in message: edit_channel_config(ctx.channel.id, "commands_enabled", True) await ctx.send("Commands Enabled") elif "disable" in message: edit_channel_config(ctx.channel.id, "commands_enabled", False) await ctx.send("Commands Disabled") else: await ctx.send("Usage: !commandz (enable|disable)") @bot.command() 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() 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: folder_path = "python_temp_scripts/" if not os.path.exists(folder_path): os.makedirs(folder_path) random_num = random.randint(0,100) filename = f"{folder_path}{random_num}.py" 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: await ctx.send("Usage: !python (codeblock)") @bot.command() 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() 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) @bot.command(pass_context=True) async def disconnect(ctx): voice_client = discord.utils.get(bot.voice_clients, guild=ctx.guild) await voice_client.disconnect() @bot.command(pass_context=True) async def xplore_audio(ctx, arg): voice_channel = get(ctx.guild.voice_channels, name=arg) directory = "C:/Users/bottl/Music/xploreaudio/Recordings/" filename = random.choice(os.listdir(directory)) print(filename) voice_client = await voice_channel.connect() audio_source = discord.FFmpegPCMAudio(directory+filename) await ctx.send("Playing: " + filename) voice_client.play(audio_source) while voice_client.is_playing(): await asyncio.sleep(1) await voice_client.disconnect() @bot.command() async def change_model(ctx, model_choice='0'): url = STABLE_DIFFUSION_URL response = requests.get(url=f'{url}/sdapi/v1/options') config_json = response.json() current_model = config_json["sd_model_checkpoint"] output = 'Current Model: ' + current_model +'\n' if model_choice == '1': if current_model != "deliberate_v2.safetensors [9aba26abdf]": model_name = "deliberate_v2.safetensors [9aba26abdf]" else: await ctx.send("Already set to use DeliberateV2") return elif model_choice == '2': if current_model != "AnythingV5_v5PrtRE.safetensors [7f96a1a9ca]": model_name = "AnythingV5_v5PrtRE.safetensors [7f96a1a9ca]" else: await ctx.send("Already set to use AnythingV5") return elif model_choice == '3': if current_model != "Anything-V3.0.ckpt [8712e20a5d]": model_name = "Anything-V3.0.ckpt [8712e20a5d]" else: await ctx.send("Already set to use AnythingV3") return else: output += "1: DeliberateV2\n2: AnythingV5\n3: AnythingV3" await ctx.send(output) return payload = {"sd_model_checkpoint": model_name} response = requests.post(url=f'{url}/sdapi/v1/options', json=payload) output = "Changed model to: " + model_name await ctx.send(output) @bot.command() async def imagine(ctx): prompt = ctx.message.content.split(" ", maxsplit=1)[1] key_value_pairs, prompt = extract_key_value_pairs(prompt) #negative_prompt = "" 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" await ctx.send("Please be patient this may take some time! Generating: " + prompt + ".") url = STABLE_DIFFUSION_URL payload = { "prompt": prompt, "steps": 25, "negative_prompt": negative_prompt } payload = combine_dicts(payload, key_value_pairs) try: response = requests.post(url=f'{url}/sdapi/v1/txt2img', json=payload) r = response.json() for i in r['images']: if not os.path.isdir("ai_art/" + str(ctx.author.id)): os.makedirs("ai_art/" + str(ctx.author.id)) image = Image.open(io.BytesIO(base64.b64decode(i.split(",", 1)[0]))) png_payload = {"image": "data:image/png;base64," + i} response2 = requests.post(url=f'{url}/sdapi/v1/png-info', json=png_payload) pnginfo = PngImagePlugin.PngInfo() pnginfo.add_text("parameters", response2.json().get("info")) my_filename = "ai_art/" + str(ctx.author.id) + '/' + prompt[0:15] + str(random.randint(0, 10000000)) + ".png" 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) except: await ctx.send("My image generation service may not be running.") @bot.command() async def describe(ctx): 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 except: print("Couldn't find image.") return r = requests.get(file_url, stream=True) if not os.path.isdir(f"clip/{ctx.author.id}"): os.makedirs(f"clip/{ctx.author.id}") imageName = f"clip/{ctx.author.id}/{random.randint(0,10000000)}.png" with open(imageName, 'wb') as out_file: print(f"Saving image: {imageName}") shutil.copyfileobj(r.raw, out_file) img_link = my_open_img_file(imageName) url = STABLE_DIFFUSION_URL payload = {"image": img_link} response = requests.post(url=f"{url}/sdapi/v1/interrogate", json=payload) r = response.json() await ctx.send(r.get("caption")) @bot.command() async def reimagine(ctx): #see http://127.0.0.1:7860/docs for info, must be running stable diffusion with --api try: try: file_url = ctx.message.content.split(" ", maxsplit=2)[1] prompt = ctx.message.content.split(" ", maxsplit=2)[2] except: print("no linked image") try: file_url = ctx.message.attachments[0].url prompt = ctx.message.content.split(" ", maxsplit=1)[1] except: print("no attached image") except: print("couldn't find image") key_value_pairs, prompt = extract_key_value_pairs(prompt) r = requests.get(file_url, stream=True) if not os.path.isdir("reimagining/"+ str(ctx.author.id)): os.makedirs("reimagining/"+ str(ctx.author.id)) imageName = "reimagining/" + str(ctx.author.id) +"/"+ str(random.randint(0,10000000)) + '.png' with open(imageName, 'wb') as out_file: print('Saving image: ' + imageName) shutil.copyfileobj(r.raw, out_file) img_link = my_open_img_file(imageName) 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" #negative_prompt = "" await ctx.send("Please be patient this may take some time! Generating: " + prompt + ".") try: url = STABLE_DIFFUSION_URL payload = {"init_images": [img_link], "prompt": prompt,"steps": 40, "negative_prompt": negative_prompt, "denoising_strength": 0.5} payload = combine_dicts(payload, key_value_pairs) response = requests.post(url=f'{url}/sdapi/v1/img2img', json=payload) r = response.json() for i in r['images']: if not os.path.isdir("reimagined/"+ str(ctx.author.id)): os.makedirs("reimagined/"+ str(ctx.author.id)) image = Image.open(io.BytesIO(base64.b64decode(i.split(",",1)[0]))) png_payload = {"image": "data:image/png;base64," + i} response2 = requests.post(url=f'{url}/sdapi/v1/png-info', json=png_payload) pnginfo = PngImagePlugin.PngInfo() pnginfo.add_text("parameters", response2.json().get("info")) my_filename = "reimagined/" + str(ctx.author.id) + '/' + prompt[0:15] + str(random.randint(0,10000000)) + ".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) except: await ctx.send("My image generation service may not be running.") @bot.command() 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() 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() async def kill(ctx): if ctx.author.id == 242018983241318410: exit() else: await ctx.channel.send("You don't have permission to do that.") @bot.command() 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_message(ctx): logfile = "logs/{0}.log".format(str(ctx.channel.id)) channel_vars = await get_channel_config(ctx.channel.id) await react_to_msg(ctx, channel_vars["react_to_msgs"]) #emoji reactions chat_history_string = await log_chat_and_get_history(ctx, logfile, channel_vars) 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)