Fix webhook avatar mismatch: pass avatar_url at send time

- Fixed missing client parameter in animated GIF webhook update path
- Added get_persona_avatar_urls() helper that returns bot's current Discord
  avatar URL for Miku persona (always fresh, no cache lag)
- Pass avatar_url on every webhook.send() call in bipolar_mode.py,
  persona_dialogue.py, and api.py so avatars always match current pfp
  regardless of webhook cache state
This commit is contained in:
2026-02-25 13:20:18 +02:00
parent 9b74acd03b
commit 0edf1ef1c0
4 changed files with 55 additions and 13 deletions

View File

@@ -1230,11 +1230,17 @@ async def manual_send_webhook(
for file_info in file_data: for file_info in file_data:
discord_files.append(discord.File(io.BytesIO(file_info['content']), filename=file_info['filename'])) discord_files.append(discord.File(io.BytesIO(file_info['content']), filename=file_info['filename']))
# Send via webhook with display name # Get current avatar URL for the persona
from utils.bipolar_mode import get_persona_avatar_urls
avatar_urls = get_persona_avatar_urls()
avatar_url = avatar_urls.get("evil_miku") if persona == "evil" else avatar_urls.get("miku")
# Send via webhook with display name and current avatar
if discord_files: if discord_files:
await webhook.send( await webhook.send(
content=message, content=message,
username=display_name, username=display_name,
avatar_url=avatar_url,
files=discord_files, files=discord_files,
wait=True wait=True
) )
@@ -1242,6 +1248,7 @@ async def manual_send_webhook(
await webhook.send( await webhook.send(
content=message, content=message,
username=display_name, username=display_name,
avatar_url=avatar_url,
wait=True wait=True
) )

View File

@@ -259,6 +259,26 @@ def toggle_bipolar_mode() -> bool:
# WEBHOOK MANAGEMENT # WEBHOOK MANAGEMENT
# ============================================================================ # ============================================================================
def get_persona_avatar_urls() -> dict:
"""Get current avatar URLs for Miku and Evil Miku personas.
Returns a dict with 'miku' and 'evil_miku' avatar URL strings (or None).
Uses the bot's current Discord avatar for Miku (always up-to-date).
Evil Miku falls back to the webhook's stored avatar (passed as None).
"""
miku_url = None
evil_url = None
# For Miku: use the bot's actual Discord avatar URL (always matches current pfp)
if globals.client and globals.client.user:
try:
miku_url = str(globals.client.user.display_avatar.url)
except Exception:
pass
return {"miku": miku_url, "evil_miku": evil_url}
async def get_or_create_webhooks_for_channel(channel: discord.TextChannel) -> dict: async def get_or_create_webhooks_for_channel(channel: discord.TextChannel) -> dict:
"""Get or create webhooks for a channel for bipolar mode messaging """Get or create webhooks for a channel for bipolar mode messaging
@@ -887,15 +907,18 @@ async def run_argument(channel: discord.TextChannel, client, trigger_context: st
return return
# Send via webhook # Send via webhook
avatar_urls = get_persona_avatar_urls()
if initiator == "evil": if initiator == "evil":
await webhooks["evil_miku"].send( await webhooks["evil_miku"].send(
content=initial_message, content=initial_message,
username=get_evil_miku_display_name() username=get_evil_miku_display_name(),
avatar_url=avatar_urls.get("evil_miku")
) )
else: else:
await webhooks["miku"].send( await webhooks["miku"].send(
content=initial_message, content=initial_message,
username=get_miku_display_name() username=get_miku_display_name(),
avatar_url=avatar_urls.get("miku")
) )
# Add to conversation history for context # Add to conversation history for context
@@ -991,15 +1014,18 @@ async def run_argument(channel: discord.TextChannel, client, trigger_context: st
if final_message and not final_message.startswith("Error") and not final_message.startswith("Sorry"): if final_message and not final_message.startswith("Error") and not final_message.startswith("Sorry"):
# Send winner's final message via webhook # Send winner's final message via webhook
avatar_urls = get_persona_avatar_urls()
if winner == "evil": if winner == "evil":
await webhooks["evil_miku"].send( await webhooks["evil_miku"].send(
content=final_message, content=final_message,
username=get_evil_miku_display_name() username=get_evil_miku_display_name(),
avatar_url=avatar_urls.get("evil_miku")
) )
else: else:
await webhooks["miku"].send( await webhooks["miku"].send(
content=final_message, content=final_message,
username=get_miku_display_name() username=get_miku_display_name(),
avatar_url=avatar_urls.get("miku")
) )
# Record result in scoreboard with arbiter's reasoning # Record result in scoreboard with arbiter's reasoning
@@ -1057,15 +1083,18 @@ async def run_argument(channel: discord.TextChannel, client, trigger_context: st
return return
# Send via webhook # Send via webhook
avatar_urls = get_persona_avatar_urls()
if current_speaker == "evil": if current_speaker == "evil":
await webhooks["evil_miku"].send( await webhooks["evil_miku"].send(
content=response, content=response,
username=get_evil_miku_display_name() username=get_evil_miku_display_name(),
avatar_url=avatar_urls.get("evil_miku")
) )
else: else:
await webhooks["miku"].send( await webhooks["miku"].send(
content=response, content=response,
username=get_miku_display_name() username=get_miku_display_name(),
avatar_url=avatar_urls.get("miku")
) )
# Add to conversation history for context # Add to conversation history for context

View File

@@ -881,7 +881,8 @@ This pushed things over the edge into a full argument."""
from utils.bipolar_mode import ( from utils.bipolar_mode import (
get_or_create_webhooks_for_channel, get_or_create_webhooks_for_channel,
get_miku_display_name, get_miku_display_name,
get_evil_miku_display_name get_evil_miku_display_name,
get_persona_avatar_urls
) )
webhooks = await get_or_create_webhooks_for_channel(channel) webhooks = await get_or_create_webhooks_for_channel(channel)
@@ -891,9 +892,11 @@ This pushed things over the edge into a full argument."""
webhook = webhooks["evil_miku"] if persona == "evil" else webhooks["miku"] webhook = webhooks["evil_miku"] if persona == "evil" else webhooks["miku"]
display_name = get_evil_miku_display_name() if persona == "evil" else get_miku_display_name() display_name = get_evil_miku_display_name() if persona == "evil" else get_miku_display_name()
avatar_urls = get_persona_avatar_urls()
avatar_url = avatar_urls.get("evil_miku") if persona == "evil" else avatar_urls.get("miku")
try: try:
await webhook.send(content=content, username=display_name) await webhook.send(content=content, username=display_name, avatar_url=avatar_url)
except Exception as e: except Exception as e:
logger.error(f"Error sending as {persona}: {e}") logger.error(f"Error sending as {persona}: {e}")

View File

@@ -442,10 +442,13 @@ class ProfilePictureManager:
# Update bipolar webhook avatars if bipolar mode is active # Update bipolar webhook avatars if bipolar mode is active
if globals.BIPOLAR_MODE: if globals.BIPOLAR_MODE:
from bot.utils.bipolar_mode import update_webhook_avatars try:
updated = await update_webhook_avatars() from utils.bipolar_mode import update_webhook_avatars
updated = await update_webhook_avatars(globals.client)
if debug: if debug:
logger.info(f"Updated bipolar webhook avatars: {updated}") logger.info(f"Updated bipolar webhook avatars: {updated}")
except Exception as e:
logger.warning(f"Failed to update bipolar webhook avatars: {e}")
return result return result