parent
29b70f28e0
commit
1e7bb46d51
@ -1,4 +0,0 @@
|
||||
DISCORD_BOT_TOKEN=
|
||||
MENTION_CHANNEL_ID=
|
||||
AUTH_COOKIE=
|
||||
AUTH_COOKIE_SRCHHPGUSR=
|
@ -1,6 +0,0 @@
|
||||
FROM python:3.9.16
|
||||
WORKDIR /bot
|
||||
COPY requirements.txt /bot/
|
||||
RUN pip install -r requirements.txt
|
||||
COPY . /bot
|
||||
CMD python bot.py
|
@ -1,120 +0,0 @@
|
||||
import discord
|
||||
import os
|
||||
import src.log
|
||||
import sys
|
||||
import pkg_resources
|
||||
import json
|
||||
from discord.ext import commands
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
bot = commands.Bot(command_prefix="!", intents=discord.Intents.all())
|
||||
|
||||
# init loggger
|
||||
logger = src.log.setup_logger(__name__)
|
||||
|
||||
|
||||
def restart_bot():
|
||||
# Replace current process with new instance of bot.py
|
||||
os.execl(sys.executable, sys.executable, "bot.py")
|
||||
|
||||
|
||||
def check_verion() -> None:
|
||||
# Read the requirements.txt file and add each line to a list
|
||||
with open("requirements.txt") as f:
|
||||
required = f.read().splitlines()
|
||||
|
||||
# For each library listed in requirements.txt, check if the corresponding version is installed
|
||||
for package in required:
|
||||
# Use the pkg_resources library to get information about the installed version of the library
|
||||
package_name, package_verion = package.split("==")
|
||||
installed = pkg_resources.get_distribution(package_name)
|
||||
# Extract the library name and version number
|
||||
name, version = installed.project_name, installed.version
|
||||
# Compare the version number to see if it matches the one in requirements.txt
|
||||
if package != f"{name}=={version}":
|
||||
logger.error(
|
||||
f"{name} version {version} is installed but does not match the requirements"
|
||||
)
|
||||
sys.exit()
|
||||
|
||||
|
||||
@bot.event
|
||||
async def on_ready():
|
||||
bot_status = discord.Status.online
|
||||
bot_activity = discord.Activity(type=discord.ActivityType.playing, name="bing.com")
|
||||
await bot.change_presence(status=bot_status, activity=bot_activity)
|
||||
for Filename in os.listdir("./cogs"):
|
||||
if Filename.endswith(".py"):
|
||||
await bot.load_extension(f"cogs.{Filename[:-3]}")
|
||||
logger.info(f"{bot.user} is now running!")
|
||||
print("Bot is Up and Ready!")
|
||||
try:
|
||||
synced = await bot.tree.sync()
|
||||
print(f"Synced {len(synced)} commands")
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
# Load command
|
||||
@commands.is_owner()
|
||||
@bot.command()
|
||||
async def load(ctx, extension):
|
||||
await bot.load_extension(f"cogs.{extension}")
|
||||
await ctx.author.send(f"> **Loaded {extension} done.**")
|
||||
|
||||
|
||||
# Unload command
|
||||
@commands.is_owner()
|
||||
@bot.command()
|
||||
async def unload(ctx, extension):
|
||||
await bot.unload_extension(f"cogs.{extension}")
|
||||
await ctx.author.send(f"> **Un-Loaded {extension} done.**")
|
||||
|
||||
|
||||
# Empty discord_bot.log file
|
||||
@commands.is_owner()
|
||||
@bot.command()
|
||||
async def clean(ctx):
|
||||
open("discord_bot.log", "w").close()
|
||||
await ctx.author.send(f"> **Successfully emptied the file!**")
|
||||
|
||||
|
||||
# Get discord_bot.log file
|
||||
@commands.is_owner()
|
||||
@bot.command()
|
||||
async def getLog(ctx):
|
||||
try:
|
||||
with open("discord_bot.log", "rb") as f:
|
||||
file = discord.File(f)
|
||||
await ctx.author.send(file=file)
|
||||
await ctx.author.send("> **Send successfully!**")
|
||||
except:
|
||||
await ctx.author.send("> **Send failed!**")
|
||||
|
||||
|
||||
# Upload new Bing cookies and restart the bot
|
||||
@commands.is_owner()
|
||||
@bot.command()
|
||||
async def upload(ctx):
|
||||
if ctx.message.attachments:
|
||||
for attachment in ctx.message.attachments:
|
||||
if str(attachment)[-4:] == ".txt":
|
||||
content = await attachment.read()
|
||||
with open("cookies.json", "w", encoding="utf-8") as f:
|
||||
json.dump(json.loads(content), f, indent=2)
|
||||
if not isinstance(ctx.channel, discord.abc.PrivateChannel):
|
||||
await ctx.message.delete()
|
||||
await ctx.author.send(f"> **Upload new cookies successfully!**")
|
||||
logger.warning("\x1b[31mCookies has been setup successfully\x1b[0m")
|
||||
restart_bot()
|
||||
else:
|
||||
await ctx.author.send("> **Didn't get any txt file.**")
|
||||
else:
|
||||
await ctx.author.send("> **Didn't get any file.**")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
check_verion()
|
||||
bot.run(os.getenv("DISCORD_BOT_TOKEN"))
|
@ -1,148 +0,0 @@
|
||||
import os
|
||||
import discord
|
||||
import json
|
||||
from typing import Optional
|
||||
from EdgeGPT.ImageGen import ImageGenAsync, ImageGen
|
||||
from EdgeGPT.EdgeGPT import Chatbot
|
||||
from discord import app_commands
|
||||
from core.classes import Cog_Extension
|
||||
from src import log
|
||||
from src.imageCreate import create_image, get_using_create, set_using_create
|
||||
from src.response import send_message, get_using_send, set_using_send
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
logger = log.setup_logger(__name__)
|
||||
|
||||
users_chatbot = {}
|
||||
users_image_generator = {}
|
||||
user_conversation_style = {}
|
||||
|
||||
async def init_chatbot(user_id):
|
||||
with open("./cookies.json", encoding="utf-8") as file:
|
||||
cookie_json = json.load(file)
|
||||
for cookie in cookie_json:
|
||||
if cookie.get("name") == "_U":
|
||||
auth_cookie = cookie.get("value")
|
||||
break
|
||||
|
||||
auth_cookie = os.environ.get("AUTH_COOKIE")
|
||||
auth_cookie_SRCHHPGUSR = os.environ.get("AUTH_COOKIE_SRCHHPGUSR")
|
||||
# auth_cookie_SRCHHPGUSR = os.environ.get("AUTH_COOKIE_SRCHHPGUSR")
|
||||
users_chatbot[user_id] = UserChatbot(cookies=cookie_json)
|
||||
users_image_generator[user_id] = ImageGenAsync(auth_cookie, quiet=True)
|
||||
user_conversation_style[user_id] = "balanced"
|
||||
|
||||
class UserChatbot:
|
||||
def __init__(self, cookies):
|
||||
self.chatbot = Chatbot(cookies=cookies)
|
||||
|
||||
async def send_message(self, interaction, message, conversation_style):
|
||||
await send_message(self.chatbot, interaction, message, conversation_style)
|
||||
|
||||
async def create_image(self, interaction, prompt: str, image_generator):
|
||||
await create_image(interaction, prompt, image_generator)
|
||||
|
||||
async def reset(self):
|
||||
await self.chatbot.reset()
|
||||
|
||||
class EdgeGPT(Cog_Extension):
|
||||
# Chat with Bing
|
||||
@app_commands.command(name="bing", description="Have a chat with Bing")
|
||||
async def bing(self, interaction: discord.Interaction, *, message: str):
|
||||
try:
|
||||
using = await get_using_send(interaction.user.id)
|
||||
except:
|
||||
await set_using_send(interaction.user.id, False)
|
||||
using = await get_using_send(interaction.user.id)
|
||||
if not using:
|
||||
await interaction.response.defer(ephemeral=False, thinking=True)
|
||||
username = str(interaction.user)
|
||||
usermessage = message
|
||||
channel = str(interaction.channel)
|
||||
user_id = interaction.user.id
|
||||
if user_id not in users_chatbot:
|
||||
await init_chatbot(interaction.user.id)
|
||||
conversation_style = user_conversation_style[user_id]
|
||||
logger.info(f"\x1b[31m{username}\x1b[0m : '{usermessage}' ({channel}) [Style: {conversation_style}]")
|
||||
await users_chatbot[user_id].send_message(interaction, usermessage, conversation_style)
|
||||
else:
|
||||
await interaction.response.defer(ephemeral=True, thinking=True)
|
||||
await interaction.followup.send("> **Please wait for your last conversation to finish.**")
|
||||
|
||||
# Reset Bing conversation
|
||||
@app_commands.command(name="reset", description="Reset Bing conversation")
|
||||
async def reset(self, interaction: discord.Interaction):
|
||||
await interaction.response.defer(ephemeral=True, thinking=True)
|
||||
user_id = interaction.user.id
|
||||
try:
|
||||
await users_chatbot[user_id].reset()
|
||||
await interaction.followup.send("> **Info: Reset finish.**")
|
||||
logger.warning("\x1b[31mBing has been successfully reset\x1b[0m")
|
||||
except:
|
||||
await interaction.followup.send(f"> **You don't have any conversation yet.**")
|
||||
logger.exception("Bing reset failed.")
|
||||
|
||||
# Switch conversation style
|
||||
@app_commands.command(name="switch_style", description="Switch conversation style")
|
||||
@app_commands.choices(style=[app_commands.Choice(name="Creative", value="creative"), app_commands.Choice(name="Balanced", value="balanced"), app_commands.Choice(name="Precise", value="precise")])
|
||||
async def switch_style(self, interaction: discord.Interaction, style: app_commands.Choice[str]):
|
||||
await interaction.response.defer(ephemeral=True, thinking=True)
|
||||
user_id = interaction.user.id
|
||||
if user_id not in users_chatbot:
|
||||
await init_chatbot(user_id)
|
||||
user_conversation_style[user_id] = style.value
|
||||
await interaction.followup.send(f"> **Info: successfull switch conversation style to {style.value}.**")
|
||||
logger.warning(f"\x1b[31mConversation style has been successfully switch to {style.value}\x1b[0m")
|
||||
|
||||
# Set and delete personal Bing Cookies
|
||||
@app_commands.command(name="bing_cookies", description="Set or delete Bing Cookies")
|
||||
@app_commands.choices(choice=[app_commands.Choice(name="set", value="set"), app_commands.Choice(name="delete", value="delete")])
|
||||
async def cookies_setting(self, interaction: discord.Interaction, choice: app_commands.Choice[str], cookies_file: Optional[discord.Attachment]=None):
|
||||
await interaction.response.defer(ephemeral=True, thinking=True)
|
||||
user_id = interaction.user.id
|
||||
if choice.value == "set":
|
||||
try:
|
||||
content = json.loads(await cookies_file.read())
|
||||
for cookie in content:
|
||||
if cookie.get("name") == "_U":
|
||||
auth_cookie = cookie.get("value")
|
||||
break
|
||||
users_image_generator[user_id] = ImageGenAsync(auth_cookie, quiet=True)
|
||||
users_chatbot[user_id] = UserChatbot(cookies=content)
|
||||
user_conversation_style[user_id] = "balanced"
|
||||
await interaction.followup.send("> **Upload successful!**")
|
||||
logger.warning(f"\x1b[31m{interaction.user} set Bing Cookies successful\x1b[0m")
|
||||
except:
|
||||
await interaction.followup.send("> **Please upload your Bing Cookies.**")
|
||||
else:
|
||||
try:
|
||||
del users_chatbot[user_id]
|
||||
del users_image_generator[user_id]
|
||||
del user_conversation_style[user_id]
|
||||
await interaction.followup.send("> **Delete finish.**")
|
||||
logger.warning(f"\x1b[31m{interaction.user} delete Cookies\x1b[0m")
|
||||
except:
|
||||
await interaction.followup.send("> **You don't have any Bing Cookies.**")
|
||||
|
||||
# Create images
|
||||
@app_commands.command(name="create_image", description="generate image by Bing image creator")
|
||||
async def create_image(self, interaction: discord.Interaction, *, prompt: str):
|
||||
user_id = interaction.user.id
|
||||
if interaction.user.id not in users_chatbot:
|
||||
await init_chatbot(user_id)
|
||||
try:
|
||||
using = await get_using_create(user_id)
|
||||
except:
|
||||
await set_using_create(user_id, False)
|
||||
using = await get_using_create(user_id)
|
||||
if not using:
|
||||
logger.info(f"\x1b[31m{interaction.user}\x1b[0m : '{prompt}' ({interaction.channel}) [BingImageCreator]")
|
||||
await users_chatbot[user_id].create_image(interaction, prompt, users_image_generator[user_id] )
|
||||
else:
|
||||
await interaction.response.defer(ephemeral=True, thinking=True)
|
||||
await interaction.followup.send("> **Please wait for your last image to create finish.**")
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(EdgeGPT(bot))
|
@ -1,321 +0,0 @@
|
||||
import discord
|
||||
import re
|
||||
import os
|
||||
import json
|
||||
import asyncio
|
||||
from EdgeGPT.EdgeGPT import Chatbot, ConversationStyle
|
||||
from dotenv import load_dotenv
|
||||
from discord.ext import commands
|
||||
from core.classes import Cog_Extension
|
||||
from functools import partial
|
||||
from src import log
|
||||
|
||||
load_dotenv()
|
||||
|
||||
USE_SUGGEST_RESPONSES = True
|
||||
try:
|
||||
MENTION_CHANNEL_ID = int(os.getenv("MENTION_CHANNEL_ID"))
|
||||
except:
|
||||
MENTION_CHANNEL_ID = None
|
||||
logger = log.setup_logger(__name__)
|
||||
sem = asyncio.Semaphore(1)
|
||||
conversation_style = "balanced"
|
||||
|
||||
with open("./cookies.json", encoding="utf-8") as file:
|
||||
cookies = json.load(file)
|
||||
chatbot = Chatbot(cookies=cookies)
|
||||
|
||||
|
||||
# To add suggest responses
|
||||
class MyView(discord.ui.View):
|
||||
def __init__(self, chatbot: Chatbot, suggest_responses: list):
|
||||
super().__init__(timeout=120)
|
||||
# Add buttons
|
||||
for label in suggest_responses:
|
||||
button = discord.ui.Button(label=label)
|
||||
|
||||
# Button event
|
||||
async def callback(
|
||||
interaction: discord.Interaction, button: discord.ui.Button
|
||||
):
|
||||
await interaction.response.defer(ephemeral=False, thinking=True)
|
||||
# When click the button, all buttons will disable.
|
||||
for child in self.children:
|
||||
child.disabled = True
|
||||
await interaction.followup.edit_message(
|
||||
message_id=interaction.message.id, view=self
|
||||
)
|
||||
username = str(interaction.user)
|
||||
usermessage = button.label
|
||||
channel = str(interaction.channel)
|
||||
logger.info(
|
||||
f"\x1b[31m{username}\x1b[0m : '{usermessage}' ({channel}) [Style: {conversation_style}] [button]"
|
||||
)
|
||||
task = asyncio.create_task(
|
||||
send_message(chatbot, interaction, usermessage)
|
||||
)
|
||||
await asyncio.gather(task)
|
||||
|
||||
self.add_item(button)
|
||||
self.children[-1].callback = partial(callback, button=button)
|
||||
|
||||
|
||||
# Show Dropdown
|
||||
class DropdownView(discord.ui.View):
|
||||
def __init__(self):
|
||||
super().__init__(timeout=180)
|
||||
|
||||
options = [
|
||||
discord.SelectOption(
|
||||
label="Creative",
|
||||
description="Switch conversation style to Creative",
|
||||
emoji="🎨",
|
||||
),
|
||||
discord.SelectOption(
|
||||
label="Balanced",
|
||||
description="Switch conversation style to Balanced",
|
||||
emoji="⚖️",
|
||||
),
|
||||
discord.SelectOption(
|
||||
label="Precise",
|
||||
description="Switch conversation style to Precise",
|
||||
emoji="🔎",
|
||||
),
|
||||
discord.SelectOption(
|
||||
label="Reset", description="Reset conversation", emoji="🔄"
|
||||
),
|
||||
]
|
||||
|
||||
dropdown = discord.ui.Select(
|
||||
placeholder="Choose setting", min_values=1, max_values=1, options=options
|
||||
)
|
||||
|
||||
dropdown.callback = self.dropdown_callback
|
||||
self.add_item(dropdown)
|
||||
|
||||
# Dropdown event
|
||||
async def dropdown_callback(self, interaction: discord.Interaction):
|
||||
await interaction.response.defer(ephemeral=False, thinking=True)
|
||||
if interaction.data["values"][0] == "Creative":
|
||||
await set_conversation_style("creative")
|
||||
await interaction.followup.send(
|
||||
f"> **Info: successfull switch conversation style to *{interaction.data['values'][0]}*.**"
|
||||
)
|
||||
logger.warning(
|
||||
f"\x1b[31mConversation style has been successfully switch to {interaction.data['values'][0]}\x1b[0m"
|
||||
)
|
||||
elif interaction.data["values"][0] == "Balanced":
|
||||
await set_conversation_style("balanced")
|
||||
await interaction.followup.send(
|
||||
f"> **Info: successfull switch conversation style to *{interaction.data['values'][0]}*.**"
|
||||
)
|
||||
logger.warning(
|
||||
f"\x1b[31mConversation style has been successfully switch to {interaction.data['values'][0]}\x1b[0m"
|
||||
)
|
||||
elif interaction.data["values"][0] == "Precise":
|
||||
await set_conversation_style("precise")
|
||||
await interaction.followup.send(
|
||||
f"> **Info: successfull switch conversation style to *{interaction.data['values'][0]}*.**"
|
||||
)
|
||||
logger.warning(
|
||||
f"\x1b[31mConversation style has been successfully switch to {interaction.data['values'][0]}\x1b[0m"
|
||||
)
|
||||
else:
|
||||
await chatbot.reset()
|
||||
await interaction.followup.send(f"> **Info: Reset finish.**")
|
||||
logger.warning("\x1b[31mBing has been successfully reset\x1b[0m")
|
||||
# disable dropdown after select
|
||||
for dropdown in self.children:
|
||||
dropdown.disabled = True
|
||||
await interaction.followup.edit_message(
|
||||
message_id=interaction.message.id, view=self
|
||||
)
|
||||
|
||||
|
||||
# Set conversation style
|
||||
async def set_conversation_style(style: str):
|
||||
global conversation_style
|
||||
conversation_style = style
|
||||
|
||||
|
||||
async def set_chatbot(cookies):
|
||||
global chatbot
|
||||
chatbot = Chatbot(cookies=cookies)
|
||||
|
||||
|
||||
async def send_message(chatbot: Chatbot, message, user_message: str):
|
||||
async with sem:
|
||||
if isinstance(message, discord.message.Message):
|
||||
await message.channel.typing()
|
||||
reply = ""
|
||||
text = ""
|
||||
link_embed = ""
|
||||
images_embed = []
|
||||
all_url = []
|
||||
try:
|
||||
# Change conversation style
|
||||
if conversation_style == "creative":
|
||||
reply = await chatbot.ask(
|
||||
prompt=user_message,
|
||||
conversation_style=ConversationStyle.creative,
|
||||
simplify_response=True,
|
||||
)
|
||||
elif conversation_style == "precise":
|
||||
reply = await chatbot.ask(
|
||||
prompt=user_message,
|
||||
conversation_style=ConversationStyle.precise,
|
||||
simplify_response=True,
|
||||
)
|
||||
else:
|
||||
reply = await chatbot.ask(
|
||||
prompt=user_message,
|
||||
conversation_style=ConversationStyle.balanced,
|
||||
simplify_response=True,
|
||||
)
|
||||
|
||||
# Get reply text
|
||||
text = f"{reply['text']}"
|
||||
text = re.sub(r"\[\^(\d+)\^\]", lambda match: "", text)
|
||||
|
||||
# Get the URL, if available
|
||||
try:
|
||||
if len(reply["sources"]) != 0:
|
||||
for i, url in enumerate(reply["sources"], start=1):
|
||||
if len(url["providerDisplayName"]) == 0:
|
||||
all_url.append(f"{i}. {url['seeMoreUrl']}")
|
||||
else:
|
||||
all_url.append(
|
||||
f"{i}. [{url['providerDisplayName']}]({url['seeMoreUrl']})"
|
||||
)
|
||||
link_text = "\n".join(all_url)
|
||||
link_embed = discord.Embed(description=link_text)
|
||||
except:
|
||||
pass
|
||||
|
||||
# Set the final message
|
||||
if isinstance(message, discord.interactions.Interaction):
|
||||
user_message = user_message.replace("\n", "")
|
||||
ask = f"> **{user_message}**\t(***style: {conversation_style}***)\n\n"
|
||||
response = f"{ask}{text}"
|
||||
else:
|
||||
response = f"{text}\t(***style: {conversation_style}***)"
|
||||
|
||||
# Discord limit about 2000 characters for a message
|
||||
while len(response) > 2000:
|
||||
temp = response[:2000]
|
||||
response = response[2000:]
|
||||
if isinstance(message, discord.interactions.Interaction):
|
||||
await message.followup.send(temp)
|
||||
else:
|
||||
await message.channel.send(temp)
|
||||
|
||||
# Get the image, if available
|
||||
try:
|
||||
if len(link_embed) == 0:
|
||||
all_image = re.findall(
|
||||
"https?://[\w\./]+", str(reply["sources_text"])
|
||||
)
|
||||
[
|
||||
images_embed.append(
|
||||
discord.Embed(url="https://www.bing.com/").set_image(
|
||||
url=image_link
|
||||
)
|
||||
)
|
||||
for image_link in all_image
|
||||
]
|
||||
except:
|
||||
pass
|
||||
|
||||
if USE_SUGGEST_RESPONSES:
|
||||
suggest_responses = reply["suggestions"]
|
||||
if images_embed:
|
||||
if isinstance(message, discord.interactions.Interaction):
|
||||
await message.followup.send(
|
||||
response,
|
||||
view=MyView(chatbot, suggest_responses),
|
||||
embeds=images_embed,
|
||||
wait=True,
|
||||
)
|
||||
else:
|
||||
await message.channel.send(
|
||||
response,
|
||||
view=MyView(chatbot, suggest_responses),
|
||||
embeds=images_embed,
|
||||
)
|
||||
elif link_embed:
|
||||
if isinstance(message, discord.interactions.Interaction):
|
||||
await message.followup.send(
|
||||
response,
|
||||
view=MyView(chatbot, suggest_responses),
|
||||
embed=link_embed,
|
||||
wait=True,
|
||||
)
|
||||
else:
|
||||
await message.channel.send(
|
||||
response,
|
||||
view=MyView(chatbot, suggest_responses),
|
||||
embed=link_embed,
|
||||
)
|
||||
else:
|
||||
if isinstance(message, discord.interactions.Interaction):
|
||||
await message.followup.send(
|
||||
response, view=MyView(chatbot, suggest_responses), wait=True
|
||||
)
|
||||
else:
|
||||
await message.channel.send(
|
||||
response, view=MyView(chatbot, suggest_responses)
|
||||
)
|
||||
else:
|
||||
if images_embed:
|
||||
if isinstance(message, discord.interactions.Interaction):
|
||||
await message.followup.send(
|
||||
response, embeds=images_embed, wait=True
|
||||
)
|
||||
else:
|
||||
await message.channel.send(response, embeds=images_embed)
|
||||
elif link_embed:
|
||||
if isinstance(message, discord.interactions.Interaction):
|
||||
await message.followup.send(
|
||||
response, embed=link_embed, wait=True
|
||||
)
|
||||
else:
|
||||
await message.channel.send(response, embed=link_embed)
|
||||
else:
|
||||
if isinstance(message, discord.interactions.Interaction):
|
||||
await message.followup.send(response, wait=True)
|
||||
else:
|
||||
await message.channel.send(response)
|
||||
except Exception as e:
|
||||
if isinstance(message, discord.interactions.Interaction):
|
||||
await message.followup.send(f">>> **Error: {e}**")
|
||||
else:
|
||||
await message.channel.send(f">>> **Error: {e}**")
|
||||
logger.exception(f"Error while sending message: {e}")
|
||||
|
||||
|
||||
class Event(Cog_Extension):
|
||||
@commands.Cog.listener()
|
||||
async def on_message(self, message: discord.Message):
|
||||
if message.author == self.bot.user:
|
||||
return
|
||||
if self.bot.user in message.mentions:
|
||||
if not MENTION_CHANNEL_ID or message.channel.id == MENTION_CHANNEL_ID:
|
||||
content = re.sub(r"<@.*?>", "", message.content).strip()
|
||||
if len(content) > 0:
|
||||
username = str(message.author)
|
||||
channel = str(message.channel)
|
||||
logger.info(
|
||||
f"\x1b[31m{username}\x1b[0m : '{content}' ({channel}) [Style: {conversation_style}]"
|
||||
)
|
||||
task = asyncio.create_task(send_message(chatbot, message, content))
|
||||
await asyncio.gather(task)
|
||||
else:
|
||||
await message.channel.send(view=DropdownView())
|
||||
elif MENTION_CHANNEL_ID is not None:
|
||||
await message.channel.send(
|
||||
f"> **Can only be mentioned at <#{self.bot.get_channel(MENTION_CHANNEL_ID).id}>**"
|
||||
)
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(Event(bot))
|
@ -1,35 +0,0 @@
|
||||
import discord
|
||||
from core.classes import Cog_Extension
|
||||
from discord import app_commands
|
||||
|
||||
|
||||
class Help(Cog_Extension):
|
||||
@app_commands.command(name="help", description="Show how to use")
|
||||
async def help(self, interaction: discord.Interaction):
|
||||
embed = discord.Embed(
|
||||
title="Help",
|
||||
)
|
||||
embed.add_field(
|
||||
name="/bing_cookies",
|
||||
value="Set and delete your Bing Cookies.",
|
||||
inline=False,
|
||||
)
|
||||
embed.add_field(name="/bing", value="Chat with Bing.", inline=False)
|
||||
embed.add_field(
|
||||
name="/reset", value="Reset your Bing conversation.", inline=False
|
||||
)
|
||||
embed.add_field(
|
||||
name="/switch_style",
|
||||
value="Switch your Bing conversation style.",
|
||||
inline=False,
|
||||
)
|
||||
embed.add_field(
|
||||
name="/create_image",
|
||||
value="Generate image by Bing Image Creator.",
|
||||
inline=False,
|
||||
)
|
||||
await interaction.response.send_message(embed=embed)
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(Help(bot))
|
@ -1,11 +0,0 @@
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
spartan:
|
||||
container_name: Spartan
|
||||
build: .
|
||||
environment:
|
||||
- DISCORD_BOT_TOKEN=${DISCORD_BOT_TOKEN}
|
||||
volumes:
|
||||
- ./cookies.json:/bot/cookies.json
|
||||
- ./config.yml:/bot/config.yml
|
@ -1,6 +0,0 @@
|
||||
[
|
||||
{
|
||||
"name": "cookie1",
|
||||
"value": "1lEXeWRSIPUsQ0S3tdAc3v7BexGK2qBlzsXz8j52w_HNBoOsegjiwRySQHmfoWduHVUxSXo6cETPP2qNrYWAz6k7wn43WGO9i7ll9_Wl7M6HA2c9twbKByfAtAB5fr26wPawQ6y1GCdakD_Kr4xdD20fvkytnmOmZu7Ktnb9mUVE605AAbJcIA9SOlRN5410ZPOnZA1cIzr4WtAFWNfQKPG6Sxk_zO5zvXQfYTyMNmOI"
|
||||
}
|
||||
]
|
@ -1,6 +0,0 @@
|
||||
from discord.ext import commands
|
||||
|
||||
|
||||
class Cog_Extension(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
@ -1,4 +0,0 @@
|
||||
discord.py==2.3.2
|
||||
python-dotenv==1.0.0
|
||||
PyYAML==6.0.1
|
||||
bing-chat==1.9.3
|
@ -1,40 +0,0 @@
|
||||
import discord
|
||||
import asyncio
|
||||
from src import log
|
||||
|
||||
logger = log.setup_logger(__name__)
|
||||
using_func = {}
|
||||
|
||||
|
||||
async def get_using_create(user_id):
|
||||
return using_func[user_id]
|
||||
|
||||
|
||||
async def set_using_create(user_id, status: bool):
|
||||
using_func[user_id] = status
|
||||
|
||||
|
||||
async def create_image(interaction: discord.Interaction, prompt: str, image_generator):
|
||||
await interaction.response.defer(ephemeral=False, thinking=True)
|
||||
using_func[interaction.user.id] = True
|
||||
try:
|
||||
embeds = []
|
||||
prompts = f"> **{prompt}** - <@{str(interaction.user.id)}> (***BingImageCreator***)\n\n"
|
||||
# Fetches image links
|
||||
images = await image_generator.get_images(prompt)
|
||||
# Add embed to list of embeds
|
||||
[
|
||||
embeds.append(
|
||||
discord.Embed(url="https://www.bing.com/").set_image(url=image_link)
|
||||
)
|
||||
for image_link in images
|
||||
]
|
||||
await interaction.followup.send(prompts, embeds=embeds, wait=True)
|
||||
except asyncio.TimeoutError:
|
||||
await interaction.followup.send("> **Error: Request timed out.**")
|
||||
logger.exception("Error while create image: Request timed out.")
|
||||
except Exception as e:
|
||||
await interaction.followup.send(f"> **Error: {e}**")
|
||||
logger.exception(f"Error while create image: {e}")
|
||||
finally:
|
||||
using_func[interaction.user.id] = False
|
@ -1,66 +0,0 @@
|
||||
import os
|
||||
import logging
|
||||
import logging.handlers
|
||||
|
||||
|
||||
class CustomFormatter(logging.Formatter):
|
||||
LEVEL_COLORS = [
|
||||
(logging.DEBUG, "\x1b[40;1m"),
|
||||
(logging.INFO, "\x1b[34;1m"),
|
||||
(logging.WARNING, "\x1b[33;1m"),
|
||||
(logging.ERROR, "\x1b[31m"),
|
||||
(logging.CRITICAL, "\x1b[41m"),
|
||||
]
|
||||
FORMATS = {
|
||||
level: logging.Formatter(
|
||||
f"\x1b[30;1m%(asctime)s\x1b[0m {color}%(levelname)-8s\x1b[0m \x1b[35m%(name)s\x1b[0m -> %(message)s",
|
||||
"%Y-%m-%d %H:%M:%S",
|
||||
)
|
||||
for level, color in LEVEL_COLORS
|
||||
}
|
||||
|
||||
def format(self, record):
|
||||
formatter = self.FORMATS.get(record.levelno)
|
||||
if formatter is None:
|
||||
formatter = self.FORMATS[logging.DEBUG]
|
||||
|
||||
# Override the traceback to always print in red
|
||||
if record.exc_info:
|
||||
text = formatter.formatException(record.exc_info)
|
||||
record.exc_text = f"\x1b[31m{text}\x1b[0m"
|
||||
|
||||
output = formatter.format(record)
|
||||
|
||||
# Remove the cache layer
|
||||
record.exc_text = None
|
||||
return output
|
||||
|
||||
|
||||
def setup_logger(module_name: str) -> logging.Logger:
|
||||
# create logger
|
||||
library, _, _ = module_name.partition(".py")
|
||||
logger = logging.getLogger(library)
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
if not logger.handlers:
|
||||
# create console handler
|
||||
console_handler = logging.StreamHandler()
|
||||
console_handler.setLevel(logging.INFO)
|
||||
console_handler.setFormatter(CustomFormatter())
|
||||
# specify that the log file path is the same as `main.py` file path
|
||||
grandparent_dir = os.path.abspath(__file__ + "/../../")
|
||||
log_name = "discord_bot.log"
|
||||
log_path = os.path.join(grandparent_dir, log_name)
|
||||
# create local log handler
|
||||
log_handler = logging.handlers.RotatingFileHandler(
|
||||
filename=log_path,
|
||||
encoding="utf-8",
|
||||
maxBytes=32 * 1024 * 1024, # 32 MiB
|
||||
backupCount=2, # Rotate through 5 files
|
||||
)
|
||||
log_handler.setFormatter(CustomFormatter())
|
||||
# Add handlers to logger
|
||||
logger.addHandler(log_handler)
|
||||
logger.addHandler(console_handler)
|
||||
|
||||
return logger
|
@ -1,194 +0,0 @@
|
||||
import discord
|
||||
import re
|
||||
from EdgeGPT.EdgeGPT import Chatbot, ConversationStyle
|
||||
from src import log
|
||||
from functools import partial
|
||||
|
||||
USE_SUGGEST_RESPONSES = True
|
||||
logger = log.setup_logger(__name__)
|
||||
using_func = {}
|
||||
|
||||
|
||||
# To add suggest responses
|
||||
class MyView(discord.ui.View):
|
||||
def __init__(
|
||||
self,
|
||||
interaction: discord.Interaction,
|
||||
chatbot: Chatbot,
|
||||
conversation_style: str,
|
||||
suggest_responses: list,
|
||||
):
|
||||
super().__init__(timeout=120)
|
||||
self.button_author = interaction.user.id
|
||||
# Add buttons
|
||||
for label in suggest_responses:
|
||||
button = discord.ui.Button(label=label)
|
||||
|
||||
# Button event
|
||||
async def callback(
|
||||
interaction: discord.Interaction,
|
||||
button_author: int,
|
||||
button: discord.ui.Button,
|
||||
):
|
||||
if interaction.user.id != button_author:
|
||||
await interaction.response.defer(ephemeral=True, thinking=True)
|
||||
await interaction.followup.send(
|
||||
"You don't have permission to press this button."
|
||||
)
|
||||
elif not using_func[interaction.user.id]:
|
||||
await interaction.response.defer(ephemeral=False, thinking=True)
|
||||
# When click the button, all buttons will disable.
|
||||
for child in self.children:
|
||||
child.disabled = True
|
||||
await interaction.followup.edit_message(
|
||||
message_id=interaction.message.id, view=self
|
||||
)
|
||||
username = str(interaction.user)
|
||||
usermessage = button.label
|
||||
channel = str(interaction.channel)
|
||||
logger.info(
|
||||
f"\x1b[31m{username}\x1b[0m : '{usermessage}' ({channel}) [Style: {conversation_style}] [button]"
|
||||
)
|
||||
await send_message(
|
||||
chatbot, interaction, usermessage, conversation_style
|
||||
)
|
||||
else:
|
||||
await interaction.response.defer(ephemeral=True, thinking=True)
|
||||
await interaction.followup.send(
|
||||
"Please wait for your last conversation to finish."
|
||||
)
|
||||
|
||||
self.add_item(button)
|
||||
self.children[-1].callback = partial(
|
||||
callback, button_author=self.button_author, button=button
|
||||
)
|
||||
|
||||
|
||||
async def get_using_send(user_id):
|
||||
return using_func[user_id]
|
||||
|
||||
|
||||
async def set_using_send(user_id, status: bool):
|
||||
using_func[user_id] = status
|
||||
|
||||
|
||||
async def send_message(
|
||||
chatbot: Chatbot,
|
||||
interaction: discord.Interaction,
|
||||
user_message: str,
|
||||
conversation_style: str,
|
||||
):
|
||||
using_func[interaction.user.id] = True
|
||||
reply = ""
|
||||
text = ""
|
||||
link_embed = ""
|
||||
images_embed = []
|
||||
all_url = []
|
||||
try:
|
||||
# Change conversation style
|
||||
if conversation_style == "creative":
|
||||
reply = await chatbot.ask(
|
||||
prompt=user_message,
|
||||
conversation_style=ConversationStyle.creative,
|
||||
simplify_response=True,
|
||||
)
|
||||
elif conversation_style == "precise":
|
||||
reply = await chatbot.ask(
|
||||
prompt=user_message,
|
||||
conversation_style=ConversationStyle.precise,
|
||||
simplify_response=True,
|
||||
)
|
||||
else:
|
||||
reply = await chatbot.ask(
|
||||
prompt=user_message,
|
||||
conversation_style=ConversationStyle.balanced,
|
||||
simplify_response=True,
|
||||
)
|
||||
|
||||
# Get reply text
|
||||
text = f"{reply['text']}"
|
||||
text = re.sub(r"\[\^(\d+)\^\]", lambda match: "", text)
|
||||
|
||||
# Get the URL, if available
|
||||
try:
|
||||
if len(reply["sources"]) != 0:
|
||||
for i, url in enumerate(reply["sources"], start=1):
|
||||
if len(url["providerDisplayName"]) == 0:
|
||||
all_url.append(f"{i}. {url['seeMoreUrl']}")
|
||||
else:
|
||||
all_url.append(
|
||||
f"{i}. [{url['providerDisplayName']}]({url['seeMoreUrl']})"
|
||||
)
|
||||
link_text = "\n".join(all_url)
|
||||
link_embed = discord.Embed(description=link_text)
|
||||
except:
|
||||
pass
|
||||
|
||||
# Set the final message
|
||||
user_message = user_message.replace("\n", "")
|
||||
ask = f"> **{user_message}** - <@{str(interaction.user.id)}> (***style: {conversation_style}***)\n\n"
|
||||
response = f"{ask}{text}"
|
||||
|
||||
# Discord limit about 2000 characters for a message
|
||||
while len(response) > 2000:
|
||||
temp = response[:2000]
|
||||
response = response[2000:]
|
||||
await interaction.followup.send(temp)
|
||||
|
||||
# Get the image, if available
|
||||
try:
|
||||
if len(link_embed) == 0:
|
||||
all_image = re.findall("https?://[\w\./]+", str(reply["sources_text"]))
|
||||
[
|
||||
images_embed.append(
|
||||
discord.Embed(url="https://www.bing.com/").set_image(
|
||||
url=image_link
|
||||
)
|
||||
)
|
||||
for image_link in all_image
|
||||
]
|
||||
except:
|
||||
pass
|
||||
# Add all suggest responses in list
|
||||
if USE_SUGGEST_RESPONSES:
|
||||
suggest_responses = reply["suggestions"]
|
||||
if images_embed:
|
||||
await interaction.followup.send(
|
||||
response,
|
||||
view=MyView(
|
||||
interaction, chatbot, conversation_style, suggest_responses
|
||||
),
|
||||
embeds=images_embed,
|
||||
wait=True,
|
||||
)
|
||||
elif link_embed:
|
||||
await interaction.followup.send(
|
||||
response,
|
||||
view=MyView(
|
||||
interaction, chatbot, conversation_style, suggest_responses
|
||||
),
|
||||
embed=link_embed,
|
||||
wait=True,
|
||||
)
|
||||
else:
|
||||
await interaction.followup.send(
|
||||
response,
|
||||
view=MyView(
|
||||
interaction, chatbot, conversation_style, suggest_responses
|
||||
),
|
||||
wait=True,
|
||||
)
|
||||
else:
|
||||
if images_embed:
|
||||
await interaction.followup.send(
|
||||
response, embeds=images_embed, wait=True
|
||||
)
|
||||
elif link_embed:
|
||||
await interaction.followup.send(response, embed=link_embed, wait=True)
|
||||
else:
|
||||
await interaction.followup.send(response, wait=True)
|
||||
except Exception as e:
|
||||
await interaction.followup.send(f">>> **Error: {e}**")
|
||||
logger.exception(f"Error while sending message: {e}")
|
||||
finally:
|
||||
using_func[interaction.user.id] = False
|
@ -1,197 +0,0 @@
|
||||
import asyncio
|
||||
import argparse
|
||||
from collections import Counter
|
||||
import json
|
||||
import pathlib
|
||||
import re
|
||||
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
import gradio as gr
|
||||
from gradio import utils
|
||||
import requests
|
||||
|
||||
from typing import Dict, List
|
||||
|
||||
from utils import *
|
||||
|
||||
|
||||
lock = asyncio.Lock()
|
||||
|
||||
bot = commands.Bot("", intents=discord.Intents(messages=True, guilds=True))
|
||||
|
||||
|
||||
GUILD_SPACES_FILE = "guild_spaces.pkl"
|
||||
|
||||
|
||||
if pathlib.Path(GUILD_SPACES_FILE).exists():
|
||||
guild_spaces = read_pickle_file(GUILD_SPACES_FILE)
|
||||
assert isinstance(guild_spaces, dict), f"{GUILD_SPACES_FILE} in invalid format."
|
||||
guild_blocks = {}
|
||||
delete_keys = []
|
||||
for k, v in guild_spaces.items():
|
||||
try:
|
||||
guild_blocks[k] = gr.Interface.load(v, src="spaces")
|
||||
except ValueError:
|
||||
delete_keys.append(k)
|
||||
for k in delete_keys:
|
||||
del guild_spaces[k]
|
||||
else:
|
||||
guild_spaces: Dict[int, str] = {}
|
||||
guild_blocks: Dict[int, gr.Blocks] = {}
|
||||
|
||||
|
||||
HASHED_USERS_FILE = "users.pkl"
|
||||
|
||||
if pathlib.Path(HASHED_USERS_FILE).exists():
|
||||
hashed_users = read_pickle_file(HASHED_USERS_FILE)
|
||||
assert isinstance(hashed_users, list), f"{HASHED_USERS_FILE} in invalid format."
|
||||
else:
|
||||
hashed_users: List[str] = []
|
||||
|
||||
|
||||
@bot.event
|
||||
async def on_ready():
|
||||
print(f"Logged in as {bot.user}")
|
||||
print(f"Running in {len(bot.guilds)} servers...")
|
||||
|
||||
|
||||
async def run_prediction(space: gr.Blocks, *inputs):
|
||||
inputs = list(inputs)
|
||||
fn_index = 0
|
||||
processed_inputs = space.serialize_data(fn_index=fn_index, inputs=inputs)
|
||||
batch = space.dependencies[fn_index]["batch"]
|
||||
|
||||
if batch:
|
||||
processed_inputs = [[inp] for inp in processed_inputs]
|
||||
|
||||
outputs = await space.process_api(
|
||||
fn_index=fn_index, inputs=processed_inputs, request=None, state={}
|
||||
)
|
||||
outputs = outputs["data"]
|
||||
|
||||
if batch:
|
||||
outputs = [out[0] for out in outputs]
|
||||
|
||||
processed_outputs = space.deserialize_data(fn_index, outputs)
|
||||
processed_outputs = utils.resolve_singleton(processed_outputs)
|
||||
|
||||
return processed_outputs
|
||||
|
||||
|
||||
async def display_stats(message: discord.Message):
|
||||
await message.channel.send(
|
||||
f"Running in {len(bot.guilds)} servers\n"
|
||||
f"Total # of users: {len(hashed_users)}\n"
|
||||
f"------------------"
|
||||
)
|
||||
await message.channel.send(f"Most popular spaces:")
|
||||
# display the top 10 most frequently occurring strings and their counts
|
||||
spaces = guild_spaces.values()
|
||||
counts = Counter(spaces)
|
||||
for space, count in counts.most_common(10):
|
||||
await message.channel.send(f"- {space}: {count}")
|
||||
|
||||
|
||||
async def load_space(guild: discord.Guild, message: discord.Message, content: str):
|
||||
iframe_url = (
|
||||
requests.get(f"https://huggingface.co/api/spaces/{content}/host")
|
||||
.json()
|
||||
.get("host")
|
||||
)
|
||||
if iframe_url is None:
|
||||
return await message.channel.send(
|
||||
f"Space: {content} not found. If you'd like to make a prediction, enclose the inputs in quotation marks."
|
||||
)
|
||||
else:
|
||||
await message.channel.send(
|
||||
f"Loading Space: https://huggingface.co/spaces/{content}..."
|
||||
)
|
||||
interface = gr.Interface.load(content, src="spaces")
|
||||
guild_spaces[guild.id] = content
|
||||
guild_blocks[guild.id] = interface
|
||||
asyncio.create_task(update_pickle_file(guild_spaces, GUILD_SPACES_FILE))
|
||||
if len(content) > 32 - len(f"{bot.name} []"): # type: ignore
|
||||
nickname = content[: 32 - len(f"{bot.name} []") - 3] + "..." # type: ignore
|
||||
else:
|
||||
nickname = content
|
||||
nickname = f"{bot.name} [{nickname}]" # type: ignore
|
||||
await guild.me.edit(nick=nickname)
|
||||
await message.channel.send(
|
||||
"Ready to make predictions! Type in your inputs and enclose them in quotation marks."
|
||||
)
|
||||
|
||||
|
||||
async def disconnect_space(bot: commands.Bot, guild: discord.Guild):
|
||||
guild_spaces.pop(guild.id, None)
|
||||
guild_blocks.pop(guild.id, None)
|
||||
asyncio.create_task(update_pickle_file(guild_spaces, GUILD_SPACES_FILE))
|
||||
await guild.me.edit(nick=bot.name) # type: ignore
|
||||
|
||||
|
||||
async def make_prediction(guild: discord.Guild, message: discord.Message, content: str):
|
||||
if guild.id in guild_spaces:
|
||||
params = re.split(r' (?=")', content)
|
||||
params = [p.strip("'\"") for p in params]
|
||||
space = guild_blocks[guild.id]
|
||||
predictions = await run_prediction(space, *params)
|
||||
if isinstance(predictions, (tuple, list)):
|
||||
for p in predictions:
|
||||
await send_file_or_text(message.channel, p)
|
||||
else:
|
||||
await send_file_or_text(message.channel, predictions)
|
||||
return
|
||||
else:
|
||||
await message.channel.send(
|
||||
"No Space is currently running. Please type in the name of a Hugging Face Space name first, e.g. abidlabs/en2fr"
|
||||
)
|
||||
await guild.me.edit(nick=bot.name) # type: ignore
|
||||
|
||||
|
||||
@bot.event
|
||||
async def on_message(message: discord.Message):
|
||||
if message.author == bot.user:
|
||||
return
|
||||
h = hash_user_id(message.author.id)
|
||||
if h not in hashed_users:
|
||||
hashed_users.append(h)
|
||||
asyncio.create_task(update_pickle_file(hashed_users, HASHED_USERS_FILE))
|
||||
else:
|
||||
if message.content:
|
||||
content = remove_tags(message.content)
|
||||
guild = message.channel.guild
|
||||
assert guild, "Message not sent in a guild."
|
||||
|
||||
if content.strip() == "exit":
|
||||
await disconnect_space(bot, guild)
|
||||
elif content.strip() == "stats":
|
||||
await display_stats(message)
|
||||
elif content.startswith('"') or content.startswith("'"):
|
||||
await make_prediction(guild, message, content)
|
||||
else:
|
||||
await load_space(guild, message, content)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--token",
|
||||
type=str,
|
||||
help="API key for the Discord bot. You can set this to your Discord token if you'd like to make your own clone of the Gradio Bot.",
|
||||
required=False,
|
||||
default="",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.token.strip():
|
||||
discord_token = args.token
|
||||
bot.env = "staging" # type: ignore
|
||||
bot.name = "StagingBot" # type: ignore
|
||||
else:
|
||||
with open("secrets.json") as fp:
|
||||
discord_token = json.load(fp)["discord_token"]
|
||||
bot.env = "prod" # type: ignore
|
||||
bot.name = "GradioBot" # type: ignore
|
||||
|
||||
bot.run(discord_token)
|
@ -1,41 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import pickle
|
||||
import hashlib
|
||||
import pathlib
|
||||
from typing import Dict, List
|
||||
|
||||
import discord
|
||||
|
||||
lock = asyncio.Lock()
|
||||
|
||||
|
||||
async def update_pickle_file(data: Dict | List, file_path: str):
|
||||
async with lock:
|
||||
with open(file_path, "wb") as fp:
|
||||
pickle.dump(data, fp)
|
||||
|
||||
|
||||
def read_pickle_file(file_path: str):
|
||||
with open(file_path, "rb") as fp:
|
||||
return pickle.load(fp)
|
||||
|
||||
|
||||
async def send_file_or_text(channel, file_or_text: str):
|
||||
# if the file exists, send as a file
|
||||
if pathlib.Path(str(file_or_text)).exists():
|
||||
with open(file_or_text, "rb") as f:
|
||||
return await channel.send(file=discord.File(f))
|
||||
else:
|
||||
return await channel.send(file_or_text)
|
||||
|
||||
|
||||
def remove_tags(content: str) -> str:
|
||||
content = content.replace("<@1040198143695933501>", "")
|
||||
content = content.replace("<@1057338428938788884>", "")
|
||||
return content.strip()
|
||||
|
||||
|
||||
def hash_user_id(user_id: int) -> str:
|
||||
return hashlib.sha256(str(user_id).encode("utf-8")).hexdigest()
|
@ -1,2 +0,0 @@
|
||||
OPENAI_API_KEY="YOUR_API_KEY"
|
||||
DALLE_COOKIE="YOUR_COOKIE"
|
@ -1,71 +0,0 @@
|
||||
MythGen: A Dynamic New Art Form
|
||||
Overview
|
||||
|
||||

|
||||
|
||||
|
||||
MythGen is an Iterative Multimedia Generator that allows users to create their own comic stories based on textual prompts. The system integrates state-of-the-art language and image models to provide a seamless and creative experience.
|
||||
Features
|
||||
|
||||
Initial Prompting: Kick-start your story with an initial text prompt.
|
||||
Artistic Style Suffix: Maintain a consistent artistic style throughout your comic.
|
||||
Image Generation: Generate captivating comic panels based on textual captions.
|
||||
Caption Generation: Produce engaging captions for each comic panel.
|
||||
Interactive Story Building: Select your favorite panels and captions to build your story iteratively.
|
||||
Storyboard: View the sequence of your selected panels and their associated captions.
|
||||
State Management: Keep track of the current state of your comic generation process.
|
||||
User-Friendly Interface: Easy-to-use interface built on Gradio.
|
||||
|
||||
Prerequisites
|
||||
OpenAI API Key
|
||||
|
||||
You will need an OpenAI API key to access GPT-3 for generating captions. Follow these steps to obtain one:
|
||||
|
||||
Visit OpenAI's Developer Dashboard.
|
||||
Sign up for an API key and follow the verification process.
|
||||
Once verified, you will be provided with an API key.
|
||||
|
||||
Bing Image Creator Cookie
|
||||
|
||||
You should obtain your cookie to run this program. Follow these steps to obtain your cookie:
|
||||
|
||||
Go to Bing Image Creator in your browser and log in to your account.
|
||||
Press Ctrl+Shift+J to open developer tools.
|
||||
Navigate to the Application section.
|
||||
Click on the Cookies section.
|
||||
Find the variable _U and copy its value.
|
||||
|
||||
How to Use
|
||||
|
||||
Initial Prompt: Start by inputting your initial comic concept.
|
||||
Select a Panel: Choose your favorite panel and caption from the generated options.
|
||||
Iterate: Use the "Next Part" button to generate the next part of your comic based on your latest selection.
|
||||
View Storyboard: See your selected comic panels and captions in a storyboard for a comprehensive view of your comic.
|
||||
Finalize: Continue this process until you've created your full comic story.
|
||||
|
||||
Installation
|
||||
|
||||
bash
|
||||
|
||||
pip install -r requirements.txt
|
||||
|
||||
Running MythGen
|
||||
|
||||
bash
|
||||
|
||||
python main.py
|
||||
|
||||
This will launch the Gradio interface where you can interact with MythGen.
|
||||
Dependencies
|
||||
|
||||
Python 3.x
|
||||
Gradio
|
||||
OpenAI's GPT-3
|
||||
DALL-E
|
||||
|
||||
Contributing
|
||||
|
||||
We welcome contributions! Please read the CONTRIBUTING.md for guidelines on how to contribute to this project.
|
||||
License
|
||||
|
||||
This project is licensed under the MIT License. See LICENSE.md for details.
|
@ -1,6 +0,0 @@
|
||||
[
|
||||
{
|
||||
"name": "cookie1",
|
||||
"value": "1lEXeWRSIPUsQ0S3tdAc3v7BexGK2qBlzsXz8j52w_HNBoOsegjiwRySQHmfoWduHVUxSXo6cETPP2qNrYWAz6k7wn43WGO9i7ll9_Wl7M6HA2c9twbKByfAtAB5fr26wPawQ6y1GCdakD_Kr4xdD20fvkytnmOmZu7Ktnb9mUVE605AAbJcIA9SOlRN5410ZPOnZA1cIzr4WtAFWNfQKPG6Sxk_zO5zvXQfYTyMNmOI"
|
||||
}
|
||||
]
|
@ -1,8 +0,0 @@
|
||||
dalle3==0.0.7
|
||||
Flask==2.3.2
|
||||
gradio==3.48.0
|
||||
openai==0.28.1
|
||||
Pillow==10.1.0
|
||||
python-dotenv==1.0.0
|
||||
Requests==2.31.0
|
||||
swarms==1.8.2
|
@ -1,6 +0,0 @@
|
||||
ELEVEN_LABS_API_KEY = "<your_api_key>" # https://elevenlabs.io/speech-synthesis
|
||||
OPENAI_API_KEY = "<your_api_key>" # https://platform.openai.com/account/api-keys
|
||||
DISCORD_TOKEN="discord_token"
|
||||
API_BASE="api_base"
|
||||
SYSTEM_MESSAGE=""
|
||||
BOT_ID="your_bot_token"
|
@ -1,17 +0,0 @@
|
||||
# Use an official Python runtime as a parent image
|
||||
FROM python:3.10
|
||||
|
||||
# Set the working directory in the container to /app
|
||||
WORKDIR /app
|
||||
|
||||
# Add the current directory contents into the container at /app
|
||||
ADD . /app
|
||||
|
||||
# Install any needed packages specified in requirements.txt
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# Make port 80 available to the world outside this container
|
||||
EXPOSE 80
|
||||
|
||||
# Run DiscordInterpreter.py when the container launches
|
||||
CMD ["python", "main.py"]
|
@ -1,124 +0,0 @@
|
||||
---
|
||||
title: open-interpreter
|
||||
app_file: jarvis.py
|
||||
sdk: gradio
|
||||
sdk_version: 3.33.1
|
||||
---
|
||||
# Open-Sourcerer: The Code Sorcerer's Apprentice
|
||||

|
||||
|
||||
Greetings, fellow developer! Welcome to the realm of the Open-Sourcerer, your trusty assistant in the magical world of open source projects. Open-Sourcerer is here to assist you in finding, integrating, and mastering the arcane arts of open source code.
|
||||
|
||||
## Introduction
|
||||
|
||||
Open-Sourcerer is your magical companion, capable of traversing the vast landscapes of the internet, particularly GitHub, to discover open source projects that align with your desires. It can also lend you a hand in weaving these projects into your own creations.
|
||||
|
||||
### How Does Open-Sourcerer Work?
|
||||
|
||||
Open-Sourcerer operates in two phases:
|
||||
|
||||
1. **Discovery**: It explores the realms of GitHub to unearth repositories that resonate with your quest.
|
||||
|
||||
2. **Integration and Assistance**: Once you've chosen your allies (repositories), Open-Sourcerer helps you integrate them into your own codebase. It can even conjure code snippets to assist you.
|
||||
|
||||
## Installation
|
||||
|
||||
Before embarking on this mystical journey, ensure you have the following:
|
||||
|
||||
- Python (version X.X.X)
|
||||
- Git (version X.X.X)
|
||||
- Your favorite code editor (e.g., Visual Studio Code)
|
||||
|
||||
Now, let's summon the Open-Sourcerer:
|
||||
|
||||
```shell
|
||||
pip install open-sourcerer
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Open-Sourcerer must be attuned to your intentions. Let's configure it:
|
||||
|
||||
```shell
|
||||
open-sourcerer configure
|
||||
```
|
||||
|
||||
Follow the instructions to set up your preferences, such as the programming languages and search keywords that align with your project.
|
||||
|
||||
## MVP (Minimum Viable Potion) Tasks
|
||||
|
||||
1. **Prepare the Cauldron**
|
||||
- [ ] Create a dedicated workspace/repository for Open-Sourcerer.
|
||||
|
||||
2. **Web Scrying**
|
||||
- [ ] Implement web scraping to search GitHub for relevant open source projects.
|
||||
|
||||
3. **Submodule Conjuring**
|
||||
- [ ] Develop a submodule management system to add selected GitHub repositories as submodules to your workspace.
|
||||
|
||||
4. **Bloop Integration**
|
||||
- [ ] Integrate Open-Sourcerer with the Bloop tool (https://github.com/BloopAI/bloop).
|
||||
- [ ] Implement code generation and assistance features.
|
||||
|
||||
5. **Version Control & Long-Term Memory**
|
||||
- [ ] Set up version control for the workspace and submodules.
|
||||
- [ ] Create a vector database to store project information for long-term memory.
|
||||
|
||||
6. **Magical Interface (Optional)**
|
||||
- [ ] Create a user-friendly interface for interacting with Open-Sourcerer.
|
||||
|
||||
7. **Testing & Documentation**
|
||||
- [ ] Ensure the reliability of Open-Sourcerer through thorough testing.
|
||||
- [ ] Document the magic spells for fellow developers.
|
||||
|
||||
## Stretch Goals (Beyond the Sorcerer's Hat)
|
||||
|
||||
1. **Advanced Recommendation Alchemy**
|
||||
- [ ] Enhance the recommendation algorithm using machine learning or NLP.
|
||||
|
||||
2. **Explore Other Realms**
|
||||
- [ ] Expand Open-Sourcerer's reach to platforms like GitLab, Bitbucket, and more.
|
||||
|
||||
3. **Code Quality Insights**
|
||||
- [ ] Add code review and quality analysis features for recommended projects.
|
||||
|
||||
4. **Summon a Community**
|
||||
- [ ] Create a community where developers can collaborate on recommended open source projects.
|
||||
|
||||
5. **Editor Enchantments**
|
||||
- [ ] Develop plugins/extensions for popular code editors to provide real-time assistance.
|
||||
|
||||
6. **Language Understanding Scrolls**
|
||||
- [ ] Improve Open-Sourcerer's natural language understanding capabilities.
|
||||
|
||||
7. **Continuous Learning**
|
||||
- [ ] Implement a mechanism for Open-Sourcerer to learn and adapt from user interactions.
|
||||
|
||||
8. **Security Warding**
|
||||
- [ ] Add security scanning to identify vulnerabilities in recommended projects.
|
||||
|
||||
9. **Mobile App (Optional)**
|
||||
- [ ] Create a mobile app version of Open-Sourcerer for convenience on your travels.
|
||||
|
||||
10. **Licensing & Compliance**
|
||||
- [ ] Ensure Open-Sourcerer checks the licensing of recommended projects for legal compliance.
|
||||
|
||||
11. **Performance Enhancements**
|
||||
- [ ] Optimize Open-Sourcerer's performance for faster results.
|
||||
|
||||
## How to Contribute
|
||||
|
||||
As we embark on this magical quest, we invite other sorcerers to join us. Feel free to contribute to Open-Sourcerer's development and help us unlock even more mystical powers.
|
||||
|
||||
```shell
|
||||
git clone https://github.com/your-fork/open-sourcerer.git
|
||||
cd open-sourcerer
|
||||
# Create a virtual environment and activate it
|
||||
pip install -r requirements.txt
|
||||
python setup.py install
|
||||
```
|
||||
|
||||
May your code be bug-free and your projects prosperous! The Open-Sourcerer awaits your commands.
|
||||
```
|
||||
|
||||
Feel free to adapt and expand this README with more details, graphics, and styling to make it engaging and in line with the sorcerer theme.
|
@ -1,9 +0,0 @@
|
||||
version: '3'
|
||||
services:
|
||||
my-python-app:
|
||||
container_name: Open-Soucerer
|
||||
build: .
|
||||
ports:
|
||||
- "80:80"
|
||||
env_file:
|
||||
- ./.env
|
@ -1,77 +0,0 @@
|
||||
import openai
|
||||
import os
|
||||
import dotenv
|
||||
import logging
|
||||
import gradio as gr
|
||||
from BingImageCreator import ImageGen
|
||||
from swarms.models.bing_chat import BingChat
|
||||
|
||||
# from swarms.models.bingchat import BingChat
|
||||
dotenv.load_dotenv(".env")
|
||||
|
||||
# Initialize the EdgeGPTModel
|
||||
model = BingChat()
|
||||
|
||||
response = model("Generate")
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
accumulated_story = ""
|
||||
latest_caption = ""
|
||||
standard_suffix = ""
|
||||
storyboard = []
|
||||
|
||||
caption = "Create comic about opensourcerer a robot wizard"
|
||||
|
||||
def generate_images_with_bingchat(caption):
|
||||
img_path = model.create_img(caption)
|
||||
img_urls = model.images(caption)
|
||||
return img_urls
|
||||
|
||||
def generate_single_caption(text):
|
||||
prompt = f"A comic about {text}."
|
||||
response = model(text)
|
||||
return response
|
||||
|
||||
def interpret_text_with_gpt(text, suffix):
|
||||
return generate_single_caption(f"{text} {suffix}")
|
||||
|
||||
def create_standard_suffix(original_prompt):
|
||||
return f"In the style of {original_prompt}"
|
||||
|
||||
def gradio_interface(text=None, next_button_clicked=False):
|
||||
global accumulated_story, latest_caption, standard_suffix, storyboard
|
||||
|
||||
if not standard_suffix:
|
||||
standard_suffix = create_standard_suffix(text)
|
||||
|
||||
if next_button_clicked:
|
||||
new_caption = generate_single_caption(latest_caption + " " + standard_suffix)
|
||||
new_urls = generate_images_with_bingchat(new_caption)
|
||||
latest_caption = new_caption
|
||||
storyboard.append((new_urls, new_caption))
|
||||
|
||||
elif text:
|
||||
caption = generate_single_caption(text + " " + standard_suffix)
|
||||
comic_panel_urls = generate_images_with_bingchat(caption)
|
||||
latest_caption = caption
|
||||
storyboard.append((comic_panel_urls, caption))
|
||||
|
||||
storyboard_html = ""
|
||||
for urls, cap in storyboard:
|
||||
for url in urls:
|
||||
storyboard_html += f'<img src="{url}" alt="{cap}" width="300"/><br>{cap}<br>'
|
||||
|
||||
return storyboard_html
|
||||
|
||||
if __name__ == "__main__":
|
||||
iface = gr.Interface(
|
||||
fn=gradio_interface,
|
||||
inputs=[
|
||||
gr.inputs.Textbox(default="Type your story concept here", optional=True, label="Story Concept"),
|
||||
gr.inputs.Checkbox(label="Generate Next Part")
|
||||
],
|
||||
outputs=[gr.outputs.HTML()],
|
||||
live=False # Submit button will appear
|
||||
)
|
||||
iface.launch()
|
@ -1,6 +0,0 @@
|
||||
openai-whisper
|
||||
py-cord
|
||||
discord
|
||||
open-interpreter
|
||||
elevenlabs
|
||||
gradio
|
@ -1,97 +0,0 @@
|
||||
import gradio_client as grc
|
||||
import interpreter
|
||||
import time
|
||||
import gradio as gr
|
||||
from pydub import AudioSegment
|
||||
import io
|
||||
from elevenlabs import generate, play, set_api_key
|
||||
import dotenv
|
||||
|
||||
dotenv.load_dotenv(".env")
|
||||
|
||||
# interpreter.model = "TheBloke/Mistral-7B-OpenOrca-GGUF"
|
||||
interpreter.auto_run = True
|
||||
|
||||
|
||||
set_api_key("ELEVEN_LABS_API_KEY")
|
||||
|
||||
|
||||
def get_audio_length(audio_bytes):
|
||||
# Create a BytesIO object from the byte array
|
||||
byte_io = io.BytesIO(audio_bytes)
|
||||
|
||||
# Load the audio data with PyDub
|
||||
audio = AudioSegment.from_mp3(byte_io)
|
||||
|
||||
# Get the length of the audio in milliseconds
|
||||
length_ms = len(audio)
|
||||
|
||||
# Optionally convert to seconds
|
||||
length_s = length_ms / 1000.0
|
||||
|
||||
return length_s
|
||||
|
||||
|
||||
def speak(text):
|
||||
speaking = True
|
||||
audio = generate(text=text, voice="Daniel")
|
||||
play(audio, notebook=True)
|
||||
|
||||
audio_length = get_audio_length(audio)
|
||||
time.sleep(audio_length)
|
||||
|
||||
|
||||
# @title Text-only JARVIS
|
||||
# @markdown Run this cell for a ChatGPT-like interface.
|
||||
|
||||
|
||||
with gr.Blocks() as demo:
|
||||
chatbot = gr.Chatbot()
|
||||
msg = gr.Textbox()
|
||||
|
||||
def user(user_message, history):
|
||||
return "", history + [[user_message, None]]
|
||||
|
||||
def bot(history):
|
||||
user_message = history[-1][0]
|
||||
history[-1][1] = ""
|
||||
active_block_type = ""
|
||||
|
||||
for chunk in interpreter.chat(user_message, stream=True, display=False):
|
||||
# Message
|
||||
if "message" in chunk:
|
||||
if active_block_type != "message":
|
||||
active_block_type = "message"
|
||||
history[-1][1] += chunk["message"]
|
||||
yield history
|
||||
|
||||
# Code
|
||||
if "language" in chunk:
|
||||
language = chunk["language"]
|
||||
if "code" in chunk:
|
||||
if active_block_type != "code":
|
||||
active_block_type = "code"
|
||||
history[-1][1] += f"\n```{language}\n"
|
||||
history[-1][1] += chunk["code"]
|
||||
yield history
|
||||
|
||||
# Output
|
||||
if "executing" in chunk:
|
||||
history[-1][1] += "\n```\n\n```text\n"
|
||||
yield history
|
||||
if "output" in chunk:
|
||||
if chunk["output"] != "KeyboardInterrupt":
|
||||
history[-1][1] += chunk["output"] + "\n"
|
||||
yield history
|
||||
if "end_of_execution" in chunk:
|
||||
history[-1][1] = history[-1][1].strip()
|
||||
history[-1][1] += "\n```\n"
|
||||
yield history
|
||||
|
||||
msg.submit(user, [msg, chatbot], [msg, chatbot], queue=False).then(
|
||||
bot, chatbot, chatbot
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
demo.queue()
|
||||
demo.launch(debug=True)
|
@ -1,2 +0,0 @@
|
||||
node_modules
|
||||
.env
|
@ -1,3 +0,0 @@
|
||||
DISCORD_TOKEN=
|
||||
DISCORD_CLIENT_ID=
|
||||
DISCORD_GUILD_ID=
|
@ -1,10 +0,0 @@
|
||||
FROM node:19-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package.json /app
|
||||
RUN npm install
|
||||
|
||||
COPY . .
|
||||
|
||||
CMD [ "node", "index.js" ]
|
@ -1,42 +0,0 @@
|
||||
|
||||
# Server-Bot
|
||||
|
||||
[View on Docker Hub](https://hub.docker.com/r/allenrkeen/server-bot)
|
||||
### Discord bot to remotely monitor and control a docker based server. Using the docker socket.
|
||||
|
||||
Setup is pretty straightforward.
|
||||
1. Create a new application in the *[discord developer portal](https://discord.com/developers/applications)*
|
||||
2. Go to the bot section and click *Add Bot*
|
||||
3. Reset Token and keep the token somewhere secure (This will be referred to as "DISCORD_TOKEN" in .env and docker environment variables)
|
||||
4. Get the "Application ID" from the General Information tab of your application (This will be referred to as "DISCORD_CLIENT_ID" in .env and docker environment variables)
|
||||
5. *Optional:* If you have developer mode enabled in Discord, get your server's ID by right-clicking on the server name and clicking "Copy ID" (This will be referred to as "DISCORD_GUILD_ID" in .env and docker environment variables)
|
||||
- If you skip this, it will still work, but commands will be published globally instead of to your server and can take up to an hour to be available in your server.
|
||||
- Using the Server ID will be more secure, making the commands available only in the specified server.
|
||||
6. Run the application in your preffered method.
|
||||
- Run the docker container with the provided [docker-compose.yml](docker-compose.yml) or the docker run command below.
|
||||
|
||||
```bash
|
||||
docker run -v /var/run/docker.sock:/var/run/docker.sock --name server-bot \
|
||||
-e DISCORD_TOKEN=your_token_here \
|
||||
-e DISCORD_CLIENT_ID=your_client_id_here \
|
||||
-e DISCORD_GUILD_ID=your_guild_id_here \
|
||||
allenrkeen/server-bot:latest
|
||||
```
|
||||
|
||||
- Clone the repo, cd into the server-bot directory and run "npm install" to install dependencies, then "npm run start" to start the server
|
||||
7. The program will build an invite link with the correct permissions and put it in the logs. Click the link and confirm the server to add the bot to.
|
||||
|
||||
|
||||
Current commands:
|
||||
- /allcontainers
|
||||
- provides container name and status for all containers
|
||||
- /restartcontainer
|
||||
- provides an autocomplete list of running containers to select from, or just type in container name then restarts the container
|
||||
- /stopcontainer
|
||||
- provides an autocomplete list of running containers to select from, or just type in container name then stops the container
|
||||
- /startcontainer
|
||||
- provides an autocomplete list of stopped containers to select from, or just type in container name then starts the container
|
||||
- /ping
|
||||
- Replies with "Pong!" when the bot is listening
|
||||
- /server
|
||||
- Replies with Server Name and member count, good for testing.
|
@ -1,22 +0,0 @@
|
||||
/*
|
||||
* This file is used to delete all commands from the Discord API.
|
||||
* Only use this if you want to delete all commands and understand the consequences.
|
||||
*/
|
||||
|
||||
require('dotenv').config();
|
||||
const token = process.env.DISCORD_TOKEN;
|
||||
const clientID = process.env.DISCORD_CLIENT_ID;
|
||||
const guildID = process.env.DISCORD_GUILD_ID;
|
||||
const { REST, Routes } = require('discord.js');
|
||||
const fs = require('node:fs');
|
||||
|
||||
const rest = new REST({ version: '10' }).setToken(token);
|
||||
|
||||
rest.put(Routes.applicationCommands(clientID), { body: [] })
|
||||
.then(() => console.log('Successfully deleted application (/) commands.'))
|
||||
.catch(console.error);
|
||||
|
||||
rest.put(Routes.applicationGuildCommands(clientID, guildID), { body: [] })
|
||||
.then(() => console.log('Successfully deleted guild (/) commands.'))
|
||||
.catch(console.error);
|
||||
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
This script pushes all commands in the commands folder to be usable in discord.
|
||||
*/
|
||||
|
||||
require('dotenv').config();
|
||||
const token = process.env.DISCORD_TOKEN;
|
||||
const clientID = process.env.DISCORD_CLIENT_ID;
|
||||
const guildID = process.env.DISCORD_GUILD_ID;
|
||||
const { REST, Routes } = require('discord.js');
|
||||
const fs = require('node:fs');
|
||||
|
||||
const commands = [];
|
||||
|
||||
// Get all commands from the commands folder
|
||||
|
||||
const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js'));
|
||||
console.log(commandFiles);
|
||||
|
||||
for (const file of commandFiles) {
|
||||
const command = require(`../commands/${file}`);
|
||||
commands.push(command.data.toJSON());
|
||||
}
|
||||
|
||||
const rest = new REST({ version: '10' }).setToken(token);
|
||||
|
||||
// console.log(commands);
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const rest = new REST({ version: '10' }).setToken(token);
|
||||
|
||||
console.log('Started refreshing application (/) commands.');
|
||||
|
||||
//publish to guild if guildID is set, otherwise publish to global
|
||||
if (guildID) {
|
||||
const data = await rest.put(
|
||||
Routes.applicationGuildCommands(clientID, guildID),
|
||||
{ body: commands },
|
||||
);
|
||||
console.log('Successfully reloaded '+ data.length +' commands.');
|
||||
} else {
|
||||
const data = await rest.put(
|
||||
Routes.applicationCommands(clientID),
|
||||
{ body: commands },
|
||||
);
|
||||
console.log('Successfully reloaded '+ data.length +' commands.');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
})();
|
||||
|
@ -1,39 +0,0 @@
|
||||
/* A command that lists all containers with their status */
|
||||
|
||||
const { SlashCommandBuilder, EmbedBuilder } = require("discord.js");
|
||||
const Docker = require('node-docker-api').Docker;
|
||||
|
||||
module.exports = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName("allcontainers")
|
||||
.setDescription("Lists all containers"),
|
||||
async execute(interaction) {
|
||||
outArray = [];
|
||||
interaction.reply('Listing all containers...');
|
||||
|
||||
//create docker client
|
||||
const docker = new Docker({ socketPath: '/var/run/docker.sock' });
|
||||
|
||||
// get all containers
|
||||
const containers = await docker.container.list({ all: true});
|
||||
|
||||
// create array of containers with name and status
|
||||
outArray = containers.map(c => {
|
||||
return {
|
||||
name: c.data.Names[0].slice(1),
|
||||
status: c.data.State
|
||||
};
|
||||
});
|
||||
|
||||
embedCount = Math.ceil(outArray.length / 25);
|
||||
for (let i = 0; i < embedCount; i++) {
|
||||
const embed = new EmbedBuilder()
|
||||
.setTitle('Containers')
|
||||
.addFields(outArray.slice(i * 25, (i + 1) * 25).map(e => {
|
||||
return { name: e.name, value: e.status };
|
||||
}))
|
||||
.setColor(0x00AE86);
|
||||
interaction.channel.send({ embeds: [embed] });
|
||||
}
|
||||
},
|
||||
};
|
@ -1,69 +0,0 @@
|
||||
const { SlashCommandBuilder, EmbedBuilder } = require("discord.js");
|
||||
const Docker = require('node-docker-api').Docker;
|
||||
|
||||
module.exports = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName("restartcontainer")
|
||||
.setDescription("Restarts a Docker container")
|
||||
.addStringOption(option =>
|
||||
option.setName('container')
|
||||
.setDescription('The container to restart')
|
||||
.setRequired(true)
|
||||
.setAutocomplete(true)),
|
||||
async autocomplete(interaction) {
|
||||
try {
|
||||
// Create docker client
|
||||
const docker = new Docker({ socketPath: '/var/run/docker.sock' });
|
||||
|
||||
// Get list of running containers
|
||||
const containers = await docker.container.list({ all: true, filters: { status: ['running'] } });
|
||||
const runningContainers = containers.map(c => c.data.Names[0].slice(1));
|
||||
|
||||
// Filter list of containers by focused value
|
||||
const focusedValue = interaction.options.getFocused(true);
|
||||
const filteredContainers = runningContainers.filter(container => container.startsWith(focusedValue.value));
|
||||
|
||||
//slice if more than 25
|
||||
let sliced;
|
||||
if (filteredContainers.length > 25) {
|
||||
sliced = filteredContainers.slice(0, 25);
|
||||
} else {
|
||||
sliced = filteredContainers;
|
||||
}
|
||||
|
||||
// Respond with filtered list of containers
|
||||
await interaction.respond(sliced.map(container => ({ name: container, value: container })));
|
||||
|
||||
} catch (error) {
|
||||
// Handle error
|
||||
console.error(error);
|
||||
await interaction.reply('An error occurred while getting the list of running containers.');
|
||||
}
|
||||
},
|
||||
async execute(interaction) {
|
||||
try {
|
||||
// create docker client
|
||||
const docker = new Docker({ socketPath: '/var/run/docker.sock' });
|
||||
|
||||
// Get container name from options
|
||||
const container = interaction.options.getString('container');
|
||||
|
||||
// Restart container
|
||||
await interaction.reply(`Restarting container "${container}"...`);
|
||||
const containers = await docker.container.list({ all: true, filters: { name: [container] } });
|
||||
if (containers.length === 0) {
|
||||
await interaction.followUp(`Container "${container}" does not exist.`);
|
||||
throw new Error(`Container "${container}" does not exist.`);
|
||||
}
|
||||
await containers[0].restart();
|
||||
|
||||
|
||||
// Confirm that container was restarted
|
||||
await interaction.followUp(`Container "${container}" was successfully restarted.`);
|
||||
} catch (error) {
|
||||
// Handle error
|
||||
console.error(error);
|
||||
await interaction.followUp(`An error occurred while trying to restart the container "${container}".`);
|
||||
}
|
||||
}
|
||||
};
|
@ -1,92 +0,0 @@
|
||||
const { SlashCommandBuilder, EmbedBuilder } = require("discord.js");
|
||||
const Docker = require('node-docker-api').Docker;
|
||||
|
||||
module.exports = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName("startcontainer")
|
||||
.setDescription("Starts a Docker container")
|
||||
.addStringOption(option =>
|
||||
option.setName('container')
|
||||
.setDescription('The container to start')
|
||||
.setRequired(true)
|
||||
.setAutocomplete(true)),
|
||||
async autocomplete(interaction) {
|
||||
try {
|
||||
// Create docker client
|
||||
const docker = new Docker({ socketPath: '/var/run/docker.sock' });
|
||||
|
||||
// Get list of running containers
|
||||
const containers = await docker.container.list({ all: true, filters: { status: ['exited'] } });
|
||||
const runningContainers = containers.map(c => c.data.Names[0].slice(1));
|
||||
|
||||
// Filter list of containers by focused value
|
||||
const focusedValue = interaction.options.getFocused(true);
|
||||
const filteredContainers = runningContainers.filter(container => container.startsWith(focusedValue.value));
|
||||
|
||||
//slice if more than 25
|
||||
let sliced;
|
||||
if (filteredContainers.length > 25) {
|
||||
sliced = filteredContainers.slice(0, 25);
|
||||
} else {
|
||||
sliced = filteredContainers;
|
||||
}
|
||||
|
||||
// Respond with filtered list of containers
|
||||
await interaction.respond(sliced.map(container => ({ name: container, value: container })));
|
||||
|
||||
} catch (error) {
|
||||
// Handle error
|
||||
console.error(error);
|
||||
await interaction.reply('An error occurred while getting the list of running containers.');
|
||||
}
|
||||
},
|
||||
async execute(interaction) {
|
||||
try {
|
||||
// Get container name from options
|
||||
const containerName = interaction.options.getString('container');
|
||||
|
||||
// Start container in interactive mode
|
||||
await interaction.reply(`Starting container "${containerName}" in interactive mode...`);
|
||||
const container = docker.getContainer(containerName);
|
||||
const info = await container.inspect();
|
||||
if (!info) {
|
||||
await interaction.followUp(`Container "${containerName}" does not exist.`);
|
||||
throw new Error(`Container "${containerName}" does not exist.`);
|
||||
}
|
||||
await container.start({
|
||||
AttachStdin: true,
|
||||
AttachStdout: true,
|
||||
AttachStderr: true,
|
||||
Tty: true,
|
||||
OpenStdin: true,
|
||||
StdinOnce: false
|
||||
});
|
||||
|
||||
// Attach to container's streams
|
||||
const stream = await container.attach({
|
||||
stream: true,
|
||||
stdin: true,
|
||||
stdout: true,
|
||||
stderr: true
|
||||
});
|
||||
|
||||
// Use socket.io for real-time communication with the container
|
||||
io.on('connection', (socket) => {
|
||||
socket.on('containerInput', (data) => {
|
||||
stream.write(data + '\n'); // Send input to the container
|
||||
});
|
||||
|
||||
stream.on('data', (data) => {
|
||||
socket.emit('containerOutput', data.toString()); // Send container's output to the client
|
||||
});
|
||||
});
|
||||
|
||||
// Confirm that container was started
|
||||
await interaction.followUp(`Container "${containerName}" was successfully started in interactive mode.`);
|
||||
} catch (error) {
|
||||
// Handle error
|
||||
console.error(error);
|
||||
await interaction.followUp(`An error occurred while trying to start the container "${containerName}" in interactive mode.`);
|
||||
}
|
||||
},
|
||||
};
|
@ -1,68 +0,0 @@
|
||||
const { SlashCommandBuilder, EmbedBuilder } = require("discord.js");
|
||||
const Docker = require('node-docker-api').Docker;
|
||||
|
||||
module.exports = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName("stopcontainer")
|
||||
.setDescription("Stops a Docker container")
|
||||
.addStringOption(option =>
|
||||
option.setName('container')
|
||||
.setDescription('The container to stop')
|
||||
.setRequired(true)
|
||||
.setAutocomplete(true)),
|
||||
async autocomplete(interaction) {
|
||||
try {
|
||||
// Create docker client
|
||||
const docker = new Docker({ socketPath: '/var/run/docker.sock' });
|
||||
|
||||
// Get list of running containers
|
||||
const containers = await docker.container.list({ all: true, filters: { status: ['running'] } });
|
||||
const runningContainers = containers.map(c => c.data.Names[0].slice(1));
|
||||
|
||||
// Filter list of containers by focused value
|
||||
const focusedValue = interaction.options.getFocused(true);
|
||||
const filteredContainers = runningContainers.filter(container => container.startsWith(focusedValue.value));
|
||||
|
||||
//slice if more than 25
|
||||
let sliced;
|
||||
if (filteredContainers.length > 25) {
|
||||
sliced = filteredContainers.slice(0, 25);
|
||||
} else {
|
||||
sliced = filteredContainers;
|
||||
}
|
||||
|
||||
// Respond with filtered list of containers
|
||||
await interaction.respond(sliced.map(container => ({ name: container, value: container })));
|
||||
|
||||
} catch (error) {
|
||||
// Handle error
|
||||
console.error(error);
|
||||
await interaction.reply('An error occurred while getting the list of running containers.');
|
||||
}
|
||||
},
|
||||
async execute(interaction) {
|
||||
try {
|
||||
// create docker client
|
||||
const docker = new Docker({ socketPath: '/var/run/docker.sock' });
|
||||
|
||||
// Get container name from options
|
||||
const container = interaction.options.getString('container');
|
||||
|
||||
// Restart container
|
||||
await interaction.reply(`Stopping container "${container}"...`);
|
||||
const containers = await docker.container.list({ all: true, filters: { name: [container] } });
|
||||
if (containers.length === 0) {
|
||||
await interaction.followUp(`Container "${container}" does not exist.`);
|
||||
throw new Error(`Container "${container}" does not exist.`);
|
||||
}
|
||||
await containers[0].stop();
|
||||
|
||||
// Confirm that container was restarted
|
||||
await interaction.followUp(`Container "${container}" was successfully stopped.`);
|
||||
} catch (error) {
|
||||
// Handle error
|
||||
console.error(error);
|
||||
await interaction.followUp(`An error occurred while trying to stop the container "${container}".`);
|
||||
}
|
||||
}
|
||||
};
|
@ -1,12 +0,0 @@
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
server-bot:
|
||||
container_name: Leonidas
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock #required
|
||||
env_file:
|
||||
- ./.env # environment:
|
@ -1,89 +0,0 @@
|
||||
require('dotenv').config();
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const token = process.env.DISCORD_TOKEN;
|
||||
const clientID = process.env.DISCORD_CLIENT_ID;
|
||||
|
||||
// Require the necessary discord.js classes
|
||||
const { Client, Collection, Events, GatewayIntentBits } = require('discord.js');
|
||||
|
||||
// Create a new client instance
|
||||
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
|
||||
|
||||
//run backend/deployCommands.js
|
||||
const { exec } = require('child_process');
|
||||
exec('node backend/deployCommands.js', (err, stdout, stderr) => {
|
||||
if (err) {
|
||||
//some err occurred
|
||||
console.error(err);
|
||||
} else {
|
||||
// print complete output
|
||||
console.log(stdout);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
// When the client is ready, run this code
|
||||
client.once(Events.ClientReady, c => {
|
||||
console.log(`Ready! Logged in as ${c.user.tag}`);
|
||||
});
|
||||
|
||||
// Log in to Discord with your client's token
|
||||
client.login(token);
|
||||
|
||||
// Create a new collection for commands
|
||||
client.commands = new Collection();
|
||||
|
||||
const commandsPath = path.join(__dirname, 'commands');
|
||||
const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js'));
|
||||
|
||||
for (const file of commandFiles) {
|
||||
const filePath = path.join(commandsPath, file);
|
||||
const command = require(filePath);
|
||||
// Set a new item in the Collection with the key as the name of the command and the value as the exported module
|
||||
if ('data' in command && 'execute' in command) {
|
||||
client.commands.set(command.data.name, command);
|
||||
} else {
|
||||
console.log(`Command ${file} is missing 'data' or 'execute'`);
|
||||
}
|
||||
}
|
||||
//build and display invite link
|
||||
const inviteLink = 'https://discord.com/oauth2/authorize?client_id='+clientID+'&permissions=2147534912&scope=bot%20applications.commands';
|
||||
|
||||
console.log(`Invite link: ${inviteLink}`);
|
||||
|
||||
// execute on slash command
|
||||
client.on(Events.InteractionCreate, async interaction => {
|
||||
if (interaction.isChatInputCommand()) {
|
||||
const command = client.commands.get(interaction.commandName);
|
||||
|
||||
if (!command) {
|
||||
console.error('No command matching ${interaction.commandName} was found.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await command.execute(interaction);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
// await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true });
|
||||
}
|
||||
} else if (interaction.isAutocomplete()) {
|
||||
|
||||
const command = client.commands.get(interaction.commandName);
|
||||
|
||||
if (!command) {
|
||||
console.error('No command matching ${interaction.commandName} was found.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await command.autocomplete(interaction);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
// await interaction.({ content: 'There was an error while executing this command!', ephemeral: true });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,723 +0,0 @@
|
||||
{
|
||||
"name": "server-bot",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "server-bot",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"discord.js": "^14.7.1",
|
||||
"dockerode": "^3.3.4",
|
||||
"dotenv": "^16.0.3",
|
||||
"node-docker-api": "^1.1.22"
|
||||
}
|
||||
},
|
||||
"node_modules/@balena/dockerignore": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@balena/dockerignore/-/dockerignore-1.0.2.tgz",
|
||||
"integrity": "sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q=="
|
||||
},
|
||||
"node_modules/@discordjs/builders": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.4.0.tgz",
|
||||
"integrity": "sha512-nEeTCheTTDw5kO93faM1j8ZJPonAX86qpq/QVoznnSa8WWcCgJpjlu6GylfINTDW6o7zZY0my2SYdxx2mfNwGA==",
|
||||
"dependencies": {
|
||||
"@discordjs/util": "^0.1.0",
|
||||
"@sapphire/shapeshift": "^3.7.1",
|
||||
"discord-api-types": "^0.37.20",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"ts-mixer": "^6.0.2",
|
||||
"tslib": "^2.4.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@discordjs/collection": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.3.0.tgz",
|
||||
"integrity": "sha512-ylt2NyZ77bJbRij4h9u/wVy7qYw/aDqQLWnadjvDqW/WoWCxrsX6M3CIw9GVP5xcGCDxsrKj5e0r5evuFYwrKg==",
|
||||
"engines": {
|
||||
"node": ">=16.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@discordjs/rest": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-1.5.0.tgz",
|
||||
"integrity": "sha512-lXgNFqHnbmzp5u81W0+frdXN6Etf4EUi8FAPcWpSykKd8hmlWh1xy6BmE0bsJypU1pxohaA8lQCgp70NUI3uzA==",
|
||||
"dependencies": {
|
||||
"@discordjs/collection": "^1.3.0",
|
||||
"@discordjs/util": "^0.1.0",
|
||||
"@sapphire/async-queue": "^1.5.0",
|
||||
"@sapphire/snowflake": "^3.2.2",
|
||||
"discord-api-types": "^0.37.23",
|
||||
"file-type": "^18.0.0",
|
||||
"tslib": "^2.4.1",
|
||||
"undici": "^5.13.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@discordjs/util": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/util/-/util-0.1.0.tgz",
|
||||
"integrity": "sha512-e7d+PaTLVQav6rOc2tojh2y6FE8S7REkqLldq1XF4soCx74XB/DIjbVbVLtBemf0nLW77ntz0v+o5DytKwFNLQ==",
|
||||
"engines": {
|
||||
"node": ">=16.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@sapphire/async-queue": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz",
|
||||
"integrity": "sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==",
|
||||
"engines": {
|
||||
"node": ">=v14.0.0",
|
||||
"npm": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@sapphire/shapeshift": {
|
||||
"version": "3.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.8.1.tgz",
|
||||
"integrity": "sha512-xG1oXXBhCjPKbxrRTlox9ddaZTvVpOhYLmKmApD/vIWOV1xEYXnpoFs68zHIZBGbqztq6FrUPNPerIrO1Hqeaw==",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"lodash": "^4.17.21"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=v14.0.0",
|
||||
"npm": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@sapphire/snowflake": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.4.0.tgz",
|
||||
"integrity": "sha512-zZxymtVO6zeXVMPds+6d7gv/OfnCc25M1Z+7ZLB0oPmeMTPeRWVPQSS16oDJy5ZsyCOLj7M6mbZml5gWXcVRNw==",
|
||||
"engines": {
|
||||
"node": ">=v14.0.0",
|
||||
"npm": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tokenizer/token": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz",
|
||||
"integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "18.11.18",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz",
|
||||
"integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA=="
|
||||
},
|
||||
"node_modules/@types/ws": {
|
||||
"version": "8.5.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz",
|
||||
"integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/asn1": {
|
||||
"version": "0.2.6",
|
||||
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
|
||||
"integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
|
||||
"dependencies": {
|
||||
"safer-buffer": "~2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/bcrypt-pbkdf": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
|
||||
"integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
|
||||
"dependencies": {
|
||||
"tweetnacl": "^0.14.3"
|
||||
}
|
||||
},
|
||||
"node_modules/bl": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
||||
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
|
||||
"dependencies": {
|
||||
"buffer": "^5.5.0",
|
||||
"inherits": "^2.0.4",
|
||||
"readable-stream": "^3.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"node_modules/buildcheck": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buildcheck/-/buildcheck-0.0.3.tgz",
|
||||
"integrity": "sha512-pziaA+p/wdVImfcbsZLNF32EiWyujlQLwolMqUQE8xpKNOH7KmZQaY8sXN7DGOEzPAElo9QTaeNRfGnf3iOJbA==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/busboy": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
|
||||
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
|
||||
"dependencies": {
|
||||
"streamsearch": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.16.0"
|
||||
}
|
||||
},
|
||||
"node_modules/chownr": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
|
||||
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
|
||||
},
|
||||
"node_modules/core-util-is": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
|
||||
},
|
||||
"node_modules/cpu-features": {
|
||||
"version": "0.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.4.tgz",
|
||||
"integrity": "sha512-fKiZ/zp1mUwQbnzb9IghXtHtDoTMtNeb8oYGx6kX2SYfhnG0HNdBEBIzB9b5KlXu5DQPhfy3mInbBxFcgwAr3A==",
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"buildcheck": "0.0.3",
|
||||
"nan": "^2.15.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/discord-api-types": {
|
||||
"version": "0.37.24",
|
||||
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.24.tgz",
|
||||
"integrity": "sha512-1+Fb4huJCihdbkJLcq2p7nBmtlmAryNwjefT8wwJnL8c7bc7WA87Oaa5mbLe96QvZyfwnwRCDX40H0HhcVV50g=="
|
||||
},
|
||||
"node_modules/discord.js": {
|
||||
"version": "14.7.1",
|
||||
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.7.1.tgz",
|
||||
"integrity": "sha512-1FECvqJJjjeYcjSm0IGMnPxLqja/pmG1B0W2l3lUY2Gi4KXiyTeQmU1IxWcbXHn2k+ytP587mMWqva2IA87EbA==",
|
||||
"dependencies": {
|
||||
"@discordjs/builders": "^1.4.0",
|
||||
"@discordjs/collection": "^1.3.0",
|
||||
"@discordjs/rest": "^1.4.0",
|
||||
"@discordjs/util": "^0.1.0",
|
||||
"@sapphire/snowflake": "^3.2.2",
|
||||
"@types/ws": "^8.5.3",
|
||||
"discord-api-types": "^0.37.20",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"lodash.snakecase": "^4.1.1",
|
||||
"tslib": "^2.4.1",
|
||||
"undici": "^5.13.0",
|
||||
"ws": "^8.11.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/docker-modem": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/docker-modem/-/docker-modem-3.0.6.tgz",
|
||||
"integrity": "sha512-h0Ow21gclbYsZ3mkHDfsYNDqtRhXS8fXr51bU0qr1dxgTMJj0XufbzX+jhNOvA8KuEEzn6JbvLVhXyv+fny9Uw==",
|
||||
"dependencies": {
|
||||
"debug": "^4.1.1",
|
||||
"readable-stream": "^3.5.0",
|
||||
"split-ca": "^1.0.1",
|
||||
"ssh2": "^1.11.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dockerode": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/dockerode/-/dockerode-3.3.4.tgz",
|
||||
"integrity": "sha512-3EUwuXnCU+RUlQEheDjmBE0B7q66PV9Rw5NiH1sXwINq0M9c5ERP9fxgkw36ZHOtzf4AGEEYySnkx/sACC9EgQ==",
|
||||
"dependencies": {
|
||||
"@balena/dockerignore": "^1.0.2",
|
||||
"docker-modem": "^3.0.0",
|
||||
"tar-fs": "~2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "16.0.3",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
|
||||
"integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/end-of-stream": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
|
||||
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
|
||||
"dependencies": {
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
||||
},
|
||||
"node_modules/file-type": {
|
||||
"version": "18.0.0",
|
||||
"resolved": "https://registry.npmjs.org/file-type/-/file-type-18.0.0.tgz",
|
||||
"integrity": "sha512-jjMwFpnW8PKofLE/4ohlhqwDk5k0NC6iy0UHAJFKoY1fQeGMN0GDdLgHQrvCbSpMwbqzoCZhRI5dETCZna5qVA==",
|
||||
"dependencies": {
|
||||
"readable-web-to-node-stream": "^3.0.2",
|
||||
"strtok3": "^7.0.0",
|
||||
"token-types": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sindresorhus/file-type?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-constants": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
|
||||
},
|
||||
"node_modules/ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"node_modules/isarray": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||
"integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ=="
|
||||
},
|
||||
"node_modules/jsonparse": {
|
||||
"version": "0.0.5",
|
||||
"resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-0.0.5.tgz",
|
||||
"integrity": "sha512-fw7Q/8gFR8iSekUi9I+HqWIap6mywuoe7hQIg3buTVjuZgALKj4HAmm0X6f+TaL4c9NJbvyFQdaI2ppr5p6dnQ==",
|
||||
"engines": [
|
||||
"node >= 0.2.0"
|
||||
]
|
||||
},
|
||||
"node_modules/JSONStream": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-0.10.0.tgz",
|
||||
"integrity": "sha512-8XbSFFd43EG+1thjLNFIzCBlwXti0yKa7L+ak/f0T/pkC+31b7G41DXL/JzYpAoYWZ2eCPiu4IIqzijM8N0a/w==",
|
||||
"dependencies": {
|
||||
"jsonparse": "0.0.5",
|
||||
"through": ">=2.2.7 <3"
|
||||
},
|
||||
"bin": {
|
||||
"JSONStream": "index.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"node_modules/lodash.snakecase": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz",
|
||||
"integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw=="
|
||||
},
|
||||
"node_modules/memorystream": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
|
||||
"integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==",
|
||||
"engines": {
|
||||
"node": ">= 0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mkdirp-classic": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
|
||||
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"node_modules/nan": {
|
||||
"version": "2.17.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz",
|
||||
"integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/node-docker-api": {
|
||||
"version": "1.1.22",
|
||||
"resolved": "https://registry.npmjs.org/node-docker-api/-/node-docker-api-1.1.22.tgz",
|
||||
"integrity": "sha512-8xfOiuLDJQw+l58i66lUNQhRhS5fAExqQbLolmyqMucrsDON7k7eLMIHphcBwwB7utwCHCQkcp73gSAmzSiAiw==",
|
||||
"dependencies": {
|
||||
"docker-modem": "^0.3.1",
|
||||
"memorystream": "^0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/node-docker-api/node_modules/debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"dependencies": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-docker-api/node_modules/docker-modem": {
|
||||
"version": "0.3.7",
|
||||
"resolved": "https://registry.npmjs.org/docker-modem/-/docker-modem-0.3.7.tgz",
|
||||
"integrity": "sha512-4Xn4ZVtc/2DEFtxY04lOVeF7yvxwXGVo0sN8FKRBnLhBcwQ78Hb56j+Z5yAXXUhoweVhzGeBeGWahS+af0/mcg==",
|
||||
"dependencies": {
|
||||
"debug": "^2.6.0",
|
||||
"JSONStream": "0.10.0",
|
||||
"readable-stream": "~1.0.26-4",
|
||||
"split-ca": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/node-docker-api/node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"node_modules/node-docker-api/node_modules/readable-stream": {
|
||||
"version": "1.0.34",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
|
||||
"integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==",
|
||||
"dependencies": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.1",
|
||||
"isarray": "0.0.1",
|
||||
"string_decoder": "~0.10.x"
|
||||
}
|
||||
},
|
||||
"node_modules/node-docker-api/node_modules/string_decoder": {
|
||||
"version": "0.10.31",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
|
||||
"integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ=="
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/peek-readable": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz",
|
||||
"integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==",
|
||||
"engines": {
|
||||
"node": ">=14.16"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/Borewit"
|
||||
}
|
||||
},
|
||||
"node_modules/pump": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
|
||||
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
|
||||
"dependencies": {
|
||||
"end-of-stream": "^1.1.0",
|
||||
"once": "^1.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/readable-web-to-node-stream": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz",
|
||||
"integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==",
|
||||
"dependencies": {
|
||||
"readable-stream": "^3.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/Borewit"
|
||||
}
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"node_modules/split-ca": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/split-ca/-/split-ca-1.0.1.tgz",
|
||||
"integrity": "sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ=="
|
||||
},
|
||||
"node_modules/ssh2": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/ssh2/-/ssh2-1.11.0.tgz",
|
||||
"integrity": "sha512-nfg0wZWGSsfUe/IBJkXVll3PEZ//YH2guww+mP88gTpuSU4FtZN7zu9JoeTGOyCNx2dTDtT9fOpWwlzyj4uOOw==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"asn1": "^0.2.4",
|
||||
"bcrypt-pbkdf": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.16.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"cpu-features": "~0.0.4",
|
||||
"nan": "^2.16.0"
|
||||
}
|
||||
},
|
||||
"node_modules/streamsearch": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
|
||||
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/strtok3": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz",
|
||||
"integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==",
|
||||
"dependencies": {
|
||||
"@tokenizer/token": "^0.3.0",
|
||||
"peek-readable": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.16"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/Borewit"
|
||||
}
|
||||
},
|
||||
"node_modules/tar-fs": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.1.tgz",
|
||||
"integrity": "sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA==",
|
||||
"dependencies": {
|
||||
"chownr": "^1.1.1",
|
||||
"mkdirp-classic": "^0.5.2",
|
||||
"pump": "^3.0.0",
|
||||
"tar-stream": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tar-stream": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
|
||||
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
|
||||
"dependencies": {
|
||||
"bl": "^4.0.3",
|
||||
"end-of-stream": "^1.4.1",
|
||||
"fs-constants": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^3.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/through": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
||||
"integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="
|
||||
},
|
||||
"node_modules/token-types": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz",
|
||||
"integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==",
|
||||
"dependencies": {
|
||||
"@tokenizer/token": "^0.3.0",
|
||||
"ieee754": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.16"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/Borewit"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-mixer": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.2.tgz",
|
||||
"integrity": "sha512-zvHx3VM83m2WYCE8XL99uaM7mFwYSkjR2OZti98fabHrwkjsCvgwChda5xctein3xGOyaQhtTeDq/1H/GNvF3A=="
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
|
||||
"integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA=="
|
||||
},
|
||||
"node_modules/tweetnacl": {
|
||||
"version": "0.14.5",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
|
||||
"integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="
|
||||
},
|
||||
"node_modules/undici": {
|
||||
"version": "5.14.0",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-5.14.0.tgz",
|
||||
"integrity": "sha512-yJlHYw6yXPPsuOH0x2Ib1Km61vu4hLiRRQoafs+WUgX1vO64vgnxiCEN9dpIrhZyHFsai3F0AEj4P9zy19enEQ==",
|
||||
"dependencies": {
|
||||
"busboy": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.18"
|
||||
}
|
||||
},
|
||||
"node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.11.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
|
||||
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": "^5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
{
|
||||
"name": "server-bot",
|
||||
"version": "1.0.0",
|
||||
"description": "Discord bot to remotely monitor and control a docker based server",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "nodemon index.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/allenrkeen/server-bot.git"
|
||||
},
|
||||
"keywords": [
|
||||
"discord",
|
||||
"docker",
|
||||
"linux",
|
||||
"selfhost"
|
||||
],
|
||||
"author": "allenrkeen",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/allenrkeen/server-bot/issues"
|
||||
},
|
||||
"homepage": "https://github.com/allenrkeen/server-bot#readme",
|
||||
"dependencies": {
|
||||
"discord.js": "^14.7.1",
|
||||
"dotenv": "^16.0.3",
|
||||
"node-docker-api": "^1.1.22"
|
||||
}
|
||||
}
|
Loading…
Reference in new issue