everybody wants to change the world but noone wants to die

This commit is contained in:
WhatDidYouExpect 2025-06-29 19:44:56 +02:00
parent 6d81539fc5
commit e6905b1d0a
6 changed files with 181 additions and 83 deletions

1
.gitignore vendored
View file

@ -8,3 +8,4 @@ memory.json
venv/ venv/
output.png output.png
.vscode/ .vscode/
received_memory.json

59
bot.py
View file

@ -5,6 +5,8 @@ import time
import random import random
import traceback import traceback
import subprocess import subprocess
import tempfile
import shutil
from modules.globalvars import * from modules.globalvars import *
from modules.prestartchecks import start_checks from modules.prestartchecks import start_checks
@ -35,7 +37,6 @@ from modules.image import gen_image
sys.excepthook = handle_exception sys.excepthook = handle_exception
check_for_update() # Check for updates (from modules/version.py) check_for_update() # Check for updates (from modules/version.py)
launched = False
# Ensure required NLTK resources are available # Ensure required NLTK resources are available
def check_resources(): def check_resources():
@ -240,10 +241,60 @@ async def talk(ctx, sentence_size: int = 5):
bot.help_command = None bot.help_command = None
# Command: Show help information # Command: Show help information
import uuid
import random
@bot.hybrid_command(description=f"{get_translation(LOCALE, 'command_desc_help')}") @bot.hybrid_command(description=f"{get_translation(LOCALE, 'command_desc_help')}")
async def image(ctx): async def image(ctx):
await gen_image() assets_folder = "assets/images"
await send_message(ctx, file=discord.File("output.png")) temp_input = None
def get_random_asset_image():
files = [f for f in os.listdir(assets_folder) if f.lower().endswith(('.png', '.jpg', '.jpeg', '.webp'))]
if not files:
return None
return os.path.join(assets_folder, random.choice(files))
if ctx.message.attachments:
attachment = ctx.message.attachments[0]
if attachment.content_type and attachment.content_type.startswith("image/"):
ext = os.path.splitext(attachment.filename)[1]
temp_input = f"tempy{ext}"
await attachment.save(temp_input)
input_path = temp_input
else:
fallback_image = get_random_asset_image()
if fallback_image is None:
await ctx.reply("No image available to process.")
return
temp_input = tempfile.mktemp(suffix=os.path.splitext(fallback_image)[1])
shutil.copy(fallback_image, temp_input)
input_path = temp_input
else:
fallback_image = get_random_asset_image()
if fallback_image is None:
await ctx.reply("No image available to process.")
return
# got lazy here
temp_input = tempfile.mktemp(suffix=os.path.splitext(fallback_image)[1])
shutil.copy(fallback_image, temp_input)
input_path = temp_input
output_path = await gen_image(input_path)
if output_path is None or not os.path.isfile(output_path):
if temp_input and os.path.exists(temp_input):
os.remove(temp_input)
await ctx.reply("Failed to generate text on the image.")
return
await ctx.send(file=discord.File(output_path))
if temp_input and os.path.exists(temp_input):
os.remove(temp_input)
# Remove default help command to use custom help # Remove default help command to use custom help
@ -259,7 +310,7 @@ async def help(ctx):
) )
command_categories = { command_categories = {
f"{get_translation(LOCALE, 'command_help_categories_general')}": ["mem", "talk", "about", "ping"], f"{get_translation(LOCALE, 'command_help_categories_general')}": ["mem", "talk", "about", "ping", "image"],
f"{get_translation(LOCALE, 'command_help_categories_admin')}": ["stats", "retrain"] f"{get_translation(LOCALE, 'command_help_categories_admin')}": ["stats", "retrain"]
} }

48
cogs/filesharing.py Normal file
View file

