diff --git a/cogs/aimod_cog.py b/cogs/aimod_cog.py index 25c1c42..0272a95 100644 --- a/cogs/aimod_cog.py +++ b/cogs/aimod_cog.py @@ -1066,6 +1066,27 @@ class AIModerationCog(commands.Cog): embed.add_field(name="Action", value=action, inline=False) if ref: embed.add_field(name="Infraction", value=f"Message ID: {ref}", inline=False) + msg_snip = ( + target_infraction.get("message_content") if target_infraction else None + ) + if msg_snip: + embed.add_field( + name="Message Snippet", + value=f"`{msg_snip}`", + inline=False, + ) + attachments = ( + target_infraction.get("attachments") if target_infraction else None + ) + if attachments: + attach_text = "\n".join(attachments) + if len(attach_text) > 1024: + attach_text = attach_text[:1021] + "..." + embed.add_field( + name="Attachments", + value=attach_text, + inline=False, + ) embed.add_field(name="Appeal", value=reason, inline=False) embed.add_field(name="AI Review", value=ai_review[:1000], inline=False) embed.timestamp = discord.utils.utcnow() @@ -1095,6 +1116,7 @@ class AIModerationCog(commands.Cog): return appeals = get_user_appeals(interaction.guild.id, user.id) + history = get_user_infraction_history(interaction.guild.id, user.id) if not appeals: await interaction.response.send_message( f"{user.mention} has no appeals.", ephemeral=False @@ -1116,6 +1138,23 @@ class AIModerationCog(commands.Cog): ref = appeal.get("infraction_reference") if ref: value = f"Infraction: {ref}\n" + value + for infr in history: + if str(infr.get("message_id")) == str(ref): + msg_snip = infr.get("message_content") + if msg_snip: + value += f"\nSnippet: {msg_snip}" + attachments = infr.get("attachments") + if attachments: + attach_txt = ", ".join(attachments) + if len(attach_txt) > 200: + attach_txt = attach_txt[:197] + "..." + value += f"\nAttachments: {attach_txt}" + reason = infr.get("reasoning") + if reason: + if len(reason) > 150: + reason = reason[:147] + "..." + value += f"\nAI Reasoning: {reason}" + break embed.add_field(name=f"Appeal #{i} - {ts}", value=value, inline=False) await interaction.response.send_message(embed=embed, ephemeral=False) @@ -1124,7 +1163,7 @@ class AIModerationCog(commands.Cog): description="Run sample appeals through the AI review system (admin only).", ) async def appeal_testcases(self, interaction: discord.Interaction): - """Run a few hardcoded appeal scenarios through the AI.""" + """Run a few hardcoded appeal scenarios through the AI with context.""" if not interaction.user.guild_permissions.administrator: await interaction.response.send_message( "You must be an administrator to use this command.", @@ -1135,48 +1174,21 @@ class AIModerationCog(commands.Cog): await interaction.response.defer(thinking=True, ephemeral=True) scenarios = [ - ( - "Warn for spam", - "I got excited and posted too many messages.", - { - "message_id": 111111, - "channel_id": 222222, - "message_content": "Buy cheap gold now! Buy cheap gold now!", - "attachments": [], - "reasoning": "Excessive repetitive advertising.", - }, - ), - ( - "Mute for harassment", - "I was only teasing my friend and didn't mean to harass anyone.", - { - "message_id": 333333, - "channel_id": 444444, - "message_content": "You're an idiot and everyone hates you", - "attachments": [], - "reasoning": "Targeted personal insults after a warning.", - }, - ), - ( - "Ban for posting slurs", - "I'm sorry for what I said and promise it will not happen again.", - { - "message_id": 555555, - "channel_id": 666666, - "message_content": "", - "attachments": [], - "reasoning": "User used an explicit hateful slur.", - }, - ), + ("WARN", "I was excited and sent many messages quickly."), + ("MUTE", "I only quoted a meme and it was taken as harassment."), + ("BAN", "I posted NSFW art but believed it was allowed."), ] results: list[tuple[str, str]] = [] - for action, text, context in scenarios: + for idx, (action, text) in enumerate(scenarios, 1): + dummy_infraction = { + "message_id": 1000 + idx, + "channel_id": interaction.channel.id, + "message_content": f"Example offending message {idx}", + "attachments": [], + "reasoning": "Automated moderation reasoning sample", + } result = await self.run_appeal_ai( - interaction.guild, - interaction.user, - action, - text, - context, + interaction.guild, interaction.user, action, text, dummy_infraction ) results.append((action, result)) @@ -2806,50 +2818,23 @@ CRITICAL: Do NOT output anything other than the required JSON response. """Run a few hardcoded appeals through the appeal AI for testing.""" await interaction.response.defer(thinking=True, ephemeral=True) scenarios = [ - ( - "WARN", - "I was warned for spamming but I only sent a few messages quickly.", - { - "message_id": 777777, - "channel_id": 888888, - "message_content": "Check out spam.com! spam.com spam.com", - "attachments": [], - "reasoning": "User repeatedly posted unsolicited links.", - }, - ), - ( - "MUTE", - "I was muted for hate speech but it was just a meme quote, not harassment.", - { - "message_id": 999999, - "channel_id": 111222, - "message_content": "You people are ", - "attachments": [], - "reasoning": "Sent hateful slur towards a group.", - }, - ), - ( - "BAN", - "I was banned for posting NSFW art in the NSFW channel. It wasn't porn.", - { - "message_id": 333444, - "channel_id": 555666, - "message_content": "[attached image]", - "attachments": ["https://example.com/nsfw.png"], - "reasoning": "Image was real pornography in general channel.", - }, - ), + ("WARN", "I was excited and sent many messages quickly."), + ("MUTE", "I only quoted a meme and it was taken as harassment."), + ("BAN", "I posted NSFW art but believed it was allowed."), ] results = [] guild = interaction.guild - for action, text, context in scenarios: + for idx, (action, text) in enumerate(scenarios, 1): + dummy_infraction = { + "message_id": 2000 + idx, + "channel_id": interaction.channel.id, + "message_content": f"Test offending message {idx}", + "attachments": [], + "reasoning": "Initial moderation reasoning sample", + } review = await self.run_appeal_ai( - guild, - interaction.user, - action, - text, - context, + guild, interaction.user, action, text, dummy_infraction ) results.append((action, text, review))