Compare commits
No commits in common. "main" and "rewrite/source-overhaul" have entirely different histories.
main
...
rewrite/so
39 changed files with 1138 additions and 1379 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -12,4 +12,3 @@ received_memory.json
|
|||
translation_report.txt
|
||||
translationcompleteness.py
|
||||
modules/volta
|
||||
log.txt
|
2
.gitmodules
vendored
2
.gitmodules
vendored
|
@ -1,3 +1,3 @@
|
|||
[submodule "modules/volta"]
|
||||
path = modules/volta
|
||||
url = https://forgejo.expect.ovh/gooberinc/volta
|
||||
url = https://github.com/gooberinc/volta
|
||||
|
|
|
@ -5,5 +5,4 @@ Special thanks to [Charlie's Computers](https://github.com/PowerPCFan) for being
|
|||
|
||||
[Goober Central](https://github.com/whatdidyouexpect/goober-central)
|
||||
|
||||
[Another mirror](https://forgejo.expect.ovh/gooberinc/goober)
|
||||
no promises that it'll be stable
|
||||

|
||||
|
|
|
@ -8,6 +8,9 @@ by PowerPCFan
|
|||
[Cog Manager](https://github.com/WhatDidYouExpect/goober/blob/main/cogs/cogmanager.py)
|
||||
by expect
|
||||
|
||||
[TensorFlow integration](https://github.com/WhatDidYouExpect/goober/blob/main/cogs/tf.py)
|
||||
by SuperSilly2 (requires Python 3.7 - 3.10, tensorflow-metal/tensorflow-gpu and tensorflow/tensorflow-macos)
|
||||
|
||||
[Web Scraper](https://raw.githubusercontent.com/WhatDidYouExpect/goober/refs/heads/main/cogs/webscraper.py)
|
||||
by expect (requires goober version 0.11.7.2 or higher)
|
||||
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import discord
|
||||
from discord.ext import commands
|
||||
import os
|
||||
from modules.globalvars import ownerid
|
||||
|
||||
COG_PREFIX = "assets.cogs."
|
||||
|
||||
class CogManager(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
@ -17,7 +16,7 @@ class CogManager(commands.Cog):
|
|||
await ctx.send("Please provide the cog name to load.")
|
||||
return
|
||||
try:
|
||||
await self.bot.load_extension(COG_PREFIX + cog_name)
|
||||
await self.bot.load_extension(f"cogs.{cog_name}")
|
||||
await ctx.send(f"Loaded cog `{cog_name}` successfully.")
|
||||
except Exception as e:
|
||||
await ctx.send(f"Error loading cog `{cog_name}`: {e}")
|
||||
|
@ -31,7 +30,7 @@ class CogManager(commands.Cog):
|
|||
await ctx.send("Please provide the cog name to unload.")
|
||||
return
|
||||
try:
|
||||
await self.bot.unload_extension(COG_PREFIX + cog_name)
|
||||
await self.bot.unload_extension(f"cogs.{cog_name}")
|
||||
await ctx.send(f"Unloaded cog `{cog_name}` successfully.")
|
||||
except Exception as e:
|
||||
await ctx.send(f"Error unloading cog `{cog_name}`: {e}")
|
||||
|
@ -45,8 +44,8 @@ class CogManager(commands.Cog):
|
|||
await ctx.send("Please provide the cog name to reload.")
|
||||
return
|
||||
try:
|
||||
await self.bot.unload_extension(COG_PREFIX + cog_name)
|
||||
await self.bot.load_extension(COG_PREFIX + cog_name)
|
||||
await self.bot.unload_extension(f"cogs.{cog_name}")
|
||||
await self.bot.load_extension(f"cogs.{cog_name}")
|
||||
await ctx.send(f"Reloaded cog `{cog_name}` successfully.")
|
||||
except Exception as e:
|
||||
await ctx.send(f"Error reloading cog `{cog_name}`: {e}")
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
import random
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
|
||||
class eightball(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
@commands.command()
|
||||
async def eightball(self, ctx):
|
||||
answer = random.randint(1, 20)
|
||||
text = "Nothing"
|
||||
if answer==1:
|
||||
text = "It is certain."
|
||||
elif answer==2:
|
||||
text = "It is decidedly so."
|
||||
elif answer==3:
|
||||
text = "Without a doubt."
|
||||
elif answer==4:
|
||||
text = "Yes definitely."
|
||||
elif answer==5:
|
||||
text = "You may rely on it."
|
||||
elif answer==6:
|
||||
text = "As I see it, yes."
|
||||
elif answer==7:
|
||||
text = "Most likely."
|
||||
elif answer==8:
|
||||
text = "Outlook good."
|
||||
elif answer==9:
|
||||
text = "Yes."
|
||||
elif answer==10:
|
||||
text = "Signs point to yes."
|
||||
elif answer==11:
|
||||
text = "Reply hazy, try again."
|
||||
elif answer==12:
|
||||
text = "Ask again later."
|
||||
elif answer==13:
|
||||
text = "Better not tell you now."
|
||||
elif answer==14:
|
||||
text = "Cannot predict now."
|
||||
elif answer==15:
|
||||
text = "Concentrate and ask again."
|
||||
elif answer==16:
|
||||
text = "Don't count on it."
|
||||
elif answer==17:
|
||||
text = "My reply is no."
|
||||
elif answer==18:
|
||||
text = "My sources say no."
|
||||
elif answer==19:
|
||||
text = "Outlook not so good."
|
||||
elif answer==20:
|
||||
text = "Very doubtful."
|
||||
|
||||
await ctx.send(text)
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(eightball(bot))
|
|
@ -1,98 +0,0 @@
|
|||
import discord
|
||||
from discord.ext import commands
|
||||
from modules.image import *
|
||||
from modules.volta.main import _
|
||||
from PIL import Image, ImageEnhance, ImageFilter, ImageOps, ImageChops, ImageColor
|
||||
import os, random, shutil, tempfile
|
||||
|
||||
async def deepfryimage(path):
|
||||
with Image.open(path).convert("RGB") as im:
|
||||
# make it burn
|
||||
for _ in range(3):
|
||||
im = im.resize((int(im.width * 0.7), int(im.height * 0.7)))
|
||||
im = im.resize((int(im.width * 1.5), int(im.height * 1.5)))
|
||||
im = ImageEnhance.Contrast(im).enhance(random.uniform(5, 10))
|
||||
im = ImageEnhance.Sharpness(im).enhance(random.uniform(10, 50))
|
||||
im = ImageEnhance.Brightness(im).enhance(random.uniform(1.5, 3))
|
||||
r, g, b = im.split()
|
||||
r = r.point(lambda i: min(255, i * random.uniform(1.2, 2.0)))
|
||||
g = g.point(lambda i: min(255, i * random.uniform(0.5, 1.5)))
|
||||
b = b.point(lambda i: min(255, i * random.uniform(0.5, 2.0)))
|
||||
channels = [r, g, b]
|
||||
random.shuffle(channels)
|
||||
im = Image.merge("RGB", tuple(channels))
|
||||
overlay_color = tuple(random.randint(0, 255) for _ in range(3))
|
||||
overlay = Image.new("RGB", im.size, overlay_color)
|
||||
im = ImageChops.add(im, overlay, scale=2.0, offset=random.randint(-64, 64))
|
||||
|
||||
im = im.filter(ImageFilter.EDGE_ENHANCE_MORE)
|
||||
im = im.filter(ImageFilter.GaussianBlur(radius=random.uniform(0.5, 2)))
|
||||
for _ in range(3):
|
||||
tmp_path = tempfile.mktemp(suffix=".jpg")
|
||||
im.save(tmp_path, format="JPEG", quality=random.randint(5, 15))
|
||||
im = Image.open(tmp_path)
|
||||
if random.random() < 0.3:
|
||||
im = ImageOps.posterize(im, bits=random.choice([2, 3, 4]))
|
||||
if random.random() < 0.2:
|
||||
im = ImageOps.invert(im)
|
||||
out_path = tempfile.mktemp(suffix=".jpg")
|
||||
im.save(out_path, format="JPEG", quality=5)
|
||||
return out_path
|
||||
|
||||
|
||||
class whami(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
|
||||
@commands.command()
|
||||
async def fuckup(self, ctx):
|
||||
assets_folder = "assets/images"
|
||||
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'))
|
||||
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'))
|
||||
return
|
||||
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_meme(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_generate_image'))
|
||||
return
|
||||
|
||||
deepfried_path = await deepfryimage(output_path)
|
||||
await ctx.send(file=discord.File(deepfried_path))
|
||||
|
||||
if temp_input and os.path.exists(temp_input):
|
||||
os.remove(temp_input)
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(whami(bot))
|
29
assets/cogs/grabtemplate.py
Normal file
29
assets/cogs/grabtemplate.py
Normal file
|
@ -0,0 +1,29 @@
|
|||
import discord
|
||||
from discord.ext import commands
|
||||
import os
|
||||
import requests
|
||||
import ast
|
||||
from modules.globalvars import VERSION_URL
|
||||
|
||||
|
||||
class grabTemplate(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
def download_json():
|
||||
response = requests.get(f"{VERSION_URL}/goob/template.json")
|
||||
if response.status_code == 200:
|
||||
if os.path.exists("memory.json"):
|
||||
return
|
||||
else:
|
||||
userinput = input("Do you want to download the template json instead of starting from scratch?\n(Y/N)\n")
|
||||
if userinput.lower() == "y":
|
||||
with open("memory.json", "w", encoding="utf-8") as file:
|
||||
file.write(response.text)
|
||||
else:
|
||||
print("Starting from scratch...")
|
||||
elif response.status_code == 404:
|
||||
print("File not found on goober central!!")
|
||||
download_json()
|
||||
async def setup(bot):
|
||||
await bot.add_cog(grabTemplate(bot))
|
|
@ -1,123 +0,0 @@
|
|||
import discord
|
||||
from discord.ext import commands
|
||||
from discord import app_commands
|
||||
import aiohttp
|
||||
import re
|
||||
|
||||
class Lyrics(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
@app_commands.command(name="lyrics", description="Get lyrics for a song")
|
||||
@app_commands.describe(
|
||||
artist="Name of the artist",
|
||||
song="Title of the song",
|
||||
language="Target language code (optional)"
|
||||
)
|
||||
@app_commands.choices(language=[
|
||||
app_commands.Choice(name="Bulgarian", value="bg"),
|
||||
app_commands.Choice(name="Czech", value="cs"),
|
||||
app_commands.Choice(name="Danish", value="da"),
|
||||
app_commands.Choice(name="German", value="de"),
|
||||
app_commands.Choice(name="Greek", value="el"),
|
||||
app_commands.Choice(name="English", value="en"),
|
||||
app_commands.Choice(name="Spanish", value="es"),
|
||||
app_commands.Choice(name="Estonian", value="et"),
|
||||
app_commands.Choice(name="Finnish", value="fi"),
|
||||
app_commands.Choice(name="French", value="fr"),
|
||||
app_commands.Choice(name="Irish", value="ga"),
|
||||
app_commands.Choice(name="Croatian", value="hr"),
|
||||
app_commands.Choice(name="Hungarian", value="hu"),
|
||||
app_commands.Choice(name="Italian", value="it"),
|
||||
app_commands.Choice(name="Lithuanian", value="lt"),
|
||||
app_commands.Choice(name="Latvian", value="lv"),
|
||||
app_commands.Choice(name="Maltese", value="mt"),
|
||||
app_commands.Choice(name="Dutch", value="nl"),
|
||||
app_commands.Choice(name="Polish", value="pl"),
|
||||
app_commands.Choice(name="Portuguese", value="pt"),
|
||||
app_commands.Choice(name="Romanian", value="ro"),
|
||||
app_commands.Choice(name="Slovak", value="sk"),
|
||||
app_commands.Choice(name="Slovene", value="sl"),
|
||||
app_commands.Choice(name="Swedish", value="sv"),
|
||||
])
|
||||
async def lyrics(self, interaction: discord.Interaction, artist: str = None, song: str = None, language: app_commands.Choice[str] = None):
|
||||
await interaction.response.defer()
|
||||
if not artist or not song:
|
||||
member = interaction.guild.get_member(interaction.user.id)
|
||||
if not member:
|
||||
member = await interaction.guild.fetch_member(interaction.user.id)
|
||||
act_artist, act_song = await self.get_artist_song_from_presence(member)
|
||||
if act_artist and act_song:
|
||||
artist = artist or act_artist
|
||||
song = song or act_song
|
||||
else:
|
||||
await interaction.followup.send("No artist or song provided and couldn't find it from your current activity.")
|
||||
return
|
||||
|
||||
lyrics = await self.fetch_lyrics(artist, song)
|
||||
if not lyrics:
|
||||
await interaction.followup.send(f"Could not find lyrics for **{artist} - {song}**")
|
||||
return
|
||||
|
||||
if language:
|
||||
translated = await self.translate_text(lyrics, language.value)
|
||||
if translated:
|
||||
lyrics = translated
|
||||
|
||||
if len(lyrics) > 1900:
|
||||
lyrics = lyrics[:1900] + "\n\n[...lyrics truncated...]"
|
||||
|
||||
embed = discord.Embed(
|
||||
title=f"{artist} - {song}",
|
||||
description=lyrics,
|
||||
color=discord.Color.blue()
|
||||
)
|
||||
embed.set_footer(text=f"Requested by {interaction.user}", icon_url=interaction.user.display_avatar.url)
|
||||
await interaction.followup.send(embed=embed)
|
||||
|
||||
async def get_artist_song_from_presence(self, member: discord.Member):
|
||||
for activity in member.activities:
|
||||
if isinstance(activity, discord.Spotify):
|
||||
return activity.artist, activity.title
|
||||
return None, None
|
||||
|
||||
|
||||
async def fetch_lyrics(self, artist, song):
|
||||
artist_q = artist.replace(' ', '+').lower()
|
||||
song_q = song.replace(' ', '+').lower()
|
||||
|
||||
url = f"https://lrclib.net/api/get?artist_name={artist_q}&track_name={song_q}"
|
||||
print(url)
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
try:
|
||||
async with session.get(url) as resp:
|
||||
if resp.status != 200:
|
||||
return None
|
||||
data = await resp.json()
|
||||
return data.get('plainLyrics')
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
async def translate_text(self, text: str, target_lang: str) -> str | None:
|
||||
translate_url = "https://translate.googleapis.com/translate_a/single"
|
||||
params = {
|
||||
"client": "gtx",
|
||||
"sl": "auto",
|
||||
"tl": target_lang,
|
||||
"dt": "t",
|
||||
"q": text
|
||||
}
|
||||
async with aiohttp.ClientSession() as session:
|
||||
try:
|
||||
async with session.get(translate_url, params=params) as resp:
|
||||
if resp.status != 200:
|
||||
return None
|
||||
result = await resp.json()
|
||||
translated_chunks = [item[0] for item in result[0] if item[0]]
|
||||
return ''.join(translated_chunks)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(Lyrics(bot))
|
|
@ -1,66 +0,0 @@
|
|||
from discord.ext import commands
|
||||
import discord
|
||||
from collections import defaultdict, Counter
|
||||
import datetime
|
||||
from modules.globalvars import ownerid
|
||||
class StatsCog(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.start_time = datetime.datetime.utcnow()
|
||||
self.active_users = set()
|
||||
self.total_messages = 0
|
||||
self.command_usage = Counter()
|
||||
self.user_message_counts = Counter()
|
||||
self.messages_per_hour = defaultdict(int)
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_message(self, message):
|
||||
if message.author.bot:
|
||||
return
|
||||
self.active_users.add(message.author.id)
|
||||
self.total_messages += 1
|
||||
self.user_message_counts[message.author.id] += 1
|
||||
|
||||
now = datetime.datetime.utcnow()
|
||||
hour_key = now.strftime("%Y-%m-%d %H")
|
||||
self.messages_per_hour[hour_key] += 1
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_command(self, ctx):
|
||||
self.command_usage[ctx.command.qualified_name] += 1
|
||||
|
||||
@commands.command()
|
||||
async def spyware(self, ctx):
|
||||
if ctx.author.id != ownerid:
|
||||
return
|
||||
uptime = datetime.datetime.utcnow() - self.start_time
|
||||
hours_elapsed = max((uptime.total_seconds() / 3600), 1)
|
||||
avg_per_hour = self.total_messages / hours_elapsed
|
||||
if self.messages_per_hour:
|
||||
peak_hour, peak_count = max(self.messages_per_hour.items(), key=lambda x: x[1])
|
||||
else:
|
||||
peak_hour, peak_count = "N/A", 0
|
||||
|
||||
top_users = self.user_message_counts.most_common(5)
|
||||
|
||||
embed = discord.Embed(title="Community Stats", color=discord.Color.blue())
|
||||
embed.add_field(name="Uptime", value=str(uptime).split('.')[0], inline=False)
|
||||
embed.add_field(name="Total Messages", value=str(self.total_messages), inline=True)
|
||||
embed.add_field(name="Active Users", value=str(len(self.active_users)), inline=True)
|
||||
embed.add_field(name="Avg Messages/Hour", value=f"{avg_per_hour:.2f}", inline=True)
|
||||
embed.add_field(name="Peak Hour (UTC)", value=f"{peak_hour}: {peak_count} messages", inline=True)
|
||||
|
||||
top_str = "\n".join(
|
||||
f"<@{user_id}>: {count} messages" for user_id, count in top_users
|
||||
) or "No data"
|
||||
embed.add_field(name="Top Chatters", value=top_str, inline=False)
|
||||
|
||||
cmd_str = "\n".join(
|
||||
f"{cmd}: {count}" for cmd, count in self.command_usage.most_common(5)
|
||||
) or "No commands used yet"
|
||||
embed.add_field(name="Top Commands", value=cmd_str, inline=False)
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(StatsCog(bot))
|
155
assets/cogs/tf.py.disabled
Normal file
155
assets/cogs/tf.py.disabled
Normal file
|
@ -0,0 +1,155 @@
|
|||
import discord
|
||||
from discord.ext import commands
|
||||
import os
|
||||
import numpy as np
|
||||
import json
|
||||
import pickle
|
||||
import functools
|
||||
import re
|
||||
import time
|
||||
import asyncio
|
||||
|
||||
ready = True
|
||||
MODEL_MATCH_STRING = r"[0-9]{2}_[0-9]{2}_[0-9]{4}-[0-9]{2}_[0-9]{2}"
|
||||
|
||||
try:
|
||||
import tensorflow as tf
|
||||
from tensorflow import keras
|
||||
from tensorflow.keras.preprocessing.text import Tokenizer
|
||||
from tensorflow.keras.preprocessing.sequence import pad_sequences
|
||||
from tensorflow.keras.models import Sequential, load_model
|
||||
from tensorflow.keras.layers import Embedding, LSTM, Dense
|
||||
from tensorflow.keras.backend import clear_session
|
||||
|
||||
if tf.config.list_physical_devices('GPU'):
|
||||
print("Using GPU acceleration")
|
||||
elif tf.config.list_physical_devices('Metal'):
|
||||
print("Using Metal for macOS acceleration")
|
||||
except ImportError:
|
||||
print("ERROR: Failed to import TensorFlow. Ensure you have the correct dependencies:")
|
||||
print("tensorflow>=2.15.0")
|
||||
print("For macOS (Apple Silicon): tensorflow-metal")
|
||||
ready = False
|
||||
|
||||
|
||||
class TFCallback(keras.callbacks.Callback):
|
||||
def __init__(self, bot, progress_embed: discord.Embed, message):
|
||||
self.embed = progress_embed
|
||||
self.bot = bot
|
||||
self.message = message
|
||||
self.times = [time.time()]
|
||||
|
||||
async def send_message(self, message: str, description: str, **kwargs):
|
||||
if "epoch" in kwargs:
|
||||
self.times.append(time.time())
|
||||
avg_epoch_time = np.mean(np.diff(self.times))
|
||||
description = f"ETA: {round(avg_epoch_time)}s"
|
||||
self.embed.add_field(name=f"<t:{round(time.time())}:t> - {message}", value=description, inline=False)
|
||||
await self.message.edit(embed=self.embed)
|
||||
|
||||
def on_train_end(self, logs=None):
|
||||
self.bot.loop.create_task(self.send_message("Training stopped", "Training has been stopped."))
|
||||
|
||||
def on_epoch_begin(self, epoch, logs=None):
|
||||
self.bot.loop.create_task(self.send_message(f"Starting epoch {epoch}", "This might take a while", epoch=True))
|
||||
|
||||
def on_epoch_end(self, epoch, logs=None):
|
||||
self.bot.loop.create_task(self.send_message(f"Epoch {epoch} ended", f"Accuracy: {round(logs.get('accuracy', 0.0), 4)}"))
|
||||
|
||||
|
||||
class Ai:
|
||||
def __init__(self):
|
||||
model_path = settings.get("model_path")
|
||||
if model_path:
|
||||
self.__load_model(model_path)
|
||||
self.is_loaded = model_path is not None
|
||||
self.batch_size = 64
|
||||
|
||||
def generate_model_name(self):
|
||||
return time.strftime('%d_%m_%Y-%H_%M', time.localtime())
|
||||
|
||||
def __load_model(self, model_path):
|
||||
clear_session()
|
||||
self.model = load_model(os.path.join(model_path, "model.h5"))
|
||||
model_name = os.path.basename(model_path)
|
||||
try:
|
||||
with open(os.path.join(model_path, "tokenizer.pkl"), "rb") as f:
|
||||
self.tokenizer = pickle.load(f)
|
||||
except FileNotFoundError:
|
||||
print("Failed to load tokenizer, using default.")
|
||||
self.tokenizer = Tokenizer()
|
||||
with open("memory.json", "r") as f:
|
||||
self.tokenizer.fit_on_texts(json.load(f))
|
||||
self.is_loaded = True
|
||||
|
||||
def reload_model(self):
|
||||
clear_session()
|
||||
model_path = settings.get("model_path")
|
||||
if model_path:
|
||||
self.__load_model(model_path)
|
||||
self.is_loaded = True
|
||||
|
||||
async def run_async(self, func, bot, *args, **kwargs):
|
||||
return await bot.loop.run_in_executor(None, functools.partial(func, *args, **kwargs))
|
||||
|
||||
|
||||
class Learning(Ai):
|
||||
def create_model(self, memory, epochs=2):
|
||||
memory = memory[:2000]
|
||||
tokenizer = Tokenizer()
|
||||
tokenizer.fit_on_texts(memory)
|
||||
sequences = tokenizer.texts_to_sequences(memory)
|
||||
X, y = [], []
|
||||
for seq in sequences:
|
||||
for i in range(1, len(seq)):
|
||||
X.append(seq[:i])
|
||||
y.append(seq[i])
|
||||
maxlen = max(map(len, X))
|
||||
X = pad_sequences(X, maxlen=maxlen, padding="pre")
|
||||
y = np.array(y)
|
||||
|
||||
model = Sequential([
|
||||
Embedding(input_dim=VOCAB_SIZE, output_dim=128, input_length=maxlen),
|
||||
LSTM(64),
|
||||
Dense(VOCAB_SIZE, activation="softmax")
|
||||
])
|
||||
|
||||
model.compile(optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"])
|
||||
history = model.fit(X, y, epochs=epochs, batch_size=64, callbacks=[tf_callback])
|
||||
self.save_model(model, tokenizer, history)
|
||||
|
||||
def save_model(self, model, tokenizer, history, name=None):
|
||||
name = name or self.generate_model_name()
|
||||
model_dir = os.path.join("models", name)
|
||||
os.makedirs(model_dir, exist_ok=True)
|
||||
|
||||
with open(os.path.join(model_dir, "info.json"), "w") as f:
|
||||
json.dump(history.history, f)
|
||||
with open(os.path.join(model_dir, "tokenizer.pkl"), "wb") as f:
|
||||
pickle.dump(tokenizer, f)
|
||||
model.save(os.path.join(model_dir, "model.h5"))
|
||||
|
||||
|
||||
class Generation(Ai):
|
||||
def generate_sentence(self, word_amount, seed):
|
||||
if not self.is_loaded:
|
||||
return False
|
||||
for _ in range(word_amount):
|
||||
token_list = self.tokenizer.texts_to_sequences([seed])[0]
|
||||
token_list = pad_sequences([token_list], maxlen=self.model.input_shape[1], padding="pre")
|
||||
predicted_word_index = np.argmax(self.model.predict(token_list, verbose=0), axis=-1)[0]
|
||||
output_word = next((w for w, i in self.tokenizer.word_index.items() if i == predicted_word_index), "")
|
||||
seed += " " + output_word
|
||||
return seed
|
||||
|
||||
|
||||
VOCAB_SIZE = 100_000
|
||||
settings = {}
|
||||
learning = Learning()
|
||||
generation = Generation()
|
||||
|
||||
tf_callback = None
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(Tf(bot))
|
|
@ -60,7 +60,7 @@ class GooberWeb(commands.Cog):
|
|||
try:
|
||||
user = await self.bot.fetch_user(int(user_id))
|
||||
blacklisted_users.append({
|
||||
"name": f"{user.name}",
|
||||
"name": f"{user.name}#{user.discriminator}",
|
||||
"avatar_url": str(user.avatar.url) if user.avatar else str(user.default_avatar.url),
|
||||
"id": user.id
|
||||
})
|
||||
|
@ -158,7 +158,7 @@ class GooberWeb(commands.Cog):
|
|||
self._update_command_stats(command.name, interaction.user)
|
||||
|
||||
def _update_command_stats(self, command_name, user):
|
||||
self.last_command = f"{command_name} (by {user.name})"
|
||||
self.last_command = f"{command_name} (by {user.name}#{user.discriminator})"
|
||||
self.last_command_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
if self.websockets:
|
||||
asyncio.create_task(self.update_clients())
|
||||
|
@ -380,7 +380,7 @@ class GooberWeb(commands.Cog):
|
|||
if owner_id:
|
||||
try:
|
||||
owner = await self.bot.fetch_user(int(owner_id))
|
||||
owner_username = f"{owner.name}"
|
||||
owner_username = f"{owner.name}#{owner.discriminator}"
|
||||
owner_pfp = str(owner.avatar.url) if owner and owner.avatar else ""
|
||||
except:
|
||||
pass
|
||||
|
@ -877,4 +877,4 @@ class GooberWeb(commands.Cog):
|
|||
return web.json_response(stats)
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(GooberWeb(bot))
|
||||
await bot.add_cog(GooberWeb(bot))
|
|
@ -3,6 +3,6 @@
|
|||
This folder contains localization files for the project.
|
||||
|
||||
**Notice:**
|
||||
The Spanish and French locales currently do not have maintainers. If you are interested in helping maintain or improve these translations, please consider contributing!
|
||||
The Maltese, Frisian, Estonian, Spanish, and French locales currently do not have maintainers. If you are interested in helping maintain or improve these translations, please consider contributing!
|
||||
|
||||
Thank you for supporting localization efforts!
|
|
@ -1,23 +1,5 @@
|
|||
{
|
||||
"minigames_hangman_game": "Word: {display_word()}\nWrong guesses: {wrong_guesses}/{max_wrong}",
|
||||
"minigames_hangman_lost": "You lost! The word was:",
|
||||
"minigames_hangman_won": "You won! The word was:",
|
||||
"minigames_hangman_already_guessed": "You already guessed",
|
||||
"minigames_hangman_user_letter_guess": "Your letter guess",
|
||||
"minigames_hangman_guess": "Guess a Letter",
|
||||
"minigames_hangman_api_failed": "Failed to get a random word.",
|
||||
"minigames_hangman": "Play Hangman with a random word",
|
||||
"minigames_click_to_guess": "Click to guess a number from 1 to 10",
|
||||
"minigames_guess_button": "Guess",
|
||||
"minigames_wrong_number": "Wrong! The number was",
|
||||
"minigames_correct": "Correct!",
|
||||
"minigames_invalid_number": "Invalid number!",
|
||||
"minigames_guess_the_number": "Guess the number",
|
||||
"minigames_your_guess": "Your guess (1-10)",
|
||||
"memory_file_valid": "The memory.json file is valid!",
|
||||
"file_aint_uft8": "File is not valid UTF-8 text. Might be binary or corrupted.",
|
||||
"psutil_not_installed": "Memory check skipped.",
|
||||
"not_cloned": "Goober is not cloned! Please clone it from Git.",
|
||||
"not_cloned": "Goober is not cloned! Please clone it from GitHub.",
|
||||
"checks_disabled": "Checks are disabled!",
|
||||
"unhandled_exception": "An unhandled exception occurred. Please report this issue on GitHub.",
|
||||
"active_users:": "Active users:",
|
||||
|
@ -83,7 +65,7 @@
|
|||
"synced_commands": "Synced",
|
||||
"synced_commands2": "commands!",
|
||||
"fail_commands_sync": "Failed to sync commands:",
|
||||
"started": "{name} has started!\nYou're the star of the show now baby!",
|
||||
"started": "{name} has started!",
|
||||
"name_check": "Error checking name availability:",
|
||||
"name_taken": "Name is already taken. Please choose a different name.",
|
||||
"name_check2": "Error during name availability check:",
|
||||
|
@ -116,7 +98,7 @@
|
|||
"command_markov_retrain": "Retraining the Markov model... Please wait.",
|
||||
"command_markov_memory_not_found": "Error: memory file not found!",
|
||||
"command_markov_memory_is_corrupt": "Error: memory file is corrupt!",
|
||||
"command_markov_retraining": "Processing {data_size} data points...",
|
||||
"command_markov_retraining": "Processing {processed_data}/{data_size} data points...",
|
||||
"command_markov_retrain_successful": "Markov model retrained successfully using {data_size} data points!",
|
||||
"command_desc_talk":"talks n like stuf",
|
||||
"command_talk_insufficent_text": "I need to learn more from messages before I can talk.",
|
||||
|
@ -130,7 +112,6 @@
|
|||
"command_ran": "Info: {message.author.name} ran {message.content}",
|
||||
"command_ran_s": "Info: {interaction.user} ran ",
|
||||
"command_desc_ping": "ping",
|
||||
"command_desc_setlang": "Set a new language for the bot (temporarily)",
|
||||
"command_ping_embed_desc": "Bot Latency:",
|
||||
"command_ping_footer": "Requested by",
|
||||
"command_about_desc": "about",
|
||||
|
@ -146,6 +127,6 @@
|
|||
"command_stats_embed_field2name": "Version",
|
||||
"command_stats_embed_field2value": "Local: {local_version} \nLatest: {latest_version}",
|
||||
"command_stats_embed_field3name": "Variable Info",
|
||||
"command_stats_embed_field3value": "Name: {NAME} \nPrefix: {PREFIX} \nOwner ID: {ownerid}\nPing line: {PING_LINE} \nMemory Sharing Enabled: {showmemenabled} \nUser Training Enabled: {USERTRAIN_ENABLED}\nSong: {song} \nSplashtext: ```{splashtext}```"
|
||||
"command_stats_embed_field3value": "Name: {NAME} \nPrefix: {PREFIX} \nOwner ID: {ownerid} \nCooldown: {cooldown_time} \nPing line: {PING_LINE} \nMemory Sharing Enabled: {showmemenabled} \nUser Training Enabled: {USERTRAIN_ENABLED}\nSong: {song} \nSplashtext: ```{splashtext}```"
|
||||
}
|
||||
|
||||
|
|
|
@ -73,5 +73,5 @@
|
|||
"command_stats_embed_field2name": "Version",
|
||||
"command_stats_embed_field2value": "Version local: {local_version} \nUltima version: {latest_version}",
|
||||
"command_stats_embed_field3name": "informacion sobre las variables",
|
||||
"command_stats_embed_field3value": "Nombre: {NAME} \nPrefijo: {PREFIX} \nID del propietario: {ownerid}\nLinea de ping: {PING_LINE} \nCompartir memoria habilitada: {showmemenabled} \nEntrenamiento de usuario habilitado: {USERTRAIN_ENABLED} \nCancion: {song} \nTexto de bienvenida: ```{splashtext}```"
|
||||
"command_stats_embed_field3value": "Nombre: {NAME} \nPrefijo: {PREFIX} \nID del propietario: {ownerid} \nTiempo de reutilizacion: {cooldown_time} \nLinea de ping: {PING_LINE} \nCompartir memoria habilitada: {showmemenabled} \nEntrenamiento de usuario habilitado: {USERTRAIN_ENABLED} \nCancion: {song} \nTexto de bienvenida: ```{splashtext}```"
|
||||
}
|
131
assets/locales/et.json
Normal file
131
assets/locales/et.json
Normal file
|
@ -0,0 +1,131 @@
|
|||
{
|
||||
"checks_disabled": "Tarkistukset on poistettu käytöstä!",
|
||||
"active_users:": "Aktiiviset käyttäjät:",
|
||||
"spacy_initialized": "spaCy ja spacytextblob ovat valmiita.",
|
||||
"spacy_model_not_found": "spaCy mallia ei löytynyt! Ladataan se....`",
|
||||
"unhandled_exception": "Käsittelemätön virhe tapahtui. Ilmoita tästä GitHubiin.",
|
||||
"env_file_not_found": ".env faili ei leitud! Palun loo see vajalike muutujatega.",
|
||||
"error_fetching_active_users": "Aktiivsete kasutajate hankimisel tekkis viga: {error}",
|
||||
"error_sending_alive_ping": "Elusoleku ping'i saatmisel tekkis viga: {error}",
|
||||
"already_started": "Olen juba käivitatud! Ei uuenda...",
|
||||
"please_restart": "Palun taaskäivita goober!",
|
||||
"local_ahead": "Kohalik {remote}/{branch} on ees või ajakohane. Ei uuenda...",
|
||||
"remote_ahead": "Kaug-{remote}/{branch} on ees. Uuendan...",
|
||||
"cant_find_local_version": "Ma ei leia local_version muutujat! Või on seda muudetud ja see pole täisarv!",
|
||||
"running_prestart_checks": "Käivitamiseelsed kontrollid käivad...",
|
||||
"continuing_in_seconds": "Jätkan {seconds} sekundi pärast... Vajuta suvalist klahvi, et vahele jätta.",
|
||||
"missing_requests_psutil": "Puuduvad requests ja psutil! Palun paigalda need käsuga: `pip install requests psutil`",
|
||||
"requirements_not_found": "requirements.txt faili ei leitud asukohast {path}, kas seda on muudetud?",
|
||||
"warning_failed_parse_imports": "Hoiatus: Importide parsimine ebaõnnestus failist {filename}: {error}",
|
||||
"cogs_dir_not_found": "Cogs kataloogi ei leitud asukohast {path}, jätan vahele.",
|
||||
"std_lib_local_skipped": "STD LIB / KOHALIK {package} (kontroll vahele jäetud)",
|
||||
"ok_installed": "OK",
|
||||
"missing_package": "PUUDUB",
|
||||
"missing_package2": "ei ole paigaldatud",
|
||||
"missing_packages_detected": "Tuvastati puuduvad paketid:",
|
||||
"telling_goober_central": "Teavitan goober central aadressil {url}",
|
||||
"failed_to_contact": "Ei õnnestunud ühendust saada {url}: {error}",
|
||||
"all_requirements_satisfied": "Kõik nõuded on täidetud.",
|
||||
"ping_to": "Ping aadressile {host}: {latency} ms",
|
||||
"high_latency": "Tuvastatud kõrge latentsus! Võid kogeda viivitusi vastustes.",
|
||||
"could_not_parse_latency": "Latentsust ei õnnestunud parsida.",
|
||||
"ping_failed": "Ping aadressile {host} ebaõnnestus.",
|
||||
"error_running_ping": "Ping'i käivitamisel tekkis viga: {error}",
|
||||
"memory_usage": "Mälu kasutus: {used} GB / {total} GB ({percent}%)",
|
||||
"memory_above_90": "Mälu kasutus on üle 90% ({percent}%). Kaalu mälu vabastamist.",
|
||||
"total_memory": "Kogu mälu: {total} GB",
|
||||
"used_memory": "Kasutatud mälu: {used} GB",
|
||||
"low_free_memory": "Tuvastatud vähe vaba mälu! Ainult {free} GB saadaval.",
|
||||
"measuring_cpu": "Mõõdan protsessori kasutust tuuma kohta...",
|
||||
"core_usage": "Tuuma {idx}: [{bar}] {usage}%",
|
||||
"total_cpu_usage": "Kogu protsessori kasutus: {usage}%",
|
||||
"high_avg_cpu": "Kõrge keskmine protsessori kasutus: {usage}%",
|
||||
"really_high_cpu": "Väga kõrge protsessori koormus! Süsteem võib hakata tõrkuma.",
|
||||
"memory_file": "Mälufail: {size} MB",
|
||||
"memory_file_large": "Mälufail on 1GB või suurem, kaalu selle kustutamist ruumi vabastamiseks.",
|
||||
"memory_file_corrupted": "Mälufail on rikutud! JSON dekodeerimise viga: {error}",
|
||||
"consider_backup_memory": "Kaalu mälufaili varundamist ja uuesti loomist.",
|
||||
"memory_file_encoding": "Mälufailil on kodeeringu probleemid: {error}",
|
||||
"error_reading_memory": "Viga mälufaili lugemisel: {error}",
|
||||
"memory_file_not_found": "Mälufaili ei leitud.",
|
||||
"modification_warning": "Gooberit on muudetud! Kõik muudatused lähevad uuendamisel kaotsi!",
|
||||
"reported_version": "Teatatud versioon:",
|
||||
"current_hash": "Praegune räsi:",
|
||||
"not_found": "ei leitud!",
|
||||
"version_error": "Versiooni infot ei õnnestunud hankida. Staatuskood",
|
||||
"loaded_cog": "Laaditud cog:",
|
||||
"loaded_cog2": "Laaditud moodul:",
|
||||
"cog_fail": "Cog'i laadimine ebaõnnestus:",
|
||||
"cog_fail2": "Mooduli laadimine ebaõnnestus:",
|
||||
"no_model": "Salvestatud Markovi mudelit ei leitud. Alustan nullist.",
|
||||
"folder_created": "Kaust '{folder_name}' loodud.",
|
||||
"folder_exists": "Kaust '{folder_name}' on juba olemas. Jätan vahele...",
|
||||
"logged_in": "Sisse logitud kui",
|
||||
"synced_commands": "Sünkroonitud",
|
||||
"synced_commands2": "käsku!",
|
||||
"fail_commands_sync": "Käskude sünkroonimine ebaõnnestus:",
|
||||
"started": "{name} on käivitatud!",
|
||||
"name_check": "Viga nime saadavuse kontrollimisel:",
|
||||
"name_taken": "Nimi on juba võetud. Palun vali teine nimi.",
|
||||
"name_check2": "Viga nime saadavuse kontrolli ajal:",
|
||||
"add_token": "Token: {token}\nPalun lisa see token oma .env faili kui",
|
||||
"token_exists": "Token on juba .env failis olemas. Kasutan olemasolevat tokenit.",
|
||||
"registration_error": "Registreerimisel tekkis viga:",
|
||||
"version_backup": "Varukoopia loodud:",
|
||||
"backup_error": "Viga: {LOCAL_VERSION_FILE} ei leitud varundamiseks.",
|
||||
"model_loaded": "Markovi mudel laaditud asukohast",
|
||||
"fetch_update_fail": "Uuenduse infot ei õnnestunud hankida.",
|
||||
"invalid_server": "Viga: Serverilt saadud versiooni info on vigane.",
|
||||
"goober_server_alert": "Hoiatus goober centralilt!\n",
|
||||
"new_version": "Uus versioon saadaval: {latest_version} (Praegune: {local_version})",
|
||||
"changelog": "Vaata {VERSION_URL}/goob/changes.txt, et näha muudatuste logi\n\n",
|
||||
"invalid_version": "Versioon: {local_version} ei ole kehtiv!",
|
||||
"invalid_version2": "Kui see on tahtlik, siis ignoreeri seda teadet, muidu vajuta Y, et tõmmata serverist kehtiv versioon sõltumata praegu töötavast gooberi versioonist",
|
||||
"invalid_version3": "Praegune versioon varundatakse faili current_version.bak..",
|
||||
"input": "(Y või mõni muu klahv, et ignoreerida....)",
|
||||
"modification_ignored": "Oled muutnud",
|
||||
"modification_ignored2": "IGNOREWARNING on seatud väärtusele false..",
|
||||
"latest_version": "Kasutad uusimat versiooni:",
|
||||
"latest_version2": "Vaata {VERSION_URL}/goob/changes.txt, et näha muudatuste logi",
|
||||
"pinging_disabled": "Pingimine on keelatud! Ei teavita serverit...",
|
||||
"goober_ping_success": "Sisse logitud goober centralisse kui {NAME}",
|
||||
"goober_ping_fail": "Andmete saatmine ebaõnnestus. Server tagastas staatuse:",
|
||||
"goober_ping_fail2": "Andmete saatmisel tekkis viga:",
|
||||
"sentence_positivity": "Lause positiivsus on:",
|
||||
"command_edit_fail": "Sõnumi muutmine ebaõnnestus:",
|
||||
"command_desc_retrain": "Treeni Markovi mudelit käsitsi uuesti.",
|
||||
"command_markov_retrain": "Markovi mudelit treenitakse uuesti... Palun oota.",
|
||||
"command_markov_memory_not_found": "Viga: mälufaili ei leitud!",
|
||||
"command_markov_memory_is_corrupt": "Viga: mälufail on rikutud!",
|
||||
"command_markov_retraining": "Töötlen {processed_data}/{data_size} andmepunkti...",
|
||||
"command_markov_retrain_successful": "Markovi mudel treeniti edukalt uuesti, kasutades {data_size} andmepunkti!",
|
||||
"command_desc_talk": "räägib ja muud sellist",
|
||||
"command_talk_insufficent_text": "Mul on vaja rohkem sõnumeid õppimiseks, enne kui saan rääkida.",
|
||||
"command_talk_generation_fail": "Mul pole hetkel midagi öelda!",
|
||||
"command_desc_help": "abi",
|
||||
"command_help_embed_title": "Boti abi",
|
||||
"command_help_embed_desc": "Käskude loetelu kategooriate kaupa.",
|
||||
"command_help_categories_general": "Üldine",
|
||||
"command_help_categories_admin": "Administreerimine",
|
||||
"command_help_categories_custom": "Kohandatud käsud",
|
||||
"command_ran": "Info: {message.author.name} käivitas {message.content}",
|
||||
"command_ran_s": "Info: {interaction.user} käivitas ",
|
||||
"command_desc_ping": "ping",
|
||||
"command_ping_embed_desc": "Boti latentsus:",
|
||||
"command_ping_footer": "Soovis",
|
||||
"command_about_desc": "teave",
|
||||
"command_about_embed_title": "Minust",
|
||||
"command_about_embed_field1": "Nimi",
|
||||
"command_about_embed_field2name": "Versioon",
|
||||
"command_about_embed_field2value": "Kohalik: {local_version} \nViimane: {latest_version}",
|
||||
"command_desc_stats": "statistika",
|
||||
"command_stats_embed_title": "Boti statistika",
|
||||
"command_stats_embed_desc": "Andmed boti mälu kohta.",
|
||||
"command_stats_embed_field1name": "Faili statistika",
|
||||
"command_stats_embed_field1value": "Suurus: {file_size} baiti\nRead: {line_count}",
|
||||
"command_stats_embed_field2name": "Versioon",
|
||||
"command_stats_embed_field2value": "Kohalik: {local_version} \nViimane: {latest_version}",
|
||||
"command_stats_embed_field3name": "Muutuja info",
|
||||
"command_stats_embed_field3value": "Nimi: {NAME} \nPrefiks: {PREFIX} \nOmaniku ID: {ownerid} \nJahtumisaeg: {cooldown_time} \nPingirida: {PING_LINE} \nMälu jagamine lubatud: {showmemenabled} \nKasutajaõpe lubatud: {USERTRAIN_ENABLED}\nLaul: {song} \nSplashtekst: ```{splashtext}```"
|
||||
}
|
||||
|
|
@ -1,6 +1,4 @@
|
|||
{
|
||||
"memory_file_valid": "memory.json on toimiva!",
|
||||
"file_aint_uft8": "Tiedosto ei ole UTF-8 tekstiä. Saattaa olla binääriä tai korruptoitunut.",
|
||||
"active_users:": "Aktiiviset käyttäjät:",
|
||||
"cog_fail2": "Moduulin lataaminen epäonnistui:",
|
||||
"command_ran_s": "Info: {interaction.user} suoritti",
|
||||
|
@ -70,7 +68,7 @@
|
|||
"synced_commands": "Synkronoitiin",
|
||||
"synced_commands2": "komennot!",
|
||||
"fail_commands_sync": "Komentojen synkronointi epäonnistui:",
|
||||
"started": "{name} on käynnistynyt!\nOlet nyt sarjan tähti, beibi!",
|
||||
"started": "{name} on käynnistynyt!",
|
||||
"name_check": "Nimen saatavuuden tarkistus epäonnistui:",
|
||||
"name_taken": "Nimi on jo käytössä. Valitse toinen nimi.",
|
||||
"name_check2": "Virhe tapahtui nimen saatavuuden tarkistamisessa:",
|
||||
|
@ -130,6 +128,6 @@
|
|||
"command_stats_embed_field2name": "Versio",
|
||||
"command_stats_embed_field2value": "Paikallinen: {local_version} \nUusin: {latest_version}",
|
||||
"command_stats_embed_field3name": "Muuttajainformaatio",
|
||||
"command_stats_embed_field3value": "Nimi: {NAME} \nEtuliite: {PREFIX} \nOmistajan ID: {ownerid}\nPing-linja: {PING_LINE} \nMuistin jako päällä: {showmemenabled} \nOppiminen käyttäjistä: {USERTRAIN_ENABLED}\nLaulu: {song} \nRoisketeksti: ```{splashtext}```"
|
||||
"command_stats_embed_field3value": "Nimi: {NAME} \nEtuliite: {PREFIX} \nOmistajan ID: {ownerid} \nJäähtymisaika: {cooldown_time} \nPing-linja: {PING_LINE} \nMuistin jako päällä: {showmemenabled} \nOppiminen käyttäjistä: {USERTRAIN_ENABLED}\nLaulu: {song} \nRoisketeksti: ```{splashtext}```"
|
||||
}
|
||||
|
||||
|
130
assets/locales/fr.json
Normal file
130
assets/locales/fr.json
Normal file
|
@ -0,0 +1,130 @@
|
|||
{
|
||||
"checks_disabled": "Les vérifications sont désactivées !",
|
||||
"unhandled_exception": "Une exception non gérée est survenue. Merci de rapporter ce problème sur GitHub.",
|
||||
"active_users:": "Utilisateurs actifs :",
|
||||
"spacy_initialized": "spaCy et spacytextblob sont prêts.",
|
||||
"spacy_model_not_found": "Le modèle spaCy est introuvable ! Téléchargement en cours...",
|
||||
"env_file_not_found": "Le fichier .env est introuvable ! Créez-en un avec les variables nécessaires.",
|
||||
"error_fetching_active_users": "Erreur lors de la récupération des utilisateurs actifs : {error}",
|
||||
"error_sending_alive_ping": "Erreur lors de l’envoi du ping actif : {error}",
|
||||
"already_started": "J’ai déjà démarré ! Je ne me mets pas à jour...",
|
||||
"please_restart": "Redémarre, stp !",
|
||||
"local_ahead": "Local {remote}/{branch} est en avance ou à jour. Pas de mise à jour...",
|
||||
"remote_ahead": "Remote {remote}/{branch} est en avance. Mise à jour en cours...",
|
||||
"cant_find_local_version": "Je ne trouve pas la variable local_version ! Ou elle a été modifiée et ce n’est pas un entier !",
|
||||
"running_prestart_checks": "Exécution des vérifications préalables au démarrage...",
|
||||
"continuing_in_seconds": "Reprise dans {seconds} secondes... Appuie sur une touche pour passer.",
|
||||
"missing_requests_psutil": "requests et psutil manquants ! Installe-les avec pip : `pip install requests psutil`",
|
||||
"requirements_not_found": "requirements.txt introuvable à {path}, a-t-il été modifié ?",
|
||||
"warning_failed_parse_imports": "Avertissement : Échec du parsing des imports depuis {filename} : {error}",
|
||||
"cogs_dir_not_found": "Répertoire des cogs introuvable à {path}, scan ignoré.",
|
||||
"std_lib_local_skipped": "LIB STD / LOCAL {package} (vérification sautée)",
|
||||
"ok_installed": "OK",
|
||||
"missing_package": "MANQUANT",
|
||||
"missing_package2": "n’est pas installé",
|
||||
"missing_packages_detected": "Packages manquants détectés :",
|
||||
"telling_goober_central": "Envoi à goober central à {url}",
|
||||
"failed_to_contact": "Impossible de contacter {url} : {error}",
|
||||
"all_requirements_satisfied": "Toutes les dépendances sont satisfaites.",
|
||||
"ping_to": "Ping vers {host} : {latency} ms",
|
||||
"high_latency": "Latence élevée détectée ! Tu pourrais avoir des délais de réponse.",
|
||||
"could_not_parse_latency": "Impossible d’analyser la latence.",
|
||||
"ping_failed": "Ping vers {host} échoué.",
|
||||
"error_running_ping": "Erreur lors du ping : {error}",
|
||||
"memory_usage": "Utilisation mémoire : {used} Go / {total} Go ({percent}%)",
|
||||
"memory_above_90": "Usage mémoire au-dessus de 90% ({percent}%). Pense à libérer de la mémoire.",
|
||||
"total_memory": "Mémoire totale : {total} Go",
|
||||
"used_memory": "Mémoire utilisée : {used} Go",
|
||||
"low_free_memory": "Mémoire libre faible détectée ! Seulement {free} Go disponibles.",
|
||||
"measuring_cpu": "Mesure de l’usage CPU par cœur...",
|
||||
"core_usage": "Cœur {idx} : [{bar}] {usage}%",
|
||||
"total_cpu_usage": "Usage total CPU : {usage}%",
|
||||
"high_avg_cpu": "Moyenne CPU élevée : {usage}%",
|
||||
"really_high_cpu": "Charge CPU vraiment élevée ! Le système pourrait ralentir ou planter.",
|
||||
"memory_file": "Fichier mémoire : {size} Mo",
|
||||
"memory_file_large": "Fichier mémoire de 1 Go ou plus, pense à le nettoyer pour libérer de l’espace.",
|
||||
"memory_file_corrupted": "Fichier mémoire corrompu ! Erreur JSON : {error}",
|
||||
"consider_backup_memory": "Pense à sauvegarder et recréer le fichier mémoire.",
|
||||
"memory_file_encoding": "Problèmes d’encodage du fichier mémoire : {error}",
|
||||
"error_reading_memory": "Erreur lecture fichier mémoire : {error}",
|
||||
"memory_file_not_found": "Fichier mémoire introuvable.",
|
||||
"modification_warning": "Goober a été modifié ! Toutes les modifications seront perdues lors d'une mise à jour !",
|
||||
"reported_version": "Version rapportée :",
|
||||
"current_hash": "Hachage actuel :",
|
||||
"not_found": "n'est pas trouvé !",
|
||||
"version_error": "Impossible de récupérer les informations de version. Code d'état",
|
||||
"loaded_cog": "Cog chargé :",
|
||||
"loaded_cog2": "Module chargé :",
|
||||
"cog_fail": "Échec du chargement du cog :",
|
||||
"cog_fail2": "Échec du chargement du module :",
|
||||
"no_model": "Aucun modèle Markov sauvegardé trouvé. Démarrage à partir de zéro.",
|
||||
"folder_created": "Dossier '{folder_name}' créé.",
|
||||
"folder_exists": "Le dossier '{folder_name}' existe déjà. Ignorons...",
|
||||
"logged_in": "Connecté en tant que",
|
||||
"synced_commands": "Synchronisé",
|
||||
"synced_commands2": "commandes !",
|
||||
"fail_commands_sync": "Échec de la synchronisation des commandes :",
|
||||
"started": "{name} a démarré !",
|
||||
"name_check": "Erreur lors de la vérification de la disponibilité du nom :",
|
||||
"name_taken": "Le nom est déjà pris. Veuillez choisir un autre nom.",
|
||||
"name_check2": "Erreur lors de la vérification de la disponibilité du nom :",
|
||||
"add_token": "Token : {token}\nVeuillez ajouter ce token à votre fichier .env comme",
|
||||
"token_exists": "Le token existe déjà dans .env. Utilisation du token existant.",
|
||||
"registration_error": "Erreur lors de l'enregistrement :",
|
||||
"version_backup": "Sauvegarde créée :",
|
||||
"backup_error": "Erreur : {LOCAL_VERSION_FILE} introuvable pour la sauvegarde.",
|
||||
"model_loaded": "Modèle Markov chargé depuis",
|
||||
"fetch_update_fail": "Impossible de récupérer les informations de mise à jour.",
|
||||
"invalid_server": "Erreur : Informations de version invalides reçues du serveur.",
|
||||
"goober_server_alert": "Alerte du serveur Goober central !\n",
|
||||
"new_version": "Nouvelle version disponible : {latest_version} (Actuelle : {local_version})",
|
||||
"changelog": "Consultez {VERSION_URL}/goob/changes.txt pour voir les modifications\n\n",
|
||||
"invalid_version": "La version : {local_version} n'est pas valide !",
|
||||
"invalid_version2": "Si c'est intentionnel, ignorez ce message. Sinon, appuyez sur Y pour récupérer une version valide depuis le serveur, quelle que soit la version actuelle de Goober.",
|
||||
"invalid_version3": "La version actuelle sera sauvegardée dans current_version.bak..",
|
||||
"input": "(Y ou toute autre touche pour ignorer...)",
|
||||
"modification_ignored": "Vous avez modifié",
|
||||
"modification_ignored2": "IGNOREWARNING est désactivé..",
|
||||
"latest_version": "Vous utilisez la dernière version :",
|
||||
"latest_version2": "Consultez {VERSION_URL}/goob/changes.txt pour voir les modifications",
|
||||
"pinging_disabled": "Le ping est désactivé ! Je ne préviens pas le serveur que je suis en ligne...",
|
||||
"goober_ping_success": "Connecté à Goober central en tant que {NAME}",
|
||||
"goober_ping_fail": "Échec de l'envoi des données. Le serveur a retourné le code d'état :",
|
||||
"goober_ping_fail2": "Une erreur est survenue lors de l'envoi des données :",
|
||||
"sentence_positivity": "La positivité de la phrase est :",
|
||||
"command_edit_fail": "Échec de la modification du message :",
|
||||
"command_desc_retrain": "Réentraîne manuellement le modèle Markov.",
|
||||
"command_markov_retrain": "Réentraînement du modèle Markov... Veuillez patienter.",
|
||||
"command_markov_memory_not_found": "Erreur : fichier de mémoire introuvable !",
|
||||
"command_markov_memory_is_corrupt": "Erreur : le fichier de mémoire est corrompu !",
|
||||
"command_markov_retraining": "Traitement de {processed_data}/{data_size} points de données...",
|
||||
"command_markov_retrain_successful": "Modèle Markov réentraîné avec succès en utilisant {data_size} points de données !",
|
||||
"command_desc_talk": "parle et tout ça",
|
||||
"command_talk_insufficent_text": "Je dois apprendre plus de messages avant de pouvoir parler.",
|
||||
"command_talk_generation_fail": "Je n'ai rien à dire pour le moment !",
|
||||
"command_desc_help": "aide",
|
||||
"command_help_embed_title": "Aide du bot",
|
||||
"command_help_embed_desc": "Liste des commandes regroupées par catégorie.",
|
||||
"command_help_categories_general": "Général",
|
||||
"command_help_categories_admin": "Administration",
|
||||
"command_help_categories_custom": "Commandes personnalisées",
|
||||
"command_ran": "Info : {message.author.name} a exécuté {message.content}",
|
||||
"command_ran_s": "Info : {interaction.user} a exécuté ",
|
||||
"command_desc_ping": "ping",
|
||||
"command_ping_embed_desc": "Latence du bot :",
|
||||
"command_ping_footer": "Demandé par",
|
||||
"command_about_desc": "à propos",
|
||||
"command_about_embed_title": "À propos de moi",
|
||||
"command_about_embed_field1": "Nom",
|
||||
"command_about_embed_field2name": "Version",
|
||||
"command_about_embed_field2value": "Locale : {local_version} \nDernière : {latest_version}",
|
||||
"command_desc_stats": "statistiques",
|
||||
"command_stats_embed_title": "Statistiques du bot",
|
||||
"command_stats_embed_desc": "Données sur la mémoire du bot.",
|
||||
"command_stats_embed_field1name": "Statistiques du fichier",
|
||||
"command_stats_embed_field1value": "Taille : {file_size} octets\nLignes : {line_count}",
|
||||
"command_stats_embed_field2name": "Version",
|
||||
"command_stats_embed_field2value": "Locale : {local_version} \nDernière : {latest_version}",
|
||||
"command_stats_embed_field3name": "Informations variables",
|
||||
"command_stats_embed_field3value": "Nom : {NAME} \nPréfixe : {PREFIX} \nID du propriétaire : {ownerid} \nTemps de recharge : {cooldown_time} \nLigne de ping : {PING_LINE} \nPartage de mémoire activé : {showmemenabled} \nEntraînement utilisateur activé : {USERTRAIN_ENABLED} \nChanson : {song} \nTexte de démarrage : ```{splashtext}```"
|
||||
}
|
|
@ -1,149 +0,0 @@
|
|||
{
|
||||
"minigames_hangman_game": "Mot à deviner : {display_word()}\nMauvaises guesses : {wrong_guesses}/{max_wrong}",
|
||||
"minigames_hangman_lost": "T'es échoué solide! Le mot était :",
|
||||
"minigames_hangman_won": "T'as gagné en masse! Le mot était :",
|
||||
"minigames_hangman_already_guessed": "T'as déjà essayé ça mon chum",
|
||||
"minigames_hangman_user_letter_guess": "Ta guess de lettre",
|
||||
"minigames_hangman_guess": "Devine une lettre",
|
||||
"minigames_hangman_api_failed": "Ça a chié en essayant d'avoir un mot aléatoire.",
|
||||
"minigames_hangman": "Jouer au Pendu avec un mot pogné au hasard",
|
||||
"minigames_click_to_guess": "Clique pour deviner un chiffre entre 1 pis 10",
|
||||
"minigames_guess_button": "Devine",
|
||||
"minigames_wrong_number": "Nope! C'était",
|
||||
"minigames_correct": "Bonne guess!",
|
||||
"minigames_invalid_number": "Chiffre pas valide!",
|
||||
"minigames_guess_the_number": "Devine le chiffre",
|
||||
"minigames_your_guess": "Ta guess (1-10)",
|
||||
"memory_file_valid": "Le fichier memory.json est correct!",
|
||||
"file_aint_uft8": "Le fichier est pas du bon UTF-8. Ça doit être binaire ou scrap.",
|
||||
"psutil_not_installed": "Vérification de mémoire skipée.",
|
||||
"not_cloned": "Goober est pas cloné! Va donc le cloner depuis Git.",
|
||||
"checks_disabled": "Les checks sont désactivées!",
|
||||
"unhandled_exception": "Y'a eu une erreur pas prévue. Rapporte ça sur GitHub mon gars.",
|
||||
"active_users:": "Monde actif :",
|
||||
"spacy_initialized": "spaCy pis spacytextblob sont prêts.",
|
||||
"spacy_model_not_found": "Le modèle spaCy est introuvable! On le télécharge...",
|
||||
"env_file_not_found": "Le fichier .env est pas là! Fais-en un avec les variables nécessaires.",
|
||||
"error_fetching_active_users": "Ça a chié en essayant de pogner les utilisateurs actifs : {error}",
|
||||
"error_sending_alive_ping": "Ça a chié en envoyant le ping : {error}",
|
||||
"already_started": "J'suis déjà parti! J'me mets pas à jour...",
|
||||
"please_restart": "Redémarre-moi donc!",
|
||||
"local_ahead": "La version locale {remote}/{branch} est à jour. Pas besoin d'update...",
|
||||
"remote_ahead": "La version remote {remote}/{branch} est en avance. On update...",
|
||||
"cant_find_local_version": "J'arrive pas à trouver la variable local_version! Ou ben elle a été modifiée pis c'est pas un chiffre!",
|
||||
"running_prestart_checks": "On fait les checks avant de partir...",
|
||||
"continuing_in_seconds": "On continue dans {seconds} secondes... Appuie sur une touche pour skip.",
|
||||
"missing_requests_psutil": "Y manque requests pis psutil! Installe-les avec pip : `pip install requests psutil`",
|
||||
"requirements_not_found": "requirements.txt introuvable à {path}, est-ce qu'il a été modifié?",
|
||||
"warning_failed_parse_imports": "Attention : Ça a chié en lisant les imports de {filename} : {error}",
|
||||
"cogs_dir_not_found": "Le dossier des cogs est pas à {path}, on skip le scan.",
|
||||
"std_lib_local_skipped": "LIB STD / LOCAL {package} (check skipé)",
|
||||
"ok_installed": "OK",
|
||||
"missing_package": "MANQUANT",
|
||||
"missing_package2": "est pas installé",
|
||||
"missing_packages_detected": "Y'a des affaires qui manquent :",
|
||||
"telling_goober_central": "J'envoie ça à goober central à {url}",
|
||||
"failed_to_contact": "J'ai pas réussi à contacter {url} : {error}",
|
||||
"all_requirements_satisfied": "Tout ce qu'il faut est installé.",
|
||||
"ping_to": "Ping à {host} : {latency} ms",
|
||||
"high_latency": "Latence élevée! Ça pourrait être lent.",
|
||||
"could_not_parse_latency": "J'ai pas pu comprendre la latence.",
|
||||
"ping_failed": "Le ping à {host} a chié.",
|
||||
"error_running_ping": "Ça a chié en faisant le ping : {error}",
|
||||
"memory_usage": "Mémoire utilisée : {used} Go / {total} Go ({percent}%)",
|
||||
"memory_above_90": "La mémoire est à plus de 90% ({percent}%). Libère de la mémoire.",
|
||||
"total_memory": "Mémoire totale : {total} Go",
|
||||
"used_memory": "Mémoire utilisée : {used} Go",
|
||||
"low_free_memory": "Y'a presque plus de mémoire! Juste {free} Go de libre.",
|
||||
"measuring_cpu": "On check l'usage CPU par coeur...",
|
||||
"core_usage": "Coeur {idx} : [{bar}] {usage}%",
|
||||
"total_cpu_usage": "Usage total CPU : {usage}%",
|
||||
"high_avg_cpu": "CPU trop élevé : {usage}%",
|
||||
"really_high_cpu": "Le CPU est en tabarnak! Ça pourrait crasher.",
|
||||
"memory_file": "Fichier mémoire : {size} Mo",
|
||||
"memory_file_large": "Fichier mémoire de 1 Go ou plus, nettoie ça pour faire de la place.",
|
||||
"memory_file_corrupted": "Fichier mémoire scrap! Erreur JSON : {error}",
|
||||
"consider_backup_memory": "Pense à faire un backup pis recréer le fichier mémoire.",
|
||||
"memory_file_encoding": "Problème d'encodage du fichier mémoire : {error}",
|
||||
"error_reading_memory": "Ça a chié en lisant le fichier mémoire : {error}",
|
||||
"memory_file_not_found": "Fichier mémoire pas trouvé.",
|
||||
"modification_warning": "Goober a été modifié! Tes modifications vont être perdues à l'update!",
|
||||
"reported_version": "Version rapportée :",
|
||||
"current_hash": "Hash actuel :",
|
||||
"not_found": "est pas trouvé!",
|
||||
"version_error": "J'ai pas pu avoir les infos de version. Code d'état",
|
||||
"loaded_cog": "Cog chargé :",
|
||||
"loaded_cog2": "Module chargé :",
|
||||
"cog_fail": "Ça a chié en chargeant le cog :",
|
||||
"cog_fail2": "Ça a chié en chargeant le module :",
|
||||
"no_model": "Y'a pas de modèle Markov de sauvegardé. On part de zéro.",
|
||||
"folder_created": "Dossier '{folder_name}' créé.",
|
||||
"folder_exists": "Le dossier '{folder_name}' existe déjà. On skip...",
|
||||
"logged_in": "Connecté en tant que",
|
||||
"synced_commands": "Synchronisé",
|
||||
"synced_commands2": "commandes!",
|
||||
"fail_commands_sync": "Ça a chié en synchronisant les commandes :",
|
||||
"started": "{name} est parti!",
|
||||
"name_check": "Ça a chié en checkant si le nom est libre :",
|
||||
"name_taken": "Le nom est déjà pris. Choisis-en un autre.",
|
||||
"name_check2": "Ça a chié en checkant si le nom est libre :",
|
||||
"add_token": "Token : {token}\nAjoute ce token dans ton .env comme",
|
||||
"token_exists": "Le token existe déjà dans .env. On utilise celui-là.",
|
||||
"registration_error": "Ça a chié en s'enregistrant :",
|
||||
"version_backup": "Backup créé :",
|
||||
"backup_error": "Erreur : {LOCAL_VERSION_FILE} pas trouvé pour le backup.",
|
||||
"model_loaded": "Modèle Markov chargé depuis",
|
||||
"fetch_update_fail": "J'ai pas pu avoir les infos d'update.",
|
||||
"invalid_server": "Erreur : Infos de version invalides du serveur.",
|
||||
"goober_server_alert": "Alerte du serveur Goober central!\n",
|
||||
"new_version": "Nouvelle version disponible : {latest_version} (Actuelle : {local_version})",
|
||||
"changelog": "Va voir {VERSION_URL}/goob/changes.txt pour les changements\n\n",
|
||||
"invalid_version": "La version : {local_version} est pas valide!",
|
||||
"invalid_version2": "Si c'est fait exprès, ignore ça. Sinon, appuie sur Y pour avoir une version valide du serveur, peu importe ta version actuelle de Goober.",
|
||||
"invalid_version3": "La version actuelle va être backupée dans current_version.bak..",
|
||||
"input": "(Y ou n'importe quelle touche pour skip...)",
|
||||
"modification_ignored": "T'as modifié",
|
||||
"modification_ignored2": "IGNOREWARNING est désactivé..",
|
||||
"latest_version": "T'as la dernière version :",
|
||||
"latest_version2": "Va voir {VERSION_URL}/goob/changes.txt pour les changements",
|
||||
"pinging_disabled": "Le ping est désactivé! J'dis pas au serveur que j'suis en ligne...",
|
||||
"goober_ping_success": "Connecté à Goober central en tant que {NAME}",
|
||||
"goober_ping_fail": "Ça a chié en envoyant les données. Le serveur a retourné :",
|
||||
"goober_ping_fail2": "Ça a chié en envoyant les données :",
|
||||
"sentence_positivity": "La phrase est positive à :",
|
||||
"command_edit_fail": "Ça a chié en éditant le message :",
|
||||
"command_desc_retrain": "Réentraîne le modèle Markov à la main.",
|
||||
"command_markov_retrain": "Réentraînement du modèle Markov... Attend un peu.",
|
||||
"command_markov_memory_not_found": "Erreur : fichier mémoire pas trouvé!",
|
||||
"command_markov_memory_is_corrupt": "Erreur : fichier mémoire scrap!",
|
||||
"command_markov_retraining": "Traitement de {processed_data}/{data_size} points de données...",
|
||||
"command_markov_retrain_successful": "Modèle Markov réentraîné avec succès avec {data_size} points de données!",
|
||||
"command_desc_talk": "parle pis toute",
|
||||
"command_talk_insufficent_text": "J'ai pas assez appris pour pouvoir parler.",
|
||||
"command_talk_generation_fail": "J'ai rien à dire pour l'instant!",
|
||||
"command_desc_help": "aide",
|
||||
"command_help_embed_title": "Aide du bot",
|
||||
"command_help_embed_desc": "Liste des commandes par catégorie.",
|
||||
"command_help_categories_general": "Général",
|
||||
"command_help_categories_admin": "Admin",
|
||||
"command_help_categories_custom": "Commandes perso",
|
||||
"command_ran": "Info : {message.author.name} a fait {message.content}",
|
||||
"command_ran_s": "Info : {interaction.user} a fait ",
|
||||
"command_desc_ping": "ping",
|
||||
"command_ping_embed_desc": "Latence du bot :",
|
||||
"command_ping_footer": "Demandé par",
|
||||
"command_about_desc": "à propos",
|
||||
"command_about_embed_title": "À propos de moi",
|
||||
"command_about_embed_field1": "Nom",
|
||||
"command_about_embed_field2name": "Version",
|
||||
"command_about_embed_field2value": "Locale : {local_version} \nDernière : {latest_version}",
|
||||
"command_desc_stats": "stats",
|
||||
"command_stats_embed_title": "Stats du bot",
|
||||
"command_stats_embed_desc": "Infos sur la mémoire du bot.",
|
||||
"command_stats_embed_field1name": "Stats du fichier",
|
||||
"command_stats_embed_field1value": "Taille : {file_size} octets\nLignes : {line_count}",
|
||||
"command_stats_embed_field2name": "Version",
|
||||
"command_stats_embed_field2value": "Locale : {local_version} \nDernière : {latest_version}",
|
||||
"command_stats_embed_field3name": "Infos variables",
|
||||
"command_stats_embed_field3value": "Nom : {NAME} \nPréfixe : {PREFIX} \nID du proprio : {ownerid}\nLigne de ping : {PING_LINE} \nPartage de mémoire activé : {showmemenabled} \nEntraînement utilisateur activé : {USERTRAIN_ENABLED} \nChanson : {song} \nTexte de démarrage : ```{splashtext}```"
|
||||
}
|
125
assets/locales/fy.json
Normal file
125
assets/locales/fy.json
Normal file
|
@ -0,0 +1,125 @@
|
|||
{
|
||||
"env_file_not_found": "It .env-bestân is net fûn! Meitsje ien mei de fereaske fariabelen.",
|
||||
"error_fetching_active_users": "Flater by it opheljen fan aktive brûkers: {error}",
|
||||
"error_sending_alive_ping": "Flater by it ferstjoeren fan alive ping: {error}",
|
||||
"already_started": "Ik bin al start! Gjin update...",
|
||||
"please_restart": "Start opnij, goober!",
|
||||
"local_ahead": "Lokaal {remote}/{branch} is foarút of by de tiid. Gjin update...",
|
||||
"remote_ahead": "Remote {remote}/{branch} is foarút. Update wurdt útfierd...",
|
||||
"cant_find_local_version": "Kin de local_version-fariabele net fine! Of it is ferboud en gjin integer mear!",
|
||||
"running_prestart_checks": "Pre-start kontrôles wurde útfierd...",
|
||||
"continuing_in_seconds": "Trochgean oer {seconds} sekonden... Druk op in toets om oer te slaan.",
|
||||
"missing_requests_psutil": "Requests en psutil ûntbrekke! Ynstallearje se mei pip: `pip install requests psutil`",
|
||||
"requirements_not_found": "requirements.txt net fûn op {path}, is it ferboud?",
|
||||
"warning_failed_parse_imports": "Warskôging: Ynlêzen fan imports út {filename} mislearre: {error}",
|
||||
"cogs_dir_not_found": "Cogs-map net fûn op {path}, oerslein.",
|
||||
"std_lib_local_skipped": "STD LIB / LOKAAL {package} (kontrôle oerslein)",
|
||||
"ok_installed": "OK",
|
||||
"missing_package": "NET FÛN",
|
||||
"missing_package2": "is net ynstallearre",
|
||||
"missing_packages_detected": "Untbrekkende pakketten fûn:",
|
||||
"telling_goober_central": "Ynformaasje ferstjoerd nei goober central op {url}",
|
||||
"failed_to_contact": "Kontakt mei {url} mislearre: {error}",
|
||||
"all_requirements_satisfied": "Alle easken binne foldien.",
|
||||
"ping_to": "Ping nei {host}: {latency} ms",
|
||||
"high_latency": "Hege latency ûntdutsen! Jo kinne fertraging ûnderfine.",
|
||||
"could_not_parse_latency": "Latency koe net lêzen wurde.",
|
||||
"ping_failed": "Ping nei {host} mislearre.",
|
||||
"error_running_ping": "Flater by it útfieren fan ping: {error}",
|
||||
"memory_usage": "Unthâldbrûk: {used} GB / {total} GB ({percent}%)",
|
||||
"memory_above_90": "Unthâldbrûk is boppe 90% ({percent}%). Frij wat ûnthâld op.",
|
||||
"total_memory": "Totaal Unthâld: {total} GB",
|
||||
"used_memory": "Brûkt Unthâld: {used} GB",
|
||||
"low_free_memory": "Leech frij ûnthâld ûntdutsen! Mar {free} GB beskikber.",
|
||||
"measuring_cpu": "CPU-brûk per kearn wurdt metten...",
|
||||
"core_usage": "Kearn {idx}: [{bar}] {usage}%",
|
||||
"total_cpu_usage": "Totale CPU-brûk: {usage}%",
|
||||
"high_avg_cpu": "Heech gemiddeld CPU-brûk: {usage}%",
|
||||
"really_high_cpu": "Tige hege CPU-lêst! It systeem kin traach wurde of hingje.",
|
||||
"memory_file": "Unthâld-bestân: {size} MB",
|
||||
"memory_file_large": "Unthâld-bestân is 1GB of mear, wiskje om romte frij te meitsjen.",
|
||||
"memory_file_corrupted": "Unthâld-bestân is skansearre! JSON decode-flater: {error}",
|
||||
"consider_backup_memory": "Tink derom om in reservekopy fan it ûnthâld-bestân te meitsjen en opnij oan te meitsjen.",
|
||||
"memory_file_encoding": "Unthâld-bestân hat enkodearingsproblemen: {error}",
|
||||
"error_reading_memory": "Flater by it lêzen fan ûnthâld-bestân: {error}",
|
||||
"memory_file_not_found": "Unthâld-bestân net fûn.",
|
||||
"modification_warning": "Goober is oanpast! Wizigingen sille ferlern gean by in update!",
|
||||
"reported_version": "Melde ferzje:",
|
||||
"current_hash": "Aktuele Hash:",
|
||||
"not_found": "net fûn!",
|
||||
"version_error": "Koe ferzje-ynfo net ophelje. Statuskoade",
|
||||
"loaded_cog": "Cog laden:",
|
||||
"loaded_cog2": "Module laden:",
|
||||
"cog_fail": "Cog laden mislearre:",
|
||||
"cog_fail2": "Module laden mislearre:",
|
||||
"no_model": "Gjin bewarre Markov-model fûn. Fanôf nij begjinne.",
|
||||
"folder_created": "Map '{folder_name}' oanmakke.",
|
||||
"folder_exists": "Map '{folder_name}' bestiet al. oerslein...",
|
||||
"logged_in": "Ynlogd as",
|
||||
"synced_commands": "Kommando's syngronisearre",
|
||||
"synced_commands2": "kommando's!",
|
||||
"fail_commands_sync": "Syngronisaasje fan kommando's mislearre:",
|
||||
"started": "{name} is begûn!",
|
||||
"name_check": "Flater by it kontrolearjen fan namme beskikberens:",
|
||||
"name_taken": "Namme is al yn gebrûk. Kies in oare.",
|
||||
"name_check2": "Flater by nammekontrôle:",
|
||||
"add_token": "Token: {token}\nFoegje dizze token ta oan jo .env-bestân as",
|
||||
"token_exists": "Token bestiet al yn .env. Fierder mei besteande token.",
|
||||
"registration_error": "Flater by registraasje:",
|
||||
"version_backup": "Reservekopy makke:",
|
||||
"backup_error": "Flater: {LOCAL_VERSION_FILE} net fûn foar reservekopy.",
|
||||
"model_loaded": "Markov-model laden fan",
|
||||
"fetch_update_fail": "Koe update-ynformaasje net ophelje.",
|
||||
"invalid_server": "Flater: Unjildige ferzje ynformaasje ûntfongen fan server.",
|
||||
"goober_server_alert": "Warskôging fan goober central!\n",
|
||||
"new_version": "Nije ferzje beskikber: {latest_version} (Aktueel: {local_version})",
|
||||
"changelog": "Sjoch {VERSION_URL}/goob/changes.txt foar de wizigingslog\n\n",
|
||||
"invalid_version": "De ferzje: {local_version} is net jildich!",
|
||||
"invalid_version2": "As dit bewust is, negearje dit dan. Oars druk op Y om in jildige ferzje fan 'e server te heljen.",
|
||||
"invalid_version3": "De aktuele ferzje wurdt bewarre as current_version.bak..",
|
||||
"input": "(Y of in oare toets om te negearjen....)",
|
||||
"modification_ignored": "Jo hawwe oanpassingen dien oan",
|
||||
"modification_ignored2": "IGNOREWARNING is ynsteld op false..",
|
||||
"latest_version": "Jo brûke de lêste ferzje:",
|
||||
"latest_version2": "Sjoch {VERSION_URL}/goob/changes.txt foar de wizigingslog",
|
||||
"pinging_disabled": "Pingjen is útskeakele! Gjin melding oan de server...",
|
||||
"goober_ping_success": "Ynlogd op goober central as {NAME}",
|
||||
"goober_ping_fail": "Ferstjoeren fan gegevens mislearre. Server joech statuskoade:",
|
||||
"goober_ping_fail2": "Flater by it ferstjoeren fan gegevens:",
|
||||
"sentence_positivity": "Positiviteit fan sin is:",
|
||||
"command_edit_fail": "Flater by it bewurkjen fan berjocht:",
|
||||
"command_desc_retrain": "Traind it Markov-model opnij.",
|
||||
"command_markov_retrain": "Markov-model wurdt opnij traind... Wachtsje efkes.",
|
||||
"command_markov_memory_not_found": "Flater: ûnthâld-bestân net fûn!",
|
||||
"command_markov_memory_is_corrupt": "Flater: ûnthâld-bestân is skansearre!",
|
||||
"command_markov_retraining": "Ferwurket {processed_data}/{data_size} gegevenspunten...",
|
||||
"command_markov_retrain_successful": "Markov-model mei sukses opnij traind mei {data_size} gegevenspunten!",
|
||||
"command_desc_talk": "praat en sa",
|
||||
"command_talk_insufficent_text": "Ik moat mear leare fan berjochten foardat ik prate kin.",
|
||||
"command_talk_generation_fail": "Ik ha no neat te sizzen!",
|
||||
"command_desc_help": "help",
|
||||
"command_help_embed_title": "Bot Help",
|
||||
"command_help_embed_desc": "List mei kommando's groepearre op kategory.",
|
||||
"command_help_categories_general": "Algemien",
|
||||
"command_help_categories_admin": "Behear",
|
||||
"command_help_categories_custom": "Oanpaste Kommando's",
|
||||
"command_ran": "Info: {message.author.name} hat {message.content} útfierd",
|
||||
"command_ran_s": "Info: {interaction.user} hat útfierd ",
|
||||
"command_desc_ping": "ping",
|
||||
"command_ping_embed_desc": "Bot Latency:",
|
||||
"command_ping_footer": "Frege troch",
|
||||
"command_about_desc": "oer",
|
||||
"command_about_embed_title": "Oer my",
|
||||
"command_about_embed_field1": "Namme",
|
||||
"command_about_embed_field2name": "Ferzje",
|
||||
"command_about_embed_field2value": "Lokaal: {local_version} \nLêste: {latest_version}",
|
||||
"command_desc_stats": "stats",
|
||||
"command_stats_embed_title": "Bot Statistyk",
|
||||
"command_stats_embed_desc": "Gegevens oer it ûnthâld fan de bot.",
|
||||
"command_stats_embed_field1name": "Bestân Statistyk",
|
||||
"command_stats_embed_field1value": "Grutte: {file_size} bytes\nRigels: {line_count}",
|
||||
"command_stats_embed_field2name": "Ferzje",
|
||||
"command_stats_embed_field2value": "Lokaal: {local_version} \nLêste: {latest_version}",
|
||||
"command_stats_embed_field3name": "Fariabel Info",
|
||||
"command_stats_embed_field3value": "Namme: {NAME} \nFoarheaksel: {PREFIX} \nEigner ID: {ownerid} \nCooldown: {cooldown_time} \nPingrigel: {PING_LINE} \nUnthâld Dielen Ynskeakele: {showmemenabled} \nBrûkerstraining Ynskeakele: {USERTRAIN_ENABLED}\nLiet: {song} \nSplashtekst: ```{splashtext}```"
|
||||
}
|
|
@ -1,23 +1,5 @@
|
|||
{
|
||||
"minigames_hangman_game": "Parola: {display_word()}\nErrori: {wrong_guesses}/{max_wrong}",
|
||||
"minigames_hangman_lost": "Hai perso! La parola era:",
|
||||
"minigames_hangman_won": "Hai vinto! La parola era:",
|
||||
"minigames_hangman_already_guessed": "Hai già indovinato",
|
||||
"minigames_hangman_user_letter_guess": "La tua lettera",
|
||||
"minigames_hangman_guess": "Indovina una lettera",
|
||||
"minigames_hangman_api_failed": "Impossibile ottenere una parola casuale.",
|
||||
"minigames_hangman": "Gioca all'impiccato con una parola casuale",
|
||||
"minigames_click_to_guess": "Clicca per indovinare un numero da 1 a 10",
|
||||
"minigames_guess_button": "Indovina",
|
||||
"minigames_wrong_number": "Sbagliato! Il numero era",
|
||||
"minigames_correct": "Corretto!",
|
||||
"minigames_invalid_number": "Numero non valido!",
|
||||
"minigames_guess_the_number": "Indovina il numero",
|
||||
"minigames_your_guess": "Il tuo numero (1-10)",
|
||||
"memory_file_valid": "Il file JSON è valido!",
|
||||
"file_aint_utf8": "Il file non è un UTF-8 valido. Forse è binario?",
|
||||
"psutil_not_installed": "Controllo memoria saltato.",
|
||||
"not_cloned": "Goober non è stato clonato! Clonalo da Git.",
|
||||
"not_cloned": "Goober non è stato clonato! Clonalo da GitHub.",
|
||||
"checks_disabled": "I controlli sono disabilitati!",
|
||||
"unhandled_exception": "Si è verificata un'eccezione non gestita. Segnala questo problema su GitHub, per favore.",
|
||||
"active_users:": "Utenti attivi:",
|
||||
|
@ -84,7 +66,7 @@
|
|||
"synced_commands": "Sincronizzati",
|
||||
"synced_commands2": "comandi!",
|
||||
"fail_commands_sync": "Impossibile sincronizzare i comandi:",
|
||||
"started": "{name} è stato avviato!\nIl palco è tuo!",
|
||||
"started": "{name} è stato avviato!",
|
||||
"name_check": "Errore nel controllo disponibilità del nome:",
|
||||
"name_taken": "Il nome è già preso. Scegli un nome diverso.",
|
||||
"name_check2": "Errore durante il controllo della disponibilità del nome:",
|
||||
|
@ -117,7 +99,7 @@
|
|||
"command_markov_retrain": "Rafforzamento del modello Markov in corso... Attendere.",
|
||||
"command_markov_memory_not_found": "Errore: file di memoria non trovato!",
|
||||
"command_markov_memory_is_corrupt": "Errore: file di memoria corrotto!",
|
||||
"command_markov_retraining": "Elaborazione di {data_size} punti dati...",
|
||||
"command_markov_retraining": "Elaborazione di {processed_data}/{data_size} punti dati...",
|
||||
"command_markov_retrain_successful": "Modello Markov rafforzato con successo utilizzando {data_size} punti dati!",
|
||||
"command_desc_talk": "parla n come stuf",
|
||||
"command_talk_insufficent_text": "Ho bisogno di imparare di più dai messaggi prima di poter parlare.",
|
||||
|
@ -131,7 +113,6 @@
|
|||
"command_ran": "Info: {message.author.name} ha eseguito {message.content}",
|
||||
"command_ran_s": "Info: {interaction.user} ha eseguito ",
|
||||
"command_desc_ping": "ping",
|
||||
"command_desc_setlang": "Imposta una nuova lingua per il bot (temporaneamente)",
|
||||
"command_ping_embed_desc": "Latenza del bot:",
|
||||
"command_ping_footer": "Richiesto da",
|
||||
"command_about_desc": "informazioni",
|
||||
|
@ -147,6 +128,6 @@
|
|||
"command_stats_embed_field2name": "Versione",
|
||||
"command_stats_embed_field2value": "Locale: {local_version} \nUltima: {latest_version}",
|
||||
"command_stats_embed_field3name": "Informazioni sulle variabili",
|
||||
"command_stats_embed_field3value": "Nome: {NAME} \nPrefisso: {PREFIX} \nID Proprietario: {ownerid}\nLinea ping: {PING_LINE} \nMemoria Condivisa Abilitata: {showmemenabled} \nAddestramento Utente Abilitato: {USERTRAIN_ENABLED}\nCanzone: {song} \nSplashtext: ```{splashtext}```"
|
||||
"command_stats_embed_field3value": "Nome: {NAME} \nPrefisso: {PREFIX} \nID Proprietario: {ownerid} \nCooldown: {cooldown_time} \nLinea ping: {PING_LINE} \nMemoria Condivisa Abilitata: {showmemenabled} \nAddestramento Utente Abilitato: {USERTRAIN_ENABLED}\nCanzone: {song} \nSplashtext: ```{splashtext}```"
|
||||
}
|
||||
|
||||
|
|
125
assets/locales/mt.json
Normal file
125
assets/locales/mt.json
Normal file
|
@ -0,0 +1,125 @@
|
|||
{
|
||||
"env_file_not_found": "Ma nstab l‑file .env! Oħloq wieħed bil‑varjabbli meħtieġa.",
|
||||
"error_fetching_active_users": "Żball waqt il‑ġbir tal‑utenti attivi: {error}",
|
||||
"error_sending_alive_ping": "Żball biex jintbagħat l‑alive ping: {error}",
|
||||
"already_started": "Illum diġà bdejt! Ma sejħinx l‑aġġornament…",
|
||||
"please_restart": "Irristartja jekk jogħġbok, goober!",
|
||||
"local_ahead": "L‑lokali {remote}/{branch} qiegħed qabel jew parallelament. Ma qed naġġornax…",
|
||||
"remote_ahead": "Il‑remote {remote}/{branch} hu 'l quddiem. Qed naġġorna…",
|
||||
"cant_find_local_version": "Ma nistax insib il‑varjabbli local_version! Jew ġie ħassar u mhux intier!",
|
||||
"running_prestart_checks": "Qed inħadmu ċ‑ċekkjijiet tal‑pre‑start…",
|
||||
"continuing_in_seconds": "Se nkunu qed inkomplu fi żmien {seconds} sekondi… Agħfas kwalunkwe buttuna biex tiċċekkja.",
|
||||
"missing_requests_psutil": "M’hemmx requests u psutil! Poġġihom b’pip: `pip install requests psutil`",
|
||||
"requirements_not_found": "requirements.txt mhux instab f’{path}, ġie modifikat?",
|
||||
"warning_failed_parse_imports": "Twissija: Parse tal‑imports f’{filename} fallita: {error}",
|
||||
"cogs_dir_not_found": "Direttorju “cogs” mhux instab f’{path}, qed niskippjaw l‑iskan.",
|
||||
"std_lib_local_skipped": "STD LIB / LOKALI {package} (ċekk skippjat)",
|
||||
"ok_installed": "OK",
|
||||
"missing_package": "NINNEŻER",
|
||||
"missing_package2": "mhux installat",
|
||||
"missing_packages_detected": "Parzijiet nieqsa ġew skoperti:",
|
||||
"telling_goober_central": "Qed ninfurmaw lill‑goober central f’{url}",
|
||||
"failed_to_contact": "Falliment fil‑kuntatt ma’ {url}: {error}",
|
||||
"all_requirements_satisfied": "Il‑ħtiġijiet kollha laqgħu.",
|
||||
"ping_to": "Ping lejn {host}: {latency} ms",
|
||||
"high_latency": "Latentizza għolja skoperta! Possibbli dewmien fir‑rispons.",
|
||||
"could_not_parse_latency": "Ma nistax ninterpreta l‑latentizza.",
|
||||
"ping_failed": "Ping lejn {host} falla.",
|
||||
"error_running_ping": "Żball fl‑eżekuzzjoni tal‑ping: {error}",
|
||||
"memory_usage": "Użu ta' memorja: {used} GB / {total} GB ({percent}%)",
|
||||
"memory_above_90": "Użu ta’ memorja fuq 90% ({percent}%). Ħsieb li tnaddaf xi ħaġa.",
|
||||
"total_memory": "Memorja totali: {total} GB",
|
||||
"used_memory": "Memorja użata: {used} GB",
|
||||
"low_free_memory": "Memorja ħielsa baxxa! Biss {free} GB disponibbli.",
|
||||
"measuring_cpu": "Qed nkejlu l‑CPU għal kull core…",
|
||||
"core_usage": "Core {idx}: [{bar}] {usage}%",
|
||||
"total_cpu_usage": "Użu totali tal‑CPU: {usage}%",
|
||||
"high_avg_cpu": "Użu medju għoli tal‑CPU: {usage}%",
|
||||
"really_high_cpu": "Użu eċċessiv tal‑CPU! Is‑sistema tista’ tieħu throttle jew tieqaf.",
|
||||
"memory_file": "Fajl tal‑memorja: {size} MB",
|
||||
"memory_file_large": "Il‑fajl tal‑memorja hu 1 GB jew aktar, ħsieb biex tiċċara għandu tagħmel sens.",
|
||||
"memory_file_corrupted": "Il‑fajl tal‑memorja hu korrott! Żball JSON decode: {error}",
|
||||
"consider_backup_memory": "Inħeġġuk biex tagħmel backup u terġa’ toħloq il‑fajl tal‑memorja.",
|
||||
"memory_file_encoding": "Il‑fajl tal‑memorja għandu issues ta’ kodifika: {error}",
|
||||
"error_reading_memory": "Żball fil‑qari tal‑fajl tal‑memorja: {error}",
|
||||
"memory_file_not_found": "Fajl tal‑memorja mhux instab.",
|
||||
"modification_warning": "Il‑Goober ġie mmodifikat! Kull tibdil jintilef fl‑aġġornament!",
|
||||
"reported_version": "Verżjoni rrappurtata:",
|
||||
"current_hash": "Hash attwali:",
|
||||
"not_found": "mhux instab!",
|
||||
"version_error": "Ma nistax niġbor informazzjoni dwar il‑verżjoni. Kodiċi ta’ stat",
|
||||
"loaded_cog": "Cog imlaħħaq:",
|
||||
"loaded_cog2": "Modulu imlaħħaq:",
|
||||
"cog_fail": "Falliment fit‑tagħbija tal‑cog:",
|
||||
"cog_fail2": "Falliment fit‑tagħbija tal‑modulu:",
|
||||
"no_model": "Ma nstab l-ebda Markov model maħżun. Bdejt minn null.",
|
||||
"folder_created": "Folder ‘{folder_name}’ ġie maħluq.",
|
||||
"folder_exists": "Folder ‘{folder_name}’ diġà teżisti. qed niskippja…",
|
||||
"logged_in": "Id‑depożitu bħala",
|
||||
"synced_commands": "Sync sseħħ",
|
||||
"synced_commands2": "kmandi!",
|
||||
"fail_commands_sync": "Falliment tas‑sync tal‑kmandi:",
|
||||
"started": "{name} beda!",
|
||||
"name_check": "Żball fil‑ċekk tal‑isem:",
|
||||
"name_taken": "L‑isem diġà jieħu. Sib ieħor, jekk jogħġbok.",
|
||||
"name_check2": "Żball waqt iċ‑ċekk tal‑availabbiltà ta’ l‑isem:",
|
||||
"add_token": "Token: {token}\nŻid dan fil‑.env bħala",
|
||||
"token_exists": "Token diġà jeżisti fil‑.env. Qed inkomplu bil‑token attwali.",
|
||||
"registration_error": "Żball fir‑reġistrazzjoni:",
|
||||
"version_backup": "Backup maħluq:",
|
||||
"backup_error": "Żball: {LOCAL_VERSION_FILE} mhux instab għaż‑backup.",
|
||||
"model_loaded": "Markov model imlaħħaq minn",
|
||||
"fetch_update_fail": "Ma setgħux jiġbdu informazzjoni dwar l‑aġġornament.",
|
||||
"invalid_server": "Żball: Informazzjoni dwar il‑verżjoni misjuba mis‑server mhix valida.",
|
||||
"goober_server_alert": "Allarm minn goober central!\n",
|
||||
"new_version": "Verżjoni ġdida disponibbli: {latest_version} (Attwali: {local_version})",
|
||||
"changelog": "Eżamina {VERSION_URL}/goob/changes.txt biex tara l‑modifiki\n\n",
|
||||
"invalid_version": "Il‑verżjoni: {local_version} mhix valida!",
|
||||
"invalid_version2": "Jekk intenzjonata, ignora; inkella agħfas Y biex tittrasferixxi verżjoni valida mill‑server minkejja l‑verżjoni ta’ goober attwali",
|
||||
"invalid_version3": "Il‑verżjoni attwali tkun backuppjata għal current_version.bak..",
|
||||
"input": "(Y jew kwalunkwe buttuna oħra biex tinjoraha…)",
|
||||
"modification_ignored": "Int immodifikajt",
|
||||
"modification_ignored2": "IGNOREWARNING hija false..",
|
||||
"latest_version": "Int qed tuża l‑verżjoni l‑iktar ġdida:",
|
||||
"latest_version2": "Ara {VERSION_URL}/goob/changes.txt biex tara l‑log tal‑modifiki",
|
||||
"pinging_disabled": "Pinging imblukkat! Ma qed ninfurmakx li għadek online…",
|
||||
"goober_ping_success": "Logged fil‑goober central bħala {NAME}",
|
||||
"goober_ping_fail": "Falliment fl‑invjaġġ tal‑data. Il‑server irrisponda b’kodiċi stat:",
|
||||
"goober_ping_fail2": "Żball seħħ waqt li bagħta data:",
|
||||
"sentence_positivity": "Posittività ta’ sentenza hi:",
|
||||
"command_edit_fail": "Falliment fit‑tbiddel tal‑messaġġ:",
|
||||
"command_desc_retrain": "Retrain il‑Markov model b’manu.",
|
||||
"command_markov_retrain": "Qed inretrain il‑Markov model… Awżilja, jekk jogħġbok.",
|
||||
"command_markov_memory_not_found": "Żball: fajl tal‑memorja maħżun mhux instab!",
|
||||
"command_markov_memory_is_corrupt": "Żball: fajl tal‑memorja hu korrott!",
|
||||
"command_markov_retraining": "Qed nipproċessa {processed_data}/{data_size} punti tad‑data…",
|
||||
"command_markov_retrain_successful": "Markov model retrained b’suċċess bl‑użu ta’ {data_size} punti tad‑data!",
|
||||
"command_desc_talk": "jitkellem bħal affarijiet",
|
||||
"command_talk_insufficent_text": "Għandi bżonn nitgħallem iktar mill‑messaġġi qabel nista’ nitkellem.",
|
||||
"command_talk_generation_fail": "M’għandi xejn x’ngħid bħalissa!",
|
||||
"command_desc_help": "għin",
|
||||
"command_help_embed_title": "Għajnuna tal‑Bot",
|
||||
"command_help_embed_desc": "Lista ta’ kmandi maqsuma b’kategoriji.",
|
||||
"command_help_categories_general": "Ġenerali",
|
||||
"command_help_categories_admin": "Amministrazzjoni",
|
||||
"command_help_categories_custom": "Kmandi Personalizzati",
|
||||
"command_ran": "Info: {message.author.name} użani {message.content}",
|
||||
"command_ran_s": "Info: {interaction.user} użani ",
|
||||
"command_desc_ping": "ping",
|
||||
"command_ping_embed_desc": "Latentizza tal‑Bot:",
|
||||
"command_ping_footer": "Mtitlub minn",
|
||||
"command_about_desc": "dwar",
|
||||
"command_about_embed_title": "Dwar jien",
|
||||
"command_about_embed_field1": "Isem",
|
||||
"command_about_embed_field2name": "Verżjoni",
|
||||
"command_about_embed_field2value": "Lokali: {local_version} \nĠdida: {latest_version}",
|
||||
"command_desc_stats": "stats",
|
||||
"command_stats_embed_title": "Stati tal‑Bot",
|
||||
"command_stats_embed_desc": "Informazzjoni dwar il‑memorja tal‑bot.",
|
||||
"command_stats_embed_field1name": "Statistika tal‑Fajl",
|
||||
"command_stats_embed_field1value": "Daqs: {file_size} bytes\nLinji: {line_count}",
|
||||
"command_stats_embed_field2name": "Verżjoni",
|
||||
"command_stats_embed_field2value": "Lokali: {local_version} \nĠdida: {latest_version}",
|
||||
"command_stats_embed_field3name": "Informazzjoni Varjabbli",
|
||||
"command_stats_embed_field3value": "Isem: {NAME} \nPrefiss: {PREFIX} \nID ta’ Sid: {ownerid} \nCooldown: {cooldown_time} \nPing line: {PING_LINE} \nImoħħar Memenja: {showmemenabled} \nUser Training Attiva: {USERTRAIN_ENABLED}\nKan ta’: {song} \nSplashtext: ```{splashtext}```"
|
||||
}
|
196
bot.py
196
bot.py
|
@ -7,52 +7,39 @@ import traceback
|
|||
import subprocess
|
||||
import tempfile
|
||||
import shutil
|
||||
import psutil
|
||||
import uuid
|
||||
import asyncio
|
||||
import platform
|
||||
import sys
|
||||
from typing import List, Dict, Set, Optional, Tuple, Any, Union, Callable, Coroutine, TypeVar, Type
|
||||
import logging
|
||||
|
||||
from modules.globalvars import *
|
||||
from modules.prestartchecks import start_checks
|
||||
from modules.logger import GooberFormatter
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger("goober")
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
console_handler = logging.StreamHandler()
|
||||
console_handler.setLevel(logging.DEBUG)
|
||||
console_handler.setFormatter(GooberFormatter())
|
||||
|
||||
file_handler = logging.FileHandler("log.txt", mode="w+", encoding="UTF-8")
|
||||
file_handler.setLevel(logging.DEBUG)
|
||||
file_handler.setFormatter(GooberFormatter(colors=False))
|
||||
|
||||
logger.addHandler(console_handler)
|
||||
logger.addHandler(file_handler)
|
||||
|
||||
# Print splash text and check for updates
|
||||
print(splashtext) # Print splash text (from modules/globalvars.py)
|
||||
start_checks()
|
||||
|
||||
import requests
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
from discord import app_commands
|
||||
from discord import Colour, Embed, File, Interaction, Message
|
||||
from discord.abc import Messageable
|
||||
|
||||
from better_profanity import profanity
|
||||
from discord.ext import commands
|
||||
|
||||
from modules.volta.main import _, set_language
|
||||
from modules.central import ping_server
|
||||
from modules.volta.main import _
|
||||
from modules.markovmemory import *
|
||||
from modules.version import *
|
||||
from modules.sentenceprocessing import *
|
||||
from modules.unhandledexception import handle_exception
|
||||
from modules.image import gen_meme, gen_demotivator
|
||||
from modules.minigames import guessthenumber, hangman
|
||||
|
||||
sys.excepthook = handle_exception
|
||||
check_for_update() # Check for updates (from modules/version.py)
|
||||
|
||||
# Type aliases
|
||||
T = TypeVar('T')
|
||||
MessageContext = Union[commands.Context, discord.Interaction]
|
||||
|
@ -64,11 +51,21 @@ currenthash: str = ""
|
|||
launched: bool = False
|
||||
slash_commands_enabled: bool = False
|
||||
|
||||
# Set up Discord bot intents and create bot instance
|
||||
intents: discord.Intents = discord.Intents.default()
|
||||
intents.messages = True
|
||||
intents.message_content = True
|
||||
bot: commands.Bot = commands.Bot(
|
||||
command_prefix=PREFIX,
|
||||
intents=intents,
|
||||
allowed_mentions=discord.AllowedMentions(everyone=False, roles=False, users=False, replied_user=True)
|
||||
)
|
||||
|
||||
# Load memory and Markov model for text generation
|
||||
memory: List[str] = load_memory()
|
||||
markov_model: Optional[markovify.Text] = load_markov_model()
|
||||
if not markov_model:
|
||||
logger.error(_('markov_model_not_found'))
|
||||
print(f"{RED}{(_('markov_model_not_found'))}{RESET}")
|
||||
memory = load_memory()
|
||||
markov_model = train_markov_model(memory)
|
||||
|
||||
|
@ -82,17 +79,28 @@ async def load_cogs_from_folder(bot, folder_name="assets/cogs"):
|
|||
module_path = folder_name.replace("/", ".").replace("\\", ".") + f".{cog_name}"
|
||||
try:
|
||||
await bot.load_extension(module_path)
|
||||
logger.info(f"{(_('loaded_cog'))} {cog_name}")
|
||||
print(f"{GREEN}{(_('loaded_cog'))} {cog_name}{RESET}")
|
||||
except Exception as e:
|
||||
logger.error(f"{(_('cog_fail'))} {cog_name} {e}")
|
||||
print(f"{RED}{(_('cog_fail'))} {cog_name} {e}{RESET}")
|
||||
traceback.print_exc()
|
||||
|
||||
async def fetch_active_users() -> str:
|
||||
try:
|
||||
response: requests.Response = requests.get(f"{VERSION_URL}/active-users")
|
||||
if response.status_code == 200:
|
||||
return response.text.strip()
|
||||
else:
|
||||
return "?"
|
||||
except Exception as e:
|
||||
print(f"{RED}{(_('error_fetching_active_users'))}{RESET} {e}")
|
||||
return "?"
|
||||
|
||||
async def send_alive_ping_periodically() -> None:
|
||||
while True:
|
||||
try:
|
||||
requests.post(f"{VERSION_URL}/aliveping", json={"name": NAME})
|
||||
except Exception as e:
|
||||
logger.error(f"{(_('error_sending_alive_ping'))}{RESET} {e}")
|
||||
print(f"{RED}{(_('error_sending_alive_ping'))}{RESET} {e}")
|
||||
await asyncio.sleep(60)
|
||||
|
||||
# Event: Called when the bot is ready
|
||||
|
@ -101,7 +109,6 @@ async def on_ready() -> None:
|
|||
global launched
|
||||
global slash_commands_enabled
|
||||
global NAME
|
||||
global status
|
||||
|
||||
folder_name: str = "cogs"
|
||||
if launched:
|
||||
|
@ -110,30 +117,29 @@ async def on_ready() -> None:
|
|||
await load_cogs_from_folder(bot)
|
||||
try:
|
||||
synced: List[discord.app_commands.AppCommand] = await bot.tree.sync()
|
||||
logger.info(f"{_('synced_commands')} {len(synced)} {(_('synced_commands2'))}")
|
||||
print(f"{GREEN}{_('synced_commands')} {len(synced)} {(_('synced_commands2'))} {RESET}")
|
||||
slash_commands_enabled = True
|
||||
logger.info(f"{(_('started')).format(name=NAME)}")
|
||||
ping_server() # ping_server from modules/central.py
|
||||
|
||||
active_users: str = await fetch_active_users()
|
||||
print(f"{GREEN}{(_('active_users:'))} {active_users}{RESET}")
|
||||
print(f"{GREEN}{(_('started')).format(name=NAME)}{RESET}")
|
||||
|
||||
bot.loop.create_task(send_alive_ping_periodically())
|
||||
except discord.errors.Forbidden as perm_error:
|
||||
logger.error(f"Permission error while syncing commands: {perm_error}")
|
||||
logger.error("Make sure the bot has the 'applications.commands' scope and is invited with the correct permissions.")
|
||||
print(f"{RED}Permission error while syncing commands: {perm_error}{RESET}")
|
||||
print(f"{RED}Make sure the bot has the 'applications.commands' scope and is invited with the correct permissions.{RESET}")
|
||||
quit()
|
||||
except Exception as e:
|
||||
logger.error(f"{_('fail_commands_sync')} {e}")
|
||||
print(f"{RED}{(_('fail_commands_sync'))} {e}{RESET}")
|
||||
traceback.print_exc()
|
||||
quit()
|
||||
|
||||
if not song:
|
||||
return
|
||||
|
||||
status = {
|
||||
"idle": discord.Status.idle,
|
||||
"dnd": discord.Status.dnd,
|
||||
"invisible": discord.Status.invisible,
|
||||
"online": discord.Status.online
|
||||
}.get(status.lower(), discord.Status.online)
|
||||
await bot.change_presence(status=status, activity=discord.Activity(type=discord.ActivityType.listening, name=f"{song}"))
|
||||
return
|
||||
await bot.change_presence(activity=discord.Activity(type=discord.ActivityType.listening, name=f"{song}"))
|
||||
launched = True
|
||||
|
||||
@bot.event
|
||||
async def on_command_error(ctx: commands.Context, error: commands.CommandError) -> None:
|
||||
from modules.unhandledexception import handle_exception
|
||||
|
@ -174,12 +180,14 @@ async def retrain(ctx: commands.Context) -> None:
|
|||
|
||||
for i, data in enumerate(memory):
|
||||
processed_data += 1
|
||||
if processed_data % 1000 == 0 or processed_data == data_size:
|
||||
await send_message(ctx, f"{(_('command_markov_retraining')).format(processed_data=processed_data, data_size=data_size)}", edit=True, message_reference=processing_message_ref)
|
||||
|
||||
global markov_model
|
||||
markov_model = train_markov_model(memory)
|
||||
save_markov_model(markov_model)
|
||||
|
||||
await send_message(ctx, f"{_('command_markov_retrain_successful').format(data_size=data_size)}", edit=True, message_reference=processing_message_ref)
|
||||
await send_message(ctx, f"{(_('command_markov_retrain_successful')).format(data_size=data_size)}", edit=True, message_reference=processing_message_ref)
|
||||
|
||||
# Command: Generate a sentence using the Markov model
|
||||
@bot.hybrid_command(description=f"{(_('command_desc_talk'))}")
|
||||
|
@ -211,21 +219,15 @@ async def talk(ctx: commands.Context, sentence_size: int = 5) -> None:
|
|||
combined_message: str = f"{coherent_response}\n[jif]({gif_url})"
|
||||
else:
|
||||
combined_message: str = coherent_response
|
||||
logger.info(combined_message)
|
||||
print(combined_message)
|
||||
os.environ['gooberlatestgen'] = combined_message
|
||||
await send_message(ctx, combined_message)
|
||||
else:
|
||||
await send_message(ctx, f"{(_('command_talk_generation_fail'))}")
|
||||
|
||||
@bot.hybrid_command(description=f"RAM")
|
||||
async def ramusage(ctx):
|
||||
process = psutil.Process(os.getpid())
|
||||
mem = process.memory_info().rss
|
||||
await send_message(ctx, f"Total memory used: {mem / 1024 / 1024:.2f} MB")
|
||||
|
||||
# Command: Generate an image
|
||||
@bot.hybrid_command(description=f"{(_('command_desc_help'))}")
|
||||
async def impact(ctx: commands.Context, text: Optional[str] = None) -> None:
|
||||
async def impact(ctx: commands.Context) -> None:
|
||||
assets_folder: str = "assets/images"
|
||||
temp_input: Optional[str] = None
|
||||
|
||||
|
@ -245,7 +247,7 @@ async def impact(ctx: commands.Context, text: Optional[str] = None) -> None:
|
|||
else:
|
||||
fallback_image: Optional[str] = get_random_asset_image()
|
||||
if fallback_image is None:
|
||||
await ctx.reply(_('no_image_available'))
|
||||
await ctx.reply((_('no_image_available')))
|
||||
return
|
||||
temp_input = tempfile.mktemp(suffix=os.path.splitext(fallback_image)[1])
|
||||
shutil.copy(fallback_image, temp_input)
|
||||
|
@ -253,19 +255,18 @@ async def impact(ctx: commands.Context, text: Optional[str] = None) -> None:
|
|||
else:
|
||||
fallback_image = get_random_asset_image()
|
||||
if fallback_image is None:
|
||||
await ctx.reply(_('no_image_available'))
|
||||
await ctx.reply((_('no_image_available')))
|
||||
return
|
||||
temp_input = tempfile.mktemp(suffix=os.path.splitext(fallback_image)[1])
|
||||
shutil.copy(fallback_image, temp_input)
|
||||
input_path = temp_input
|
||||
|
||||
output_path: Optional[str] = await gen_meme(input_path, custom_text=text)
|
||||
|
||||
output_path: Optional[str] = await gen_meme(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_generate_image'))
|
||||
await ctx.reply((_('failed_generate_image')))
|
||||
return
|
||||
|
||||
await ctx.send(file=discord.File(output_path))
|
||||
|
@ -295,7 +296,7 @@ async def demotivator(ctx: commands.Context) -> None:
|
|||
else:
|
||||
fallback_image: Optional[str] = get_random_asset_image()
|
||||
if fallback_image is None:
|
||||
await ctx.reply(_('no_image_available'))
|
||||
await ctx.reply((_('no_image_available')))
|
||||
return
|
||||
temp_input = tempfile.mktemp(suffix=os.path.splitext(fallback_image)[1])
|
||||
shutil.copy(fallback_image, temp_input)
|
||||
|
@ -303,7 +304,7 @@ async def demotivator(ctx: commands.Context) -> None:
|
|||
else:
|
||||
fallback_image = get_random_asset_image()
|
||||
if fallback_image is None:
|
||||
await ctx.reply(_('no_image_available'))
|
||||
await ctx.reply((_('no_image_available')))
|
||||
return
|
||||
temp_input = tempfile.mktemp(suffix=os.path.splitext(fallback_image)[1])
|
||||
shutil.copy(fallback_image, temp_input)
|
||||
|
@ -333,8 +334,8 @@ async def help(ctx: commands.Context) -> None:
|
|||
)
|
||||
|
||||
command_categories: Dict[str, List[str]] = {
|
||||
f"{(_('command_help_categories_general'))}": ["mem", "talk", "about", "ping", "impact", "demotivator", "help"],
|
||||
f"{(_('command_help_categories_admin'))}": ["stats", "retrain", "setlanguage"]
|
||||
f"{(_('command_help_categories_general'))}": ["mem", "talk", "about", "ping", "image"],
|
||||
f"{(_('command_help_categories_admin'))}": ["stats", "retrain"]
|
||||
}
|
||||
|
||||
custom_commands: List[str] = []
|
||||
|
@ -352,16 +353,6 @@ async def help(ctx: commands.Context) -> None:
|
|||
|
||||
await send_message(ctx, embed=embed)
|
||||
|
||||
@bot.hybrid_command(description=f"{(_('command_desc_setlang'))}")
|
||||
@app_commands.describe(locale="Choose your language")
|
||||
async def setlanguage(ctx: commands.Context, locale: str) -> None:
|
||||
if ctx.author.id != ownerid:
|
||||
await ctx.send(":thumbsdown:")
|
||||
return
|
||||
await ctx.defer()
|
||||
set_language(locale)
|
||||
await ctx.send(":thumbsup:")
|
||||
|
||||
# Event: Called on every message
|
||||
@bot.event
|
||||
async def on_message(message: discord.Message) -> None:
|
||||
|
@ -372,37 +363,22 @@ async def on_message(message: discord.Message) -> None:
|
|||
|
||||
if str(message.author.id) in BLACKLISTED_USERS:
|
||||
return
|
||||
|
||||
|
||||
if message.content.startswith((f"{PREFIX}talk", f"{PREFIX}mem", f"{PREFIX}help", f"{PREFIX}stats", f"{PREFIX}")):
|
||||
logger.info(f"{(_('command_ran')).format(message=message)}")
|
||||
print(f"{(_('command_ran')).format(message=message)}")
|
||||
await bot.process_commands(message)
|
||||
return
|
||||
|
||||
if profanity.contains_profanity(message.content):
|
||||
return
|
||||
|
||||
if message.content:
|
||||
if not USERTRAIN_ENABLED:
|
||||
return
|
||||
formatted_message: str = message.content
|
||||
cleaned_message: str = formatted_message
|
||||
formatted_message: str = append_mentions_to_18digit_integer(message.content)
|
||||
cleaned_message: str = preprocess_message(formatted_message)
|
||||
if cleaned_message:
|
||||
memory.append(cleaned_message)
|
||||
message_metadata = {
|
||||
"user_id": str(message.author.id),
|
||||
"user_name": str(message.author),
|
||||
"guild_id": str(message.guild.id) if message.guild else "DM",
|
||||
"guild_name": str(message.guild.name) if message.guild else "DM",
|
||||
"channel_id": str(message.channel.id),
|
||||
"channel_name": str(message.channel),
|
||||
"message": message.content,
|
||||
"timestamp": time.time()
|
||||
}
|
||||
try:
|
||||
if isinstance(memory, list):
|
||||
memory.append({"_meta": message_metadata})
|
||||
else:
|
||||
logger.warning("Memory is not a list; can't append metadata")
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to append metadata to memory: {e}")
|
||||
|
||||
save_memory(memory)
|
||||
|
||||
sentiment_score = is_positive(message.content) # doesnt work but im scared to change the logic now please ignore
|
||||
|
@ -413,18 +389,14 @@ async def on_message(message: discord.Message) -> None:
|
|||
try:
|
||||
await message.add_reaction(emoji)
|
||||
except Exception as e:
|
||||
logger.info(f"Failed to react with emoji: {e}")
|
||||
print(f"Failed to react with emoji: {e}")
|
||||
|
||||
await bot.process_commands(message)
|
||||
|
||||
# Event: Called on every interaction (slash command, etc.)
|
||||
@bot.event
|
||||
async def on_interaction(interaction: discord.Interaction) -> None:
|
||||
name = None
|
||||
if interaction.data.get('name') is None:
|
||||
name = "Unknown"
|
||||
else:
|
||||
name = interaction.data['name']
|
||||
logger.info(f"{(_('command_ran_s')).format(interaction=interaction)}{name}")
|
||||
print(f"{(_('command_ran_s')).format(interaction=interaction)}{interaction.data['name']}")
|
||||
|
||||
# Global check: Block blacklisted users from running commands
|
||||
@bot.check
|
||||
|
@ -433,11 +405,11 @@ async def block_blacklisted(ctx: commands.Context) -> bool:
|
|||
try:
|
||||
if isinstance(ctx, discord.Interaction):
|
||||
if not ctx.response.is_done():
|
||||
await ctx.response.send_message(_('blacklisted'), ephemeral=True)
|
||||
await ctx.response.send_message((_('blacklisted')), ephemeral=True)
|
||||
else:
|
||||
await ctx.followup.send(_('blacklisted'), ephemeral=True)
|
||||
await ctx.followup.send((_('blacklisted')), ephemeral=True)
|
||||
else:
|
||||
await ctx.send(_('blacklisted_user'), ephemeral=True)
|
||||
await ctx.send((_('blacklisted_user')), ephemeral=True)
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
|
@ -461,17 +433,6 @@ async def ping(ctx: commands.Context) -> None:
|
|||
|
||||
await ctx.send(embed=LOLembed)
|
||||
|
||||
def get_git_remote_url():
|
||||
try:
|
||||
url = subprocess.check_output(
|
||||
["git", "config", "--get", "remote.origin.url"],
|
||||
text=True,
|
||||
stderr=subprocess.DEVNULL,
|
||||
).strip()
|
||||
return url
|
||||
except subprocess.CalledProcessError:
|
||||
return "Unknown"
|
||||
|
||||
# Command: Show about information
|
||||
@bot.hybrid_command(description=f"{(_('command_about_desc'))}")
|
||||
async def about(ctx: commands.Context) -> None:
|
||||
|
@ -481,9 +442,7 @@ async def about(ctx: commands.Context) -> None:
|
|||
embed: discord.Embed = discord.Embed(title=f"{(_('command_about_embed_title'))}", description="", color=Colour(0x000000))
|
||||
embed.add_field(name=f"{(_('command_about_embed_field1'))}", value=f"{NAME}", inline=False)
|
||||
embed.add_field(name=f"{(_('command_about_embed_field2name'))}", value=f"{(_('command_about_embed_field2value')).format(local_version=local_version, latest_version=latest_version)}", inline=False)
|
||||
embed.add_field(name=f"Git", value=get_git_remote_url())
|
||||
embed.add_field(name=f"OS", value=platform.platform())
|
||||
|
||||
|
||||
await send_message(ctx, embed=embed)
|
||||
|
||||
# Command: Show bot statistics (admin only)
|
||||
|
@ -503,9 +462,8 @@ async def stats(ctx: commands.Context) -> None:
|
|||
embed: discord.Embed = discord.Embed(title=f"{(_('command_stats_embed_title'))}", description=f"{(_('command_stats_embed_desc'))}", color=Colour(0x000000))
|
||||
embed.add_field(name=f"{(_('command_stats_embed_field1name'))}", value=f"{(_('command_stats_embed_field1value')).format(file_size=file_size, line_count=line_count)}", inline=False)
|
||||
embed.add_field(name=f"{(_('command_stats_embed_field2name'))}", value=f"{(_('command_stats_embed_field2value')).format(local_version=local_version, latest_version=latest_version)}", inline=False)
|
||||
embed.add_field(name=f"{(_('command_stats_embed_field3name'))}", value=f"{(_('command_stats_embed_field3value')).format(NAME=NAME, PREFIX=PREFIX, ownerid=ownerid, PING_LINE=PING_LINE, showmemenabled=showmemenabled, USERTRAIN_ENABLED=USERTRAIN_ENABLED, song=song, splashtext=splashtext)}", inline=False)
|
||||
embed.add_field(name=f"OS", value=platform.platform())
|
||||
embed.add_field(name="Python Version", value=platform.python_version())
|
||||
embed.add_field(name=f"{(_('command_stats_embed_field3name'))}", value=f"{(_('command_stats_embed_field3value')).format(NAME=NAME, PREFIX=PREFIX, ownerid=ownerid, cooldown_time=cooldown_time, PING_LINE=PING_LINE, showmemenabled=showmemenabled, USERTRAIN_ENABLED=USERTRAIN_ENABLED, song=song, splashtext=splashtext)}", inline=False)
|
||||
|
||||
await send_message(ctx, embed=embed)
|
||||
|
||||
# Command: Upload memory.json to litterbox.catbox.moe and return the link
|
||||
|
@ -515,7 +473,7 @@ async def mem(ctx: commands.Context) -> None:
|
|||
return
|
||||
command: str = """curl -F "reqtype=fileupload" -F "time=1h" -F "fileToUpload=@memory.json" https://litterbox.catbox.moe/resources/internals/api.php"""
|
||||
memorylitter: subprocess.CompletedProcess = subprocess.run(command, shell=True, capture_output=True, text=True)
|
||||
logger.debug(memorylitter)
|
||||
print(memorylitter)
|
||||
await send_message(ctx, memorylitter.stdout.strip())
|
||||
|
||||
# Helper: Improve sentence coherence (simple capitalization fix)
|
||||
|
|
245
botminimal.py
245
botminimal.py
|
@ -1,245 +0,0 @@
|
|||
import discord
|
||||
from discord.ext import commands, tasks
|
||||
import json
|
||||
import markovify
|
||||
import nltk
|
||||
from nltk.tokenize import word_tokenize
|
||||
import random
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
# download NLTK data files
|
||||
nltk.download('punkt')
|
||||
MEMORY_FILE = "memory.json"
|
||||
MEMORY_LOADED_FILE = "MEMORY_LOADED"
|
||||
|
||||
def load_memory():
|
||||
data = []
|
||||
|
||||
# Try to load data from MEMORY_FILE
|
||||
try:
|
||||
with open(MEMORY_FILE, "r") as f:
|
||||
data = json.load(f)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
return data
|
||||
|
||||
# Save memory data to MEMORY_FILE
|
||||
def save_memory(memory):
|
||||
with open(MEMORY_FILE, "w") as f:
|
||||
json.dump(memory, f, indent=4)
|
||||
|
||||
def train_markov_model(memory, additional_data=None):
|
||||
if not memory:
|
||||
return None
|
||||
filtered_memory = [line for line in memory if isinstance(line, str)]
|
||||
if additional_data:
|
||||
filtered_memory.extend(line for line in additional_data if isinstance(line, str))
|
||||
if not filtered_memory:
|
||||
return None
|
||||
text = "\n".join(filtered_memory)
|
||||
model = markovify.NewlineText(text, state_size=2)
|
||||
return model
|
||||
|
||||
#this doesnt work and im extremely pissed and mad
|
||||
def append_mentions_to_18digit_integer(message):
|
||||
pattern = r'\b\d{18}\b'
|
||||
return re.sub(pattern, lambda match: f"<@{match.group(0)}>", message)
|
||||
|
||||
def preprocess_message(message):
|
||||
message = append_mentions_to_18digit_integer(message)
|
||||
tokens = word_tokenize(message)
|
||||
tokens = [token for token in tokens if token.isalnum()]
|
||||
return " ".join(tokens)
|
||||
|
||||
|
||||
intents = discord.Intents.default()
|
||||
intents.messages = True
|
||||
intents.message_content = True
|
||||
bot = commands.Bot(command_prefix="g!", intents=intents)
|
||||
memory = load_memory()
|
||||
markov_model = train_markov_model(memory)
|
||||
|
||||
generated_sentences = set()
|
||||
used_words = set()
|
||||
|
||||
@bot.event
|
||||
async def on_ready():
|
||||
print(f"Logged in as {bot.user}")
|
||||
post_message.start()
|
||||
|
||||
positive_keywords = ["happy", "good", "great", "amazing", "awesome", "joy", "love", "fantastic", "positive", "cheerful", "victory", "favorite", "lmao", "lol", "xd", "XD", "xD", "Xd"]
|
||||
|
||||
positive_gifs = [
|
||||
"https://tenor.com/view/chill-guy-my-new-character-gif-2777893510283028272",
|
||||
"https://tenor.com/view/goodnight-goodnight-friends-weezer-weezer-goodnight-gif-7322052181075806988"
|
||||
]
|
||||
|
||||
def is_positive(sentence):
|
||||
sentence_lower = sentence.lower()
|
||||
return any(keyword in sentence_lower for keyword in positive_keywords)
|
||||
|
||||
@bot.command()
|
||||
async def ask(ctx):
|
||||
await ctx.send("Command undergoing fixes!")
|
||||
#not really lol
|
||||
|
||||
@bot.command()
|
||||
async def talk(ctx):
|
||||
if markov_model:
|
||||
response = None
|
||||
for _ in range(10): # im going to shit my pants 10 times to get a coherent sentence
|
||||
response = markov_model.make_sentence(tries=100)
|
||||
if response and response not in generated_sentences:
|
||||
# preprocess shit for grammer
|
||||
response = improve_sentence_coherence(response)
|
||||
generated_sentences.add(response)
|
||||
break
|
||||
|
||||
if response:
|
||||
async with ctx.typing():
|
||||
cleaned_response = re.sub(r'[^\w\s]', '', response)
|
||||
cleaned_response = cleaned_response.lower()
|
||||
coherent_response = rephrase_for_coherence(cleaned_response)
|
||||
if random.random() < 0.9:
|
||||
if is_positive(coherent_response):
|
||||
gif_url = random.choice(positive_gifs)
|
||||
combined_message = f"{coherent_response}\n[jif]({gif_url})"
|
||||
await ctx.send(combined_message)
|
||||
else:
|
||||
await ctx.send(coherent_response)
|
||||
else:
|
||||
await ctx.send(coherent_response)
|
||||
else:
|
||||
await ctx.send("I have nothing to say right now!")
|
||||
else:
|
||||
await ctx.send("I need to learn more from messages before I can talk.")
|
||||
|
||||
def improve_sentence_coherence(sentence):
|
||||
|
||||
sentence = sentence.replace(" i ", " I ")
|
||||
return sentence
|
||||
|
||||
def rephrase_for_coherence(sentence):
|
||||
|
||||
words = sentence.split()
|
||||
|
||||
coherent_sentence = " ".join(words)
|
||||
return coherent_sentence
|
||||
|
||||
bot.help_command = None
|
||||
|
||||
|
||||
@bot.command()
|
||||
async def help(ctx, *args):
|
||||
|
||||
if args:
|
||||
command_name = args[0]
|
||||
command = bot.get_command(command_name)
|
||||
|
||||
if command:
|
||||
embed = discord.Embed(
|
||||
title=f"Help: g!{command_name}",
|
||||
description=f"**Description:** {command.help}",
|
||||
color=discord.Color.blue()
|
||||
)
|
||||
await ctx.send(embed=embed)
|
||||
else:
|
||||
await ctx.send(f"Command `{command_name}` not found.")
|
||||
else:
|
||||
|
||||
embed = discord.Embed(
|
||||
title="Bot Help",
|
||||
description="List of commands grouped by category.",
|
||||
color=discord.Color.blue()
|
||||
)
|
||||
|
||||
command_categories = {
|
||||
"General": ["show_memory", "talk", "ask", "ping"],
|
||||
"Debug": ["word_usage"]
|
||||
}
|
||||
|
||||
for category, commands_list in command_categories.items():
|
||||
commands_in_category = "\n".join([f"g!{command}" for command in commands_list])
|
||||
embed.add_field(name=category, value=commands_in_category, inline=False)
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@bot.event
|
||||
async def on_message(message):
|
||||
global memory, markov_model, last_random_talk_time
|
||||
|
||||
if message.author.bot:
|
||||
return
|
||||
|
||||
|
||||
if message.content.startswith(("g!talk", "g!show_memory", "g!help", "g!")):
|
||||
await bot.process_commands(message)
|
||||
return
|
||||
|
||||
if message.content:
|
||||
formatted_message = append_mentions_to_18digit_integer(message.content)
|
||||
cleaned_message = preprocess_message(formatted_message)
|
||||
if cleaned_message:
|
||||
memory.append(cleaned_message)
|
||||
save_memory(memory)
|
||||
markov_model = train_markov_model(memory)
|
||||
|
||||
# process any commands in the message
|
||||
await bot.process_commands(message)
|
||||
|
||||
@bot.command()
|
||||
async def ping(ctx):
|
||||
await ctx.defer()
|
||||
#stolen from my expect bot very proud
|
||||
latency = round(bot.latency * 1000)
|
||||
|
||||
LOLembed = discord.Embed(
|
||||
title="Pong!!",
|
||||
description=(
|
||||
f"The Beretta fires fast and won't make you feel any better!\n"
|
||||
f"`Bot Latency: {latency}ms`\n"
|
||||
),
|
||||
color=discord.Color.blue()
|
||||
)
|
||||
LOLembed.set_footer(text=f"Requested by {ctx.author.name}", icon_url=ctx.author.avatar.url)
|
||||
|
||||
await ctx.send(embed=LOLembed) # use ctx.send instead of respond because it has nothing to respond to and its not a slash command
|
||||
|
||||
@bot.command()
|
||||
async def show_memory(ctx):
|
||||
memory = load_memory()
|
||||
memory_text = json.dumps(memory, indent=4)
|
||||
if len(memory_text) > 1024:
|
||||
with open(MEMORY_FILE, "r") as f:
|
||||
await ctx.send(" ", file=discord.File(f, MEMORY_FILE))
|
||||
else:
|
||||
embed = discord.Embed(title="Memory Contents", description="The bot's memory.", color=discord.Color.blue())
|
||||
embed.add_field(name="Memory Data", value=f"```json\n{memory_text}\n```", inline=False)
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
def improve_sentence_coherence(sentence):
|
||||
sentence = sentence.replace(" i ", " I ")
|
||||
return sentence
|
||||
|
||||
@tasks.loop(minutes=60)
|
||||
async def post_message():
|
||||
channel_id = 1296141985253691433
|
||||
channel = bot.get_channel(channel_id)
|
||||
if channel and markov_model:
|
||||
response = None
|
||||
for _ in range(10):
|
||||
response = markov_model.make_sentence(tries=100)
|
||||
if response and response not in generated_sentences:
|
||||
generated_sentences.add(response)
|
||||
break
|
||||
|
||||
if response:
|
||||
await channel.send(response)
|
||||
|
||||
# run the bot
|
||||
TOKEN = os.getenv("DISCORDBOTTOKEN", "0")
|
||||
bot.run(TOKEN)
|
32
example.env
32
example.env
|
@ -1,20 +1,18 @@
|
|||
DISCORDBOTTOKEN=
|
||||
BOTPREFIX="g."
|
||||
PINGLINE="The Beretta fires fast and won't make you feel any better!"
|
||||
BLACKLISTEDUSERS=
|
||||
OWNERID=
|
||||
USERTRAINENABLED="true"
|
||||
SHOWMEMENABLED="true"
|
||||
LOCALE=fi
|
||||
NAME=goober
|
||||
DISCORD_BOT_TOKEN=token
|
||||
BOT_PREFIX="g."
|
||||
PING_LINE="The Beretta fires fast and won't make you feel any better!"
|
||||
BLACKLISTED_USERS=
|
||||
USERTRAIN_ENABLED="true"
|
||||
showmemenabled="true"
|
||||
NAME="an instance of goober"
|
||||
locale=fi
|
||||
ALIVEPING="true"
|
||||
AUTOUPDATE="True"
|
||||
SONG="Basket Case - Green Day"
|
||||
CHECKSDISABLED="Frue"
|
||||
gooberTOKEN=
|
||||
song="A Heart of Cold - Heaven Pierce Her"
|
||||
REACT="True"
|
||||
STATUS="idle"
|
||||
POSITIVEGIFS="https://media.discordapp.net/attachments/821047460151427135/1181371808566493184/jjpQGeno.gif, https://tenor.com/view/chill-guy-my-new-character-gif-2777893510283028272,https://tenor.com/view/goodnight-goodnight-friends-weezer-weezer-goodnight-gif-7322052181075806988"
|
||||
SPLASHTEXT="
|
||||
|
||||
POSITIVE_GIFS="https://tenor.com/view/chill-guy-my-new-character-gif-2777893510283028272, https://tenor.com/view/goodnight-goodnight-friends-weezer-weezer-goodnight-gif-7322052181075806988"
|
||||
splashtext="
|
||||
SS\
|
||||
SS |
|
||||
SSSSSS\ SSSSSS\ SSSSSS\ SSSSSSS\ SSSSSS\ SSSSSS\
|
||||
|
@ -25,5 +23,5 @@ SS | SS |SS | SS |SS | SS |SS | SS |SS ____|SS |
|
|||
\____SS | \______/ \______/ \_______/ \_______|\__|
|
||||
SS\ SS |
|
||||
\SSSSSS |
|
||||
\______/
|
||||
"
|
||||
\______/
|
||||
"
|
||||
|
|
97
modules/central.py
Normal file
97
modules/central.py
Normal file
|
@ -0,0 +1,97 @@
|
|||
import requests
|
||||
import os
|
||||
import modules.globalvars as gv
|
||||
from modules.volta.main import _
|
||||
from modules.markovmemory import get_file_info
|
||||
|
||||
# Ping the server to check if it's alive and send some info
|
||||
def ping_server():
|
||||
if gv.ALIVEPING == "false":
|
||||
# If pinging is disabled, print message and set environment variable
|
||||
print(f"{gv.YELLOW}{(_('pinging_disabled'))}{gv.RESET}")
|
||||
os.environ['gooberauthenticated'] = 'No'
|
||||
return
|
||||
# Get server alert message
|
||||
goobres = requests.get(f"{gv.VERSION_URL}/alert")
|
||||
print(f"{(_('goober_server_alert'))}{goobres.text}")
|
||||
# Gather file info for payload
|
||||
file_info = get_file_info(gv.MEMORY_FILE)
|
||||
payload = {
|
||||
"name": gv.NAME,
|
||||
"memory_file_info": file_info,
|
||||
"version": gv.local_version,
|
||||
"slash_commands": gv.slash_commands_enabled,
|
||||
"token": gv.gooberTOKEN
|
||||
}
|
||||
try:
|
||||
# Send ping to server
|
||||
response = requests.post(gv.VERSION_URL+"/ping", json=payload)
|
||||
if response.status_code == 200:
|
||||
# Success: print message and set environment variable
|
||||
print(f"{gv.GREEN}{(_('goober_ping_success')).format(NAME=gv.NAME)}{gv.RESET}")
|
||||
os.environ['gooberauthenticated'] = 'Yes'
|
||||
else:
|
||||
# Failure: print error and set environment variable
|
||||
print(f"{gv.RED}{(_('goober_ping_fail'))} {response.status_code}{gv.RESET}")
|
||||
os.environ['gooberauthenticated'] = 'No'
|
||||
except Exception as e:
|
||||
# Exception: print error and set environment variable
|
||||
print(f"{gv.RED}{(_('goober_ping_fail2'))} {str(e)}{gv.RESET}")
|
||||
os.environ['gooberauthenticated'] = 'No'
|
||||
|
||||
# Check if a given name is available for registration
|
||||
def is_name_available(NAME):
|
||||
if os.getenv("gooberTOKEN"):
|
||||
# If token is already set, skip check
|
||||
return
|
||||
try:
|
||||
# Send request to check name availability
|
||||
response = requests.post(f"{gv.VERSION_URL}/check-if-available", json={"name": NAME}, headers={"Content-Type": "application/json"})
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
return data.get("available", False)
|
||||
else:
|
||||
# Print error if request failed
|
||||
print(f"{(_('name_check'))}", response.json())
|
||||
return False
|
||||
except Exception as e:
|
||||
# Print exception if request failed
|
||||
print(f"{(_('name_check2'))}", e)
|
||||
return False
|
||||
|
||||
# Register a new name with the server
|
||||
def register_name(NAME):
|
||||
try:
|
||||
if gv.ALIVEPING == False:
|
||||
# If pinging is disabled, do nothing
|
||||
return
|
||||
# Check if the name is available
|
||||
if not is_name_available(NAME):
|
||||
if os.getenv("gooberTOKEN"):
|
||||
return
|
||||
# Name taken: print error and exit
|
||||
print(f"{RED}{(_('name_taken'))}{gv.RESET}")
|
||||
quit()
|
||||
# Register the name
|
||||
response = requests.post(f"{gv.VERSION_URL}/register", json={"name": NAME}, headers={"Content-Type": "application/json"})
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
token = data.get("token")
|
||||
if not os.getenv("gooberTOKEN"):
|
||||
# Print instructions to add token and exit
|
||||
print(f"{gv.GREEN}{(_('add_token')).format(token=token)} gooberTOKEN=<token>.{gv.gv.RESET}")
|
||||
quit()
|
||||
else:
|
||||
print(f"{gv.GREEN}{gv.gv.RESET}")
|
||||
return token
|
||||
else:
|
||||
# Print error if registration failed
|
||||
print(f"{gv.RED}{(_('token_exists')).format()}{gv.RESET}", response.json())
|
||||
return None
|
||||
except Exception as e:
|
||||
# Print exception if registration failed
|
||||
print(f"{gv.RED}{(_('registration_error')).format()}{gv.RESET}", e)
|
||||
return None
|
||||
|
||||
# Attempt to register the name at module load
|
||||
register_name(gv.NAME)
|
|
@ -2,71 +2,43 @@ import os
|
|||
import platform
|
||||
from dotenv import load_dotenv
|
||||
import pathlib
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
from discord import app_commands
|
||||
from discord import Colour, Embed, File, Interaction, Message
|
||||
from discord.abc import Messageable
|
||||
from discord.ext import commands
|
||||
import subprocess
|
||||
def get_git_branch():
|
||||
try:
|
||||
branch = subprocess.check_output(
|
||||
["git", "rev-parse", "--abbrev-ref", "HEAD"],
|
||||
stderr=subprocess.DEVNULL
|
||||
).decode('utf-8').strip()
|
||||
return branch
|
||||
except subprocess.CalledProcessError:
|
||||
return None
|
||||
|
||||
env_path = pathlib.Path(__file__).parent.parent / '.env'
|
||||
load_dotenv(dotenv_path=env_path)
|
||||
|
||||
ANSI = "\033["
|
||||
RED = f"{ANSI}31m"
|
||||
GREEN = f"{ANSI}32m"
|
||||
YELLOW = f"{ANSI}33m"
|
||||
PURPLE = f"{ANSI}35m"
|
||||
DEBUG = f"{ANSI}1;30m"
|
||||
RESET = f"{ANSI}0m"
|
||||
VERSION_URL = "https://raw.githubusercontent.com/gooberinc/version/main"
|
||||
VERSION_URL = "https://goober.expect.ovh"
|
||||
UPDATE_URL = VERSION_URL+"/latest_version.json"
|
||||
print(UPDATE_URL)
|
||||
LOCAL_VERSION_FILE = "current_version.txt"
|
||||
TOKEN = os.getenv("DISCORDBOTTOKEN", "0")
|
||||
PREFIX = os.getenv("BOTPREFIX", "g.")
|
||||
PING_LINE = os.getenv("PINGLINE")
|
||||
CHECKS_DISABLED = os.getenv("CHECKSDISABLED")
|
||||
LOCALE = os.getenv("LOCALE", "en")
|
||||
gooberTOKEN = os.getenv("GOOBERTOKEN")
|
||||
splashtext = os.getenv("SPLASHTEXT")
|
||||
ownerid = int(os.getenv("OWNERID", "0"))
|
||||
status = os.getenv("STATUS")
|
||||
showmemenabled = os.getenv("SHOWMEMENABLED")
|
||||
BLACKLISTED_USERS = os.getenv("BLACKLISTEDUSERS", "").split(",")
|
||||
USERTRAIN_ENABLED = os.getenv("USERTRAINENABLED", "true").lower() == "true"
|
||||
TOKEN = os.getenv("DISCORD_BOT_TOKEN", "0")
|
||||
PREFIX = os.getenv("BOT_PREFIX", "g.")
|
||||
PING_LINE = os.getenv("PING_LINE")
|
||||
CHECKS_DISABLED = os.getenv("CHECKS_DISABLED")
|
||||
LOCALE = os.getenv("locale", "en")
|
||||
gooberTOKEN = os.getenv("gooberTOKEN")
|
||||
splashtext = os.getenv("splashtext")
|
||||
ownerid = int(os.getenv("ownerid", "0"))
|
||||
showmemenabled = os.getenv("showmemenabled")
|
||||
BLACKLISTED_USERS = os.getenv("BLACKLISTED_USERS", "").split(",")
|
||||
USERTRAIN_ENABLED = os.getenv("USERTRAIN_ENABLED", "true").lower() == "true"
|
||||
NAME = os.getenv("NAME")
|
||||
MEMORY_FILE = "memory.json"
|
||||
MEMORY_LOADED_FILE = "MEMORY_LOADED" # is this still even used?? okay just checked its used in the markov module
|
||||
ALIVEPING = os.getenv("ALIVEPING")
|
||||
AUTOUPDATE = os.getenv("AUTOUPDATE")
|
||||
song = os.getenv("SONG")
|
||||
# IGNOREWARNING = False # is this either??? i don't think so?
|
||||
song = os.getenv("song")
|
||||
arch = platform.machine()
|
||||
slash_commands_enabled = True # 100% broken, its a newer enough version so its probably enabled by default.... fix this at somepoint or hard code it in goober central code
|
||||
launched = False
|
||||
latest_version = "0.0.0"
|
||||
local_version = "2.3.5"
|
||||
local_version = "2.0.0"
|
||||
os.environ['gooberlocal_version'] = local_version
|
||||
REACT = os.getenv("REACT")
|
||||
if get_git_branch() == "dev":
|
||||
beta = True
|
||||
# this makes goober think its a beta version, so it will not update to the latest stable version or run any version checks
|
||||
else:
|
||||
beta = False
|
||||
|
||||
|
||||
# Set up Discord bot intents and create bot instance
|
||||
intents: discord.Intents = discord.Intents.default()
|
||||
intents.messages = True
|
||||
intents.presences = True
|
||||
intents.members = True
|
||||
intents.message_content = True
|
||||
bot: commands.Bot = commands.Bot(command_prefix=PREFIX, intents=intents, allowed_mentions=discord.AllowedMentions(everyone=False, roles=False, users=False, replied_user=True))
|
||||
beta = False # this makes goober think its a beta version, so it will not update to the latest stable version or run any version checks
|
||||
|
|
@ -37,7 +37,7 @@ def split_text_to_fit(text, font, max_width, draw):
|
|||
midpoint = len(words) // 2
|
||||
return " ".join(words[:midpoint]), " ".join(words[midpoint:])
|
||||
|
||||
async def gen_meme(input_image_path, sentence_size=5, max_attempts=10, custom_text=None):
|
||||
async def gen_meme(input_image_path, sentence_size=5, max_attempts=10):
|
||||
markov_model = load_markov_model()
|
||||
if not markov_model or not os.path.isfile(input_image_path):
|
||||
return None
|
||||
|
@ -52,22 +52,19 @@ async def gen_meme(input_image_path, sentence_size=5, max_attempts=10, custom_te
|
|||
font = load_font(font_size)
|
||||
|
||||
response = None
|
||||
if custom_text:
|
||||
response = custom_text
|
||||
else:
|
||||
for _ in range(20):
|
||||
if sentence_size == 1:
|
||||
candidate = markov_model.make_short_sentence(max_chars=100, tries=100)
|
||||
if candidate:
|
||||
candidate = candidate.split()[0]
|
||||
else:
|
||||
candidate = markov_model.make_sentence(tries=100, max_words=sentence_size)
|
||||
for _ in range(20):
|
||||
if sentence_size == 1:
|
||||
candidate = markov_model.make_short_sentence(max_chars=100, tries=100)
|
||||
if candidate:
|
||||
candidate = candidate.split()[0]
|
||||
else:
|
||||
candidate = markov_model.make_sentence(tries=100, max_words=sentence_size)
|
||||
|
||||
if candidate and candidate not in generated_sentences:
|
||||
if sentence_size > 1:
|
||||
candidate = improve_sentence_coherence(candidate)
|
||||
generated_sentences.add(candidate)
|
||||
response = candidate
|
||||
if candidate and candidate not in generated_sentences:
|
||||
if sentence_size > 1:
|
||||
candidate = improve_sentence_coherence(candidate)
|
||||
generated_sentences.add(candidate)
|
||||
response = candidate
|
||||
break
|
||||
|
||||
if not response:
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
import logging
|
||||
import re
|
||||
from modules.globalvars import *
|
||||
|
||||
class GooberFormatter(logging.Formatter):
|
||||
def __init__(self, colors: bool = True): # Disable colors for TXT output
|
||||
self.colors = colors
|
||||
|
||||
self._format = f"[ %(levelname)-8s ]: %(message)s {DEBUG} [%(asctime)s.%(msecs)03d] (%(filename)s:%(funcName)s) {RESET}"
|
||||
|
||||
self.FORMATS = {
|
||||
logging.DEBUG: DEBUG + self._format + RESET,
|
||||
logging.INFO: self._format.replace("%(levelname)-8s", f"{GREEN}%(levelname)-8s{RESET}"),
|
||||
logging.WARNING: YELLOW + self._format + RESET,
|
||||
logging.ERROR: RED + self._format + RESET,
|
||||
logging.CRITICAL: PURPLE + self._format + RESET
|
||||
}
|
||||
|
||||
def format(self, record: logging.LogRecord):
|
||||
ansiescape = re.compile(r'\x1B[@-_][0-?]*[ -/]*[@-~]')
|
||||
if self.colors:
|
||||
log_fmt = self.FORMATS.get(record.levelno) # Add colors
|
||||
else:
|
||||
log_fmt = self._format # Just use the default format
|
||||
|
||||
formatter = logging.Formatter(log_fmt, datefmt="%m/%d/%y %H:%M:%S")
|
||||
formatted = formatter.format(record)
|
||||
if not self.colors:
|
||||
formatted = ansiescape.sub('', formatted)
|
||||
return formatted
|
|
@ -4,8 +4,7 @@ import markovify
|
|||
import pickle
|
||||
from modules.globalvars import *
|
||||
from modules.volta.main import _
|
||||
import logging
|
||||
logger = logging.getLogger("goober")
|
||||
|
||||
# Get file size and line count for a given file path
|
||||
def get_file_info(file_path):
|
||||
try:
|
||||
|
@ -27,6 +26,16 @@ def load_memory():
|
|||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
# If MEMORY_LOADED_FILE does not exist, load default data and mark as loaded
|
||||
if not os.path.exists(MEMORY_LOADED_FILE):
|
||||
try:
|
||||
with open(DEFAULT_DATASET_FILE, "r") as f:
|
||||
default_data = json.load(f)
|
||||
data.extend(default_data)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
with open(MEMORY_LOADED_FILE, "w") as f:
|
||||
f.write("Data loaded")
|
||||
return data
|
||||
|
||||
# Save memory data to MEMORY_FILE
|
||||
|
@ -34,15 +43,13 @@ def save_memory(memory):
|
|||
with open(MEMORY_FILE, "w") as f:
|
||||
json.dump(memory, f, indent=4)
|
||||
|
||||
# Train a Markov model using memory and optional additional data
|
||||
def train_markov_model(memory, additional_data=None):
|
||||
if not memory:
|
||||
return None
|
||||
filtered_memory = [line for line in memory if isinstance(line, str)]
|
||||
text = "\n".join(memory)
|
||||
if additional_data:
|
||||
filtered_memory.extend(line for line in additional_data if isinstance(line, str))
|
||||
if not filtered_memory:
|
||||
return None
|
||||
text = "\n".join(filtered_memory)
|
||||
text += "\n" + "\n".join(additional_data)
|
||||
model = markovify.NewlineText(text, state_size=2)
|
||||
return model
|
||||
|
||||
|
@ -50,15 +57,15 @@ def train_markov_model(memory, additional_data=None):
|
|||
def save_markov_model(model, filename='markov_model.pkl'):
|
||||
with open(filename, 'wb') as f:
|
||||
pickle.dump(model, f)
|
||||
logger.info(f"Markov model saved to {filename}.")
|
||||
print(f"Markov model saved to {filename}.")
|
||||
|
||||
# Load the Markov model from a pickle file
|
||||
def load_markov_model(filename='markov_model.pkl'):
|
||||
try:
|
||||
with open(filename, 'rb') as f:
|
||||
model = pickle.load(f)
|
||||
logger.info(f"{_('model_loaded')} {filename}.{RESET}")
|
||||
print(f"{GREEN}{_('model_loaded')} {filename}.{RESET}")
|
||||
return model
|
||||
except FileNotFoundError:
|
||||
logger.error(f"{filename} {_('not_found')}{RESET}")
|
||||
print(f"{RED}{filename} {_('not_found')}{RESET}")
|
||||
return None
|
|
@ -1,71 +0,0 @@
|
|||
import random
|
||||
import discord
|
||||
from discord import ui, Interaction, TextStyle
|
||||
from discord.ext import commands
|
||||
import aiohttp
|
||||
import asyncio
|
||||
from modules.globalvars import bot
|
||||
from modules.volta.main import _
|
||||
|
||||
# @bot.hybrid_command(description=_('minigames_guess_the_number'))
|
||||
async def guessthenumber(ctx: commands.Context):
|
||||
number = random.randint(1, 10)
|
||||
class GuessModal(ui.Modal, title=_('minigames_guess_the_number')):
|
||||
guess = ui.TextInput(label=_('minigames_your_guess'), style=TextStyle.short)
|
||||
async def on_submit(self, interaction: Interaction):
|
||||
try:
|
||||
user_guess = int(self.guess.value)
|
||||
except:
|
||||
await interaction.response.send_message(_('minigames_invalid_number'), ephemeral=True)
|
||||
return
|
||||
if user_guess == number:
|
||||
await interaction.response.send_message(_('minigames_correct'), ephemeral=True)
|
||||
else:
|
||||
await interaction.response.send_message(f"{_('minigames_wrong_number')} {number}.", ephemeral=True)
|
||||
async def button_callback(interaction: Interaction):
|
||||
await interaction.response.send_modal(GuessModal())
|
||||
button = ui.Button(label=_('minigames_guess_button'), style=discord.ButtonStyle.primary)
|
||||
button.callback = button_callback
|
||||
view = ui.View()
|
||||
view.add_item(button)
|
||||
await ctx.send(_('minigames_click_to_guess'), view=view)
|
||||
|
||||
# @bot.hybrid_command(description=_('minigames_hangman')) nope nope nope fuck no nope no thanks no nuh uh not today nope
|
||||
async def hangman(ctx: commands.Context):
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get("https://random-word-api.herokuapp.com/word?number=1") as resp:
|
||||
if resp.status != 200:
|
||||
await ctx.send("Failed to get a random word.")
|
||||
return
|
||||
data = await resp.json()
|
||||
word = data[0].lower()
|
||||
print(word)
|
||||
guessed_letters = set()
|
||||
wrong_guesses = 0
|
||||
max_wrong = 6
|
||||
def display_word():
|
||||
return " ".join([c if c in guessed_letters else "_" for c in word])
|
||||
class GuessModal(ui.Modal, title=_('minigames_hangman_guess')):
|
||||
letter = ui.TextInput(label=_('minigames_hangman_user_letter_guess'), style=TextStyle.short, max_length=1)
|
||||
async def on_submit(self, interaction: Interaction):
|
||||
nonlocal guessed_letters, wrong_guesses
|
||||
guess = self.letter.value.lower()
|
||||
if guess in guessed_letters:
|
||||
await interaction.response.send_message(f"{_('minigames_hangman_already_guessed')}'{guess}'!", ephemeral=True)
|
||||
return
|
||||
guessed_letters.add(guess)
|
||||
if guess not in word:
|
||||
wrong_guesses += 1
|
||||
if all(c in guessed_letters for c in word):
|
||||
await interaction.response.edit_message(content=f"{_('minigames_hangman_won')} **{word}**", view=None)
|
||||
elif wrong_guesses >= max_wrong:
|
||||
await interaction.response.edit_message(content=f"{_('minigames_hangman_lost')} **{word}**", view=None)
|
||||
else:
|
||||
await interaction.response.edit_message(content=_('minigames_hangman_game').format(display_word=display_word(),wrong_guesses=wrong_guesses,max_wrong=max_wrong), view=view)
|
||||
async def button_callback(interaction: Interaction):
|
||||
await interaction.response.send_modal(GuessModal())
|
||||
button = ui.Button(label=_('minigames_click_to_guess'), style=discord.ButtonStyle.primary)
|
||||
button.callback = button_callback
|
||||
view = ui.View()
|
||||
view.add_item(button)
|
||||
await ctx.send(_('minigames_hangman_game').format(display_word=display_word,wrong_guesses=wrong_guesses,max_wrong=max_wrong), view=view)
|
|
@ -1,5 +1,6 @@
|
|||
from modules.globalvars import *
|
||||
from modules.volta.main import _, check_missing_translations
|
||||
from modules.volta.main import _, get_translation, load_translations, set_language, translations
|
||||
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
|
@ -8,11 +9,7 @@ import sysconfig
|
|||
import ast
|
||||
import json
|
||||
import re
|
||||
from spacy.util import is_package
|
||||
import importlib.metadata
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger("goober")
|
||||
|
||||
# import shutil
|
||||
psutilavaliable = True
|
||||
|
@ -21,22 +18,39 @@ try:
|
|||
import psutil
|
||||
except ImportError:
|
||||
psutilavaliable = False
|
||||
logger.error(_('missing_requests_psutil'))
|
||||
print(RED, _('missing_requests_psutil'), RESET)
|
||||
|
||||
def check_for_model():
|
||||
if is_package("en_core_web_sm"):
|
||||
logger.info("Model is installed.")
|
||||
else:
|
||||
logger.info("Model is not installed.")
|
||||
|
||||
|
||||
def iscloned():
|
||||
if os.path.exists(".git"):
|
||||
return True
|
||||
else:
|
||||
logger.error(f"{_('not_cloned')}")
|
||||
print(f"{RED}{(_('not_cloned'))}{RESET}")
|
||||
sys.exit(1)
|
||||
|
||||
def check_missing_translations():
|
||||
if LOCALE == "en":
|
||||
print("Locale is English, skipping missing key check.")
|
||||
return
|
||||
load_translations()
|
||||
|
||||
en_keys = set(translations.get("en", {}).keys())
|
||||
locale_keys = set(translations.get(LOCALE, {}).keys())
|
||||
|
||||
missing_keys = en_keys - locale_keys
|
||||
total_keys = len(en_keys)
|
||||
missing_count = len(missing_keys)
|
||||
|
||||
if missing_count > 0:
|
||||
percent_missing = (missing_count / total_keys) * 100
|
||||
print(f"{YELLOW}Warning: {missing_count}/{total_keys} keys missing in locale '{LOCALE}' ({percent_missing:.1f}%)!{RESET}")
|
||||
for key in sorted(missing_keys):
|
||||
print(f" - {key}")
|
||||
time.sleep(5)
|
||||
else:
|
||||
print("All translation keys present for locale:", LOCALE)
|
||||
|
||||
|
||||
|
||||
def get_stdlib_modules():
|
||||
stdlib_path = pathlib.Path(sysconfig.get_paths()['stdlib'])
|
||||
modules = set()
|
||||
|
@ -59,26 +73,47 @@ def check_requirements():
|
|||
PACKAGE_ALIASES = {
|
||||
"discord": "discord.py",
|
||||
"better_profanity": "better-profanity",
|
||||
"dotenv": "python-dotenv",
|
||||
"pil": "pillow"
|
||||
}
|
||||
|
||||
parent_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
requirements_path = os.path.abspath(os.path.join(parent_dir, '..', 'requirements.txt'))
|
||||
|
||||
if not os.path.exists(requirements_path):
|
||||
logger.error(f"{(_('requirements_not_found')).format(path=requirements_path)}")
|
||||
print(f"{RED}{(_('requirements_not_found')).format(path=requirements_path)}{RESET}")
|
||||
return
|
||||
|
||||
with open(requirements_path, 'r') as f:
|
||||
lines = f.readlines()
|
||||
requirements = set()
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if line and not line.startswith('#'):
|
||||
base_pkg = line.split('==')[0].lower()
|
||||
aliased_pkg = PACKAGE_ALIASES.get(base_pkg, base_pkg)
|
||||
requirements.add(aliased_pkg)
|
||||
requirements = {
|
||||
line.strip() for line in lines
|
||||
if line.strip() and not line.startswith('#')
|
||||
}
|
||||
|
||||
cogs_dir = os.path.abspath(os.path.join(parent_dir, '..', 'assets', 'cogs'))
|
||||
if os.path.isdir(cogs_dir):
|
||||
for filename in os.listdir(cogs_dir):
|
||||
if filename.endswith('.py'):
|
||||
filepath = os.path.join(cogs_dir, filename)
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
try:
|
||||
tree = ast.parse(f.read(), filename=filename)
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, ast.Import):
|
||||
for alias in node.names:
|
||||
pkg = alias.name.split('.')[0]
|
||||
if pkg in STD_LIB_MODULES or pkg == 'modules':
|
||||
continue
|
||||
requirements.add(pkg)
|
||||
elif isinstance(node, ast.ImportFrom):
|
||||
if node.module:
|
||||
pkg = node.module.split('.')[0]
|
||||
if pkg in STD_LIB_MODULES or pkg == 'modules':
|
||||
continue
|
||||
requirements.add(pkg)
|
||||
except Exception as e:
|
||||
print(f"{YELLOW}{(_('warning_failed_parse_imports')).format(filename=filename, error=e)}{RESET}")
|
||||
else:
|
||||
print(f"{YELLOW}{(_('cogs_dir_not_found')).format(path=cogs_dir)}{RESET}")
|
||||
|
||||
installed_packages = {dist.metadata['Name'].lower() for dist in importlib.metadata.distributions()}
|
||||
missing = []
|
||||
|
@ -88,37 +123,43 @@ def check_requirements():
|
|||
print((_('std_lib_local_skipped')).format(package=req))
|
||||
continue
|
||||
|
||||
check_name = req.lower()
|
||||
check_name = PACKAGE_ALIASES.get(req, req).lower()
|
||||
|
||||
if check_name in installed_packages:
|
||||
logger.info(f"{_('ok_installed').format(package=check_name)} {check_name}")
|
||||
print(f"[ {GREEN}{(_('ok_installed')).format(package=check_name)}{RESET} ] {check_name}")
|
||||
else:
|
||||
logger.error(f"{(_('missing_package')).format(package=check_name)} {check_name} {(_('missing_package2'))}")
|
||||
print(f"[ {RED}{(_('missing_package')).format(package=check_name)}{RESET} ] {check_name} {(_('missing_package2'))}")
|
||||
missing.append(check_name)
|
||||
|
||||
if missing:
|
||||
logger.error(_('missing_packages_detected'))
|
||||
print(RED, _('missing_packages_detected'), RESET)
|
||||
for pkg in missing:
|
||||
print(f" - {pkg}")
|
||||
print((_('telling_goober_central')).format(url=VERSION_URL))
|
||||
payload = {
|
||||
"name": NAME,
|
||||
"version": local_version,
|
||||
"slash_commands": f"{slash_commands_enabled}\n\n**Error**\nMissing packages have been detected, Failed to start",
|
||||
"token": gooberTOKEN
|
||||
}
|
||||
try:
|
||||
requests.post(VERSION_URL + "/ping", json=payload)
|
||||
except Exception as e:
|
||||
print(f"{RED}{(_('failed_to_contact')).format(url=VERSION_URL, error=e)}{RESET}")
|
||||
sys.exit(1)
|
||||
else:
|
||||
logger.info(_('all_requirements_satisfied'))
|
||||
print(_('all_requirements_satisfied'))
|
||||
|
||||
def check_latency():
|
||||
host = "1.1.1.1"
|
||||
system = platform.system()
|
||||
|
||||
system = platform.system()
|
||||
if system == "Windows":
|
||||
cmd = ["ping", "-n", "1", "-w", "1000", host]
|
||||
latency_pattern = r"Average = (\d+)ms"
|
||||
|
||||
elif system == "Darwin":
|
||||
cmd = ["ping", "-c", "1", host]
|
||||
latency_pattern = r"time=([\d\.]+) ms"
|
||||
|
||||
else:
|
||||
cmd = ["ping", "-c", "1", "-W", "1", host]
|
||||
latency_pattern = r"time=([\d\.]+) ms"
|
||||
latency_pattern = r"time[=<]\s*([\d\.]+)\s*ms"
|
||||
|
||||
try:
|
||||
result = subprocess.run(
|
||||
|
@ -129,71 +170,82 @@ def check_latency():
|
|||
)
|
||||
|
||||
if result.returncode == 0:
|
||||
print(result.stdout)
|
||||
match = re.search(latency_pattern, result.stdout)
|
||||
if match:
|
||||
latency_ms = float(match.group(1))
|
||||
logger.info((_('ping_to')).format(host=host, latency=latency_ms))
|
||||
print((_('ping_to')).format(host=host, latency=latency_ms))
|
||||
if latency_ms > 300:
|
||||
logger.warning(f"{(_('high_latency'))}")
|
||||
print(f"{YELLOW}{(_('high_latency'))}{RESET}")
|
||||
else:
|
||||
logger.warning((_('could_not_parse_latency')))
|
||||
print(f"{YELLOW}{(_('could_not_parse_latency'))}{RESET}")
|
||||
else:
|
||||
print(result.stderr)
|
||||
logger.error(f"{(_('ping_failed')).format(host=host)}{RESET}")
|
||||
print(f"{RED}{(_('ping_failed')).format(host=host)}{RESET}")
|
||||
except Exception as e:
|
||||
logger.error((_('error_running_ping')).format(error=e))
|
||||
print(f"{RED}{(_('error_running_ping')).format(error=e)}{RESET}")
|
||||
|
||||
def check_memory():
|
||||
if psutilavaliable == False:
|
||||
return
|
||||
try:
|
||||
memory_info = psutil.virtual_memory() # type: ignore
|
||||
memory_info = psutil.virtual_memory()
|
||||
total_memory = memory_info.total / (1024 ** 3)
|
||||
used_memory = memory_info.used / (1024 ** 3)
|
||||
free_memory = memory_info.available / (1024 ** 3)
|
||||
|
||||
logger.info((_('memory_usage')).format(used=used_memory, total=total_memory, percent=(used_memory / total_memory) * 100))
|
||||
print((_('memory_usage')).format(used=used_memory, total=total_memory, percent=(used_memory / total_memory) * 100))
|
||||
if used_memory > total_memory * 0.9:
|
||||
print(f"{YELLOW}{(_('memory_above_90')).format(percent=(used_memory / total_memory) * 100)}{RESET}")
|
||||
logger.info((_('total_memory')).format(total=total_memory))
|
||||
logger.info((_('used_memory')).format(used=used_memory))
|
||||
print((_('total_memory')).format(total=total_memory))
|
||||
print((_('used_memory')).format(used=used_memory))
|
||||
if free_memory < 1:
|
||||
logger.warning(f"{(_('low_free_memory')).format(free=free_memory)}")
|
||||
print(f"{RED}{(_('low_free_memory')).format(free=free_memory)}{RESET}")
|
||||
sys.exit(1)
|
||||
except ImportError:
|
||||
logger.error(_('psutil_not_installed')) # todo: translate this into italian and put it in the translations "psutil is not installed. Memory check skipped."
|
||||
print(_('psutil_not_installed')) # todo: translate this into italian and put it in the translations "psutil is not installed. Memory check skipped."
|
||||
|
||||
def check_cpu():
|
||||
if psutilavaliable == False:
|
||||
return
|
||||
logger.info((_('measuring_cpu')))
|
||||
cpu_per_core = psutil.cpu_percent(interval=1, percpu=True) # type: ignore
|
||||
print((_('measuring_cpu')))
|
||||
cpu_per_core = psutil.cpu_percent(interval=1, percpu=True)
|
||||
for idx, core_usage in enumerate(cpu_per_core):
|
||||
bar_length = int(core_usage / 5)
|
||||
bar = '█' * bar_length + '-' * (20 - bar_length)
|
||||
if core_usage > 85:
|
||||
color = RED
|
||||
elif core_usage > 60:
|
||||
color = YELLOW
|
||||
else:
|
||||
color = GREEN
|
||||
print((_('core_usage')).format(idx=idx, bar=bar, usage=core_usage))
|
||||
total_cpu = sum(cpu_per_core) / len(cpu_per_core)
|
||||
logger.info((_('total_cpu_usage')).format(usage=total_cpu))
|
||||
print((_('total_cpu_usage')).format(usage=total_cpu))
|
||||
if total_cpu > 85:
|
||||
logger.warning(f"{(_('high_avg_cpu')).format(usage=total_cpu)}")
|
||||
print(f"{YELLOW}{(_('high_avg_cpu')).format(usage=total_cpu)}{RESET}")
|
||||
if total_cpu > 95:
|
||||
logger.error(_('really_high_cpu'))
|
||||
print(f"{RED}{(_('really_high_cpu'))}{RESET}")
|
||||
sys.exit(1)
|
||||
|
||||
def check_memoryjson():
|
||||
try:
|
||||
logger.info((_('memory_file')).format(size=os.path.getsize(MEMORY_FILE) / (1024 ** 2)))
|
||||
print((_('memory_file')).format(size=os.path.getsize(MEMORY_FILE) / (1024 ** 2)))
|
||||
if os.path.getsize(MEMORY_FILE) > 1_073_741_824:
|
||||
logger.warning(f"{(_('memory_file_large'))}")
|
||||
print(f"{YELLOW}{(_('memory_file_large'))}{RESET}")
|
||||
try:
|
||||
with open(MEMORY_FILE, 'r', encoding='utf-8') as f:
|
||||
json.load(f)
|
||||
except json.JSONDecodeError as e:
|
||||
logger.error(f"{(_('memory_file_corrupted')).format(error=e)}")
|
||||
logger.warning(f"{(_('consider_backup_memory'))}")
|
||||
print(f"{RED}{(_('memory_file_corrupted')).format(error=e)}{RESET}")
|
||||
print(f"{YELLOW}{(_('consider_backup_memory'))}{RESET}")
|
||||
except UnicodeDecodeError as e:
|
||||
logger.error(f"{(_('memory_file_encoding')).format(error=e)}")
|
||||
logger.warning(f"{(_('consider_backup_memory'))}")
|
||||
print(f"{RED}{(_('memory_file_encoding')).format(error=e)}{RESET}")
|
||||
print(f"{YELLOW}{(_('consider_backup_memory'))}{RESET}")
|
||||
except Exception as e:
|
||||
logger.error(f"{(_('error_reading_memory')).format(error=e)}")
|
||||
print(f"{RED}{(_('error_reading_memory')).format(error=e)}{RESET}")
|
||||
except FileNotFoundError:
|
||||
logger(f"{(_('memory_file_not_found'))}")
|
||||
print(f"{YELLOW}{(_('memory_file_not_found'))}{RESET}")
|
||||
|
||||
def presskey2skip(timeout):
|
||||
if os.name == 'nt':
|
||||
|
@ -229,10 +281,9 @@ def presskey2skip(timeout):
|
|||
beta = beta
|
||||
def start_checks():
|
||||
if CHECKS_DISABLED == "True":
|
||||
logger.warning(f"{(_('checks_disabled'))}")
|
||||
print(f"{YELLOW}{(_('checks_disabled'))}{RESET}")
|
||||
return
|
||||
logger.info(_('running_prestart_checks'))
|
||||
check_for_model()
|
||||
print(_('running_prestart_checks'))
|
||||
iscloned()
|
||||
check_missing_translations()
|
||||
check_requirements()
|
||||
|
@ -243,13 +294,13 @@ def start_checks():
|
|||
if os.path.exists(".env"):
|
||||
pass
|
||||
else:
|
||||
logger.warning(f"{(_('env_file_not_found'))}")
|
||||
print(f"{YELLOW}{(_('env_file_not_found'))}{RESET}")
|
||||
sys.exit(1)
|
||||
if beta == True:
|
||||
logger.warning(f"this build isnt finished yet, some things might not work as expected")
|
||||
print(f"{YELLOW}this build isnt finished yet, some things might not work as expected{RESET}")
|
||||
else:
|
||||
pass
|
||||
logger.info(_('continuing_in_seconds').format(seconds=5))
|
||||
print(_('continuing_in_seconds').format(seconds=5))
|
||||
presskey2skip(timeout=5)
|
||||
os.system('cls' if os.name == 'nt' else 'clear')
|
||||
print(splashtext)
|
|
@ -5,34 +5,29 @@ from modules.volta.main import _
|
|||
import spacy
|
||||
from spacy.tokens import Doc
|
||||
from spacytextblob.spacytextblob import SpacyTextBlob
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger("goober")
|
||||
|
||||
nlp = spacy.load("en_core_web_sm")
|
||||
nlp.add_pipe("spacytextblob")
|
||||
Doc.set_extension("polarity", getter=lambda doc: doc._.blob.polarity)
|
||||
|
||||
def check_resources():
|
||||
try:
|
||||
nlp = spacy.load("en_core_web_sm")
|
||||
except OSError:
|
||||
logging.critical((_('spacy_model_not_found')))
|
||||
print((_('spacy_model_not_found')))
|
||||
spacy.cli.download("en_core_web_sm")
|
||||
nlp = spacy.load("en_core_web_sm")
|
||||
if "spacytextblob" not in nlp.pipe_names:
|
||||
nlp.add_pipe("spacytextblob")
|
||||
logger.info((_('spacy_initialized')))
|
||||
print((_('spacy_initialized')))
|
||||
|
||||
check_resources()
|
||||
|
||||
nlp = spacy.load("en_core_web_sm")
|
||||
nlp.add_pipe("spacytextblob")
|
||||
Doc.set_extension("polarity", getter=lambda doc: doc._.blob.polarity)
|
||||
|
||||
def is_positive(sentence):
|
||||
doc = nlp(sentence)
|
||||
sentiment_score = doc._.polarity # from spacytextblob
|
||||
|
||||
debug_message = f"{(_('sentence_positivity'))} {sentiment_score}{RESET}"
|
||||
logger.debug(debug_message)
|
||||
debug_message = f"{DEBUG}{(_('sentence_positivity'))} {sentiment_score}{RESET}"
|
||||
print(debug_message)
|
||||
|
||||
return sentiment_score > 0.6 # had to raise the bar because it kept saying "death to jews" was fine and it kept reacting to them
|
||||
|
||||
|
@ -61,15 +56,20 @@ async def send_message(ctx, message=None, embed=None, file=None, edit=False, mes
|
|||
sent_message = await ctx.send(file=file)
|
||||
return sent_message
|
||||
|
||||
def append_mentions_to_18digit_integer(message):
|
||||
pattern = r'\b\d{18}\b'
|
||||
return re.sub(pattern, lambda match: "", message)
|
||||
|
||||
def preprocess_message(message):
|
||||
message = message
|
||||
message = append_mentions_to_18digit_integer(message)
|
||||
doc = nlp(message)
|
||||
tokens = [token.text for token in doc if token.is_alpha or token.is_digit]
|
||||
return " ".join(tokens)
|
||||
|
||||
def improve_sentence_coherence(sentence):
|
||||
return ""
|
||||
return re.sub(r'\bi\b', 'I', sentence)
|
||||
|
||||
def rephrase_for_coherence(sentence):
|
||||
coherent_sentence = sentence
|
||||
words = sentence.split()
|
||||
coherent_sentence = " ".join(words)
|
||||
return coherent_sentence
|
||||
|
|
|
@ -3,12 +3,6 @@ from modules.globalvars import *
|
|||
import requests
|
||||
import subprocess
|
||||
import sys
|
||||
import logging
|
||||
import json
|
||||
import time
|
||||
import random
|
||||
logger = logging.getLogger("goober")
|
||||
launched = False
|
||||
|
||||
# Run a shell command and return its output
|
||||
def run_cmd(cmd):
|
||||
|
@ -31,51 +25,34 @@ def auto_update(branch='main', remote='origin'):
|
|||
if is_remote_ahead(branch, remote):
|
||||
print(_( "remote_ahead").format(remote=remote, branch=branch))
|
||||
pull_result = run_cmd(f'git pull {remote} {branch}')
|
||||
logger.info(pull_result)
|
||||
logger.info(_( "please_restart"))
|
||||
print(pull_result)
|
||||
print(_( "please_restart"))
|
||||
sys.exit(0)
|
||||
else:
|
||||
logger.info(_( "local_ahead").format(remote=remote, branch=branch))
|
||||
print(_( "local_ahead").format(remote=remote, branch=branch))
|
||||
|
||||
# Fetch the latest version info from the update server
|
||||
def get_latest_version_info():
|
||||
try:
|
||||
unique_suffix = f"{int(time.time())}_{random.randint(0, 9999)}"
|
||||
url = f"{UPDATE_URL}?_={unique_suffix}"
|
||||
|
||||
curl_cmd = [
|
||||
"curl",
|
||||
"-s",
|
||||
"-H", "Cache-Control: no-cache",
|
||||
"-H", "Pragma: no-cache",
|
||||
url
|
||||
]
|
||||
|
||||
result = subprocess.run(curl_cmd, capture_output=True, text=True, timeout=5)
|
||||
content = result.stdout
|
||||
|
||||
if result.returncode != 0:
|
||||
logger.error(f"curl failed with return code {result.returncode}")
|
||||
response = requests.get(UPDATE_URL, timeout=5)
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
else:
|
||||
print(f"{RED}{_( 'version_error')} {response.status_code}{RESET}")
|
||||
return None
|
||||
|
||||
try:
|
||||
data = json.loads(content)
|
||||
return data
|
||||
except json.JSONDecodeError:
|
||||
logger.error("JSON decode failed")
|
||||
logger.error(content[:500])
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Exception in get_latest_version_info: {e}")
|
||||
except requests.RequestException as e:
|
||||
print(f"{RED}{_( 'version_error')} {e}{RESET}")
|
||||
return None
|
||||
|
||||
# Check if an update is available and perform update if needed
|
||||
def check_for_update():
|
||||
global latest_version, local_version, launched
|
||||
def check_for_update():
|
||||
if ALIVEPING != "True":
|
||||
return
|
||||
global latest_version, local_version
|
||||
|
||||
latest_version_info = get_latest_version_info()
|
||||
if not latest_version_info:
|
||||
logger.error(f"{_('fetch_update_fail')}")
|
||||
print(f"{_('fetch_update_fail')}")
|
||||
return None, None
|
||||
|
||||
latest_version = latest_version_info.get("version")
|
||||
|
@ -83,23 +60,24 @@ def check_for_update():
|
|||
download_url = latest_version_info.get("download_url")
|
||||
|
||||
if not latest_version or not download_url:
|
||||
logger.error(f"{RED}{_('invalid_server')}{RESET}")
|
||||
print(f"{RED}{_(LOCALE, 'invalid_server')}{RESET}")
|
||||
return None, None
|
||||
|
||||
# Check if local_version is valid
|
||||
if local_version == "0.0.0" or None:
|
||||
logger.error(f"{RED}{_('cant_find_local_version')}{RESET}")
|
||||
print(f"{RED}{_('cant_find_local_version')}{RESET}")
|
||||
return
|
||||
|
||||
# Compare local and latest versions
|
||||
if local_version < latest_version:
|
||||
logger.info(f"{YELLOW}{_('new_version').format(latest_version=latest_version, local_version=local_version)}{RESET}")
|
||||
logger.info(f"{YELLOW}{_('changelog').format(VERSION_URL=VERSION_URL)}{RESET}")
|
||||
print(f"{YELLOW}{_('new_version').format(latest_version=latest_version, local_version=local_version)}{RESET}")
|
||||
print(f"{YELLOW}{_('changelog').format(VERSION_URL=VERSION_URL)}{RESET}")
|
||||
auto_update()
|
||||
elif beta == True:
|
||||
logger.warning(f"You are running an \"unstable\" version of Goober, do not expect it to work properly.\nVersion {local_version}\nServer: {latest_version}{RESET}")
|
||||
elif local_version > latest_version and beta == True:
|
||||
print(f"{YELLOW}You are running an \"unstable\" version of Goober, do not expect it to work properly.\nVersion {local_version}{RESET}")
|
||||
elif local_version > latest_version:
|
||||
logger.warning(f"{_('modification_warning')}")
|
||||
print(f"{YELLOW}{_('modification_warning')}{RESET}")
|
||||
elif local_version == latest_version:
|
||||
logger.info(f"{_('latest_version')} {local_version}")
|
||||
logger.info(f"{_('latest_version2').format(VERSION_URL=VERSION_URL)}\n\n")
|
||||
launched = True
|
||||
print(f"{GREEN}{_('latest_version')} {local_version}{RESET}")
|
||||
print(f"{_('latest_version2').format(VERSION_URL=VERSION_URL)}\n\n")
|
||||
return latest_version
|
|
@ -3,15 +3,11 @@
|
|||
# For updates or contributions, visit: https://github.com/gooberinc/volta
|
||||
# Also, Note to self: Add more comments it needs more love
|
||||
import os
|
||||
import locale
|
||||
import json
|
||||
import pathlib
|
||||
import threading
|
||||
import platform
|
||||
import sys
|
||||
import time
|
||||
from dotenv import load_dotenv
|
||||
from functools import lru_cache
|
||||
|
||||
ANSI = "\033["
|
||||
RED = f"{ANSI}31m"
|
||||
|
@ -20,16 +16,15 @@ YELLOW = f"{ANSI}33m"
|
|||
DEBUG = f"{ANSI}1;30m"
|
||||
RESET = f"{ANSI}0m"
|
||||
|
||||
LOCALE = os.getenv("LOCALE")
|
||||
load_dotenv()
|
||||
|
||||
LOCALE = os.getenv("locale")
|
||||
module_dir = pathlib.Path(__file__).parent.parent
|
||||
working_dir = pathlib.Path.cwd()
|
||||
EXCLUDE_DIRS = {'.git', '__pycache__'}
|
||||
|
||||
locales_dirs = []
|
||||
ENGLISH_MISSING = False
|
||||
FALLBACK_LOCALE = "en"
|
||||
if os.getenv("fallback_locale"):
|
||||
FALLBACK_LOCALE = os.getenv("fallback_locale")
|
||||
|
||||
def find_locales_dirs(base_path):
|
||||
found = []
|
||||
for root, dirs, files in os.walk(base_path):
|
||||
|
@ -41,22 +36,6 @@ def find_locales_dirs(base_path):
|
|||
dirs.remove('locales')
|
||||
return found
|
||||
|
||||
def find_dotenv(start_path: pathlib.Path) -> pathlib.Path | None:
|
||||
current = start_path.resolve()
|
||||
while current != current.parent:
|
||||
candidate = current / ".env"
|
||||
if candidate.exists():
|
||||
return candidate
|
||||
current = current.parent
|
||||
return None
|
||||
|
||||
env_path = find_dotenv(pathlib.Path(__file__).parent)
|
||||
if env_path:
|
||||
load_dotenv(dotenv_path=env_path)
|
||||
print(f"[VOLTA] {GREEN}Loaded .env from {env_path}{RESET}")
|
||||
else:
|
||||
print(f"[VOLTA] {YELLOW}No .env file found from {__file__} upwards.{RESET}")
|
||||
|
||||
locales_dirs.extend(find_locales_dirs(module_dir))
|
||||
if working_dir != module_dir:
|
||||
locales_dirs.extend(find_locales_dirs(working_dir))
|
||||
|
@ -64,33 +43,6 @@ if working_dir != module_dir:
|
|||
translations = {}
|
||||
_file_mod_times = {}
|
||||
|
||||
|
||||
def get_system_locale():
|
||||
system = platform.system() # fallback incase locale isnt set
|
||||
if system == "Windows":
|
||||
lang, _ = locale.getdefaultlocale()
|
||||
return lang or os.getenv("LANG")
|
||||
elif system == "Darwin":
|
||||
try:
|
||||
import subprocess
|
||||
result = subprocess.run(
|
||||
["defaults", "read", "-g", "AppleLocale"],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.DEVNULL,
|
||||
text=True
|
||||
)
|
||||
return result.stdout.strip() or locale.getdefaultlocale()[0]
|
||||
except Exception:
|
||||
return locale.getdefaultlocale()[0]
|
||||
elif system == "Linux":
|
||||
return (
|
||||
os.getenv("LC_ALL") or
|
||||
os.getenv("LANG") or
|
||||
locale.getdefaultlocale()[0]
|
||||
)
|
||||
return locale.getdefaultlocale()[0]
|
||||
|
||||
|
||||
def load_translations():
|
||||
global translations, _file_mod_times
|
||||
translations.clear()
|
||||
|
@ -118,7 +70,6 @@ def reload_if_changed():
|
|||
current_mtime = file_path.stat().st_mtime
|
||||
if current_mtime != last_mtime:
|
||||
print(f"[VOLTA] {RED}Translation file changed: {file_path}, reloading...{RESET}")
|
||||
_lookup_translation.cache_clear()
|
||||
load_translations()
|
||||
break
|
||||
except FileNotFoundError:
|
||||
|
@ -128,81 +79,21 @@ def reload_if_changed():
|
|||
translations.pop(lang_code, None)
|
||||
|
||||
def set_language(lang: str):
|
||||
global LOCALE, ENGLISH_MISSING
|
||||
if not LOCALE:
|
||||
LOCALE = get_system_locale()
|
||||
elif lang in translations:
|
||||
global LOCALE
|
||||
if lang in translations:
|
||||
LOCALE = lang
|
||||
else:
|
||||
print(f"[VOLTA] {RED}Language '{lang}' not found, defaulting to 'en'{RESET}")
|
||||
if FALLBACK_LOCALE in translations:
|
||||
LOCALE = FALLBACK_LOCALE
|
||||
else:
|
||||
print(f"[VOLTA] {RED}The fallback translations cannot be found! No fallback available.{RESET}")
|
||||
ENGLISH_MISSING = True
|
||||
_lookup_translation.cache_clear()
|
||||
|
||||
def check_missing_translations(LOCALE=LOCALE):
|
||||
global ENGLISH_MISSING
|
||||
load_translations()
|
||||
if FALLBACK_LOCALE not in translations:
|
||||
print(f"[VOLTA] {RED}Fallback translations ({FALLBACK_LOCALE}.json) missing from assets/locales.{RESET}")
|
||||
ENGLISH_MISSING = True
|
||||
return
|
||||
if LOCALE == "en":
|
||||
print("[VOLTA] Locale is English, skipping missing key check.")
|
||||
return
|
||||
|
||||
|
||||
en_keys = set(translations.get("en", {}).keys())
|
||||
locale_keys = set(translations.get(LOCALE, {}).keys())
|
||||
|
||||
missing_keys = en_keys - locale_keys
|
||||
total_keys = len(en_keys)
|
||||
missing_count = len(missing_keys)
|
||||
|
||||
if missing_count > 0:
|
||||
percent_missing = (missing_count / total_keys) * 100
|
||||
if percent_missing == 100:
|
||||
print(f"[VOLTA] {YELLOW}Warning: All keys are missing in locale '{LOCALE}'! Defaulting back to {FALLBACK_LOCALE}{RESET}")
|
||||
set_language(FALLBACK_LOCALE)
|
||||
elif percent_missing > 0:
|
||||
print(f"[VOLTA] {YELLOW}Warning: {missing_count}/{total_keys} keys missing in locale '{LOCALE}' ({percent_missing:.1f}%)!{RESET}")
|
||||
for key in sorted(missing_keys):
|
||||
print(f" - {key}")
|
||||
time.sleep(2)
|
||||
else:
|
||||
print(f"[VOLTA] All translation keys present for locale: {LOCALE}")
|
||||
|
||||
printedsystemfallback = False
|
||||
|
||||
@lru_cache(maxsize=600)
|
||||
def _lookup_translation(lang: str, key: str):
|
||||
return translations.get(lang, {}).get(key)
|
||||
LOCALE = "en"
|
||||
|
||||
def get_translation(lang: str, key: str):
|
||||
global printedsystemfallback
|
||||
if ENGLISH_MISSING:
|
||||
return f"[VOLTA] {RED}No fallback available!{RESET}"
|
||||
lang_translations = translations.get(lang, {})
|
||||
if key in lang_translations:
|
||||
return lang_translations[key]
|
||||
fallback = translations.get("en", {}).get(key, key)
|
||||
print(f"[VOLTA] {RED}Missing key: '{key}' in language '{lang}', falling back to: '{fallback}'{RESET}") # yeah probably print this
|
||||
return fallback
|
||||
|
||||
val = _lookup_translation(lang, key)
|
||||
if val:
|
||||
return val
|
||||
sys_lang = get_system_locale().split("_")[0] if get_system_locale() else None
|
||||
if sys_lang and sys_lang != lang:
|
||||
sys_val = _lookup_translation(sys_lang, key)
|
||||
if sys_val:
|
||||
if not printedsystemfallback:
|
||||
print(f"[VOLTA] {YELLOW}Falling back to system language {sys_lang}!{RESET}")
|
||||
printedsystemfallback = True
|
||||
return sys_val
|
||||
fallback_val = _lookup_translation(FALLBACK_LOCALE, key)
|
||||
if fallback_val:
|
||||
print(f"[VOLTA] {YELLOW}Missing key: '{key}' in '{lang}', falling back to fallback locale '{FALLBACK_LOCALE}'{RESET}")
|
||||
return fallback_val
|
||||
|
||||
return f"[VOLTA] {YELLOW}Missing key: '{key}' in all locales!{RESET}"
|
||||
|
||||
def _(key: str) -> str:
|
||||
return get_translation(LOCALE, key)
|
||||
|
||||
|
@ -210,11 +101,3 @@ load_translations()
|
|||
|
||||
watchdog_thread = threading.Thread(target=reload_if_changed, daemon=True)
|
||||
watchdog_thread.start()
|
||||
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("LOCALE", help="Locale to validate")
|
||||
args = parser.parse_args()
|
||||
print("[VOLTA] Validating all locales....")
|
||||
check_missing_translations(LOCALE=f"{args.LOCALE}")
|
||||
|
|
|
@ -4,6 +4,6 @@ spacy
|
|||
spacytextblob
|
||||
requests
|
||||
psutil
|
||||
better_profanity
|
||||
python-dotenv
|
||||
dotenv
|
||||
pillow
|
|
@ -1,3 +1,3 @@
|
|||
- The catbox.moe team for memory.json file uploads
|
||||
- Charlie's Computers
|
||||
- ctih1
|
||||
The catbox.moe team
|
||||
Charlie's Computers
|
||||
ctih1
|
||||
|
|
2
todo.txt
2
todo.txt
|
@ -1,2 +1,4 @@
|
|||
- fix missing translations in some cases
|
||||
- revamp wiki
|
||||
- clean the rest
|
||||
- alot
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue