Merge pull request #9 from gooberinc/dev

Dev
This commit is contained in:
WhatDidYouExpect 2025-07-07 17:19:56 +02:00 committed by GitHub
commit 2b4c6bcf14
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 104 additions and 51 deletions

View file

@ -112,6 +112,7 @@
"command_ran": "Info: {message.author.name} ran {message.content}", "command_ran": "Info: {message.author.name} ran {message.content}",
"command_ran_s": "Info: {interaction.user} ran ", "command_ran_s": "Info: {interaction.user} ran ",
"command_desc_ping": "ping", "command_desc_ping": "ping",
"command_desc_setlang": "Set a new language for the bot (temporarily)",
"command_ping_embed_desc": "Bot Latency:", "command_ping_embed_desc": "Bot Latency:",
"command_ping_footer": "Requested by", "command_ping_footer": "Requested by",
"command_about_desc": "about", "command_about_desc": "about",

View file

@ -113,6 +113,7 @@
"command_ran": "Info: {message.author.name} ha eseguito {message.content}", "command_ran": "Info: {message.author.name} ha eseguito {message.content}",
"command_ran_s": "Info: {interaction.user} ha eseguito ", "command_ran_s": "Info: {interaction.user} ha eseguito ",
"command_desc_ping": "ping", "command_desc_ping": "ping",
"command_desc_setlang": "Imposta una nuova lingua per il bot (temporaneamente)",
"command_ping_embed_desc": "Latenza del bot:", "command_ping_embed_desc": "Latenza del bot:",
"command_ping_footer": "Richiesto da", "command_ping_footer": "Richiesto da",
"command_about_desc": "informazioni", "command_about_desc": "informazioni",

17
bot.py
View file

@ -23,6 +23,7 @@ import requests
import discord import discord
from discord.ext import commands from discord.ext import commands
from discord import app_commands
from discord import Colour, Embed, File, Interaction, Message from discord import Colour, Embed, File, Interaction, Message
from discord.abc import Messageable from discord.abc import Messageable
@ -30,7 +31,7 @@ from better_profanity import profanity
from discord.ext import commands from discord.ext import commands
from modules.central import ping_server from modules.central import ping_server
from modules.volta.main import _ from modules.volta.main import _, set_language
from modules.markovmemory import * from modules.markovmemory import *
from modules.version import * from modules.version import *
from modules.sentenceprocessing import * from modules.sentenceprocessing import *
@ -334,8 +335,8 @@ async def help(ctx: commands.Context) -> None:
) )
command_categories: Dict[str, List[str]] = { command_categories: Dict[str, List[str]] = {
f"{(_('command_help_categories_general'))}": ["mem", "talk", "about", "ping", "image"], f"{(_('command_help_categories_general'))}": ["mem", "talk", "about", "ping", "impact", "demotivator", "help"],
f"{(_('command_help_categories_admin'))}": ["stats", "retrain"] f"{(_('command_help_categories_admin'))}": ["stats", "retrain", "setlanguage"]
} }
custom_commands: List[str] = [] custom_commands: List[str] = []
@ -353,6 +354,16 @@ async def help(ctx: commands.Context) -> None:
await send_message(ctx, embed=embed) 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 # Event: Called on every message
@bot.event @bot.event
async def on_message(message: discord.Message) -> None: async def on_message(message: discord.Message) -> None:

View file

@ -37,7 +37,7 @@ 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 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 launched = False
latest_version = "0.0.0" latest_version = "0.0.0"
local_version = "2.0.1" local_version = "2.0.2"
os.environ['gooberlocal_version'] = local_version os.environ['gooberlocal_version'] = local_version
REACT = os.getenv("REACT") REACT = os.getenv("REACT")
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 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

View file

@ -26,16 +26,6 @@ def load_memory():
except FileNotFoundError: except FileNotFoundError:
pass 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 return data
# Save memory data to MEMORY_FILE # Save memory data to MEMORY_FILE

View file

@ -1,6 +1,5 @@
from modules.globalvars import * from modules.globalvars import *
from modules.volta.main import _, get_translation, load_translations, set_language, translations from modules.volta.main import _, check_missing_translations
import time import time
import os import os
import sys import sys
@ -9,6 +8,7 @@ import sysconfig
import ast import ast
import json import json
import re import re
from spacy.util import is_package
import importlib.metadata import importlib.metadata
# import shutil # import shutil
@ -20,6 +20,13 @@ except ImportError:
psutilavaliable = False psutilavaliable = False
print(RED, _('missing_requests_psutil'), RESET) print(RED, _('missing_requests_psutil'), RESET)
def check_for_model():
if is_package("en_core_web_sm"):
print("Model is installed.")
else:
print("Model is not installed.")
def iscloned(): def iscloned():
if os.path.exists(".git"): if os.path.exists(".git"):
return True return True
@ -27,30 +34,6 @@ def iscloned():
print(f"{RED}{(_('not_cloned'))}{RESET}") print(f"{RED}{(_('not_cloned'))}{RESET}")
sys.exit(1) 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(): def get_stdlib_modules():
stdlib_path = pathlib.Path(sysconfig.get_paths()['stdlib']) stdlib_path = pathlib.Path(sysconfig.get_paths()['stdlib'])
modules = set() modules = set()
@ -73,6 +56,7 @@ def check_requirements():
PACKAGE_ALIASES = { PACKAGE_ALIASES = {
"discord": "discord.py", "discord": "discord.py",
"better_profanity": "better-profanity", "better_profanity": "better-profanity",
"dotenv": "python-dotenv"
} }
parent_dir = os.path.dirname(os.path.abspath(__file__)) parent_dir = os.path.dirname(os.path.abspath(__file__))
@ -284,6 +268,7 @@ def start_checks():
print(f"{YELLOW}{(_('checks_disabled'))}{RESET}") print(f"{YELLOW}{(_('checks_disabled'))}{RESET}")
return return
print(_('running_prestart_checks')) print(_('running_prestart_checks'))
check_for_model()
iscloned() iscloned()
check_missing_translations() check_missing_translations()
check_requirements() check_requirements()

