feat: add /drama-leaderboard command with historical composite scoring
Queries Messages, AnalysisResults, and Actions tables to rank users by a composite drama score (weighted avg toxicity, peak toxicity, and action rate). Public command with configurable time period (7d/30d/90d/all-time). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -669,6 +669,78 @@ class CommandsCog(commands.Cog):
|
||||
old_mode, mode, interaction.user.display_name,
|
||||
)
|
||||
|
||||
@app_commands.command(
|
||||
name="drama-leaderboard",
|
||||
description="Show the all-time drama leaderboard for the server.",
|
||||
)
|
||||
@app_commands.describe(period="Time period to rank (default: 30d)")
|
||||
@app_commands.choices(period=[
|
||||
app_commands.Choice(name="Last 7 days", value="7d"),
|
||||
app_commands.Choice(name="Last 30 days", value="30d"),
|
||||
app_commands.Choice(name="Last 90 days", value="90d"),
|
||||
app_commands.Choice(name="All time", value="all"),
|
||||
])
|
||||
async def drama_leaderboard(
|
||||
self, interaction: discord.Interaction, period: app_commands.Choice[str] | None = None,
|
||||
):
|
||||
await interaction.response.defer()
|
||||
|
||||
period_val = period.value if period else "30d"
|
||||
if period_val == "all":
|
||||
days = None
|
||||
period_label = "All Time"
|
||||
else:
|
||||
days = int(period_val.rstrip("d"))
|
||||
period_label = f"Last {days} Days"
|
||||
|
||||
rows = await self.bot.db.get_drama_leaderboard(interaction.guild.id, days)
|
||||
if not rows:
|
||||
await interaction.followup.send(
|
||||
f"No drama data for **{period_label}**. Everyone's been suspiciously well-behaved."
|
||||
)
|
||||
return
|
||||
|
||||
# Compute composite score for each user
|
||||
scored = []
|
||||
for r in rows:
|
||||
avg_tox = r["avg_toxicity"]
|
||||
max_tox = r["max_toxicity"]
|
||||
msg_count = r["messages_analyzed"]
|
||||
action_weight = r["warnings"] + r["mutes"] * 2 + r["off_topic"] * 0.5
|
||||
action_rate = min(1.0, action_weight / msg_count * 10) if msg_count > 0 else 0.0
|
||||
composite = avg_tox * 0.4 + max_tox * 0.2 + action_rate * 0.4
|
||||
scored.append({**r, "composite": composite, "action_rate": action_rate})
|
||||
|
||||
scored.sort(key=lambda x: x["composite"], reverse=True)
|
||||
top = scored[:10]
|
||||
|
||||
medals = ["🥇", "🥈", "🥉"]
|
||||
lines = []
|
||||
for i, entry in enumerate(top):
|
||||
rank = medals[i] if i < 3 else f"`{i + 1}.`"
|
||||
|
||||
# Resolve display name from guild if possible
|
||||
member = interaction.guild.get_member(entry["user_id"])
|
||||
name = member.display_name if member else entry["username"]
|
||||
|
||||
lines.append(
|
||||
f"{rank} **{entry['composite']:.2f}** — {name}\n"
|
||||
f" Avg: {entry['avg_toxicity']:.2f} | "
|
||||
f"Peak: {entry['max_toxicity']:.2f} | "
|
||||
f"⚠️ {entry['warnings']} | "
|
||||
f"🔇 {entry['mutes']} | "
|
||||
f"📢 {entry['off_topic']}"
|
||||
)
|
||||
|
||||
embed = discord.Embed(
|
||||
title=f"Drama Leaderboard — {period_label}",
|
||||
description="\n".join(lines),
|
||||
color=discord.Color.orange(),
|
||||
)
|
||||
embed.set_footer(text=f"{len(rows)} users tracked | {sum(r['messages_analyzed'] for r in rows)} messages analyzed")
|
||||
|
||||
await interaction.followup.send(embed=embed)
|
||||
|
||||
@bcs_mode.autocomplete("mode")
|
||||
async def _mode_autocomplete(
|
||||
self, interaction: discord.Interaction, current: str,
|
||||
|
||||
Reference in New Issue
Block a user