feat: add config input for the automated generation option

This commit is contained in:
cătălin 2024-11-01 16:10:50 +01:00
commit e574277839
No known key found for this signature in database
5 changed files with 55 additions and 39 deletions

View file

@ -1,6 +1,6 @@
[project] [project]
name = "markovbot-gui" name = "markovbot-gui"
version = "0.1.0" version = "0.1.1"
description = "Markov Chain Bot GUI" description = "Markov Chain Bot GUI"
readme = "README.md" readme = "README.md"
authors = [ authors = [

View file

@ -1,5 +1,3 @@
import json
import logging
from pathlib import Path from pathlib import Path
from kivy.clock import Clock from kivy.clock import Clock
@ -10,6 +8,9 @@ from kivy.uix.label import Label
from kivy.uix.popup import Popup from kivy.uix.popup import Popup
from kivy.uix.textinput import TextInput from kivy.uix.textinput import TextInput
from src.markovbot_gui.libs.settings import Settings
from src.markovbot_gui.libs.timer import logger
class ConfigWindow(BoxLayout): class ConfigWindow(BoxLayout):
def __init__(self, config_path: Path, **kwargs): def __init__(self, config_path: Path, **kwargs):
@ -20,14 +21,13 @@ class ConfigWindow(BoxLayout):
self.padding = dp(20) self.padding = dp(20)
# Load existing configuration # Load existing configuration
self.default_config = { default_config = {
"Host": "irc.chat.twitch.tv", "Host": "irc.chat.twitch.tv",
"Port": 6667, "Port": 6667,
"Channel": "#<channel>", "Channel": "#<channel>",
"Nickname": "<name>", "Nickname": "<name>",
"Authentication": "oauth:<auth>", "Authentication": "oauth:<auth>",
"DeniedUsers": ["StreamElements", "Nightbot", "Moobot", "Marbiebot"], "DeniedUsers": ["StreamElements", "Nightbot", "Moobot", "Marbiebot"],
"AllowedUsers": [],
"Cooldown": 20, "Cooldown": 20,
"KeyLength": 2, "KeyLength": 2,
"MaxSentenceWordAmount": 25, "MaxSentenceWordAmount": 25,
@ -38,19 +38,13 @@ class ConfigWindow(BoxLayout):
"EnableGenerateCommand": True, "EnableGenerateCommand": True,
"SentenceSeparator": " - ", "SentenceSeparator": " - ",
"AllowGenerateParams": True, "AllowGenerateParams": True,
"GenerateCommands": ["!generate", "!g"],
} }
try: if config_path.exists():
if config_path.exists(): self.s = Settings.read(config_path)
with config_path.open("r") as f: else:
saved_config = json.load(f) self.s = Settings(**default_config) # type: ignore[arg-type]
# Update self.default_config with saved values self.s.write(config_path)
self.default_config.update(saved_config)
except json.JSONDecodeError:
logging.exception(f"Failed to parse config file at {config_path}")
except Exception:
logging.exception("Error loading config file")
# Create widgets # Create widgets
# Channel input # Channel input
@ -63,7 +57,7 @@ class ConfigWindow(BoxLayout):
self.channel_input = TextInput( self.channel_input = TextInput(
multiline=False, multiline=False,
size_hint_x=0.7, size_hint_x=0.7,
text=self.default_config["Channel"], text=self.s.channel,
) )
channel_layout.add_widget(channel_label) channel_layout.add_widget(channel_label)
channel_layout.add_widget(self.channel_input) channel_layout.add_widget(self.channel_input)
@ -78,7 +72,7 @@ class ConfigWindow(BoxLayout):
self.nickname_input = TextInput( self.nickname_input = TextInput(
multiline=False, multiline=False,
size_hint_x=0.7, size_hint_x=0.7,
text=self.default_config["Nickname"], text=self.s.nickname,
) )
nickname_layout.add_widget(nickname_label) nickname_layout.add_widget(nickname_label)
nickname_layout.add_widget(self.nickname_input) nickname_layout.add_widget(self.nickname_input)
@ -94,11 +88,25 @@ class ConfigWindow(BoxLayout):
multiline=False, multiline=False,
size_hint_x=0.7, size_hint_x=0.7,
password=True, password=True,
text=self.default_config["Authentication"], text=self.s.authentication,
) )
auth_layout.add_widget(auth_label) auth_layout.add_widget(auth_label)
auth_layout.add_widget(self.auth_input) auth_layout.add_widget(self.auth_input)
automatic_generation_label = Label(text="Automatic generation (seconds): ")
self.automatic_generation_input = TextInput(
multiline=False,
size_hint_x=0.7,
text=str(self.s.automatic_generation_timer),
)
automatic_generation_layout = BoxLayout(
orientation="horizontal",
size_hint_y=None,
height=dp(40),
)
automatic_generation_layout.add_widget(automatic_generation_label)
automatic_generation_layout.add_widget(self.automatic_generation_input)
# Save button # Save button
save_button = Button( save_button = Button(
text="Save", text="Save",
@ -112,21 +120,23 @@ class ConfigWindow(BoxLayout):
self.add_widget(channel_layout) self.add_widget(channel_layout)
self.add_widget(nickname_layout) self.add_widget(nickname_layout)
self.add_widget(auth_layout) self.add_widget(auth_layout)
self.add_widget(automatic_generation_layout)
self.add_widget(save_button) self.add_widget(save_button)
def save_config(self, instance): def save_config(self, instance):
# Get values from inputs
self.default_config["Channel"] = self.channel_input.text.strip()
self.default_config["Nickname"] = self.nickname_input.text.strip()
self.default_config["Authentication"] = self.auth_input.text.strip()
try: try:
# Create directory if it doesn't exist self.s.channel = self.channel_input.text.strip()
self.config_path.parent.mkdir(parents=True, exist_ok=True) self.s.nickname = self.nickname_input.text.strip()
self.s.authentication = self.auth_input.text.strip()
# Save configuration self.s.automatic_generation_timer = int(
with self.config_path.open("w") as f: self.automatic_generation_input.text
json.dump(self.default_config, f, indent=4) )
if 0 < self.s.automatic_generation_timer < 29: # noqa: PLR2004
raise ValueError(
"Value for 'Automatic generation' must be at least 30 seconds, " # noqa: EM101
"or a negative number for no automatic generations."
)
self.s.write(self.config_path)
# Show success message # Show success message
success_popup = Popup( success_popup = Popup(
@ -140,7 +150,7 @@ class ConfigWindow(BoxLayout):
Clock.schedule_once(success_popup.dismiss, 1) Clock.schedule_once(success_popup.dismiss, 1)
except Exception as e: # noqa: BLE001 except Exception as e: # noqa: BLE001
# Show error message if saving fails self.show_error_message(f"Failed to save configuration:\n{e!s}")
error_popup = Popup( error_popup = Popup(
title="Error", title="Error",
content=Label(text=f"Failed to save configuration:\n{e!s}"), content=Label(text=f"Failed to save configuration:\n{e!s}"),
@ -148,3 +158,4 @@ class ConfigWindow(BoxLayout):
size=(dp(400), dp(150)), size=(dp(400), dp(150)),
) )
error_popup.open() error_popup.open()
logger.exception("Failed to save configuration")

View file

@ -32,7 +32,8 @@ class MarkovChain:
if self.s.help_message_timer > 0: if self.s.help_message_timer > 0:
if self.s.help_message_timer < 300: # noqa: PLR2004 if self.s.help_message_timer < 300: # noqa: PLR2004
raise ValueError( raise ValueError(
'Value for "HelpMessageTimer" in must be at least 300 seconds, or a negative number for no help messages.', # noqa: EM101 'Value for "HelpMessageTimer" in must be at least 300 seconds, ' # noqa: EM101
"or a negative number for no help messages.",
) )
t = LoopingTimer(self.s.help_message_timer, self._command_help) t = LoopingTimer(self.s.help_message_timer, self._command_help)
t.start() t.start()
@ -44,6 +45,9 @@ class MarkovChain:
'Value for "Automatic_generation_message" must be at least 30 seconds, or a negative number for no ' # noqa: EM101 'Value for "Automatic_generation_message" must be at least 30 seconds, or a negative number for no ' # noqa: EM101
"automatic generations.", "automatic generations.",
) )
logger.info(
f"Automatic generation enabled, will send messages every {self.s.automatic_generation_timer} seconds"
)
t = LoopingTimer( t = LoopingTimer(
self.s.automatic_generation_timer, self.s.automatic_generation_timer,
self._command_automatic_generation, self._command_automatic_generation,

View file

@ -16,14 +16,15 @@ class BotApp(App):
self.config_path = ( self.config_path = (
platformdirs.user_config_path("markovbot_gui") / "settings.json" platformdirs.user_config_path("markovbot_gui") / "settings.json"
) )
self.data_path = platformdirs.user_data_path("markovbot_gui")
def run_bot(self, instance): def run_bot(self, instance):
bot_runner = BotRunner(settings_path=self.config_path) bot_runner = BotRunner(settings_path=self.config_path)
popup = Popup( popup = Popup(
title="Bot Running", title=f"Bot runner, database available at {self.data_path}",
content=bot_runner, content=bot_runner,
size_hint=(None, None), size_hint=(None, None),
size=(dp(600), dp(400)), size=(dp(600), dp(600)),
auto_dismiss=False, auto_dismiss=False,
) )
popup.open() popup.open()
@ -31,10 +32,10 @@ class BotApp(App):
def run_config(self, instance): def run_config(self, instance):
config_window = ConfigWindow(config_path=self.config_path) config_window = ConfigWindow(config_path=self.config_path)
popup = Popup( popup = Popup(
title=f"Bot Configuration, available at {self.config_path}", title=f"Bot configuration, available at {self.config_path}",
content=config_window, content=config_window,
size_hint=(None, None), size_hint=(None, None),
size=(dp(400), dp(400)), size=(dp(600), dp(400)),
auto_dismiss=False, auto_dismiss=False,
) )

6
uv.lock generated
View file

@ -246,7 +246,7 @@ wheels = [
[[package]] [[package]]
name = "markovbot-gui" name = "markovbot-gui"
version = "0.1.0" version = "0.1.1"
source = { virtual = "." } source = { virtual = "." }
dependencies = [ dependencies = [
{ name = "kivy", extra = ["base"] }, { name = "kivy", extra = ["base"] },
@ -260,7 +260,7 @@ dependencies = [
{ name = "twitchwebsocket" }, { name = "twitchwebsocket" },
] ]
[package.dependency-groups] [package.dev-dependencies]
dev = [ dev = [
{ name = "mypy" }, { name = "mypy" },
{ name = "pyright" }, { name = "pyright" },
@ -280,7 +280,7 @@ requires-dist = [
{ name = "twitchwebsocket", specifier = ">=1.2.1" }, { name = "twitchwebsocket", specifier = ">=1.2.1" },
] ]
[package.metadata.dependency-groups] [package.metadata.requires-dev]
dev = [ dev = [
{ name = "mypy", specifier = ">=1.13.0" }, { name = "mypy", specifier = ">=1.13.0" },
{ name = "pyright", specifier = ">=1.1.387" }, { name = "pyright", specifier = ">=1.1.387" },