View file

@ -5,9 +5,7 @@ from modules.volta.main import _
import spacy import spacy
from spacy.tokens import Doc from spacy.tokens import Doc
from spacytextblob.spacytextblob import SpacyTextBlob from spacytextblob.spacytextblob import SpacyTextBlob
nlp = spacy.load("en_core_web_sm")
nlp.add_pipe("spacytextblob")
Doc.set_extension("polarity", getter=lambda doc: doc._.blob.polarity)
def check_resources(): def check_resources():
try: try:
@ -22,6 +20,10 @@ def check_resources():
check_resources() 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): def is_positive(sentence):
doc = nlp(sentence) doc = nlp(sentence)
sentiment_score = doc._.polarity # from spacytextblob sentiment_score = doc._.polarity # from spacytextblob

View file

@ -19,8 +19,6 @@ def is_remote_ahead(branch='main', remote='origin'):
# Automatically update the local repository if the remote is ahead # Automatically update the local repository if the remote is ahead
def auto_update(branch='main', remote='origin'): def auto_update(branch='main', remote='origin'):
if launched == True:
return
if launched == True: if launched == True:
print(_("already_started")) print(_("already_started"))
return return
@ -77,7 +75,7 @@ def check_for_update():
print(f"{YELLOW}{_('new_version').format(latest_version=latest_version, local_version=local_version)}{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}") print(f"{YELLOW}{_('changelog').format(VERSION_URL=VERSION_URL)}{RESET}")
auto_update() auto_update()
elif local_version > latest_version and beta == True: elif beta == True:
print(f"{YELLOW}You are running an \"unstable\" version of Goober, do not expect it to work properly.\nVersion {local_version}{RESET}") 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: elif local_version > latest_version:
print(f"{YELLOW}{_('modification_warning')}{RESET}") print(f"{YELLOW}{_('modification_warning')}{RESET}")

View file

@ -24,7 +24,10 @@ working_dir = pathlib.Path.cwd()
EXCLUDE_DIRS = {'.git', '__pycache__'} EXCLUDE_DIRS = {'.git', '__pycache__'}
locales_dirs = [] 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): def find_locales_dirs(base_path):
found = [] found = []
for root, dirs, files in os.walk(base_path): for root, dirs, files in os.walk(base_path):
@ -36,6 +39,22 @@ def find_locales_dirs(base_path):
dirs.remove('locales') dirs.remove('locales')
return found 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)) locales_dirs.extend(find_locales_dirs(module_dir))
if working_dir != module_dir: if working_dir != module_dir:
locales_dirs.extend(find_locales_dirs(working_dir)) locales_dirs.extend(find_locales_dirs(working_dir))
@ -79,19 +98,61 @@ def reload_if_changed():
translations.pop(lang_code, None) translations.pop(lang_code, None)
def set_language(lang: str): def set_language(lang: str):
global LOCALE global LOCALE, ENGLISH_MISSING
if lang in translations: if lang in translations:
LOCALE = lang LOCALE = lang
else: else:
print(f"[VOLTA] {RED}Language '{lang}' not found, defaulting to 'en'{RESET}") print(f"[VOLTA] {RED}Language '{lang}' not found, defaulting to 'en'{RESET}")
LOCALE = "en" 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
def check_missing_translations():
global LOCALE, 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("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"{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("All translation keys present for locale:", LOCALE)
def get_translation(lang: str, key: str): def get_translation(lang: str, key: str):
if ENGLISH_MISSING:
return f"[VOLTA] {RED}No fallback available!{RESET}"
lang_translations = translations.get(lang, {}) lang_translations = translations.get(lang, {})
if key in lang_translations: if key in lang_translations:
return lang_translations[key] return lang_translations[key]
fallback = translations.get("en", {}).get(key, key) else:
print(f"[VOLTA] {RED}Missing key: '{key}' in language '{lang}', falling back to: '{fallback}'{RESET}") # yeah probably print this if key not in translations.get(FALLBACK_LOCALE, {}):
return f"[VOLTA] {YELLOW}Missing key: '{key}' in {FALLBACK_LOCALE}.json!{RESET}"
fallback = translations.get(FALLBACK_LOCALE, {}).get(key, key)
print(f"[VOLTA] {YELLOW}Missing key: '{key}' in language '{lang}', falling back to: '{fallback}' using {FALLBACK_LOCALE}.json{RESET}") # yeah probably print this
return fallback return fallback
def _(key: str) -> str: def _(key: str) -> str:
@ -101,3 +162,6 @@ load_translations()
watchdog_thread = threading.Thread(target=reload_if_changed, daemon=True) watchdog_thread = threading.Thread(target=reload_if_changed, daemon=True)
watchdog_thread.start() watchdog_thread.start()
if __name__ == '__main__':
print("Volta should not be run directly! Please use it as a module..")

View file

@ -6,4 +6,5 @@ requests
psutil psutil
better_profanity better_profanity
python-dotenv python-dotenv
dotenv
pillow pillow