diff options
| author | salmonik <raisersoft@proton.me> | 2026-03-19 22:03:03 +0100 |
|---|---|---|
| committer | salmonik <raisersoft@proton.me> | 2026-03-19 22:03:03 +0100 |
| commit | f3d8578759d2fea9e481696b7a29e2d2a1c30cc9 (patch) | |
| tree | 80e643f41fd8ed83e51c75104224c2741a5c0cf0 | |
| parent | vclogs afk/active time (diff) | |
| download | senator-sperma-f3d8578759d2fea9e481696b7a29e2d2a1c30cc9.tar.gz senator-sperma-f3d8578759d2fea9e481696b7a29e2d2a1c30cc9.zip | |
normalised times on vclogs, and improved jarvis via reply chaining
Diffstat (limited to '')
| -rw-r--r-- | cogs/jarvis.py | 95 | ||||
| -rw-r--r-- | cogs/vclogs.py | 83 | ||||
| -rw-r--r-- | 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): | |||
| 24 | 24 | ||
| 25 | @commands.Cog.listener() | 25 | @commands.Cog.listener() |
| 26 | async def on_message(self, message): | 26 | async def on_message(self, message): |
| 27 | print(message.content) | ||
| 28 | if message.author == self.bot.user: | 27 | if message.author == self.bot.user: |
| 29 | return | 28 | return |
| 30 | 29 | ||
| 30 | logger.info(message.content) | ||
| 31 | if message.mentions: | 31 | if message.mentions: |
| 32 | if message.mentions[0].id == self.bot.user.id: | 32 | if message.mentions[0].id == self.bot.user.id: |
| 33 | await self.jarvis(message) | 33 | await self.jarvis(message) |
| @@ -42,7 +42,8 @@ class Jarvis(commands.Cog): | |||
| 42 | "Content-Type": "application/json" | 42 | "Content-Type": "application/json" |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | messages = Jarvis._build_messages(message) | 45 | chain = await Jarvis._build_message_chain(message) |
| 46 | messages = Jarvis._build_messages(message, chain) | ||
| 46 | payload = Jarvis._build_payload(messages) | 47 | payload = Jarvis._build_payload(messages) |
| 47 | 48 | ||
| 48 | response_data = await Jarvis._make_api_request(payload, headers) | 49 | response_data = await Jarvis._make_api_request(payload, headers) |
| @@ -55,46 +56,48 @@ class Jarvis(commands.Cog): | |||
| 55 | await Jarvis._handle_download_action(message, channel) | 56 | await Jarvis._handle_download_action(message, channel) |
| 56 | 57 | ||
| 57 | @staticmethod | 58 | @staticmethod |
| 58 | def _build_messages(message): | 59 | async def _build_message_chain(message): |
| 60 | chain = [] | ||
| 61 | current = message | ||
| 62 | max_depth = 5 | ||
| 63 | |||
| 64 | while current and len(chain) < max_depth: | ||
| 65 | chain.append(current) | ||
| 66 | if not current.reference: | ||
| 67 | break | ||
| 68 | try: | ||
| 69 | if current.reference.resolved: | ||
| 70 | current = current.reference.resolved | ||
| 71 | else: | ||
| 72 | current = await current.channel.fetch_message(current.reference.message_id) | ||
| 73 | except discord.NotFound: | ||
| 74 | break | ||
| 75 | |||
| 76 | return list(reversed(chain)) | ||
| 77 | |||
| 78 | @staticmethod | ||
| 79 | def _build_messages(message, chain=None): | ||
| 59 | messages = [{ | 80 | messages = [{ |
| 60 | "role": "system", | 81 | "role": "system", |
| 61 | "content": "You are an alter ego of Senator Sperma Armstrong.\n" | 82 | "content": "Jesteś Senator Sperma Armostrong, także znany jako Jarvis." |
| 62 | "your task is to tell the program what to do and how to respond after receiving a message.\n" | 83 | "Twoim zadaniem, po za asystowaniem użytkownika, jest mówienie programowi nadrzędnemu jak sie zachować" |
| 63 | "message field has to be filled out in polish.\n" | 84 | "pole 'message' może być tylko wypełnione w języku Polskim." |
| 64 | "act like jarvis (only behavior wise), be a personal assistant to user, do not use emojis\n" | 85 | "zachowuj sie jak Jarvis, bądź osobistym asystentem użytkownika, nie używaj emotikon" |
| 65 | "do not ask the user if they want to do an action. the user will tell you that." | 86 | "nie pytaj sie użytkownika czy chcesz abyś coś zrobił, użytkownik ci sam powie abyś coś wykonał" |
| 66 | }] | 87 | }] |
| 67 | 88 | ||
| 68 | messages.append({ | 89 | if chain is None: |
| 69 | "role": "user", | 90 | chain = [message] |
| 70 | "content": f"{message.author.display_name}: {message.content}" | ||
| 71 | |||
| 72 | }) | ||
| 73 | 91 | ||
| 74 | if Jarvis._is_reply(message): | 92 | for msg in chain: |
| 75 | messages.extend(Jarvis._build_reply_messages(message)) | 93 | messages.append({ |
| 94 | "role": "user", | ||
| 95 | "content": f"{msg.author.display_name}: {msg.content}" | ||
| 96 | }) | ||
| 76 | 97 | ||
| 77 | return messages | 98 | return messages |
| 78 | 99 | ||
| 79 | @staticmethod | 100 | @staticmethod |
| 80 | def _is_reply(message): | ||
| 81 | return message.reference and (message.type == discord.MessageType.reply or message.reference.resolved) | ||
| 82 | |||
| 83 | @staticmethod | ||
| 84 | def _build_reply_messages(message): | ||
| 85 | original_msg = message.reference.resolved | ||
| 86 | return [ | ||
| 87 | { | ||
| 88 | "role": "user", | ||
| 89 | "content": f"{original_msg.author.display_name}: {original_msg.content}" | ||
| 90 | }, | ||
| 91 | { | ||
| 92 | "role": "user", | ||
| 93 | "content": f"{message.author.display_name}: {message.content}" | ||
| 94 | } | ||
| 95 | ] | ||
| 96 | |||
| 97 | @staticmethod | ||
| 98 | def _build_payload(messages): | 101 | def _build_payload(messages): |
| 99 | return { | 102 | return { |
| 100 | "model": "arcee-ai/trinity-large-preview:free", | 103 | "model": "arcee-ai/trinity-large-preview:free", |
| @@ -191,29 +194,5 @@ class Jarvis(commands.Cog): | |||
| 191 | logger.error(f"Details: {response['details']}") | 194 | logger.error(f"Details: {response['details']}") |
| 192 | shutil.rmtree(response["temp_dir"]) | 195 | shutil.rmtree(response["temp_dir"]) |
| 193 | 196 | ||
| 194 | @staticmethod | ||
| 195 | async def get_original(message): | ||
| 196 | if message.type == discord.MessageType.reply: | ||
| 197 | # The original message is already resolved (cached) | ||
| 198 | reply = message.reference.resolved | ||
| 199 | elif message.reference: | ||
| 200 | # If not cached, fetch it from the API | ||
| 201 | try: | ||
| 202 | reply = await message.channel.fetch_message(message.reference.message_id) | ||
| 203 | except discord.NotFound: | ||
| 204 | reply = None | ||
| 205 | else: | ||
| 206 | reply = None | ||
| 207 | |||
| 208 | if reply: | ||
| 209 | reply_content = reply.content | ||
| 210 | else: | ||
| 211 | reply_content = None | ||
| 212 | |||
| 213 | if reply_content: | ||
| 214 | return f"{message.content} [which is a reply to] {reply_content}" | ||
| 215 | else: | ||
| 216 | return message.content | ||
| 217 | |||
| 218 | def setup(bot): | 197 | def setup(bot): |
| 219 | bot.add_cog(Jarvis(bot)) | 198 | 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): | |||
| 54 | settings_file = 'settings.json' | 54 | settings_file = 'settings.json' |
| 55 | 55 | ||
| 56 | @staticmethod | 56 | @staticmethod |
| 57 | async def handle_state_change(member, channel, state_type, is_enabled, current_time, log_channel, activity_suffix=None): | 57 | async def handle_state_change(member, channel, state_type, is_enabled, log_channel): |
| 58 | """Helper method to handle voice state changes""" | 58 | """Helper method to handle voice state changes""" |
| 59 | state_messages = { | 59 | state_messages = { |
| 60 | 'deaf': { | 60 | 'deaf': { |
| 61 | True: ( | 61 | True: f"{member.display_name} jest bity przez ojca", |
| 62 | f"[{current_time}] {member.name} ogłuchnął się na {channel.name}", | 62 | False: f"{member.display_name} uciek od ojca" |
| 63 | f"{member.display_name} jest bity przez ojca" | ||
| 64 | ), | ||
| 65 | False: ( | ||
| 66 | f"[{current_time}] {member.name} odgłuchał się na {channel.name}", | ||
| 67 | f"{member.display_name} uciek od ojca" | ||
| 68 | ) | ||
| 69 | }, | 63 | }, |
| 70 | 'mute': { | 64 | 'mute': { |
| 71 | True: ( | 65 | True: f"{member.display_name} idzie robić jajecznice", |
| 72 | f"[{current_time}] {member.name} wyciszył się na {channel.name}", | 66 | False: f"{member.display_name} zrobił jajecznice" |
| 73 | f"{member.display_name} idzie robić jajecznice" | ||
| 74 | ), | ||
| 75 | False: ( | ||
| 76 | f"[{current_time}] {member.name} odciszył się na {channel.name}", | ||
| 77 | f"{member.display_name} zrobił jajecznice" | ||
| 78 | ) | ||
| 79 | } | 67 | } |
| 80 | } | 68 | } |
| 81 | 69 | ||
| 82 | message, tts_text = state_messages[state_type][is_enabled] | 70 | tts_text = state_messages[state_type][is_enabled] |
| 83 | if activity_suffix: | ||
| 84 | message = f"{message}\n{activity_suffix}" | ||
| 85 | await log_channel.send(message) | ||
| 86 | logger.info(f"Voice state change: {message}") | ||
| 87 | return tts_text, channel | 71 | return tts_text, channel |
| 88 | 72 | ||
| 89 | async def play_tts(self, channel, text): | 73 | async def play_tts(self, channel, text): |
| @@ -96,14 +80,15 @@ class VcLogs(commands.Cog): | |||
| 96 | logger.info("saving file") | 80 | logger.info("saving file") |
| 97 | tts.save(tts_file) | 81 | tts.save(tts_file) |
| 98 | 82 | ||
| 83 | voice_client = await voice_mgr.get_voice_client(channel.guild) | ||
| 84 | volume = 1.0 | ||
| 85 | |||
| 99 | if os.path.exists(VcLogs.settings_file): | 86 | if os.path.exists(VcLogs.settings_file): |
| 100 | async with aiofiles.open(VcLogs.settings_file) as f: | 87 | async with aiofiles.open(VcLogs.settings_file) as f: |
| 101 | content = await f.read() | 88 | content = await f.read() |
| 102 | data = json.loads(content) | 89 | data = json.loads(content) |
| 103 | volume = data.get('volume', 1.0) | 90 | volume = data.get('volume', 1.0) |
| 104 | 91 | ||
| 105 | voice_client = await voice_mgr.get_voice_client(channel.guild) | ||
| 106 | |||
| 107 | if voice_client is None: | 92 | if voice_client is None: |
| 108 | voice_client = await voice_mgr.join_channel(channel) | 93 | voice_client = await voice_mgr.join_channel(channel) |
| 109 | 94 | ||
| @@ -180,7 +165,7 @@ class VcLogs(commands.Cog): | |||
| 180 | 165 | ||
| 181 | message = ( | 166 | message = ( |
| 182 | f"[{current_time}] {member.name} rozłączył się z {before.channel.name}\n" | 167 | f"[{current_time}] {member.name} rozłączył się z {before.channel.name}\n" |
| 183 | f" Aktywny: {active_str} | AFK: {afk_str}" | 168 | f"Aktywny: {active_str} | AFK: {afk_str}" |
| 184 | ) | 169 | ) |
| 185 | tts_text = f"{member.display_name} jest chujem" | 170 | tts_text = f"{member.display_name} jest chujem" |
| 186 | tts_channel = before.channel | 171 | tts_channel = before.channel |
| @@ -206,7 +191,20 @@ class VcLogs(commands.Cog): | |||
| 206 | data['is_afk'] = False | 191 | data['is_afk'] = False |
| 207 | data['active_start'] = current_ts | 192 | data['active_start'] = current_ts |
| 208 | save_activity_data(activity_data) | 193 | save_activity_data(activity_data) |
| 194 | |||
| 195 | afk_str = format_duration(afk_duration) | ||
| 196 | |||
| 197 | if after.self_mute: | ||
| 198 | activity = "odciszył" | ||
| 199 | else: | ||
| 200 | activity = "odgłuchnął" | ||
| 201 | |||
| 202 | message = ( f"[{current_time}] {member.name} {activity} się na {after.channel.name}\n" | ||
| 203 | f"AFK: {afk_str}" ) | ||
| 204 | await log_channel.send(message) | ||
| 205 | logger.info(f"User returned from AFK: {message}") | ||
| 209 | elif not data.get('is_afk') and (after.self_mute or after.self_deaf): | 206 | elif not data.get('is_afk') and (after.self_mute or after.self_deaf): |
| 207 | active_since_start = 0 | ||
| 210 | if data.get('active_start'): | 208 | if data.get('active_start'): |
| 211 | active_since_start = current_ts - data['active_start'] | 209 | active_since_start = current_ts - data['active_start'] |
| 212 | data['total_active'] += active_since_start | 210 | data['total_active'] += active_since_start |
| @@ -214,38 +212,29 @@ class VcLogs(commands.Cog): | |||
| 214 | data['is_afk'] = True | 212 | data['is_afk'] = True |
| 215 | data['active_start'] = None | 213 | data['active_start'] = None |
| 216 | save_activity_data(activity_data) | 214 | save_activity_data(activity_data) |
| 215 | |||
| 216 | if after.self_mute: | ||
| 217 | activity = "wyciszył" | ||
| 218 | else: | ||
| 219 | activity = "ogłuchnął" | ||
| 220 | |||
| 221 | active_str = format_duration(active_since_start) | ||
| 222 | message = ( f"[{current_time}] {member.name} {activity} się na {after.channel.name}\n" | ||
| 223 | f"Aktywny: {active_str}" ) | ||
| 224 | await log_channel.send(message) | ||
| 225 | logger.info(f"User went AFK: {message}") | ||
| 217 | 226 | ||
| 218 | if before.self_deaf != after.self_deaf: | 227 | if before.self_deaf != after.self_deaf: |
| 219 | activity_suffix = None | ||
| 220 | if user_id in activity_data: | ||
| 221 | data = activity_data[user_id] | ||
| 222 | if after.self_deaf: | ||
| 223 | active_str = format_duration(data['total_active']) | ||
| 224 | activity_suffix = f" Aktywny przed AFK: {active_str}" | ||
| 225 | else: | ||
| 226 | active_str = format_duration(data['total_active']) | ||
| 227 | afk_str = format_duration(data['total_afk']) | ||
| 228 | activity_suffix = f" Był AFK: {afk_str} | Łączny aktywny: {active_str}" | ||
| 229 | tts_text, tts_channel = await self.handle_state_change( | 228 | tts_text, tts_channel = await self.handle_state_change( |
| 230 | member, after.channel, 'deaf', after.self_deaf, current_time, log_channel, activity_suffix | 229 | member, after.channel, 'deaf', after.self_deaf, log_channel |
| 231 | ) | 230 | ) |
| 232 | if tts_text and tts_channel: | 231 | if tts_text and tts_channel: |
| 233 | await self.play_tts(tts_channel, tts_text) | 232 | await self.play_tts(tts_channel, tts_text) |
| 234 | return | 233 | return |
| 235 | 234 | ||
| 236 | if before.self_mute != after.self_mute: | 235 | if before.self_mute != after.self_mute: |
| 237 | activity_suffix = None | ||
| 238 | if user_id in activity_data: | ||
| 239 | data = activity_data[user_id] | ||
| 240 | if after.self_mute: | ||
| 241 | active_str = format_duration(data['total_active']) | ||
| 242 | activity_suffix = f" Aktywny przed AFK: {active_str}" | ||
| 243 | else: | ||
| 244 | active_str = format_duration(data['total_active']) | ||
| 245 | afk_str = format_duration(data['total_afk']) | ||
| 246 | activity_suffix = f" Był AFK: {afk_str} | Łączny aktywny: {active_str}" | ||
| 247 | tts_text, tts_channel = await self.handle_state_change( | 236 | tts_text, tts_channel = await self.handle_state_change( |
| 248 | member, after.channel, 'mute', after.self_mute, current_time, log_channel, activity_suffix | 237 | member, after.channel, 'mute', after.self_mute, log_channel |
| 249 | ) | 238 | ) |
| 250 | 239 | ||
| 251 | if tts_text and tts_channel: | 240 | if tts_text and tts_channel: |
| @@ -29,10 +29,7 @@ logger = logging.getLogger(__name__) | |||
| 29 | loop = asyncio.new_event_loop() | 29 | loop = asyncio.new_event_loop() |
| 30 | asyncio.set_event_loop(loop) | 30 | asyncio.set_event_loop(loop) |
| 31 | 31 | ||
| 32 | intents = discord.Intents.default() | 32 | intents = discord.Intents.all() |
| 33 | intents.voice_states = True | ||
| 34 | intents.guilds = True | ||
| 35 | intents.messages = True | ||
| 36 | bot = commands.Bot(intents=intents, loop=loop) | 33 | bot = commands.Bot(intents=intents, loop=loop) |
| 37 | 34 | ||
| 38 | settings = "settings.json" | 35 | settings = "settings.json" |
| @@ -43,8 +40,6 @@ async def on_ready(): | |||
| 43 | 40 | ||
| 44 | # send the message to channel ID | 41 | # send the message to channel ID |
| 45 | channel = bot.get_channel(1081667823799111804) | 42 | channel = bot.get_channel(1081667823799111804) |
| 46 | invite = await channel.create_invite(max_age=10, max_uses=1, unique=True) | ||
| 47 | print(f"One-time invite (expires in 1 s or after 1 use): {invite.url}") | ||
| 48 | 43 | ||
| 49 | await channel.send("ŁUKASZ SPERMA AKTYWACJA") | 44 | await channel.send("ŁUKASZ SPERMA AKTYWACJA") |
| 50 | 45 | ||
