refactor: extract sentiment cog into package with shared _process_finding
Convert cogs/sentiment.py (1050 lines) into cogs/sentiment/ package: - __init__.py (656 lines): core SentimentCog with new _process_finding() that deduplicates the per-user finding loop from _process_buffered and _run_mention_scan (~90 lines each → single shared method) - actions.py: mute_user, warn_user - topic_drift.py: handle_topic_drift - channel_redirect.py: handle_channel_redirect, build_channel_context - coherence.py: handle_coherence_alert - log_utils.py: log_analysis, log_action, score_color - state.py: save_user_state, flush_dirty_states All extracted modules use plain async functions (not methods) receiving bot/config as parameters. Named log_utils.py to avoid shadowing stdlib logging. Also update CLAUDE.md with comprehensive project documentation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
54
cogs/sentiment/log_utils.py
Normal file
54
cogs/sentiment/log_utils.py
Normal file
@@ -0,0 +1,54 @@
|
||||
import logging
|
||||
|
||||
import discord
|
||||
|
||||
logger = logging.getLogger("bcs.sentiment")
|
||||
|
||||
|
||||
def score_color(score: float) -> discord.Color:
|
||||
if score >= 0.75:
|
||||
return discord.Color.red()
|
||||
if score >= 0.6:
|
||||
return discord.Color.orange()
|
||||
if score >= 0.3:
|
||||
return discord.Color.yellow()
|
||||
return discord.Color.green()
|
||||
|
||||
|
||||
async def log_analysis(
|
||||
message: discord.Message, score: float, drama_score: float,
|
||||
categories: list[str], reasoning: str, off_topic: bool, topic_category: str,
|
||||
):
|
||||
log_channel = discord.utils.get(
|
||||
message.guild.text_channels, name="bcs-log"
|
||||
)
|
||||
if not log_channel:
|
||||
return
|
||||
|
||||
# Only log notable messages (score > 0.1) to avoid spam
|
||||
if score <= 0.1:
|
||||
return
|
||||
|
||||
cat_str = ", ".join(c for c in categories if c != "none") or "none"
|
||||
embed = discord.Embed(
|
||||
title=f"Analysis: {message.author.display_name}",
|
||||
description=f"#{message.channel.name}: {message.content[:200]}",
|
||||
color=score_color(score),
|
||||
)
|
||||
embed.add_field(name="Message Score", value=f"{score:.2f}", inline=True)
|
||||
embed.add_field(name="Rolling Drama", value=f"{drama_score:.2f}", inline=True)
|
||||
embed.add_field(name="Categories", value=cat_str, inline=True)
|
||||
embed.add_field(name="Reasoning", value=reasoning[:1024] or "n/a", inline=False)
|
||||
try:
|
||||
await log_channel.send(embed=embed)
|
||||
except discord.HTTPException:
|
||||
pass
|
||||
|
||||
|
||||
async def log_action(guild: discord.Guild, text: str):
|
||||
log_channel = discord.utils.get(guild.text_channels, name="bcs-log")
|
||||
if log_channel:
|
||||
try:
|
||||
await log_channel.send(text)
|
||||
except discord.HTTPException:
|
||||
pass
|
||||
Reference in New Issue
Block a user