Compare commits
78 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da2559e704 | ||
|
|
7bb423445d | ||
|
|
f4b1280d9a | ||
|
|
e978ed6643 | ||
|
|
4b55b0e6f7 | ||
|
|
7348ffeccb | ||
|
|
0736ea2d43 | ||
|
|
0271854cbb | ||
|
|
f4a92db440 | ||
|
|
78e9cd5807 | ||
|
|
43da4a2388 | ||
|
|
c5fdb36fc4 | ||
|
|
7eee640b17 | ||
|
|
1ae4b47391 | ||
|
|
697a7df551 | ||
|
|
907c23176c | ||
|
|
8325118a2d | ||
|
|
38121d2219 | ||
|
|
771592ccdb | ||
|
|
f9dfc29a8e | ||
|
|
658cff47c9 | ||
|
|
ff5ac25392 | ||
|
|
ef9c64ec9d | ||
|
|
9228c9a661 | ||
|
|
487d91ba2e | ||
|
|
ddca750093 | ||
|
|
5e58f45967 | ||
|
|
c0a5dda5d2 | ||
|
|
8756947298 | ||
|
|
71bb156d8b | ||
|
|
1399ebca7b | ||
|
|
d9968bd500 | ||
|
|
c1d815e7d5 | ||
|
|
8b7b1aaada | ||
|
|
ee267275d6 | ||
|
|
2141abae5e | ||
|
|
e5223e8296 | ||
|
|
2151a5d93a | ||
|
|
010c57247b | ||
|
|
9fb5b023d0 | ||
|
|
b91df5435d | ||
|
|
51c6e6627e | ||
|
|
9345d005eb | ||
|
|
fe3993bda8 | ||
|
|
7237cb8da9 | ||
|
|
dfc43de1a0 | ||
|
|
d6fd8f7b7b | ||
|
|
b45db6c54b | ||
|
|
5d8edfab0a | ||
|
|
217a93d3a4 | ||
|
|
3fb59cdff7 | ||
|
|
65d6badbf6 | ||
|
|
5b8c433e95 | ||
|
|
73679351d3 | ||
|
|
8fb5f1bee8 | ||
|
|
80b00b3aea | ||
|
|
3d2b15510f | ||
|
|
114a24c1cb | ||
|
|
a2cfefe02b | ||
|
|
3fc4c0475d | ||
|
|
d53803370a | ||
|
|
8b6a59e820 | ||
|
|
3964ec0fc2 | ||
|
|
8a3c18b857 | ||
|
|
739cdb710d | ||
|
|
42ae73030f | ||
|
|
7c6c012be6 | ||
|
|
4f1322c684 | ||
|
|
7e8e9a69cd | ||
|
|
f7dc58808b | ||
|
|
b14debfb37 | ||
|
|
cd5b431127 | ||
|
|
49c10f0bf5 | ||
|
|
5cd502b19c | ||
|
|
d94163e246 | ||
|
|
995bb08a0a | ||
|
|
601bb682f7 | ||
|
|
cd51b729f7 |
16 changed files with 565 additions and 84 deletions
15
.env_default
Normal file
15
.env_default
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
discord_token='token'
|
||||||
|
flask_port='5000'
|
||||||
|
imgflip_username='username'
|
||||||
|
imgflip_password='password'
|
||||||
|
openai.api_key='api_key'
|
||||||
|
upload_phixxy='False'
|
||||||
|
ftp_server='www.example.com'
|
||||||
|
ftp_username='username'
|
||||||
|
ftp_password='password'
|
||||||
|
ftp_public_html='/home/debian/www.example.com/'
|
||||||
|
stable_diffusion_ip='disabled'
|
||||||
|
stable_diffusion_port='7861'
|
||||||
|
stable_diffusion_user=
|
||||||
|
stable_diffusion_password=
|
||||||
|
eleven_labs='api-key'
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -9,4 +9,6 @@ extensions/
|
||||||
.env
|
.env
|
||||||
databases/
|
databases/
|
||||||
channels/
|
channels/
|
||||||
.gitignore
|
.gitignore
|
||||||
|
cogs/dailies.py
|
||||||
|
cogs/idlegame.py
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ class ChatGPT(commands.Cog):
|
||||||
self.folder_setup()
|
self.folder_setup()
|
||||||
self.remind_me_loop.start()
|
self.remind_me_loop.start()
|
||||||
self.http_session = self.create_aiohttp_session()
|
self.http_session = self.create_aiohttp_session()
|
||||||
self.dalle_budget = self.get_budget()
|
|
||||||
self.logger = logging.getLogger("bot")
|
self.logger = logging.getLogger("bot")
|
||||||
self.headers = {
|
self.headers = {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
|
@ -52,7 +51,7 @@ class ChatGPT(commands.Cog):
|
||||||
self.logger.exception(f"ChatGPT failed to make directories: {e}")
|
self.logger.exception(f"ChatGPT failed to make directories: {e}")
|
||||||
|
|
||||||
def text_cost_calc(self, model, input_tokens, output_tokens):
|
def text_cost_calc(self, model, input_tokens, output_tokens):
|
||||||
cost_table = {"gpt-3.5-turbo":{"input_tokens":0.0000005,"output_tokens":0.0000015},
|
cost_table = {"gpt-4o-mini":{"input_tokens":0.00000015,"output_tokens":0.0000006},
|
||||||
"gpt-4-turbo-preview":{"input_tokens":0.00001,"output_tokens":0.00003},
|
"gpt-4-turbo-preview":{"input_tokens":0.00001,"output_tokens":0.00003},
|
||||||
"gpt-4-vision-preview":{"input_tokens":0.00001,"output_tokens":0.00003},
|
"gpt-4-vision-preview":{"input_tokens":0.00001,"output_tokens":0.00003},
|
||||||
"gpt-4o":{"input_tokens":0.000005,"output_tokens":0.000015}
|
"gpt-4o":{"input_tokens":0.000005,"output_tokens":0.000015}
|
||||||
|
|
@ -61,36 +60,6 @@ class ChatGPT(commands.Cog):
|
||||||
output_cost = cost_table[model]["output_tokens"] * output_tokens
|
output_cost = cost_table[model]["output_tokens"] * output_tokens
|
||||||
cost = input_cost + output_cost
|
cost = input_cost + output_cost
|
||||||
return cost
|
return cost
|
||||||
|
|
||||||
def get_budget(self):
|
|
||||||
month = time.strftime("%B")
|
|
||||||
year = time.strftime("%Y")
|
|
||||||
key = f"{month}_{year}"
|
|
||||||
budget_file = f"{self.data_dir}budget.json"
|
|
||||||
if not os.path.exists(budget_file):
|
|
||||||
with open(budget_file, "w") as f:
|
|
||||||
json.dump({key:self.default_budget},f)
|
|
||||||
with open(budget_file, "r") as f:
|
|
||||||
budget_dict = json.loads(f.readline())
|
|
||||||
if key not in budget_dict:
|
|
||||||
budget_dict[key] = self.default_budget
|
|
||||||
with open(budget_file, "w") as f:
|
|
||||||
json.dump(budget_dict,f)
|
|
||||||
return self.default_budget
|
|
||||||
else:
|
|
||||||
return budget_dict[key]
|
|
||||||
|
|
||||||
def budget_add(self, amount):
|
|
||||||
month = time.strftime("%B")
|
|
||||||
year = time.strftime("%Y")
|
|
||||||
key = f"{month}_{year}"
|
|
||||||
budget_file = f"{self.data_dir}budget.json"
|
|
||||||
with open(budget_file, "r") as f:
|
|
||||||
budget_dict = json.loads(f.readline())
|
|
||||||
budget_dict[key] += amount
|
|
||||||
with open(budget_file, "w") as f:
|
|
||||||
json.dump(budget_dict,f)
|
|
||||||
self.dalle_budget += amount
|
|
||||||
|
|
||||||
def add_cost(self, category: str, cost: float):
|
def add_cost(self, category: str, cost: float):
|
||||||
day = time.strftime("%d")
|
day = time.strftime("%d")
|
||||||
|
|
@ -155,28 +124,6 @@ class ChatGPT(commands.Cog):
|
||||||
categories = response_data['results'][0]['categories']
|
categories = response_data['results'][0]['categories']
|
||||||
category_scores = response_data['results'][0]['category_scores']
|
category_scores = response_data['results'][0]['category_scores']
|
||||||
return (flagged, categories, category_scores)
|
return (flagged, categories, category_scores)
|
||||||
|
|
||||||
@commands.command()
|
|
||||||
async def budget(self, ctx, command=None, budget=None):
|
|
||||||
try:
|
|
||||||
if ctx.author.id == self.admin_id:
|
|
||||||
if command == "add" and budget!= None:
|
|
||||||
self.budget_add(float(budget))
|
|
||||||
await ctx.send(f"Budget increased by {budget}")
|
|
||||||
elif command == "remove" and budget!= None:
|
|
||||||
self.budget_add(-float(budget))
|
|
||||||
await ctx.send(f"Budget decreased by {budget}")
|
|
||||||
elif command == "set" and budget!= None:
|
|
||||||
self.budget_add(float(budget) - self.dalle_budget)
|
|
||||||
await ctx.send(f"Budget set to {budget}")
|
|
||||||
else:
|
|
||||||
await ctx.send(f"The current budget is {self.dalle_budget}")
|
|
||||||
else:
|
|
||||||
await ctx.send(f"The current budget is {self.dalle_budget}")
|
|
||||||
except Exception as e:
|
|
||||||
self.logger.exception(f"Budget command failed: {e}")
|
|
||||||
await ctx.send(f"Budget command failed")
|
|
||||||
|
|
||||||
|
|
||||||
@commands.command(
|
@commands.command(
|
||||||
name="costs",
|
name="costs",
|
||||||
|
|
@ -287,7 +234,7 @@ class ChatGPT(commands.Cog):
|
||||||
user = self.bot.get_user(reminder_dict["user_id"])
|
user = self.bot.get_user(reminder_dict["user_id"])
|
||||||
return await user.send(reminder_dict["response"])
|
return await user.send(reminder_dict["response"])
|
||||||
|
|
||||||
async def answer_question(self, topic, model="gpt-3.5-turbo"):
|
async def answer_question(self, topic, model="gpt-4o-mini"):
|
||||||
data = {
|
data = {
|
||||||
"model": model,
|
"model": model,
|
||||||
"messages": [{"role": "user", "content": topic}]
|
"messages": [{"role": "user", "content": topic}]
|
||||||
|
|
@ -312,6 +259,25 @@ class ChatGPT(commands.Cog):
|
||||||
self.logger.exception("Error occurred in answer_question")
|
self.logger.exception("Error occurred in answer_question")
|
||||||
return "Error occurred in answer_question"
|
return "Error occurred in answer_question"
|
||||||
|
|
||||||
|
@commands.command()
|
||||||
|
async def translate(self, ctx):
|
||||||
|
if ctx.message.attachments:
|
||||||
|
attachment = ctx.message.attachments[0] # assuming only one attachment
|
||||||
|
await attachment.save(self.working_dir + '/' + attachment.filename)
|
||||||
|
|
||||||
|
with open(self.working_dir + '/' + attachment.filename, 'r') as file:
|
||||||
|
text = file.read()
|
||||||
|
question = f"Translate the following text to english: {text}"
|
||||||
|
# Now text contains the content of the downloaded file
|
||||||
|
translated_text = await self.answer_question(question)
|
||||||
|
# Save the translated text to a new file
|
||||||
|
with open(f'{self.working_dir}/translated_text.txt', 'w') as new_file:
|
||||||
|
new_file.write(translated_text)
|
||||||
|
|
||||||
|
# Send the text file as an attachment
|
||||||
|
file = discord.File(f'{self.working_dir}/translated_text.txt')
|
||||||
|
await ctx.send(file=file)
|
||||||
|
|
||||||
|
|
||||||
@commands.command(
|
@commands.command(
|
||||||
description="Personality",
|
description="Personality",
|
||||||
|
|
@ -402,19 +368,6 @@ class ChatGPT(commands.Cog):
|
||||||
chunks = [answer[i:i+1999] for i in range(0, len(answer), 1999)]
|
chunks = [answer[i:i+1999] for i in range(0, len(answer), 1999)]
|
||||||
for chunk in chunks:
|
for chunk in chunks:
|
||||||
await ctx.send(chunk)
|
await ctx.send(chunk)
|
||||||
|
|
||||||
@commands.command(
|
|
||||||
description="Question GPT4",
|
|
||||||
help="Ask GPT4 a question. Usage: !question_gpt4 (question)",
|
|
||||||
brief="Get an answer"
|
|
||||||
)
|
|
||||||
async def question_gpt4(self, ctx):
|
|
||||||
await ctx.send("One moment, let me think...")
|
|
||||||
question = ctx.message.content.split(" ", maxsplit=1)[1]
|
|
||||||
answer = await self.answer_question(question, "gpt-4o")
|
|
||||||
chunks = [answer[i:i+1999] for i in range(0, len(answer), 1999)]
|
|
||||||
for chunk in chunks:
|
|
||||||
await ctx.send(chunk)
|
|
||||||
|
|
||||||
async def dalle_api_call(self, prompt: str, model: str="dall-e-2", quality: str="standard", size: str="1024x1024") -> tuple:
|
async def dalle_api_call(self, prompt: str, model: str="dall-e-2", quality: str="standard", size: str="1024x1024") -> tuple:
|
||||||
if self.dalle_budget <= await self.get_monthly_cost():
|
if self.dalle_budget <= await self.get_monthly_cost():
|
||||||
|
|
@ -682,7 +635,7 @@ class ChatGPT(commands.Cog):
|
||||||
message = ctx.content[0]
|
message = ctx.content[0]
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"model": "gpt-3.5-turbo",
|
"model": "gpt-4o-mini",
|
||||||
"messages": [{"role": "system", "content": system_msg}, {"role": "user", "content": message}]
|
"messages": [{"role": "system", "content": system_msg}, {"role": "user", "content": message}]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -146,4 +146,6 @@ class InkyScreen(commands.Cog):
|
||||||
|
|
||||||
|
|
||||||
async def setup(bot):
|
async def setup(bot):
|
||||||
await bot.add_cog(InkyScreen(bot))
|
#await bot.add_cog(InkyScreen(bot))
|
||||||
|
#Temporarily disable as this is probably unused for everyone including me
|
||||||
|
pass
|
||||||
|
|
@ -159,12 +159,17 @@ class Llama(commands.Cog):
|
||||||
channel_vars = await self.get_channel_config(message.channel.id)
|
channel_vars = await self.get_channel_config(message.channel.id)
|
||||||
chat_history_string = await self.log_chat_and_get_history(message, logfile, channel_vars)
|
chat_history_string = await self.log_chat_and_get_history(message, logfile, channel_vars)
|
||||||
# Chat Response
|
# Chat Response
|
||||||
if channel_vars["llama_enabled"] and not message.author.bot or self.bot_id in [x.id for x in message.mentions]:
|
try:
|
||||||
if message.content and message.content[0] != "!":
|
if channel_vars["llama_enabled"] and not message.author.bot or self.bot_id in [x.id for x in message.mentions]:
|
||||||
await self.chat_response(message, channel_vars, chat_history_string)
|
if message.content and message.content[0] != "!":
|
||||||
elif not message.content:
|
await self.chat_response(message, channel_vars, chat_history_string)
|
||||||
await self.chat_response(message, channel_vars, chat_history_string)
|
elif not message.content:
|
||||||
|
await self.chat_response(message, channel_vars, chat_history_string)
|
||||||
|
except:
|
||||||
|
self.edit_channel_config(message.channel.id, "llama_enabled", False)
|
||||||
|
|
||||||
|
|
||||||
async def setup(bot):
|
async def setup(bot):
|
||||||
await bot.add_cog(Llama(bot))
|
#await bot.add_cog(Llama(bot))
|
||||||
|
#Temporarily disable this as it isn't really working properly
|
||||||
|
pass
|
||||||
169
cogs/message_xp.py
Normal file
169
cogs/message_xp.py
Normal file
|
|
@ -0,0 +1,169 @@
|
||||||
|
from discord.ext import commands
|
||||||
|
import discord
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from cogs.base_cog.bot_base_cog import BotBaseCog
|
||||||
|
|
||||||
|
class MessageXP(BotBaseCog):
|
||||||
|
|
||||||
|
def __init__(self, bot):
|
||||||
|
super().__init__(bot)
|
||||||
|
self.setup(__class__.__name__)
|
||||||
|
|
||||||
|
@commands.command()
|
||||||
|
async def stats(self, ctx):
|
||||||
|
author_id = str(ctx.author.id)
|
||||||
|
try:
|
||||||
|
xp_data = read_xp_file(self)
|
||||||
|
if author_id in xp_data:
|
||||||
|
level = get_level_from_xp(xp_data[author_id])
|
||||||
|
await ctx.send(f"You are level {level} with {xp_data[author_id]} XP")
|
||||||
|
else:
|
||||||
|
await ctx.send("You have 0 XP")
|
||||||
|
except:
|
||||||
|
await ctx.send("Error getting XP")
|
||||||
|
|
||||||
|
@commands.command()
|
||||||
|
async def show_json(self, ctx):
|
||||||
|
with open(os.path.join(self.data_dir, "xp.json"), "r") as xp_file:
|
||||||
|
xp_data = json.load(xp_file)
|
||||||
|
await ctx.send(xp_data)
|
||||||
|
|
||||||
|
|
||||||
|
@commands.Cog.listener()
|
||||||
|
async def on_message(self, message: discord.Message):
|
||||||
|
try:
|
||||||
|
author_id = str(message.author.id)
|
||||||
|
if message.author.bot:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
xp_data = read_xp_file(self)
|
||||||
|
if author_id in xp_data:
|
||||||
|
xp_data[author_id] += 1
|
||||||
|
else:
|
||||||
|
xp_data[author_id] = 1
|
||||||
|
|
||||||
|
with open(os.path.join(self.data_dir, "xp.json"), "w") as xp_file:
|
||||||
|
json.dump(xp_data, xp_file)
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Error adding XP: {e}")
|
||||||
|
|
||||||
|
def read_xp_file(self):
|
||||||
|
try:
|
||||||
|
with open(os.path.join(self.data_dir, "xp.json"), "r") as xp_file:
|
||||||
|
xp_data = json.load(xp_file)
|
||||||
|
return xp_data
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"No XP file found. Returning empty json object: {e}")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def get_level_from_xp(xp):
|
||||||
|
xp_dict = {
|
||||||
|
1: 0,
|
||||||
|
2: 83,
|
||||||
|
3: 174,
|
||||||
|
4: 276,
|
||||||
|
5: 388,
|
||||||
|
6: 512,
|
||||||
|
7: 650,
|
||||||
|
8: 801,
|
||||||
|
9: 801,
|
||||||
|
10: 1_154,
|
||||||
|
11: 1_358,
|
||||||
|
12: 1_584,
|
||||||
|
13: 1_833,
|
||||||
|
14: 2_107,
|
||||||
|
15: 2_411,
|
||||||
|
16: 2_746,
|
||||||
|
17: 3_115,
|
||||||
|
18: 3_523,
|
||||||
|
19: 3_973,
|
||||||
|
20: 4_470,
|
||||||
|
21: 5_018,
|
||||||
|
22: 5_624,
|
||||||
|
23: 6_291,
|
||||||
|
24: 7_028,
|
||||||
|
25: 7_842,
|
||||||
|
26: 8_740,
|
||||||
|
27: 9_730,
|
||||||
|
28: 10_824,
|
||||||
|
29: 12_031,
|
||||||
|
30: 13_363,
|
||||||
|
31: 14_833,
|
||||||
|
32: 16_456,
|
||||||
|
33: 18_247,
|
||||||
|
34: 20_224,
|
||||||
|
35: 22_406,
|
||||||
|
36: 24_815,
|
||||||
|
37: 27_473,
|
||||||
|
38: 30_408,
|
||||||
|
39: 33_648,
|
||||||
|
40: 37_224,
|
||||||
|
41: 41_171,
|
||||||
|
42: 45_529,
|
||||||
|
43: 50_339,
|
||||||
|
44: 55_649,
|
||||||
|
45: 61_512,
|
||||||
|
46: 67_983,
|
||||||
|
47: 75_127,
|
||||||
|
48: 83_014,
|
||||||
|
49: 91_721,
|
||||||
|
50: 101_333,
|
||||||
|
51: 111_945,
|
||||||
|
52: 123_660,
|
||||||
|
53: 136_594,
|
||||||
|
54: 150_872,
|
||||||
|
55: 166_636,
|
||||||
|
56: 184_040,
|
||||||
|
57: 203_254,
|
||||||
|
58: 224_466,
|
||||||
|
59: 247_886,
|
||||||
|
60: 273_742,
|
||||||
|
61: 302_288,
|
||||||
|
62: 333_804,
|
||||||
|
63: 368_599,
|
||||||
|
64: 407_015,
|
||||||
|
65: 449_428,
|
||||||
|
66: 496_254,
|
||||||
|
67: 547_953,
|
||||||
|
68: 605_032,
|
||||||
|
69: 668_051,
|
||||||
|
70: 737_627,
|
||||||
|
71: 814_445,
|
||||||
|
72: 899_257,
|
||||||
|
73: 992_895,
|
||||||
|
74: 1_096_278,
|
||||||
|
75: 1_210_421,
|
||||||
|
76: 1_336_443,
|
||||||
|
77: 1_475_581,
|
||||||
|
78: 1_629_200,
|
||||||
|
79: 1_798_808,
|
||||||
|
80: 1_986_068,
|
||||||
|
81: 2_192_818,
|
||||||
|
82: 2_421_087,
|
||||||
|
83: 2_673_114,
|
||||||
|
84: 2_951_373,
|
||||||
|
85: 3_258_594,
|
||||||
|
86: 3_597_792,
|
||||||
|
87: 3_972_294,
|
||||||
|
88: 4_385_776,
|
||||||
|
89: 4_842_295,
|
||||||
|
90: 5_346_332,
|
||||||
|
91: 5_902_831,
|
||||||
|
92: 6_517_253,
|
||||||
|
93: 7_195_629,
|
||||||
|
94: 7_944_614,
|
||||||
|
95: 8_771_558,
|
||||||
|
96: 9_684_577,
|
||||||
|
97: 10_692_629,
|
||||||
|
98: 11_805_606,
|
||||||
|
99: 13_034_431
|
||||||
|
}
|
||||||
|
for level, xp_threshold in xp_dict.items():
|
||||||
|
if xp < xp_threshold:
|
||||||
|
return level - 1
|
||||||
|
return 99
|
||||||
|
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(MessageXP(bot))
|
||||||
|
|
@ -192,7 +192,7 @@ class PhixxyCom(commands.Cog):
|
||||||
except:
|
except:
|
||||||
self.logger.exception("Something went wrong in upload_ftp_ai_images")
|
self.logger.exception("Something went wrong in upload_ftp_ai_images")
|
||||||
|
|
||||||
async def answer_question(self, topic, model="gpt-3.5-turbo"):
|
async def answer_question(self, topic, model="gpt-4o-mini"):
|
||||||
headers = {
|
headers = {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Authorization': f'Bearer {os.getenv("openai.api_key")}',
|
'Authorization': f'Bearer {os.getenv("openai.api_key")}',
|
||||||
|
|
@ -265,7 +265,7 @@ class PhixxyCom(commands.Cog):
|
||||||
topic = await self.answer_question(question)
|
topic = await self.answer_question(question)
|
||||||
self.logger.info("Writing blogpost")
|
self.logger.info("Writing blogpost")
|
||||||
title_prompt = 'generate an absurd essay title about ' + topic
|
title_prompt = 'generate an absurd essay title about ' + topic
|
||||||
title = await self.answer_question(title_prompt, model="gpt-3.5-turbo")
|
title = await self.answer_question(title_prompt, model="gpt-4o-mini")
|
||||||
prompt = 'Write a satirical essay with a serious tone titled: "' + title + '". Do not label parts of the essay.'
|
prompt = 'Write a satirical essay with a serious tone titled: "' + title + '". Do not label parts of the essay.'
|
||||||
content = await self.answer_question(prompt, model="gpt-4o")
|
content = await self.answer_question(prompt, model="gpt-4o")
|
||||||
if title in content[:len(title)]:
|
if title in content[:len(title)]:
|
||||||
|
|
|
||||||
35
cogs/rss_feeds.py
Normal file
35
cogs/rss_feeds.py
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
from discord.ext import commands, tasks
|
||||||
|
from cogs.base_cog.bot_base_cog import BotBaseCog
|
||||||
|
import feedparser
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
class RSSCog(BotBaseCog):
|
||||||
|
|
||||||
|
def __init__(self, bot):
|
||||||
|
super().__init__(bot)
|
||||||
|
self.setup(__class__.__name__)
|
||||||
|
self.rss_base_url = 'https://secure.runescape.com/m=adventurers-log/rssfeed?searchName='
|
||||||
|
self.usernames = ['Deadifyed', 'Frozener', 'Tsuki no ko', 'blue boomer4']
|
||||||
|
self.last_items = {key: None for key in self.usernames}
|
||||||
|
self.check_rss.start()
|
||||||
|
|
||||||
|
@tasks.loop(minutes=5)
|
||||||
|
async def check_rss(self):
|
||||||
|
for name in self.usernames:
|
||||||
|
rss_url = self.rss_base_url + name.replace(' ','%20')
|
||||||
|
feed = feedparser.parse(rss_url)
|
||||||
|
latest_item = feed.entries[0] if feed.entries else None
|
||||||
|
|
||||||
|
if latest_item and latest_item.title != self.last_items[name]:
|
||||||
|
self.last_items[name] = latest_item.title
|
||||||
|
channel = self.bot.get_channel(895388842834673696)
|
||||||
|
await channel.send(f"{name}: {latest_item.description}")
|
||||||
|
|
||||||
|
await asyncio.sleep(60)
|
||||||
|
|
||||||
|
@check_rss.before_loop
|
||||||
|
async def before_check_rss(self):
|
||||||
|
await self.bot.wait_until_ready()
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(RSSCog(bot))
|
||||||
|
|
@ -20,8 +20,9 @@ class SaltStraw(BotBaseCog):
|
||||||
self.url = "https://saltandstraw.com/pages/flavors"
|
self.url = "https://saltandstraw.com/pages/flavors"
|
||||||
|
|
||||||
@commands.command()
|
@commands.command()
|
||||||
async def test(self, ctx):
|
async def icecream(self, ctx):
|
||||||
await self.parse()
|
message = await self.parse()
|
||||||
|
await ctx.send(message)
|
||||||
self.logger.info(f"SaltStraw command called by {ctx.author.name}")
|
self.logger.info(f"SaltStraw command called by {ctx.author.name}")
|
||||||
|
|
||||||
async def parse(self):
|
async def parse(self):
|
||||||
|
|
@ -36,8 +37,11 @@ class SaltStraw(BotBaseCog):
|
||||||
for item in parent_sets:
|
for item in parent_sets:
|
||||||
child_set = item.find_all("div", limit=3) #limit=3 skips everything past each description, i.e. ingredients/allergens
|
child_set = item.find_all("div", limit=3) #limit=3 skips everything past each description, i.e. ingredients/allergens
|
||||||
flavor_dict[child_set[0].string] = child_set[1].string #grabbing only the title and description
|
flavor_dict[child_set[0].string] = child_set[1].string #grabbing only the title and description
|
||||||
|
message = ""
|
||||||
for item in flavor_dict:
|
for item in flavor_dict:
|
||||||
print(f"\n{item}:\n{flavor_dict[item]}\n\n")
|
print(f"\n{item}:\n{flavor_dict[item]}\n\n")
|
||||||
|
message += f"\n{item}:\n"
|
||||||
|
return message
|
||||||
|
|
||||||
async def setup(bot):
|
async def setup(bot):
|
||||||
await bot.add_cog(SaltStraw(bot))
|
await bot.add_cog(SaltStraw(bot))
|
||||||
93
cogs/ytdl.py
Normal file
93
cogs/ytdl.py
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
from discord.ext import commands, tasks
|
||||||
|
from cogs.base_cog.bot_base_cog import BotBaseCog
|
||||||
|
|
||||||
|
class YoutubeDL(BotBaseCog):
|
||||||
|
|
||||||
|
def __init__(self, bot):
|
||||||
|
super().__init__(bot)
|
||||||
|
self.setup(__class__.__name__)
|
||||||
|
self.check_for_downloads.start()
|
||||||
|
|
||||||
|
''' @commands.command()
|
||||||
|
async def youtubedl(self, ctx):
|
||||||
|
try:
|
||||||
|
# Expecting the command format to be !youtubedl <url> <video|audio>
|
||||||
|
parts = ctx.message.content.split(" ")
|
||||||
|
if len(parts) < 3:
|
||||||
|
await ctx.send("Usage: !youtubedl <url> <video|audio>")
|
||||||
|
return
|
||||||
|
|
||||||
|
url = parts[1]
|
||||||
|
video_or_audio = parts[2]
|
||||||
|
|
||||||
|
# Run the subprocess
|
||||||
|
process = subprocess.Popen(
|
||||||
|
["python3", "youtubedl.py", url, video_or_audio],
|
||||||
|
cwd="data/ytdl",
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE
|
||||||
|
)
|
||||||
|
|
||||||
|
# Wait for the process to complete and read the output
|
||||||
|
stdout, stderr = process.communicate()
|
||||||
|
|
||||||
|
# Send the output back to the user
|
||||||
|
#await ctx.send(f"std out: {stdout.decode('utf-8')}") if stdout else await ctx.send("No stdout output")
|
||||||
|
#await ctx.send(f"std err: {stderr.decode('utf-8')}") if stderr else await ctx.send("No stderr output")
|
||||||
|
await ctx.send(f"Downloading {video_or_audio} from {url}...", suppress_embeds=True)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
#await ctx.send(f"Error: {e}")
|
||||||
|
await ctx.send("Usage: !youtubedl <url> <video|audio>")'''
|
||||||
|
|
||||||
|
@commands.command()
|
||||||
|
async def youtubedl(self, ctx):
|
||||||
|
try:
|
||||||
|
# Expecting the command format to be !youtubedl <url> <video|audio>
|
||||||
|
parts = ctx.message.content.split(" ")
|
||||||
|
if len(parts) < 3:
|
||||||
|
await ctx.send("Usage: !youtubedl <url> <video|audio>")
|
||||||
|
return
|
||||||
|
|
||||||
|
url = parts[1]
|
||||||
|
video_or_audio = parts[2]
|
||||||
|
|
||||||
|
# Create a subprocess
|
||||||
|
process = await asyncio.create_subprocess_exec(
|
||||||
|
"python3", "youtubedl.py", url, video_or_audio,
|
||||||
|
cwd="data/ytdl",
|
||||||
|
stdout=asyncio.subprocess.PIPE,
|
||||||
|
stderr=asyncio.subprocess.PIPE
|
||||||
|
)
|
||||||
|
|
||||||
|
# Write a message that the download has started
|
||||||
|
await ctx.send(f"Downloading {video_or_audio} from {url}...")
|
||||||
|
|
||||||
|
# Read stdout and stderr (non-blocking)
|
||||||
|
stdout, stderr = await process.communicate()
|
||||||
|
|
||||||
|
# Send the output back to the user
|
||||||
|
if stdout:
|
||||||
|
await ctx.send(f"std out: {stdout.decode('utf-8')}")
|
||||||
|
if stderr:
|
||||||
|
await ctx.send(f"std err: {stderr.decode('utf-8')}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
await ctx.send(f"Error: {e}")
|
||||||
|
|
||||||
|
#create a task
|
||||||
|
@tasks.loop(seconds=10)
|
||||||
|
async def check_for_downloads(self):
|
||||||
|
for file in os.listdir("data/ytdl"):
|
||||||
|
if file.endswith(".txt"):
|
||||||
|
with open(f"data/ytdl/{file}", "r") as f:
|
||||||
|
url = f.read()
|
||||||
|
await self.bot.get_channel(544408659174883328).send(f"{url}")
|
||||||
|
os.remove(f"data/ytdl/{file}")
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(YoutubeDL(bot))
|
||||||
54
data/ytdl/youtubedl.py
Normal file
54
data/ytdl/youtubedl.py
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
from sys import argv
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
import subprocess
|
||||||
|
#usage python3 youtubedl.py <url> <video|audio>
|
||||||
|
|
||||||
|
def download(url, video_or_audio):
|
||||||
|
if video_or_audio == "video":
|
||||||
|
process = subprocess.Popen(["yt-dlp", "--yes-playlist", f"{url}"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
process.wait()
|
||||||
|
return True
|
||||||
|
elif video_or_audio == "audio":
|
||||||
|
process = subprocess.Popen(["yt-dlp", "-x", "--yes-playlist", url], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
process.wait()
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print("Invalid argument")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def zip_all_files():
|
||||||
|
#zip all files
|
||||||
|
current_epoch = time.time()
|
||||||
|
output_file = f"{current_epoch}.zip"
|
||||||
|
os.system(f"zip -r {output_file} *")
|
||||||
|
return output_file
|
||||||
|
|
||||||
|
def upload_to_litterbox(input_file):
|
||||||
|
''' If you want to make curl requests to the API, here is an example. Allowed values for "time" are 1h, 12h, 24h, and 72h.
|
||||||
|
curl -F "reqtype=fileupload" -F "time=1h" -F "fileToUpload=@cutie.png" https://litterbox.catbox.moe/resources/internals/api.php'''
|
||||||
|
command = f"curl -F 'reqtype=fileupload' -F 'time=1h' -F 'fileToUpload=@{input_file}' https://litterbox.catbox.moe/resources/internals/api.php"
|
||||||
|
output_url = os.popen(command).read()
|
||||||
|
#delete all files in current directory except this script
|
||||||
|
file_types = ["zip", "mp4", "mp3", "webm", "wav", "m4a", "flac", "ogg", "opus", "wma", "aac", "m4p", "m4b", "m4r", "m4v", "mp2", "mp3", "mp4", "mpa", "mpeg", "mpg", "mpv", "mxf", "ogg", "oga", "ogv", "ogx", "spx", "wav", "webm", "wma", "wv", "wvx", "weba", "webm", "webp", "wmv"]
|
||||||
|
for file in os.listdir():
|
||||||
|
if file.split(".")[-1] in file_types:
|
||||||
|
os.remove(f"{file}")
|
||||||
|
pass
|
||||||
|
return output_url
|
||||||
|
|
||||||
|
def main():
|
||||||
|
url, video_or_audio = argv[1], argv[2]
|
||||||
|
print(url, video_or_audio)
|
||||||
|
if download(url, video_or_audio):
|
||||||
|
zip_file = zip_all_files()
|
||||||
|
output_url = upload_to_litterbox(zip_file)
|
||||||
|
print(output_url)
|
||||||
|
with open(f"{time.time()}.txt", "w") as output_file:
|
||||||
|
output_file.write(output_url)
|
||||||
|
output_file.close()
|
||||||
|
else:
|
||||||
|
print("Invalid argument")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
73
flask_templates/index.html
Normal file
73
flask_templates/index.html
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Sparkytron Config</title>
|
||||||
|
</head>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background-color: #333;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
background-color: #444;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 20px;
|
||||||
|
margin-top: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control {
|
||||||
|
background-color: #555;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background-color: #6c757d;
|
||||||
|
border-color: #6c757d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:hover {
|
||||||
|
background-color: #495057;
|
||||||
|
border-color: #495057;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-success {
|
||||||
|
background-color: #198754;
|
||||||
|
color: #fff;
|
||||||
|
border-color: #198754;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="mt-5">Warning!</h1>
|
||||||
|
<p class="lead">This information is stored in PLAIN TEXT in a .env file!</p>
|
||||||
|
<form method="post">
|
||||||
|
{% for key, value in key_value_pairs.items() %}
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="{{ key }}" class="col-sm-2 col-form-label">{{ key }}</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" id="{{ key }}" name="{{ key }}" value="{{ value }}" class="form-control">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-primary">Submit</button>
|
||||||
|
|
||||||
|
{% with messages = get_flashed_messages() %}
|
||||||
|
{% if messages %}
|
||||||
|
{% for message in messages %}
|
||||||
|
<div class="alert alert-success alert-dismissible fade show mt-3" role="alert">
|
||||||
|
{{ message }}
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -8,4 +8,8 @@ asyncssh
|
||||||
psutil
|
psutil
|
||||||
aiofiles
|
aiofiles
|
||||||
inky
|
inky
|
||||||
wakeonlan
|
wakeonlan
|
||||||
|
beautifulsoup4
|
||||||
|
Flask[async]
|
||||||
|
waitress
|
||||||
|
feedparser
|
||||||
26
sparkytron_webui.py
Normal file
26
sparkytron_webui.py
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
import asyncio
|
||||||
|
import discord
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from src.bot import bot
|
||||||
|
from src.webui import flask_app
|
||||||
|
from waitress import serve
|
||||||
|
|
||||||
|
def get_flask_app(process):
|
||||||
|
flask_app.bot_process = process
|
||||||
|
flask_app.secret_key = "woaoaoahaowhawoiahoahhhhhh"
|
||||||
|
return flask_app
|
||||||
|
|
||||||
|
def main():
|
||||||
|
load_dotenv()
|
||||||
|
flask_port = os.getenv("flask_port")
|
||||||
|
if not flask_port:
|
||||||
|
flask_port = '5000'
|
||||||
|
process = subprocess.Popen([sys.executable, "sparkytron3000.py"])
|
||||||
|
flask_app = get_flask_app(process)
|
||||||
|
serve(flask_app, host='0.0.0.0', port=flask_port)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
@ -10,7 +10,6 @@ intents.message_content = True
|
||||||
bot = commands.Bot(command_prefix='!', intents=intents)
|
bot = commands.Bot(command_prefix='!', intents=intents)
|
||||||
logger = src.logger.logger_setup()
|
logger = src.logger.logger_setup()
|
||||||
|
|
||||||
|
|
||||||
async def load_cogs(bot: commands.Bot, cog_path: str) -> None:
|
async def load_cogs(bot: commands.Bot, cog_path: str) -> None:
|
||||||
for cog_file in os.listdir(cog_path):
|
for cog_file in os.listdir(cog_path):
|
||||||
if cog_file[-3:] == '.py':
|
if cog_file[-3:] == '.py':
|
||||||
|
|
@ -27,6 +26,7 @@ async def on_ready():
|
||||||
await utils.delete_all_files("tmp/")
|
await utils.delete_all_files("tmp/")
|
||||||
await load_cogs(bot, 'cogs/')
|
await load_cogs(bot, 'cogs/')
|
||||||
logger.info('We have logged in as {0.user}'.format(bot))
|
logger.info('We have logged in as {0.user}'.format(bot))
|
||||||
|
print("If using the webui, visit http://localhost:5000 to change config!")
|
||||||
except:
|
except:
|
||||||
logger.warning(f"Error in on_ready")
|
logger.warning(f"Error in on_ready")
|
||||||
|
|
||||||
|
|
@ -43,4 +43,4 @@ async def on_message(ctx):
|
||||||
except discord.ext.commands.errors.CommandNotFound:
|
except discord.ext.commands.errors.CommandNotFound:
|
||||||
logger.info("Command not found.")
|
logger.info("Command not found.")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"Error processing commands: {e}")
|
logger.warning(f"Error processing commands: {e}")
|
||||||
46
src/webui.py
Normal file
46
src/webui.py
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from flask import Flask, render_template, request, flash
|
||||||
|
|
||||||
|
logger = logging.getLogger("bot")
|
||||||
|
flask_app = Flask(__name__, template_folder='../flask_templates')
|
||||||
|
|
||||||
|
def read_env(filename):
|
||||||
|
if os.path.exists(filename):
|
||||||
|
with open(filename, 'r') as file:
|
||||||
|
key_value_pairs = {}
|
||||||
|
for line in file:
|
||||||
|
try:
|
||||||
|
key, value = line.strip().split('=')
|
||||||
|
key = key.strip()
|
||||||
|
value = value.strip()[1:-1]
|
||||||
|
key_value_pairs[key] = value
|
||||||
|
except:
|
||||||
|
print("This line isnt a kv pair")
|
||||||
|
return key_value_pairs
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@flask_app.route('/', methods=['GET', 'POST'])
|
||||||
|
async def index():
|
||||||
|
key_value_pairs = read_env('.env')
|
||||||
|
if not key_value_pairs:
|
||||||
|
logger.warn("No .env file found! Copying defaults.")
|
||||||
|
key_value_pairs = read_env('.env_default')
|
||||||
|
form_dict = {}
|
||||||
|
if request.method == 'POST':
|
||||||
|
if key_value_pairs:
|
||||||
|
for form_name in key_value_pairs.keys():
|
||||||
|
form_dict[form_name] = request.form[form_name]
|
||||||
|
with open('.env', 'w') as file:
|
||||||
|
for key, value in form_dict.items():
|
||||||
|
file.write(f"{key}='{value}'\n")
|
||||||
|
flask_app.bot_process.terminate()
|
||||||
|
flask_app.bot_process = subprocess.Popen([sys.executable, "sparkytron3000.py"])
|
||||||
|
message = "Variables Updated!"
|
||||||
|
flash(message)
|
||||||
|
return render_template('index.html', key_value_pairs = key_value_pairs)
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue