commit
2b4c6bcf14
10 changed files with 104 additions and 51 deletions
|
@ -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",
|
||||||
|
|
|
@ -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
17
bot.py
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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}")
|
||||||
|
|
|
@ -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..")
|
||||||
|
|
|
@ -6,4 +6,5 @@ requests
|
||||||
psutil
|
psutil
|
||||||
better_profanity
|
better_profanity
|
||||||
python-dotenv
|
python-dotenv
|
||||||
|
dotenv
|
||||||
pillow
|
pillow
|
Loading…
Add table
Add a link
Reference in a new issue