Added language support to python. TODO: add language placeholders

This commit is contained in:
2025-06-18 21:10:51 +02:00
parent 2a951723b1
commit fcf95dd9eb
11 changed files with 87 additions and 27 deletions
+4
View File
@@ -11,6 +11,10 @@ subreddits = "bytedicetesting"
# How many posts the bot scans when running `/re_updatediscord`.
fetch_limit = 100
# A list of flairs the post must be tagged under to be scraped.
# Leave empty to search for everything
search_flairs = ["Original Art"]
[commands]
# Disabled selected command categories. All commands and their categories can be viewed in the README.
# "admin" and "owner" categories are always enabled.
+3 -1
View File
@@ -21,7 +21,9 @@ pub async fn cmd(
let d_str = toml::to_string(&d)?;
let r = send_cmd_json("update_cfg", Some(json!([d_str])), true).await;
if r.is_some() && r.unwrap()["value"].as_bool().unwrap() {
if r.is_none() { return Ok(()); }
if r.unwrap()["value"].as_bool().unwrap() {
send_msg(
ctx,
lang!("dc_msg_reload_cfg_success", toml::to_string_pretty(&d).unwrap()),
+3 -2
View File
@@ -4,7 +4,7 @@ use std::path::Path;
use serde_json::{self, Value, json};
use tokio::sync::Mutex;
use crate::{errln, rs_println, Data, Error, CFG_DATA_RE, LANG};
use crate::{errln, rs_println, Data, Error, CFG_DATA_RE, LANG, LANG_NAME};
use crate::websocket::send_cmd_json;
@@ -220,9 +220,10 @@ pub fn load_lang_data(lang: String) {
}
let str_data = fs::read_to_string(full_path).unwrap();
let json_data = serde_json::from_str(&str_data).unwrap();
let json_data: Option<Value> = serde_json::from_str(&str_data).unwrap();
unsafe {
LANG = json_data;
LANG_NAME = Some(lang);
};
}
+1
View File
@@ -95,6 +95,7 @@ struct Data {
static CFG_DATA_RE: &str = "posts";
pub static mut LANG_NAME: Option<String> = None;
pub static mut LANG: Option<serde_json::Value> = None;
pub static mut NOPING: bool = false;
+12 -2
View File
@@ -1,5 +1,5 @@
use crate::messages::send_dm;
use crate::{errln, lang, rs_println, Args};
use crate::{errln, lang, rs_println, Args, LANG_NAME};
use std::fs;
use std::ffi::CString;
@@ -21,7 +21,17 @@ pub async fn start(args: Args) -> PyResult<()> {
let code = get_code(&format!("{}{}main.py", path, slash));
let py_args = args_str.replace(":true", ":True").replace(":false", ":False");
let app_path = CString::new(format!("args = {}\n{}", py_args, code)).unwrap();
let app_path: CString;
unsafe {
app_path = CString::new(
format!("args = {}\nlang_name = {}\n{}",
py_args,
LANG_NAME.clone().unwrap(),
code
)
).unwrap();
}
let mut traceback: String = String::new();
let mut is_error = false;
+3 -3
View File
@@ -41,6 +41,7 @@ class Bot:
self.sr = None
self.data_f: TextIOWrapper = None
self.data: dict = {}
self.flairs: list[str] = []
async def initialize(self):
self.sr = await self.r.subreddit("+".join(self.sr_list))
@@ -58,13 +59,12 @@ class Bot:
async def update_cfg_str(self, new_cfg: str) -> bool:
json_cfg = toml.loads(new_cfg)
self.sr_list = json_cfg[CFG_DATA_RE]["subreddits"].split("+")
self.sr = await self.r.subreddit("+".join(self.sr_list))
self.fetch_limit = json_cfg[CFG_DATA_RE]["fetch_limit"]
self.update_cfg(json_cfg)
return True
async def update_cfg(self, new_cfg: dict) -> bool:
self.sr_list = new_cfg[CFG_DATA_RE]["subreddits"].split("+")
self.sr = await self.r.subreddit("+".join(self.sr_list))
self.fetch_limit = new_cfg[CFG_DATA_RE]["fetch_limit"]
self.flairs = new_cfg[CFG_DATA_RE]["search_flair"]
return True
+34
View File
@@ -1,5 +1,13 @@
import json
import os
from printColors import PrintColors
G_LANG_NAME: str = ""
G_LANG: dict[str, str] = {}
DATA_PATH_LANG: str = "./data/lang/"
def py_print(*args):
print(
PrintColors.FG.blue + "Py",
@@ -15,3 +23,29 @@ def py_error(*args):
" ".join(args) + PrintColors.Special.reset
)
quit()
def lang(k: str) -> str:
t = G_LANG.get(k)
if k is None: py_error(f"Key not found in language \"{G_LANG_NAME}\": {k}")
return str(t)
def init_lang(lang_name: str):
global G_LANG, G_LANG_NAME
G_LANG_NAME = lang_name
full_path = f"{DATA_PATH_LANG}{lang_name}.json"
if not os.path.exists(full_path):
py_error(f"File for language \"{lang_name}\" ({lang_name}.json) not found!\n Hint: You can download official language files at https://github.com/ByteDice/ByteDiceAssistant in the data/langs/... folder")
with open(full_path, "r") as f:
str_data = f.read()
try:
json_data = json.loads(str_data)
except json.JSONDecodeError as e:
py_error(f"Failed to parse JSON for language \"{lang_name}\":\n{e}")
G_LANG = json_data
+5 -2
View File
@@ -19,9 +19,12 @@ async def main():
# args is supposed to be undefined.
# It gets defined in Rust.
try: await bot.set_args(args)
try:
await bot.set_args(args)
init_lang(lang_name)
except NameError:
py_print("No command args found from Rust. Don't worry though, we have backup in place.")
py_print("No command args or language name found from Rust. Don't worry though, we have backup in place.")
init_lang("en")
if bot.args["dev"]:
py_print("ARGS:", str(bot.args))
+7 -3
View File
@@ -14,7 +14,7 @@ async def add_new_posts(bot: botPy.Bot, max_age: int) -> bool:
cross_emoji = emoji.emojize(":cross_mark:")
py_print("Fetching posts...")
posts = await fetch_posts_with_flair(bot, "Original Art")
posts = await fetch_posts_with_flair(bot, bot.flairs)
py_print("Evaluating posts...")
@@ -65,11 +65,15 @@ async def add_new_posts(bot: botPy.Bot, max_age: int) -> bool:
return True
async def fetch_posts_with_flair(bot: botPy.Bot, flair_name: str) -> list[models.Submission]:
async def fetch_posts_with_flair(bot: botPy.Bot, flair_names: list[str]) -> list[models.Submission]:
posts: list[models.Submission] = []
flair_names_str = \
f"flair:{flair_names[0]}" if len(flair_names) == 1\
else " OR ".join(f"flair:{flair}" for flair in flair_names)
# ~36 OG-art posts per week, round limit to 50, 75 or 100
async for post in bot.sr.search(f"flair:\"{flair_name}\"", sort="new", limit=bot.fetch_limit):
async for post in bot.sr.search(f"{flair_names_str}", sort="new", limit=bot.fetch_limit):
posts.append(post)
return posts
+3 -2
View File
@@ -7,6 +7,7 @@ import bot as botPy
import data
import posts
import cmds
import macros
ws_global = None
is_connected = False
@@ -76,8 +77,8 @@ async def json_to_func(v: dict, bot: botPy.Bot) -> dict:
match v["value"]:
case "update_data_file": r = data .write_data (bot)
case "respond_mentions": r = await cmds .respond_to_mention(bot)
case "add_new_posts": r = await posts.add_new_posts (bot, *v["args"])
case "add_post_url": r = await posts.add_post_url (bot, *v["args"])
case "add_new_posts": r = await posts .add_new_posts (bot, *v["args"])
case "add_post_url": r = await posts .add_post_url (bot, *v["args"])
case "remove_post_url": r = data .remove_post (bot, *v["args"])
case "set_approve_post": r = data .set_approve_post (bot, *v["args"])
case "set_vote_post": r = data .set_vote_post (bot, *v["args"])
+1 -1
View File
@@ -70,7 +70,7 @@ pub async fn send_cmd_json(func_name: &str, func_args: Option<Value>, print_outp
{ return r; }
}
if !["respond_mentions"].contains(&func_name) || <Args as clap::Parser>::parse().dev {
if <Args as clap::Parser>::parse().dev {
rs_println!("Received from Python: [RESPONSE] {:?}", r);
}