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>
55 lines
1.6 KiB
Python
55 lines
1.6 KiB
Python
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
|