From f3d8578759d2fea9e481696b7a29e2d2a1c30cc9 Mon Sep 17 00:00:00 2001 From: salmonik Date: Thu, 19 Mar 2026 22:03:03 +0100 Subject: normalised times on vclogs, and improved jarvis via reply chaining --- cogs/jarvis.py | 95 +++++++++++++++++++++++----------------------------------- cogs/vclogs.py | 83 ++++++++++++++++++++++---------------------------- main.py | 7 +---- 3 files changed, 74 insertions(+), 111 deletions(-) diff --git a/cogs/jarvis.py b/cogs/jarvis.py index 4f34ea8..866700e 100644 --- a/cogs/jarvis.py +++ b/cogs/jarvis.py @@ -24,10 +24,10 @@ class Jarvis(commands.Cog): @commands.Cog.listener() async def on_message(self, message): - print(message.content) if message.author == self.bot.user: return - + + logger.info(message.content) if message.mentions: if message.mentions[0].id == self.bot.user.id: await self.jarvis(message) @@ -42,7 +42,8 @@ class Jarvis(commands.Cog): "Content-Type": "application/json" } - messages = Jarvis._build_messages(message) + chain = await Jarvis._build_message_chain(message) + messages = Jarvis._build_messages(message, chain) payload = Jarvis._build_payload(messages) response_data = await Jarvis._make_api_request(payload, headers) @@ -55,45 +56,47 @@ class Jarvis(commands.Cog): await Jarvis._handle_download_action(message, channel) @staticmethod - def _build_messages(message): + async def _build_message_chain(message): + chain = [] + current = message + max_depth = 5 + + while current and len(chain) < max_depth: + chain.append(current) + if not current.reference: + break + try: + if current.reference.resolved: + current = current.reference.resolved + else: + current = await current.channel.fetch_message(current.reference.message_id) + except discord.NotFound: + break + + return list(reversed(chain)) + + @staticmethod + def _build_messages(message, chain=None): messages = [{ "role": "system", - "content": "You are an alter ego of Senator Sperma Armstrong.\n" - "your task is to tell the program what to do and how to respond after receiving a message.\n" - "message field has to be filled out in polish.\n" - "act like jarvis (only behavior wise), be a personal assistant to user, do not use emojis\n" - "do not ask the user if they want to do an action. the user will tell you that." + "content": "Jesteś Senator Sperma Armostrong, także znany jako Jarvis." + "Twoim zadaniem, po za asystowaniem użytkownika, jest mówienie programowi nadrzędnemu jak sie zachować" + "pole 'message' może być tylko wypełnione w języku Polskim." + "zachowuj sie jak Jarvis, bądź osobistym asystentem użytkownika, nie używaj emotikon" + "nie pytaj sie użytkownika czy chcesz abyś coś zrobił, użytkownik ci sam powie abyś coś wykonał" }] - messages.append({ - "role": "user", - "content": f"{message.author.display_name}: {message.content}" - - }) + if chain is None: + chain = [message] - if Jarvis._is_reply(message): - messages.extend(Jarvis._build_reply_messages(message)) + for msg in chain: + messages.append({ + "role": "user", + "content": f"{msg.author.display_name}: {msg.content}" + }) return messages - @staticmethod - def _is_reply(message): - return message.reference and (message.type == discord.MessageType.reply or message.reference.resolved) - - @staticmethod - def _build_reply_messages(message): - original_msg = message.reference.resolved - return [ - { - "role": "user", - "content": f"{original_msg.author.display_name}: {original_msg.content}" - }, - { - "role": "user", - "content": f"{message.author.display_name}: {message.content}" - } - ] - @staticmethod def _build_payload(messages): return { @@ -191,29 +194,5 @@ class Jarvis(commands.Cog): logger.error(f"Details: {response['details']}") shutil.rmtree(response["temp_dir"]) - @staticmethod - async def get_original(message): - if message.type == discord.MessageType.reply: - # The original message is already resolved (cached) - reply = message.reference.resolved - elif message.reference: - # If not cached, fetch it from the API - try: - reply = await message.channel.fetch_message(message.reference.message_id) - except discord.NotFound: - reply = None - else: - reply = None - - if reply: - reply_content = reply.content - else: - reply_content = None - - if reply_content: - return f"{message.content} [which is a reply to] {reply_content}" - else: - return message.content - def setup(bot): bot.add_cog(Jarvis(bot)) diff --git a/cogs/vclogs.py b/cogs/vclogs.py index 0589364..f2efca7 100644 --- a/cogs/vclogs.py +++ b/cogs/vclogs.py @@ -54,36 +54,20 @@ class VcLogs(commands.Cog): settings_file = 'settings.json' @staticmethod - async def handle_state_change(member, channel, state_type, is_enabled, current_time, log_channel, activity_suffix=None): + async def handle_state_change(member, channel, state_type, is_enabled, log_channel): """Helper method to handle voice state changes""" state_messages = { 'deaf': { - True: ( - f"[{current_time}] {member.name} ogłuchnął się na {channel.name}", - f"{member.display_name} jest bity przez ojca" - ), - False: ( - f"[{current_time}] {member.name} odgłuchał się na {channel.name}", - f"{member.display_name} uciek od ojca" - ) + True: f"{member.display_name} jest bity przez ojca", + False: f"{member.display_name} uciek od ojca" }, 'mute': { - True: ( - f"[{current_time}] {member.name} wyciszył się na {channel.name}", - f"{member.display_name} idzie robić jajecznice" - ), - False: ( - f"[{current_time}] {member.name} odciszył się na {channel.name}", - f"{member.display_name} zrobił jajecznice" - ) + True: f"{member.display_name} idzie robić jajecznice", + False: f"{member.display_name} zrobił jajecznice" } } - message, tts_text = state_messages[state_type][is_enabled] - if activity_suffix: - message = f"{message}\n{activity_suffix}" - await log_channel.send(message) - logger.info(f"Voice state change: {message}") + tts_text = state_messages[state_type][is_enabled] return tts_text, channel async def play_tts(self, channel, text): @@ -96,14 +80,15 @@ class VcLogs(commands.Cog): logger.info("saving file") tts.save(tts_file) + voice_client = await voice_mgr.get_voice_client(channel.guild) + volume = 1.0 + if os.path.exists(VcLogs.settings_file): async with aiofiles.open(VcLogs.settings_file) as f: content = await f.read() data = json.loads(content) volume = data.get('volume', 1.0) - voice_client = await voice_mgr.get_voice_client(channel.guild) - if voice_client is None: voice_client = await voice_mgr.join_channel(channel) @@ -180,7 +165,7 @@ class VcLogs(commands.Cog): message = ( f"[{current_time}] {member.name} rozłączył się z {before.channel.name}\n" - f" Aktywny: {active_str} | AFK: {afk_str}" + f"Aktywny: {active_str} | AFK: {afk_str}" ) tts_text = f"{member.display_name} jest chujem" tts_channel = before.channel @@ -206,7 +191,20 @@ class VcLogs(commands.Cog): data['is_afk'] = False data['active_start'] = current_ts save_activity_data(activity_data) + + afk_str = format_duration(afk_duration) + + if after.self_mute: + activity = "odciszył" + else: + activity = "odgłuchnął" + + message = ( f"[{current_time}] {member.name} {activity} się na {after.channel.name}\n" + f"AFK: {afk_str}" ) + await log_channel.send(message) + logger.info(f"User returned from AFK: {message}") elif not data.get('is_afk') and (after.self_mute or after.self_deaf): + active_since_start = 0 if data.get('active_start'): active_since_start = current_ts - data['active_start'] data['total_active'] += active_since_start @@ -214,38 +212,29 @@ class VcLogs(commands.Cog): data['is_afk'] = True data['active_start'] = None save_activity_data(activity_data) + + if after.self_mute: + activity = "wyciszył" + else: + activity = "ogłuchnął" + + active_str = format_duration(active_since_start) + message = ( f"[{current_time}] {member.name} {activity} się na {after.channel.name}\n" + f"Aktywny: {active_str}" ) + await log_channel.send(message) + logger.info(f"User went AFK: {message}") if before.self_deaf != after.self_deaf: - activity_suffix = None - if user_id in activity_data: - data = activity_data[user_id] - if after.self_deaf: - active_str = format_duration(data['total_active']) - activity_suffix = f" Aktywny przed AFK: {active_str}" - else: - active_str = format_duration(data['total_active']) - afk_str = format_duration(data['total_afk']) - activity_suffix = f" Był AFK: {afk_str} | Łączny aktywny: {active_str}" tts_text, tts_channel = await self.handle_state_change( - member, after.channel, 'deaf', after.self_deaf, current_time, log_channel, activity_suffix + member, after.channel, 'deaf', after.self_deaf, log_channel ) if tts_text and tts_channel: await self.play_tts(tts_channel, tts_text) return if before.self_mute != after.self_mute: - activity_suffix = None - if user_id in activity_data: - data = activity_data[user_id] - if after.self_mute: - active_str = format_duration(data['total_active']) - activity_suffix = f" Aktywny przed AFK: {active_str}" - else: - active_str = format_duration(data['total_active']) - afk_str = format_duration(data['total_afk']) - activity_suffix = f" Był AFK: {afk_str} | Łączny aktywny: {active_str}" tts_text, tts_channel = await self.handle_state_change( - member, after.channel, 'mute', after.self_mute, current_time, log_channel, activity_suffix + member, after.channel, 'mute', after.self_mute, log_channel ) if tts_text and tts_channel: diff --git a/main.py b/main.py index 73ad94e..25b7b33 100644 --- a/main.py +++ b/main.py @@ -29,10 +29,7 @@ logger = logging.getLogger(__name__) loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) -intents = discord.Intents.default() -intents.voice_states = True -intents.guilds = True -intents.messages = True +intents = discord.Intents.all() bot = commands.Bot(intents=intents, loop=loop) settings = "settings.json" @@ -43,8 +40,6 @@ async def on_ready(): # send the message to channel ID channel = bot.get_channel(1081667823799111804) - invite = await channel.create_invite(max_age=10, max_uses=1, unique=True) - print(f"One-time invite (expires in 1 s or after 1 use): {invite.url}") await channel.send("ŁUKASZ SPERMA AKTYWACJA") -- cgit v1.2.3