From aa6d0bee6e528afa7cc7e684b9991bf41887fd27 Mon Sep 17 00:00:00 2001 From: Benjamyn Love Date: Thu, 15 Dec 2022 20:36:19 +1100 Subject: [PATCH 1/6] biiig changes --- commands/diffuse_cog.py | 153 ++++++++++++++++++++++++++++++++++++++++ modules/diffuseapi.py | 36 +++++----- slash_commands.py | 45 ++++++++++++ 3 files changed, 218 insertions(+), 16 deletions(-) create mode 100644 commands/diffuse_cog.py create mode 100644 slash_commands.py diff --git a/commands/diffuse_cog.py b/commands/diffuse_cog.py new file mode 100644 index 0000000..51608aa --- /dev/null +++ b/commands/diffuse_cog.py @@ -0,0 +1,153 @@ +import discord +import hashlib +from discord import app_commands +from discord.ext import commands +from modules.diffuseapi import DiffuseAPI +from base64 import b64decode, b64encode +import io + +class Confirm(discord.ui.View): + def __init__(self, api: DiffuseAPI): + super().__init__(timeout=None) + self.value = None + self.api = api + + async def callback(self, interaction: discord.Interaction): + await interaction.response.send_message("You wish to upscale this image!") + + # When the confirm function is run we will send the image to the upscale endpoint + @discord.ui.button(label='Upscale', style=discord.ButtonStyle.green) + async def confirm(self, interaction: discord.Interaction, button: discord.ui.Button): + image_data = await interaction.message.attachments[0].read() + await interaction.response.defer() + upscaled_image = await self.api.generate_upscale(b64encode(image_data).decode('utf-8')) + data = io.BytesIO(b64decode(upscaled_image)) + + await interaction.followup.send("", file=discord.File(data, "upscaled.png")) + self.stop() + + # The cancel function will delete the message + @discord.ui.button(label='Delete', style=discord.ButtonStyle.grey) + async def cancel(self, interaction: discord.Interaction, button: discord.ui.Button): + await interaction.message.delete() + + self.stop() + +class DiffuseCog(commands.Cog): + def __init__(self, bot: commands.Bot): + self.bot = bot + self.api = DiffuseAPI("https://art.jurydoak.com", ["Bot"], True, 28) + self.user_settings = {} + + def _get_user_settings(self, user_id: int): + user_data = self.user_settings.get(user_id) + if user_data == None: + self.user_settings[user_id] = { + "prompt": "", + "styles": ["Bot"], + "steps": 28, + "seed": -1, + "n_iter": 1, + "height": 768, + "width": 512, + "negative_prompts": "", + "cfg_scale": 12 + } + + + user_data = self.user_settings.get(user_id) + return user_data + + @app_commands.command(name="gen", description="Generate an image with the following prompt") + async def generate_image(self, interaction: discord.Interaction, prompt: str): + """/gen prompt (Generates an image using the prompt)""" + # This can take a while so we defer the response, this also tells the client the bot is thinking + await interaction.response.defer() + + # Create an instance of the Confirm view so we can use it in our response + view = Confirm(self.api) + + # Get any custom settings the user has entered + user_data = self._get_user_settings(interaction.user.id) + + print(f"SENDING PROMPT: {prompt} from User: {interaction.user.display_name}") + + # Send the prompt + the users custom payload to the API + image_data = await self.api.generate_image(prompt=prompt, payload=user_data) + + # Verify that an image was returned + if image_data is None: + await interaction.followup.send("Failed to generate image, please bitch at admin :3") + + + ### Bonk check + decoded_image = b64decode(image_data) + h = hashlib.md5() + h.update(decoded_image) + digest = h.digest() + + if digest == b'i\xac`\xde\xbak\xba\xab{2Z\xcc\tK\xc2~': + await interaction.followup.send("Were no stranger to lewds, but you know the rules, and so do I", file=discord.File("images/404.jpg", "404.jpg")) + return + ### /Bonk check + + # Decode the image to bytes and send it in the response as a discord.File object + data = io.BytesIO(decoded_image) + await interaction.followup.send(prompt, file=discord.File(data, "prompt.png"), view=view) + + @app_commands.command(name="steps", description="Set the amount of steps the bot will run") + async def set_steps(self, interaction: discord.Interaction, steps: int): + user_settings = self._get_user_settings(interaction.user.id) + + try: + user_settings['steps'] = int(steps) + await interaction.response.send_message("Set steps uWu", ephemeral=True) + except Exception: + await interaction.response.send_message("Failed to set steps, baka", ephemeral=True) + + + @app_commands.command(name="api", description="Swaps between the main and test API", ) + async def swap_api(self, interaction: discord.Interaction): + user_settings = self._get_user_settings(interaction.user.id) + + '''Test function, currently changes the URL and bot settings''' + if self.api.url != "http://localhost:7860": + self.api.url = "http://localhost:7860" + user_settings['style'] = ["default"] + self.api.styles = ["default"] + activity = discord.Activity(type=discord.ActivityType.listening, name="Waiting for your prompt :3 (Test API)") + await self.bot.change_presence(activity=activity) + await interaction.response.send_message("Set to fastboi") + else: + self.api.url = "https://art.jurydoak.com" + self.api.styles = ["Bot"] + user_settings['style'] = ["Bot"] + activity = discord.Activity(type=discord.ActivityType.listening, name="Waiting for your prompt :3 (Main API)") + await self.bot.change_presence(activity=activity) + await interaction.response.send_message("Set to main api") + + @app_commands.command(name="orientation", description="Set the orientation of the generated image") + async def change_orientation(self, interaction: discord.Interaction, orientation: str): + if orientation.lower() not in ["portrait", "landscape", "square"]: + await interaction.response.send_message("You can only set the orientation to portrait, landscape or square") + return + + user_data = self._get_user_settings(interaction.user.id) + match orientation.lower(): + case "portrait": + user_data['height'] = 768 + user_data['width'] = 512 + case "landscape": + user_data['height'] = 512 + user_data['width'] = 768 + case "square": + user_data['height'] = 512 + user_data['width'] = 512 + + await interaction.response.send_message(f"Set the orientation to {orientation}", ephemeral=True) + + +async def setup(bot: commands.Bot): + await bot.add_cog(DiffuseCog(bot), guild=discord.Object(id=775297479783874570)) + + diff --git a/modules/diffuseapi.py b/modules/diffuseapi.py index e65d812..9b1d081 100644 --- a/modules/diffuseapi.py +++ b/modules/diffuseapi.py @@ -18,7 +18,7 @@ class DiffuseAPI(): def set_steps(self, steps): try: new_steps = int(steps) - if 0 > new_steps < 50: + if new_steps > 0 and new_steps <= 50: self.num_steps = new_steps return True return False @@ -83,22 +83,26 @@ class DiffuseAPI(): def get_nsfw_filter(self): return self.nsfw_enabled - async def generate_image(self, prompt, neg_prompt=""): - payload = { - "prompt": prompt, - "styles": self.styles, - "steps": self.num_steps, - "seed": self.seed, - "n_iter": 1, - "height": self.height, - "width": self.width, - "negative_prompts": neg_prompt, - "cfg_scale": self.cfg_scale - } + async def generate_image(self, prompt, neg_prompt="", payload=None): + if payload is None: + payload = { + "prompt": prompt, + "styles": self.styles, + "steps": self.num_steps, + "seed": self.seed, + "n_iter": 1, + "height": self.height, + "width": self.width, + "negative_prompts": neg_prompt, + "cfg_scale": self.cfg_scale + } + + payload['prompt'] = prompt settings = { "filter_nsfw": not self.nsfw_enabled, - "enable_pnginfo": False + "enable_pnginfo": False, +# "sd_hypernetwork": "anime_3" } override_payload = { @@ -122,7 +126,7 @@ class DiffuseAPI(): "gfpgan_visibility": 0, "codeformer_visibility": 0, "codeformer_weight": 0, - "upscaling_resize": 4, + "upscaling_resize": 2, "upscaling_resize_w": 512, "upscaling_resize_h": 1024, "upscaling_crop": True, @@ -139,4 +143,4 @@ class DiffuseAPI(): return None async with session.post("/sdapi/v1/extra-single-image", json=payload) as image_json: image_data = await image_json.json() - return image_data["image"] \ No newline at end of file + return image_data["image"] diff --git a/slash_commands.py b/slash_commands.py new file mode 100644 index 0000000..e6a09ff --- /dev/null +++ b/slash_commands.py @@ -0,0 +1,45 @@ +import discord +from discord import app_commands +from discord.ext import commands +import os +import asyncio + + +try: + with open("token.secret", 'r') as f: + discord_client_token = f.read() +except FileNotFoundError: + print("Cannot locate token.secret please generate a token") + exit(69) + + +class aclient(commands.Bot): + def __init__(self): + activity = discord.Activity(type=discord.ActivityType.listening, name="Waiting for your prompt :3 (Main API)") + super().__init__(intents=discord.Intents.default(), command_prefix="!", activity=activity) + + self.synced = False + + async def load(self): + for filename in os.listdir("./commands"): + if filename.endswith(".py"): + print(f"Loading commands.{filename[:-3]}") + await self.load_extension(f"commands.{filename[:-3]}") + + async def on_ready(self): + await self.wait_until_ready() + if not self.synced: + await tree.sync(guild=discord.Object(id=775297479783874570)) + self.synced = True + print(f"We have logged in as {self.user}.") + pass + +client = aclient() +tree = client.tree + +async def main(): + await client.load() + await client.start(discord_client_token) + +# client.run(discord_client_token) +asyncio.run(main()) \ No newline at end of file -- 2.43.5 From 233e8d1e47d1e1c9e01be75f5743309b132785a3 Mon Sep 17 00:00:00 2001 From: Benjamyn Love Date: Thu, 29 Dec 2022 18:55:33 -0500 Subject: [PATCH 2/6] Update 'README.md' --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 567f69f..5b5954e 100644 --- a/README.md +++ b/README.md @@ -7,4 +7,13 @@ This aims to be a discord bot that can take a prompt from a discord message and - discord.py: Python discord module ## Notebooks - - testing.ipynb: Testing notebook with examples \ No newline at end of file + - testing.ipynb: Testing notebook with examples + + + ```mermaid + graph TD; + A-->B; + A-->C; + B-->D; + C-->D; +``` \ No newline at end of file -- 2.43.5 From f4718c83db60884bdac1fa73966d04c4bb30a4a4 Mon Sep 17 00:00:00 2001 From: Benjamyn Love Date: Mon, 21 Aug 2023 11:14:45 +1000 Subject: [PATCH 3/6] Added game --- commands/diffuse_cog.py | 228 +++++++++++++++++++++++++++++++++++-- modules/diffuseapi.py | 4 +- modules/import requests.py | 86 ++++++++++++++ slash_commands.py | 6 +- 4 files changed, 310 insertions(+), 14 deletions(-) create mode 100644 modules/import requests.py diff --git a/commands/diffuse_cog.py b/commands/diffuse_cog.py index 51608aa..d76a06c 100644 --- a/commands/diffuse_cog.py +++ b/commands/diffuse_cog.py @@ -4,8 +4,69 @@ from discord import app_commands from discord.ext import commands from modules.diffuseapi import DiffuseAPI from base64 import b64decode, b64encode +from typing import Literal import io + +class Game: + def __init__(self, player1, player2, turns_per_player, base_prompt): + self.player1 = player1 + self.player2 = player2 + self.current_turn = 1 + self.player1_turn_count = 0 + self.player2_turn_count = 0 + self.turns_per_player = turns_per_player + self.prompt = base_prompt + + # Adds new_prompt to self.prompt + def prompt_add(self, new_prompt): + self.prompt = f"{self.prompt}, {new_prompt}" + + def get_settings(self): + data = { + "prompt": self.prompt, + "styles": ["Bot"], + "steps": 28, + "seed": -1, + "n_iter": 1, + "height": 768, + "width": 512, + "negative_prompts": "", + "cfg_scale": 12 + } + return data + + def get_players(self): + return [self.player1.id, self.player2.id] + + def is_player_ingame(self, player_id): + if player_id in self.get_players(): + return True + return False + # return True if player_id in self.get_players() else False + + def take_turn(self, new_prompt): + match(self.current_turn): + case 0: + if self.player1_turn_count <= self.turns_per_player: + # Generate new prompt string + self.prompt_add(new_prompt) + # Increment turn and swap player + self.current_turn = 1 + self.player1_turn_count += 1 + return self.prompt + return None + case 1: + if self.player2_turn_count <= self.turns_per_player: + # Generate new prompt string + self.prompt_add(new_prompt) + # Increment turn and swap player + self.current_turn = 0 + self.player2_turn_count += 1 + return self.prompt + return None + + class Confirm(discord.ui.View): def __init__(self, api: DiffuseAPI): super().__init__(timeout=None) @@ -33,15 +94,19 @@ class Confirm(discord.ui.View): self.stop() + class DiffuseCog(commands.Cog): def __init__(self, bot: commands.Bot): self.bot = bot self.api = DiffuseAPI("https://art.jurydoak.com", ["Bot"], True, 28) self.user_settings = {} + self.prev_prompt = None + self.games = {} + self.users_with_active_games = [] def _get_user_settings(self, user_id: int): user_data = self.user_settings.get(user_id) - if user_data == None: + if user_data is None: self.user_settings[user_id] = { "prompt": "", "styles": ["Bot"], @@ -53,11 +118,137 @@ class DiffuseCog(commands.Cog): "negative_prompts": "", "cfg_scale": 12 } - user_data = self.user_settings.get(user_id) return user_data + + @app_commands.command(name="startgame", description="Start a DEGEN GAME with another player") + async def start_game(self, interaction: discord.Integration, player: discord.Member, base_prompt: str): + """/startgame @username (starts a game)""" + for game in self.games: + if self.games[game].is_player_ingame(interaction.user.id): + await interaction.response.send_message(f"{interaction.user.display_name} is still in a game") + if self.games[game].is_player_ingame(player.id): + await interaction.response.send_message(f"{player.display_name} is still in a game") + + game_name = interaction.user.display_name + player.display_name + game = Game(interaction.user, player, 5, base_prompt) + self.games[game_name] = game + await interaction.response.defer() + print(f"SENDING PROMPT: {game.prompt} from User: {interaction.user.display_name}") + + # Send the prompt + the users custom payload to the API + image_data = await self.api.generate_image(prompt=game.prompt, payload=game.get_settings()) + # Verify that an image was returned + if image_data is None: + await interaction.followup.send("Failed to generate image, please bitch at admin :3") + + # ### Bonk check + decoded_image = b64decode(image_data) + # Decode the image to bytes and send it in the response as a discord.File object + data = io.BytesIO(decoded_image) + await interaction.followup.send(f"Game started with {interaction.user.display_name} with {player.display_name} | 5 Turns | {game.prompt} \n Current player {game.player2.display_name}", file=discord.File(data, "prompt.png")) + + await interaction.response.send_message(f"Game started with {interaction.user.display_name} with {player.display_name} | 5 Turns | {game.prompt}") + + + @app_commands.command(name="listgames", description="List running degen games") + async def list_games(self, interaction: discord.Interaction): + """/listgames (Lists running games)""" + ret = "" + for game in self.games: + ret += f"{self.games[game].player1.display_name} vs. {self.games[game].player2.display_name}: {self.games[game].player1_turn_count + self.games[game].player2_turn_count} turns in\n" + await interaction.response.send_message(ret) + + @app_commands.command(name="stopgame", description="Stop the current game you are in.") + async def stop_game(self, interaction: discord.Interaction): + # Make sure this user is in a game + for game in self.games: + if self.games[game].is_player_ingame(interaction.user.id): + del self.games[game] + break + await interaction.response.send_message(f"Game has been removed") + + + + @app_commands.command(name="taketurn", description="Take your turn in degen game") + async def take_turn(self, interaction: discord.Interaction, prompt: str): + # Make sure this user is in a game + game_instance = None + for game in self.games: + if self.games[game].is_player_ingame(interaction.user.id): + game_instance = self.games[game] + break + + if game_instance is None: + await interaction.response.send_message(f"{interaction.user.display_name} is not in a game") + + # Get the current turn and check the appropriate players id + match(game_instance.current_turn): + case 0: + if interaction.user.id != game_instance.player1.id: + await interaction.response.send_message("It's not your turn.", ephemeral=True) + case 1: + if interaction.user.id != game_instance.player2.id: + await interaction.response.send_message("It's not your turn.") + # We are all gucci for the turn so we defer as we will be generating images now + await interaction.response.defer() + game_instance.take_turn(prompt) + + print(f"SENDING PROMPT: {game_instance.prompt} from User: {interaction.user.display_name}") + + # Send the prompt + the users custom payload to the API + image_data = await self.api.generate_image(prompt=game_instance.prompt, payload=game_instance.get_settings()) + # Verify that an image was returned + if image_data is None: + await interaction.followup.send("Failed to generate image, please bitch at admin :3") + + # ### Bonk check + decoded_image = b64decode(image_data) + # Decode the image to bytes and send it in the response as a discord.File object + data = io.BytesIO(decoded_image) + await interaction.followup.send(game_instance.prompt, file=discord.File(data, "prompt.png")) + + + + @app_commands.command(name="pregen", description="Generate an image appending your prompt to the end") + async def pregenerate_image(self, interaction: discord.Interaction, prompt: str): + """/pregen prompt (Generates an image using the prompt)""" + # This can take a while so we defer the response, this also tells the client the bot is thinking + await interaction.response.defer() + + # Create an instance of the Confirm view so we can use it in our response + view = Confirm(self.api) + new_prompt = f"{self.prev_prompt}, {prompt}" + # Get any custom settings the user has entered + user_data = self._get_user_settings(interaction.user.id) + + print(f"SENDING PROMPT: {new_prompt} from User: {interaction.user.display_name}") + + # Send the prompt + the users custom payload to the API + image_data = await self.api.generate_image(prompt=new_prompt, payload=user_data) + + # print(image_data) + # Verify that an image was returned + if image_data is None: + await interaction.followup.send("Failed to generate image, please bitch at admin :3") + + + # ### Bonk check + decoded_image = b64decode(image_data) + # h = hashlib.md5() + # h.update(decoded_image) + # digest = h.digest() + + # return await self.bonk_check(interaction, digest) + ### /Bonk check + + # Decode the image to bytes and send it in the response as a discord.File object + data = io.BytesIO(decoded_image) + self.prev_prompt = new_prompt + await interaction.followup.send(new_prompt, file=discord.File(data, "prompt.png"), view=view) + @app_commands.command(name="gen", description="Generate an image with the following prompt") async def generate_image(self, interaction: discord.Interaction, prompt: str): """/gen prompt (Generates an image using the prompt)""" @@ -75,26 +266,32 @@ class DiffuseCog(commands.Cog): # Send the prompt + the users custom payload to the API image_data = await self.api.generate_image(prompt=prompt, payload=user_data) + # print(image_data) # Verify that an image was returned if image_data is None: await interaction.followup.send("Failed to generate image, please bitch at admin :3") - ### Bonk check + # ### Bonk check decoded_image = b64decode(image_data) - h = hashlib.md5() - h.update(decoded_image) - digest = h.digest() + # h = hashlib.md5() + # h.update(decoded_image) + # digest = h.digest() - if digest == b'i\xac`\xde\xbak\xba\xab{2Z\xcc\tK\xc2~': - await interaction.followup.send("Were no stranger to lewds, but you know the rules, and so do I", file=discord.File("images/404.jpg", "404.jpg")) - return + # return await self.bonk_check(interaction, digest) ### /Bonk check # Decode the image to bytes and send it in the response as a discord.File object data = io.BytesIO(decoded_image) + self.prev_prompt = prompt await interaction.followup.send(prompt, file=discord.File(data, "prompt.png"), view=view) + # async def bonk_check(self, interaction, digest): + # digests = [b'i\xac`\xde\xbak\xba\xab{2Z\xcc\tK\xc2~'] + # if digest in digests : + # await interaction.followup.send("Were no stranger to lewds, but you know the rules, and so do I", file=discord.File("images/404.jpg", "404.jpg")) + # return + @app_commands.command(name="steps", description="Set the amount of steps the bot will run") async def set_steps(self, interaction: discord.Interaction, steps: int): user_settings = self._get_user_settings(interaction.user.id) @@ -127,7 +324,8 @@ class DiffuseCog(commands.Cog): await interaction.response.send_message("Set to main api") @app_commands.command(name="orientation", description="Set the orientation of the generated image") - async def change_orientation(self, interaction: discord.Interaction, orientation: str): + # @app_commands.choices([app_commands.Choice("portrait"), app_commands.Choice("landscape"), app_commands.Choice("square")]) + async def change_orientation(self, interaction: discord.Interaction, orientation: Literal["portrait", "landscape", "square"]): if orientation.lower() not in ["portrait", "landscape", "square"]: await interaction.response.send_message("You can only set the orientation to portrait, landscape or square") return @@ -145,7 +343,17 @@ class DiffuseCog(commands.Cog): user_data['width'] = 512 await interaction.response.send_message(f"Set the orientation to {orientation}", ephemeral=True) + + @app_commands.command(name="seed", description="Set a static seed (-1 is random)") + async def set_seed(self, interaction: discord.Interaction, seed: int): + try: + seed = int(seed) + user_settings = self._get_user_settings(interaction.user.id) + user_settings["seed"] = seed + await interaction.response.send_message(f"Set the seed to {seed}", ephemeral=True) + except: + await interaction.response.send_message("Failed to set the seed") async def setup(bot: commands.Bot): await bot.add_cog(DiffuseCog(bot), guild=discord.Object(id=775297479783874570)) diff --git a/modules/diffuseapi.py b/modules/diffuseapi.py index 9b1d081..9e19e66 100644 --- a/modules/diffuseapi.py +++ b/modules/diffuseapi.py @@ -100,7 +100,7 @@ class DiffuseAPI(): payload['prompt'] = prompt settings = { - "filter_nsfw": not self.nsfw_enabled, +# "filter_nsfw": not self.nsfw_enabled, "enable_pnginfo": False, # "sd_hypernetwork": "anime_3" } @@ -110,7 +110,7 @@ class DiffuseAPI(): } payload.update(override_payload) - + async with aiohttp.ClientSession(self.url) as session: async with session.head('/') as alive: if alive.status != 200: diff --git a/modules/import requests.py b/modules/import requests.py new file mode 100644 index 0000000..e18cde9 --- /dev/null +++ b/modules/import requests.py @@ -0,0 +1,86 @@ +import requests +import io +import os.path +from PIL import Image +from config import Config +import uuid +import openai +from base64 import b64decode + +cfg = Config() + +working_directory = "auto_gpt_workspace" + + +def generate_image(prompt): + + filename = str(uuid.uuid4()) + ".jpg" + + # DALL-E + if cfg.image_provider == 'dalle': + + openai.api_key = cfg.openai_api_key + + response = openai.Image.create( + prompt=prompt, + n=1, + size="256x256", + response_format="b64_json", + ) + + print("Image Generated for prompt:" + prompt) + + image_data = b64decode(response["data"][0]["b64_json"]) + + with open(working_directory + "/" + filename, mode="wb") as png: + png.write(image_data) + + return "Saved to disk:" + filename + + # STABLE DIFFUSION + elif cfg.image_provider == 'sd': + + API_URL = "https://api-inference.huggingface.co/models/CompVis/stable-diffusion-v1-4" + headers = {"Authorization": "Bearer " + cfg.huggingface_api_token} + + response = requests.post(API_URL, headers=headers, json={ + "inputs": prompt, + }) + + image = Image.open(io.BytesIO(response.content)) + print("Image Generated for prompt:" + prompt) + + image.save(os.path.join(working_directory, filename)) + + return "Saved to disk:" + filename + + elif cfg.image_provider == 'sdwu': + API_URL = "http://10.6.9.69:7860" + if payload is None: + payload = { + "prompt": prompt, + } + + payload['prompt'] = prompt + + settings = { + "enable_pnginfo": False, + } + + override_payload = { + "override_settings": settings + } + + payload.update(override_payload) + + request = requests.post("/sdapi/v1/txt2img", json=payload) + + image_data = request.json() + image = Image.open(io.BytesIO(image_data["images"][0])) + print("Image Generated for prompt:" + prompt) + + image.save(os.path.join(working_directory, filename)) + + return "Saved to disk:" + filename + else: + return "No Image Provider Set" \ No newline at end of file diff --git a/slash_commands.py b/slash_commands.py index e6a09ff..65b93fe 100644 --- a/slash_commands.py +++ b/slash_commands.py @@ -16,7 +16,9 @@ except FileNotFoundError: class aclient(commands.Bot): def __init__(self): activity = discord.Activity(type=discord.ActivityType.listening, name="Waiting for your prompt :3 (Main API)") - super().__init__(intents=discord.Intents.default(), command_prefix="!", activity=activity) + intents = discord.Intents.default() + intents.message_content = True + super().__init__(intents=intents, command_prefix="!", activity=activity, help_command=commands.DefaultHelpCommand()) self.synced = False @@ -42,4 +44,4 @@ async def main(): await client.start(discord_client_token) # client.run(discord_client_token) -asyncio.run(main()) \ No newline at end of file +asyncio.run(main()) -- 2.43.5 From 6e73a52eb7cf182bc9801bce1d9ede919c54483e Mon Sep 17 00:00:00 2001 From: Benjamyn Love Date: Mon, 21 Aug 2023 11:15:50 +1000 Subject: [PATCH 4/6] removed import requests.py --- modules/import requests.py | 86 -------------------------------------- 1 file changed, 86 deletions(-) delete mode 100644 modules/import requests.py diff --git a/modules/import requests.py b/modules/import requests.py deleted file mode 100644 index e18cde9..0000000 --- a/modules/import requests.py +++ /dev/null @@ -1,86 +0,0 @@ -import requests -import io -import os.path -from PIL import Image -from config import Config -import uuid -import openai -from base64 import b64decode - -cfg = Config() - -working_directory = "auto_gpt_workspace" - - -def generate_image(prompt): - - filename = str(uuid.uuid4()) + ".jpg" - - # DALL-E - if cfg.image_provider == 'dalle': - - openai.api_key = cfg.openai_api_key - - response = openai.Image.create( - prompt=prompt, - n=1, - size="256x256", - response_format="b64_json", - ) - - print("Image Generated for prompt:" + prompt) - - image_data = b64decode(response["data"][0]["b64_json"]) - - with open(working_directory + "/" + filename, mode="wb") as png: - png.write(image_data) - - return "Saved to disk:" + filename - - # STABLE DIFFUSION - elif cfg.image_provider == 'sd': - - API_URL = "https://api-inference.huggingface.co/models/CompVis/stable-diffusion-v1-4" - headers = {"Authorization": "Bearer " + cfg.huggingface_api_token} - - response = requests.post(API_URL, headers=headers, json={ - "inputs": prompt, - }) - - image = Image.open(io.BytesIO(response.content)) - print("Image Generated for prompt:" + prompt) - - image.save(os.path.join(working_directory, filename)) - - return "Saved to disk:" + filename - - elif cfg.image_provider == 'sdwu': - API_URL = "http://10.6.9.69:7860" - if payload is None: - payload = { - "prompt": prompt, - } - - payload['prompt'] = prompt - - settings = { - "enable_pnginfo": False, - } - - override_payload = { - "override_settings": settings - } - - payload.update(override_payload) - - request = requests.post("/sdapi/v1/txt2img", json=payload) - - image_data = request.json() - image = Image.open(io.BytesIO(image_data["images"][0])) - print("Image Generated for prompt:" + prompt) - - image.save(os.path.join(working_directory, filename)) - - return "Saved to disk:" + filename - else: - return "No Image Provider Set" \ No newline at end of file -- 2.43.5 From 3a2fb9a3355e13ce3a657bd733fb0f42a788c89d Mon Sep 17 00:00:00 2001 From: Benjamyn Love Date: Wed, 23 Aug 2023 15:06:10 +1000 Subject: [PATCH 5/6] Moved game to separate cog --- commands/diffuse_cog.py | 150 +---------------------------------- commands/game_cog.py | 171 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 175 insertions(+), 146 deletions(-) create mode 100644 commands/game_cog.py diff --git a/commands/diffuse_cog.py b/commands/diffuse_cog.py index d76a06c..090ca7d 100644 --- a/commands/diffuse_cog.py +++ b/commands/diffuse_cog.py @@ -8,63 +8,7 @@ from typing import Literal import io -class Game: - def __init__(self, player1, player2, turns_per_player, base_prompt): - self.player1 = player1 - self.player2 = player2 - self.current_turn = 1 - self.player1_turn_count = 0 - self.player2_turn_count = 0 - self.turns_per_player = turns_per_player - self.prompt = base_prompt - # Adds new_prompt to self.prompt - def prompt_add(self, new_prompt): - self.prompt = f"{self.prompt}, {new_prompt}" - - def get_settings(self): - data = { - "prompt": self.prompt, - "styles": ["Bot"], - "steps": 28, - "seed": -1, - "n_iter": 1, - "height": 768, - "width": 512, - "negative_prompts": "", - "cfg_scale": 12 - } - return data - - def get_players(self): - return [self.player1.id, self.player2.id] - - def is_player_ingame(self, player_id): - if player_id in self.get_players(): - return True - return False - # return True if player_id in self.get_players() else False - - def take_turn(self, new_prompt): - match(self.current_turn): - case 0: - if self.player1_turn_count <= self.turns_per_player: - # Generate new prompt string - self.prompt_add(new_prompt) - # Increment turn and swap player - self.current_turn = 1 - self.player1_turn_count += 1 - return self.prompt - return None - case 1: - if self.player2_turn_count <= self.turns_per_player: - # Generate new prompt string - self.prompt_add(new_prompt) - # Increment turn and swap player - self.current_turn = 0 - self.player2_turn_count += 1 - return self.prompt - return None class Confirm(discord.ui.View): @@ -98,18 +42,17 @@ class Confirm(discord.ui.View): class DiffuseCog(commands.Cog): def __init__(self, bot: commands.Bot): self.bot = bot - self.api = DiffuseAPI("https://art.jurydoak.com", ["Bot"], True, 28) + self.api = DiffuseAPI("https://art.jurydoak.com", ["default"], True, 28) self.user_settings = {} self.prev_prompt = None - self.games = {} - self.users_with_active_games = [] + def _get_user_settings(self, user_id: int): user_data = self.user_settings.get(user_id) if user_data is None: self.user_settings[user_id] = { "prompt": "", - "styles": ["Bot"], + "styles": ["default"], "steps": 28, "seed": -1, "n_iter": 1, @@ -123,92 +66,7 @@ class DiffuseCog(commands.Cog): return user_data - @app_commands.command(name="startgame", description="Start a DEGEN GAME with another player") - async def start_game(self, interaction: discord.Integration, player: discord.Member, base_prompt: str): - """/startgame @username (starts a game)""" - for game in self.games: - if self.games[game].is_player_ingame(interaction.user.id): - await interaction.response.send_message(f"{interaction.user.display_name} is still in a game") - if self.games[game].is_player_ingame(player.id): - await interaction.response.send_message(f"{player.display_name} is still in a game") - - game_name = interaction.user.display_name + player.display_name - game = Game(interaction.user, player, 5, base_prompt) - self.games[game_name] = game - await interaction.response.defer() - print(f"SENDING PROMPT: {game.prompt} from User: {interaction.user.display_name}") - - # Send the prompt + the users custom payload to the API - image_data = await self.api.generate_image(prompt=game.prompt, payload=game.get_settings()) - # Verify that an image was returned - if image_data is None: - await interaction.followup.send("Failed to generate image, please bitch at admin :3") - - # ### Bonk check - decoded_image = b64decode(image_data) - # Decode the image to bytes and send it in the response as a discord.File object - data = io.BytesIO(decoded_image) - await interaction.followup.send(f"Game started with {interaction.user.display_name} with {player.display_name} | 5 Turns | {game.prompt} \n Current player {game.player2.display_name}", file=discord.File(data, "prompt.png")) - - await interaction.response.send_message(f"Game started with {interaction.user.display_name} with {player.display_name} | 5 Turns | {game.prompt}") - - - @app_commands.command(name="listgames", description="List running degen games") - async def list_games(self, interaction: discord.Interaction): - """/listgames (Lists running games)""" - ret = "" - for game in self.games: - ret += f"{self.games[game].player1.display_name} vs. {self.games[game].player2.display_name}: {self.games[game].player1_turn_count + self.games[game].player2_turn_count} turns in\n" - await interaction.response.send_message(ret) - - @app_commands.command(name="stopgame", description="Stop the current game you are in.") - async def stop_game(self, interaction: discord.Interaction): - # Make sure this user is in a game - for game in self.games: - if self.games[game].is_player_ingame(interaction.user.id): - del self.games[game] - break - await interaction.response.send_message(f"Game has been removed") - - - - @app_commands.command(name="taketurn", description="Take your turn in degen game") - async def take_turn(self, interaction: discord.Interaction, prompt: str): - # Make sure this user is in a game - game_instance = None - for game in self.games: - if self.games[game].is_player_ingame(interaction.user.id): - game_instance = self.games[game] - break - - if game_instance is None: - await interaction.response.send_message(f"{interaction.user.display_name} is not in a game") - - # Get the current turn and check the appropriate players id - match(game_instance.current_turn): - case 0: - if interaction.user.id != game_instance.player1.id: - await interaction.response.send_message("It's not your turn.", ephemeral=True) - case 1: - if interaction.user.id != game_instance.player2.id: - await interaction.response.send_message("It's not your turn.") - # We are all gucci for the turn so we defer as we will be generating images now - await interaction.response.defer() - game_instance.take_turn(prompt) - - print(f"SENDING PROMPT: {game_instance.prompt} from User: {interaction.user.display_name}") - - # Send the prompt + the users custom payload to the API - image_data = await self.api.generate_image(prompt=game_instance.prompt, payload=game_instance.get_settings()) - # Verify that an image was returned - if image_data is None: - await interaction.followup.send("Failed to generate image, please bitch at admin :3") - - # ### Bonk check - decoded_image = b64decode(image_data) - # Decode the image to bytes and send it in the response as a discord.File object - data = io.BytesIO(decoded_image) - await interaction.followup.send(game_instance.prompt, file=discord.File(data, "prompt.png")) + diff --git a/commands/game_cog.py b/commands/game_cog.py new file mode 100644 index 0000000..f6fb5b4 --- /dev/null +++ b/commands/game_cog.py @@ -0,0 +1,171 @@ +import discord +import hashlib +from discord import app_commands +from discord.ext import commands +from modules.diffuseapi import DiffuseAPI +from base64 import b64decode, b64encode +from typing import Literal +import io + +class Game: + def __init__(self, player1, player2, turns_per_player, base_prompt): + self.player1 = player1 + self.player2 = player2 + self.current_turn = 1 + self.player1_turn_count = 0 + self.player2_turn_count = 0 + self.turns_per_player = turns_per_player + self.prompt = base_prompt + + # Adds new_prompt to self.prompt + def prompt_add(self, new_prompt): + self.prompt = f"{self.prompt}, {new_prompt}" + + def get_settings(self): + data = { + "prompt": self.prompt, + "styles": ["default"], + "steps": 28, + "seed": -1, + "n_iter": 1, + "height": 768, + "width": 512, + "negative_prompts": "", + "cfg_scale": 12 + } + return data + + def get_players(self): + return [self.player1.id, self.player2.id] + + def is_player_ingame(self, player_id): + if player_id in self.get_players(): + return True + return False + # return True if player_id in self.get_players() else False + + def take_turn(self, new_prompt): + match(self.current_turn): + case 0: + if self.player1_turn_count <= self.turns_per_player: + # Generate new prompt string + self.prompt_add(new_prompt) + # Increment turn and swap player + self.current_turn = 1 + self.player1_turn_count += 1 + return self.prompt + return None + case 1: + if self.player2_turn_count <= self.turns_per_player: + # Generate new prompt string + self.prompt_add(new_prompt) + # Increment turn and swap player + self.current_turn = 0 + self.player2_turn_count += 1 + return self.prompt + return None + + +class GameCog(commands.Cog): + def __init__(self, bot: commands.Bot): + self.bot = bot + self.api = DiffuseAPI("https://art.jurydoak.com", ["default"], True, 28) + self.games = {} + + + @app_commands.command(name="startgame", description="Start a DEGEN GAME with another player") + async def start_game(self, interaction: discord.Integration, player: discord.Member, base_prompt: str): + """/startgame @username (starts a game)""" + for game in self.games: + if self.games[game].is_player_ingame(interaction.user.id): + await interaction.response.send_message(f"{interaction.user.display_name} is still in a game") + if self.games[game].is_player_ingame(player.id): + await interaction.response.send_message(f"{player.display_name} is still in a game") + + game_name = interaction.user.display_name + player.display_name + game = Game(interaction.user, player, 5, base_prompt) + self.games[game_name] = game + await interaction.response.defer() + print(f"SENDING PROMPT: {game.prompt} from User: {interaction.user.display_name}") + + # Send the prompt + the users custom payload to the API + image_data = await self.api.generate_image(prompt=game.prompt, payload=game.get_settings()) + # Verify that an image was returned + if image_data is None: + await interaction.followup.send("Failed to generate image, please bitch at admin :3") + + # ### Bonk check + decoded_image = b64decode(image_data) + # Decode the image to bytes and send it in the response as a discord.File object + data = io.BytesIO(decoded_image) + await interaction.followup.send(f"Game started with {interaction.user.display_name} with {player.display_name} | 5 Turns | {game.prompt} \n Current player {game.player2.mention}", file=discord.File(data, "prompt.png")) + + await interaction.response.send_message(f"Game started with {interaction.user.display_name} with {player.display_name} | 5 Turns | {game.prompt}") + + + @app_commands.command(name="listgames", description="List running degen games") + async def list_games(self, interaction: discord.Interaction): + """/listgames (Lists running games)""" + ret = "" + for game in self.games: + ret += f"{self.games[game].player1.display_name} vs. {self.games[game].player2.display_name}: {self.games[game].player1_turn_count + self.games[game].player2_turn_count} turns in\n" + await interaction.response.send_message(ret) + + @app_commands.command(name="stopgame", description="Stop the current game you are in.") + async def stop_game(self, interaction: discord.Interaction): + # Make sure this user is in a game + for game in self.games: + if self.games[game].is_player_ingame(interaction.user.id): + del self.games[game] + break + await interaction.response.send_message(f"Game has been removed") + + + + @app_commands.command(name="taketurn", description="Take your turn in degen game") + async def take_turn(self, interaction: discord.Interaction, prompt: str): + # Make sure this user is in a game + game_instance = None + for game in self.games: + if self.games[game].is_player_ingame(interaction.user.id): + game_instance = self.games[game] + break + + if game_instance is None: + await interaction.response.send_message(f"{interaction.user.display_name} is not in a game") + + # Get the current turn and check the appropriate players id + match(game_instance.current_turn): + case 0: + if interaction.user.id != game_instance.player1.id: + await interaction.response.send_message("It's not your turn.", ephemeral=True) + case 1: + if interaction.user.id != game_instance.player2.id: + await interaction.response.send_message("It's not your turn.") + # We are all gucci for the turn so we defer as we will be generating images now + channel = interaction.channel + await interaction.response.defer(ephemeral=True) + game_instance.take_turn(prompt) + + print(f"SENDING PROMPT: {game_instance.prompt} from User: {interaction.user.display_name}") + + # Send the prompt + the users custom payload to the API + image_data = await self.api.generate_image(prompt=game_instance.prompt, payload=game_instance.get_settings()) + # Verify that an image was returned + if image_data is None: + await interaction.followup.send("Failed to generate image, please bitch at admin :3") + + # ### Bonk check + decoded_image = b64decode(image_data) + # Decode the image to bytes and send it in the response as a discord.File object + data = io.BytesIO(decoded_image) + await interaction.followup.send(game_instance.prompt, file=discord.File(data, "prompt.png"), ephemeral=True) + if game_instance.current_turn == 0: + player_name = game_instance.player1.mention + else: + player_name = game_instance.player2.mention + await channel.send(f"Turn taken: {player_name}'s turn") + +async def setup(bot: commands.Bot): + await bot.add_cog(GameCog(bot), guild=discord.Object(id=775297479783874570)) + -- 2.43.5 From 21fba2423c53a35f91cf66d6fe7ad4959f3d6064 Mon Sep 17 00:00:00 2001 From: Benjamyn Love Date: Sun, 17 Sep 2023 22:19:50 -0400 Subject: [PATCH 6/6] Update README.md Removed the shitty chart --- README.md | 9 --------- 1 file changed, 9 deletions(-) diff --git a/README.md b/README.md index 5b5954e..93d06df 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,3 @@ This aims to be a discord bot that can take a prompt from a discord message and ## Notebooks - testing.ipynb: Testing notebook with examples - - - ```mermaid - graph TD; - A-->B; - A-->C; - B-->D; - C-->D; -``` \ No newline at end of file -- 2.43.5