@ -0,0 +1,48 @@
import discord
from discord.ext import commands
from modules.globalvars import ownerid
class FileSync(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.mode = None
self.peer_id = None
self.awaiting_file = False
@commands.command()
async def syncfile(self, ctx, mode: str, peer: discord.User):
self.mode = mode.lower()
self.peer_id = peer.id
if ctx.author.id != ownerid:
await ctx.send("You don't have permission to execute this command.")
return
if self.mode == "s":
await ctx.send(f"<@{self.peer_id}> FILE_TRANSFER_REQUEST")
await ctx.send(file=discord.File("memory.json"))
await ctx.send("File sent in this channel.")
elif self.mode == "r":
await ctx.send("Waiting for incoming file...")
self.awaiting_file = True
else:
await ctx.send("Invalid mode, use 's' or 'r'.")
@commands.Cog.listener()
async def on_message(self, message):
if message.author == self.bot.user or not self.awaiting_file:
return
if message.author.id != self.peer_id:
return
if message.content == "FILE_TRANSFER_REQUEST":
print("Ping received. Awaiting file...")
if message.attachments:
for attachment in message.attachments:
if attachment.filename.endswith(".json"):
filename = "received_memory.json"
await attachment.save(filename)
print(f"File saved as {filename}")
await message.channel.send("File received and saved.")
self.awaiting_file = False
async def setup(bot):
await bot.add_cog(FileSync(bot))

View file

@ -37,6 +37,7 @@ IGNOREWARNING = False
song = os.getenv("song") song = os.getenv("song")
arch = platform.machine() arch = platform.machine()
slash_commands_enabled = False slash_commands_enabled = False
launched = False
latest_version = "0.0.0" latest_version = "0.0.0"
local_version = "1.0.2" local_version = "1.0.3"
os.environ['gooberlocal_version'] = local_version os.environ['gooberlocal_version'] = local_version

View file

@ -1,5 +1,4 @@
import os import os
import random
import re import re
from PIL import Image, ImageDraw, ImageFont from PIL import Image, ImageDraw, ImageFont
from modules.markovmemory import load_markov_model from modules.markovmemory import load_markov_model
@ -7,56 +6,42 @@ from modules.sentenceprocessing import improve_sentence_coherence, rephrase_for_
generated_sentences = set() generated_sentences = set()
async def gen_image(sentence_size=5, max_attempts=10): async def gen_image(input_image_path, sentence_size=5, max_attempts=10):
images_folder = "assets/images"
image_files = [f for f in os.listdir(images_folder) if f.lower().endswith(('.png', '.jpg', '.jpeg', '.webp'))]
if not image_files:
return
markov_model = load_markov_model() markov_model = load_markov_model()
if not markov_model: if not markov_model:
return return None
if not os.path.isfile(input_image_path):
return None
def load_font(size): def load_font(size):
return ImageFont.truetype("assets/fonts/Impact.ttf", size=size) return ImageFont.truetype("assets/fonts/Impact.ttf", size=size)
def draw_text_with_outline(draw, text, x, y, font): def draw_text_with_outline(draw, text, x, y, font):
outline_offsets = [(-2, -2), (-2, 2), (2, -2), (2, 2), (0, -2), (0, 2), (-2, 0), (2, 0)] outline_offsets = [(-2, -2), (-2, 2), (2, -2), (2, 2), (0, -2), (0, 2), (-2, 0), (2, 0)]
for ox, oy in outline_offsets: for ox, oy in outline_offsets:
draw.text((x + ox, y + oy), text, font=font, fill="black") draw.text((x + ox, y + oy), text, font=font, fill="black")
draw.text((x, y), text, font=font, fill="white") draw.text((x, y), text, font=font, fill="white")
def fits_in_width(text, font, max_width, draw):
def text_height(font, text):
bbox = draw.textbbox((0, 0), text, font=font) bbox = draw.textbbox((0, 0), text, font=font)
return bbox[3] - bbox[1]
def fits_in_width(text, font, max_width):
bbox = draw.textbbox((0,0), text, font=font)
text_width = bbox[2] - bbox[0] text_width = bbox[2] - bbox[0]
return text_width <= max_width return text_width <= max_width
def split_text_to_fit(text, font, max_width, draw):
def split_text_to_fit(text, font, max_width):
words = text.split() words = text.split()
for i in range(len(words), 0, -1): for i in range(len(words), 0, -1):
top_text = " ".join(words[:i]) top_text = " ".join(words[:i])
bottom_text = " ".join(words[i:]) bottom_text = " ".join(words[i:])
if fits_in_width(top_text, font, max_width) and fits_in_width(bottom_text, font, max_width): if fits_in_width(top_text, font, max_width, draw) and fits_in_width(bottom_text, font, max_width, draw):
return top_text, bottom_text return top_text, bottom_text
midpoint = len(words)//2 midpoint = len(words) // 2
return " ".join(words[:midpoint]), " ".join(words[midpoint:]) return " ".join(words[:midpoint]), " ".join(words[midpoint:])
coherent_response = "no text generated"
attempt = 0 attempt = 0
while attempt < max_attempts: while attempt < max_attempts:
chosen_image_path = os.path.join(images_folder, random.choice(image_files)) with Image.open(input_image_path).convert("RGBA") as img:
img = Image.open(chosen_image_path).convert("RGBA")
draw = ImageDraw.Draw(img) draw = ImageDraw.Draw(img)
width, height = img.size width, height = img.size
font_size = int(height / 10) font_size = int(height / 10)
font = load_font(font_size) font = load_font(font_size)
# Generate text
response = None response = None
for _ in range(20): for _ in range(20):
if sentence_size == 1: if sentence_size == 1:
@ -78,35 +63,44 @@ async def gen_image(sentence_size=5, max_attempts=10):
cleaned_response = re.sub(r'[^\w\s]', '', response).lower() cleaned_response = re.sub(r'[^\w\s]', '', response).lower()
coherent_response = rephrase_for_coherence(cleaned_response).upper() coherent_response = rephrase_for_coherence(cleaned_response).upper()
bbox = draw.textbbox((0, 0), coherent_response, font=font) bbox = draw.textbbox((0, 0), coherent_response, font=font)
text_width = bbox[2] - bbox[0] text_width = bbox[2] - bbox[0]
text_height_px = bbox[3] - bbox[1] text_height_px = bbox[3] - bbox[1]
max_text_height = height // 4 max_text_height = height // 4
if text_width <= width and text_height_px <= max_text_height: if text_width <= width and text_height_px <= max_text_height:
# Fits on top, draw at y=0 (top)
draw_text_with_outline(draw, coherent_response, (width - text_width) / 2, 0, font) draw_text_with_outline(draw, coherent_response, (width - text_width) / 2, 0, font)
img.save("output.png") img.save(input_image_path)
return return input_image_path
top_text, bottom_text = split_text_to_fit(coherent_response, font, width) else:
top_text, bottom_text = split_text_to_fit(coherent_response, font, width, draw)
top_bbox = draw.textbbox((0,0), top_text, font=font) top_bbox = draw.textbbox((0, 0), top_text, font=font)
bottom_bbox = draw.textbbox((0,0), bottom_text, font=font) bottom_bbox = draw.textbbox((0, 0), bottom_text, font=font)
top_height = top_bbox[3] - top_bbox[1] top_height = top_bbox[3] - top_bbox[1]
bottom_height = bottom_bbox[3] - bottom_bbox[1] bottom_height = bottom_bbox[3] - bottom_bbox[1]
if top_height <= max_text_height and bottom_height <= max_text_height: if top_height <= max_text_height and bottom_height <= max_text_height:
# top text draw_text_with_outline(draw, top_text, (width - (top_bbox[2] - top_bbox[0])) / 2, 0, font)
draw_text_with_outline(draw, top_text, (width - (top_bbox[2]-top_bbox[0])) / 2, 0, font)
y_bottom = height - bottom_height - int(height * 0.04) y_bottom = height - bottom_height - int(height * 0.04)
draw_text_with_outline(draw, bottom_text, (width - (bottom_bbox[2]-bottom_bbox[0])) / 2, y_bottom, font) draw_text_with_outline(draw, bottom_text, (width - (bottom_bbox[2] - bottom_bbox[0])) / 2, y_bottom, font)
img.save("output.png") img.save(input_image_path)
return return input_image_path
attempt += 1 attempt += 1
# If all attempts fail, cry.
with Image.open(input_image_path).convert("RGBA") as img:
draw = ImageDraw.Draw(img)
width, height = img.size
font_size = int(height / 10)
font = load_font(font_size)
truncated = coherent_response[:100] truncated = coherent_response[:100]
bbox = draw.textbbox((0, 0), truncated, font=font) bbox = draw.textbbox((0, 0), truncated, font=font)
text_width = bbox[2] - bbox[0] text_width = bbox[2] - bbox[0]
draw_text_with_outline(draw, truncated, (width - text_width) / 2, 0, font) draw_text_with_outline(draw, truncated, (width - text_width) / 2, 0, font)
img.save("output.png") img.save(input_image_path)
return input_image_path

View file

@ -17,6 +17,9 @@ def is_remote_ahead(branch='main', remote='origin'):
# Automatically update the local repository if the remote is ahead # Automatically update the local repository if the remote is ahead
def auto_update(branch='main', remote='origin'): def auto_update(branch='main', remote='origin'):
if launched == True:
print("I've already started! Im not updating...")
return
if AUTOUPDATE != "True": if AUTOUPDATE != "True":
pass # Auto-update is disabled pass # Auto-update is disabled
if is_remote_ahead(branch, remote): if is_remote_ahead(branch, remote):